Skip to content

Commit 1842356

Browse files
committed
scripts: ini_to_opencode.py
1 parent 2943210 commit 1842356

1 file changed

Lines changed: 109 additions & 0 deletions

File tree

scripts/ini_to_opencode.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Convert llama.cpp .ini model presets to opencode.json provider config
4+
"""
5+
6+
from __future__ import annotations
7+
8+
import json
9+
import logging
10+
import re
11+
import sys
12+
from pathlib import Path
13+
14+
logger = logging.getLogger(__name__)
15+
16+
17+
def parse_ini(content: str) -> dict:
18+
"""Parse simple INI format with sections and key-value pairs"""
19+
result = {}
20+
current_section = None
21+
22+
for line in content.split("\n"):
23+
line = line.strip()
24+
25+
# Skip empty lines and comments
26+
if not line or line.startswith(";") or line.startswith("#"):
27+
continue
28+
29+
# Section header
30+
section_match = re.match(r"^\[([^\]]+)\]$", line)
31+
if section_match:
32+
current_section = section_match.group(1)
33+
result[current_section] = {}
34+
continue
35+
36+
# Key-value pair
37+
if "=" in line and current_section:
38+
key, _, value = line.partition("=")
39+
key = key.strip()
40+
value = value.strip()
41+
result[current_section][key] = value
42+
43+
return result
44+
45+
46+
def ini_to_opencode(ini_file: str, output_file: str | None = None):
47+
"""Convert INI preset file to opencode.json"""
48+
49+
# Read and parse INI
50+
ini_path = Path(ini_file)
51+
ini_content = ini_path.read_text()
52+
ini_data = parse_ini(ini_content)
53+
54+
# Build opencode.json structure
55+
opencode_config = {
56+
"$schema": "https://opencode.ai/config.json",
57+
"provider": {
58+
"llamacpp": {
59+
"npm": "@ai-sdk/openai-compatible",
60+
"name": "llama.cpp (local)",
61+
"options": {"baseURL": "http://127.0.0.1:8080/v1", "apiKey": "no-key-needed"},
62+
"models": {},
63+
}
64+
},
65+
}
66+
67+
# Map INI presets to opencode models
68+
# Skip global section [*] and version
69+
for section_name, settings in ini_data.items():
70+
if section_name == "[*]" or section_name == "version":
71+
continue
72+
73+
model_id = section_name.lower().replace(" ", "-").replace(":", "-")
74+
model_config = {"name": section_name}
75+
76+
# Map common INI options to opencode/llama.cpp server settings
77+
if "model" in settings:
78+
model_config["model"] = settings["model"]
79+
80+
if "n-gpu-layer" in settings or "n-gpu-layers" in settings:
81+
gpu_layer = settings.get("n-gpu-layer") or settings.get("n-gpu-layers")
82+
model_config["n_gpu_layers"] = gpu_layer
83+
84+
if "c" in settings:
85+
model_config["context_size"] = settings["c"]
86+
87+
if "chat-template" in settings:
88+
model_config["chat_template"] = settings["chat-template"]
89+
90+
if "jinja" in settings:
91+
model_config["jinja"] = settings["jinja"].lower() == "true"
92+
93+
opencode_config["provider"]["llamacpp"]["models"][model_id] = model_config
94+
95+
# Write output
96+
output_path = Path(output_file) if output_file else ini_path.with_suffix(".json")
97+
output_path.write_text(json.dumps(opencode_config, indent=2) + "\n")
98+
99+
logger.info(json.dumps(opencode_config, indent=2))
100+
101+
102+
if __name__ == "__main__":
103+
logging.basicConfig(level=logging.INFO, format="%(message)s")
104+
105+
if len(sys.argv) < 2:
106+
logger.error("Usage: python3 ini_to_opencode.py <input.ini> [output.json]")
107+
sys.exit(1)
108+
109+
ini_to_opencode(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else None)

0 commit comments

Comments
 (0)