Skip to content

Commit 4510c2a

Browse files
committed
revert family→model/variant rename; add (family, version, variant) tags
config + :model + -m use `model` (the API string, possibly shortened to portion after last slash). Internally Profile carries `family`, `version`, `variant` from a hardcoded known-good lookup. KnownGoodCombos is now a 5-tuple. No :variant command. commonModelPrefix handles single-model providers. bump 0.2.3
1 parent 80627fc commit 4510c2a

11 files changed

Lines changed: 261 additions & 221 deletions

File tree

‎config.example‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,35 @@ current = "baseten.glm5"
1212
name = "baseten"
1313
url = "https://inference.baseten.co/v1"
1414
key = "..."
15-
models = "glm5, qwen3c"
15+
models = "glm5 qwen3c"
1616

1717
[provider]
1818
name = "openai"
1919
url = "https://api.openai.com/v1"
2020
key = "sk-..."
21-
models = "gpt-4o-mini, gpt-4o"
21+
models = "gpt-4o-mini gpt-4o"
2222

2323
[provider]
2424
name = "groq"
2525
url = "https://api.groq.com/openai/v1"
2626
key = "gsk_..."
27-
models = "llama-3.3-70b-versatile, llama-3.1-8b-instant"
27+
models = "llama-3.3-70b-versatile llama-3.1-8b-instant"
2828

2929
[provider]
3030
name = "together"
3131
url = "https://api.together.xyz/v1"
3232
key = "..."
33-
models = "meta-llama/Llama-3.3-70B-Instruct-Turbo"
33+
model_prefix = "meta-llama/"
34+
models = "Llama-3.3-70B-Instruct-Turbo"
3435

35-
# Optional per-provider `mode` selects the agent protocol:
36-
# tools (default) — OpenAI tool_calls; harness sends a tool schema
37-
# text — model emits fenced ```bash / path-then-fence / SEARCH/
38-
# REPLACE blocks; harness parses them. No schema sent.
39-
# The `:mode [text|tools]` REPL command toggles per-session for experiments.
36+
# `family` is an experimental-only override (only honored under
37+
# `--experimental`) that picks the system-prompt branch by family
38+
# name, when the (provider, model) combo isn't on the known-good
39+
# list. Known-good combos ignore it.
4040
;
4141
; [provider]
4242
; name = "deepseek"
4343
; url = "https://api.deepseek.com/v1"
4444
; key = "..."
45-
; mode = "text"
45+
; family = "deepseek"
4646
; models = "deepseek-chat"

‎src/threecode.nim‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ proc runTurns*(p: Profile, messages: var JsonNode, session: var Session) =
2323
stdout.styledWriteLine styleDim, " · interrupted", resetStyle
2424
interrupted = false
2525
return
26-
let window = contextWindowFor(p.variant)
26+
let window = contextWindowFor(p.model)
2727
var summarized = 0
2828
case decideContextAction(usage.promptTokens, window, messages.len)
2929
of caSummarize:
@@ -86,7 +86,7 @@ proc runTurns*(p: Profile, messages: var JsonNode, session: var Session) =
8686
stderr.writeLine "3code: tool_call " & name &
8787
" has malformed arguments JSON (" & e.msg & "): " & argsStr
8888
newJObject()
89-
let act = toolCallToAction(p.model, name, args)
89+
let act = toolCallToAction(p.family, name, args)
9090
let idx = session.toolLog.len + 1
9191
let silent = isSkillRead(act)
9292
# Pre-exec: dim bullet + dim banner text — "in flight" signal. After
@@ -332,7 +332,7 @@ proc main() =
332332
&"({messages.len} msg" & (if messages.len == 1: "" else: "s") & ")",
333333
resetStyle
334334
stdout.write "\n"
335-
replaySessionTail(messages, session.toolLog, prof.model)
335+
replaySessionTail(messages, session.toolLog, prof.family)
336336
stdout.write "\n"
337337
if prompt != "":
338338
messages.add %*{"role": "user", "content": buildUserMessage(messages, prompt)}

‎src/threecode/actions.nim‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ import types, util, shell
1414
# runAction returns a clean error rather than crashing.
1515
# ---------------------------------------------------------------------------
1616

17-
proc unknownTool(model, name: string): Action =
17+
proc unknownTool(family, name: string): Action =
1818
Action(kind: akBash,
19-
body: "echo 'tool not offered to model " & model & ": " & name &
19+
body: "echo 'tool not offered to family " & family & ": " & name &
2020
"' >&2; exit 1")
2121

2222
proc dispatchGlmOrQwen(name: string, args: JsonNode): Action =
@@ -58,14 +58,14 @@ proc dispatchGptOss(rawName: string, args: JsonNode): Action =
5858
else:
5959
unknownTool("gpt-oss", rawName)
6060

