@sayknow-cli/coding-agent 0.5.26 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/dist/types/config/settings-schema.d.ts +25 -5
- package/dist/types/decisions/keyword-learning.d.ts +61 -0
- package/dist/types/decisions/llm-backend.d.ts +13 -1
- package/dist/types/decisions/prompt-triage.d.ts +42 -0
- package/dist/types/decisions/skill-routing.d.ts +41 -6
- package/dist/types/hooks/native-prompt-routing.d.ts +21 -0
- package/dist/types/hooks/native-skill-hook.d.ts +3 -0
- package/dist/types/hooks/skill-keywords.d.ts +9 -0
- package/dist/types/hooks/skill-state.d.ts +20 -3
- package/dist/types/hooks/ui-skill-keywords.d.ts +15 -0
- package/dist/types/sdk/session.d.ts +3 -13
- package/dist/types/session/agent-session.d.ts +8 -0
- package/dist/types/session/auth-storage-discovery.d.ts +13 -0
- package/dist/types/tools/browser.d.ts +2 -2
- package/package.json +7 -7
- package/scripts/eval-skill-routing.ts +37 -12
- package/src/config/model-profiles.ts +19 -1
- package/src/config/settings-schema.ts +27 -5
- package/src/decisions/index.ts +8 -2
- package/src/decisions/keyword-learning.ts +678 -0
- package/src/decisions/llm-backend.ts +213 -67
- package/src/decisions/prompt-triage.ts +163 -0
- package/src/decisions/skill-routing.ts +39 -56
- package/src/decisions/typesafe-backend.ts +3 -0
- package/src/hooks/native-prompt-routing.ts +190 -0
- package/src/hooks/native-skill-hook.ts +21 -12
- package/src/hooks/skill-keywords.ts +9 -0
- package/src/hooks/skill-state.ts +41 -10
- package/src/hooks/ui-skill-keywords.ts +67 -10
- package/src/internal-urls/docs-index.generated.ts +2 -2
- package/src/sdk/session.ts +5 -82
- package/src/session/agent-session.ts +137 -37
- package/src/session/auth-storage-discovery.ts +83 -0
|
@@ -141,6 +141,21 @@ export const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[] = [
|
|
|
141
141
|
critic: "anthropic/claude-opus-5:high",
|
|
142
142
|
architect: "anthropic/claude-opus-5:xhigh",
|
|
143
143
|
}),
|
|
144
|
+
/**
|
|
145
|
+
* Opus 5.5 is a separate preset instead of a bump of `claude-opus`, because its
|
|
146
|
+
* envelope differs: it costs less than Opus 5 ($4/$20 vs $5/$25) at the same
|
|
147
|
+
* 1M context / 128K output, and it accepts the `max` adaptive level. So the deep
|
|
148
|
+
* lanes are pushed one notch above the Opus 5 preset (`architect` at `max`,
|
|
149
|
+
* `planner` at `medium` instead of `low`) while the mechanical executor lane
|
|
150
|
+
* stays on Sonnet 5. Anyone who wants the old cost/effort shape keeps `claude-opus`.
|
|
151
|
+
*/
|
|
152
|
+
profile("claude-opus-5-5", ["anthropic"], {
|
|
153
|
+
default: "anthropic/claude-opus-5-5:xhigh",
|
|
154
|
+
executor: "anthropic/claude-sonnet-5",
|
|
155
|
+
planner: "anthropic/claude-opus-5-5:medium",
|
|
156
|
+
critic: "anthropic/claude-opus-5-5:high",
|
|
157
|
+
architect: "anthropic/claude-opus-5-5:max",
|
|
158
|
+
}),
|
|
144
159
|
profile("claude-fable", ["anthropic"], {
|
|
145
160
|
default: "anthropic/claude-fable-5:xhigh",
|
|
146
161
|
executor: "anthropic/claude-sonnet-5",
|
|
@@ -402,6 +417,7 @@ const PROFILE_PRESENTATION: Record<string, ModelProfilePresentation> = {
|
|
|
402
417
|
},
|
|
403
418
|
opencodego: { displayName: "OpenCodeGo", providerGroup: "OPENCODEGO" },
|
|
404
419
|
"claude-opus": { displayName: "Claude Opus", providerGroup: "CLAUDE" },
|
|
420
|
+
"claude-opus-5-5": { displayName: "Claude Opus 5.5", providerGroup: "CLAUDE" },
|
|
405
421
|
"claude-fable": { displayName: "Claude Fable", providerGroup: "CLAUDE" },
|
|
406
422
|
"glm-eco": { displayName: "GLM Eco", providerGroup: "GLM" },
|
|
407
423
|
"glm-medium": { displayName: "GLM Medium", providerGroup: "GLM" },
|
|
@@ -460,7 +476,9 @@ const MACOS_OMLX_PROFILE_RANK = new Map<string, number>(MACOS_OMLX_PROFILE_ORDER
|
|
|
460
476
|
|
|
461
477
|
const PROFILE_RECOMMENDATIONS: Record<string, string> = {
|
|
462
478
|
"openai-codex": "codex-medium",
|
|
463
|
-
|
|
479
|
+
// Newest Anthropic flagship, and cheaper per token than the Opus 5 preset it
|
|
480
|
+
// replaces here. `claude-opus` stays selectable for the older cost/effort shape.
|
|
481
|
+
anthropic: "claude-opus-5-5",
|
|
464
482
|
"opencode-go": "opencodego",
|
|
465
483
|
zai: "glm-medium",
|
|
466
484
|
"kimi-code": "kimi-coding-plan-medium",
|
|
@@ -2008,12 +2008,32 @@ export const SETTINGS_SCHEMA = {
|
|
|
2008
2008
|
// Typed decisions
|
|
2009
2009
|
"decisions.enabled": {
|
|
2010
2010
|
type: "boolean",
|
|
2011
|
-
default:
|
|
2011
|
+
default: true,
|
|
2012
2012
|
ui: {
|
|
2013
2013
|
tab: "context",
|
|
2014
2014
|
label: "Typed decisions",
|
|
2015
2015
|
description:
|
|
2016
|
-
"
|
|
2016
|
+
"Model-backed second stage for workflow routing. The keyword table runs first on every turn and costs nothing; this handles the phrasings it cannot express, which is most wording that is not a literal match. Costs one small model call, only on turns the keyword table did not already answer, on the cheapest backend available: TypeSafe when a key is stored, else a local runtime that is running, else the small model of the provider you are chatting with. Any failure falls back to keyword-only behaviour, but a successful answer can also select a different workflow than the deep-interview ambiguity detector would have. Turn off to route on the keyword table alone.",
|
|
2017
|
+
},
|
|
2018
|
+
},
|
|
2019
|
+
|
|
2020
|
+
/**
|
|
2021
|
+
* Feed routing answers back into the deterministic keyword table.
|
|
2022
|
+
*
|
|
2023
|
+
* The hand-written table cannot be grown by hand for Korean — measured recall
|
|
2024
|
+
* was 0/9 — so it grows itself instead: a two-stem pattern that produced the
|
|
2025
|
+
* same routing answer on two distinct prompts, and was never contradicted, is
|
|
2026
|
+
* promoted and thereafter fires for free. One contradiction retracts it
|
|
2027
|
+
* permanently. Stems and hashes are stored; prompt text never is.
|
|
2028
|
+
*/
|
|
2029
|
+
"decisions.keywordLearning": {
|
|
2030
|
+
type: "boolean",
|
|
2031
|
+
default: true,
|
|
2032
|
+
ui: {
|
|
2033
|
+
tab: "context",
|
|
2034
|
+
label: "Learn routing keywords",
|
|
2035
|
+
description:
|
|
2036
|
+
"Remember the phrasings the routing model resolves, so repeating one stops costing a model call. A pattern must give the same answer on two different prompts before it fires on its own, and a single disagreement removes it for good. Only word stems and hashes are written to disk, never your prompts. Turn off to keep the keyword table frozen at its built-in entries.",
|
|
2017
2037
|
},
|
|
2018
2038
|
},
|
|
2019
2039
|
|
|
@@ -2026,12 +2046,14 @@ export const SETTINGS_SCHEMA = {
|
|
|
2026
2046
|
* mid-session invalidates the prompt cache, which on a long context costs
|
|
2027
2047
|
* more than the cheaper tier saves.
|
|
2028
2048
|
*
|
|
2029
|
-
* Needs `decisions.enabled` and at least two tiers configured.
|
|
2030
|
-
*
|
|
2049
|
+
* Needs `decisions.enabled` and at least two tiers configured. The tiers are
|
|
2050
|
+
* empty by default, so this is a no-op until the user sets them — which is why
|
|
2051
|
+
* it defaults on: shipping it off meant the routing code existed and never ran
|
|
2052
|
+
* even for users who had configured the tiers it needs.
|
|
2031
2053
|
*/
|
|
2032
2054
|
"task.modelRouting.enabled": {
|
|
2033
2055
|
type: "boolean",
|
|
2034
|
-
default:
|
|
2056
|
+
default: true,
|
|
2035
2057
|
ui: {
|
|
2036
2058
|
tab: "tasks",
|
|
2037
2059
|
label: "Route subagent models per task",
|
package/src/decisions/index.ts
CHANGED
|
@@ -43,8 +43,9 @@ export function createDecisionService(options: DecisionServiceOptions): Decision
|
|
|
43
43
|
* probabilities, and it resolves `null` immediately when no key is stored, so users
|
|
44
44
|
* who never added one pay nothing for it being in the list.
|
|
45
45
|
*
|
|
46
|
-
* The user's logged-in
|
|
47
|
-
* vendor, no extra key, works offline of TypeSafe entirely.
|
|
46
|
+
* The user's logged-in provider is the fallback and the default experience: no extra
|
|
47
|
+
* vendor, no extra key, works offline of TypeSafe entirely. Inside it, a live local
|
|
48
|
+
* runtime is tried before a hosted small model; see `llm-backend.ts`.
|
|
48
49
|
*/
|
|
49
50
|
const backends = options.backends ?? [createTypeSafeDecisionBackend(options), createLlmDecisionBackend(options)];
|
|
50
51
|
|
|
@@ -53,6 +54,11 @@ export function createDecisionService(options: DecisionServiceOptions): Decision
|
|
|
53
54
|
async decide(request: DecisionRequest): Promise<DecisionResult | null> {
|
|
54
55
|
if (!enabled || backends.length === 0) return null;
|
|
55
56
|
for (const backend of backends) {
|
|
57
|
+
// A listener added to a signal that already fired never runs, and the
|
|
58
|
+
// backends only read their own derived signal. Measured: a caller that
|
|
59
|
+
// aborted during the previous backend's await got a full attempt budget of
|
|
60
|
+
// silence from the next one instead of an immediate null.
|
|
61
|
+
if (request.signal?.aborted) return null;
|
|
56
62
|
const controller = new AbortController();
|
|
57
63
|
const abortOnCallerSignal = () => controller.abort();
|
|
58
64
|
request.signal?.addEventListener("abort", abortOnCallerSignal, { once: true });
|