61-
proc toolCallToAction*(model, name: string, args: JsonNode): Action =
62-
## Routes a tool_call to the dispatcher for the active model. The model
63-
## label comes from `Profile.model` ("glm" / "qwen" / "gpt-oss"); the
61+
proc toolCallToAction*(family, name: string, args: JsonNode): Action =
62+
## Routes a tool_call to the dispatcher for the active family. The family
63+
## label comes from `Profile.family` ("glm" / "qwen" / "gpt-oss"); the
6464
## case statement below mirrors `setup` in `prompts.nim`.
65-
case model
65+
case family
6666
of "glm", "qwen", "deepseek": dispatchGlmOrQwen(name, args)
6767
of "gpt-oss": dispatchGptOss(name, args)
68-
else: die "unknown model in tool dispatch: '" & model & "'"
68+
else: die "unknown family in tool dispatch: '" & family & "'"
6969

7070
proc nearestLineHint(content, search: string): string =
7171
## When a patch search block didn't match, point the model at the most

‎src/threecode/api.nim‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ template hint(args: varargs[untyped]) =
504504
proc callModel*(p: Profile, messages: JsonNode, usage: var Usage, lastPromptTokens: int): JsonNode =
505505
ensureReasoningField(messages)
506506
var body = %*{
507-
"model": p.variantPrefix & p.variant,
507+
"model": p.modelPrefix & p.model,
508508
"messages": messages,
509509
"stream": true,
510510
"stream_options": {"include_usage": true}
@@ -515,7 +515,7 @@ proc callModel*(p: Profile, messages: JsonNode, usage: var Usage, lastPromptToke
515515
let t0 = epochTime()
516516
decayLevel(serverRetryLevel, serverLastTs, t0)
517517
decayLevel(rateRetryLevel, rateLastTs, t0)
518-
let window = contextWindowFor(p.variant)
518+
let window = contextWindowFor(p.model)
519519
let baseLabel = contextLabel(lastPromptTokens, window)
520520
# Blank line above the upcoming spinner / bullet so the assistant
521521
# output isn't flush against the prior content (user prompt or last
@@ -619,7 +619,7 @@ proc verifyProfile*(p: Profile): (bool, string) =
619619
"Content-Type": "application/json"
620620
})
621621
let body = $(%*{
622-
"model": p.variantPrefix & p.variant,
622+
"model": p.modelPrefix & p.model,
623623
"messages": [%*{"role": "user", "content": "ping"}],
624624
"max_tokens": 1,
625625
"stream": false
@@ -636,9 +636,9 @@ proc verifyProfile*(p: Profile): (bool, string) =
636636
except CatchableError as e:
637637
return (false, e.msg)
638638

639-
proc fetchVariants*(url, key: string): seq[string] =
639+
proc fetchModels*(url, key: string): seq[string] =
640640
## GET /models on the provider — that endpoint name is OpenAI's; what it
641-
## returns is the list of variant ids this provider exposes.
641+
## returns is the list of model ids this provider exposes.
642642
let client = newHttpClient(timeout = 20000)
643643
defer: client.close()
644644
client.headers = newHttpHeaders({"Authorization": "Bearer " & key})

‎src/threecode/compact.nim‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ const
77
CompactedMarker* = "[compacted — tool output elided; use :show to view]"
88
SupersededMarker* = "[superseded — later action on same path elided this]"
99

10-
proc contextWindowFor*(variant: string): int =
11-
## Heuristic: substring match on well-known variant slugs. Cheap, and no
10+
proc contextWindowFor*(model: string): int =
11+
## Heuristic: substring match on well-known model slugs. Cheap, and no
1212
## known collisions exist in practice. Update if a provider ships a
13-
## colliding variant name.
14-
let m = variant.toLowerAscii
13+
## colliding model name.
14+
let m = model.toLowerAscii
1515
if "kimi-k2" in m: 128_000
1616
elif "qwen3-coder" in m or "qwen3_coder" in m: 262_144
1717
elif "qwen" in m: 128_000
@@ -184,7 +184,7 @@ proc applySummary*(messages: JsonNode, summary: string,
184184
proc callSummarizer(p: Profile, messages: JsonNode): string =
185185
## Fires a single meta-call to the model with a dedicated summarizer
186186
## system prompt and no tools. Returns "" on any failure.
187-
if p.name == "" or p.url == "" or p.key == "" or p.variant == "": return ""
187+
if p.name == "" or p.url == "" or p.key == "" or p.model == "": return ""
188188
# Build a trimmed payload: the summarizer prompt + every non-system
189189
# message from the live conversation. Tool_call messages are allowed —
190190
# most OpenAI-compatible providers accept them in chat completions even
@@ -205,7 +205,7 @@ proc callSummarizer(p: Profile, messages: JsonNode): string =
205205
"Content-Type": "application/json"
206206
})
207207
let body = %*{
208-
"model": p.variantPrefix & p.variant,
208+
"model": p.modelPrefix & p.model,
209209
"messages": payload,
210210
"max_tokens": SummarizeMaxTokens,
211211
"stream": false

0 commit comments

Comments
 (0)