@duetso/agent 0.2.2 → 0.2.3
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/README.md +19 -11
- package/dist/package.json +4 -4
- package/dist/src/cli/config.d.ts +10 -0
- package/dist/src/cli/config.d.ts.map +1 -0
- package/dist/src/cli/config.js +24 -0
- package/dist/src/cli/config.js.map +1 -0
- package/dist/src/cli/help.d.ts.map +1 -1
- package/dist/src/cli/help.js +11 -9
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/inline-slash.d.ts +2 -1
- package/dist/src/cli/inline-slash.d.ts.map +1 -1
- package/dist/src/cli/inline-slash.js +14 -5
- package/dist/src/cli/inline-slash.js.map +1 -1
- package/dist/src/cli/memory-query.d.ts +1 -1
- package/dist/src/cli/model.d.ts +1 -1
- package/dist/src/cli/model.d.ts.map +1 -1
- package/dist/src/cli/model.js +1 -1
- package/dist/src/cli/model.js.map +1 -1
- package/dist/src/cli/route.d.ts +84 -0
- package/dist/src/cli/route.d.ts.map +1 -0
- package/dist/src/cli/route.js +261 -0
- package/dist/src/cli/route.js.map +1 -0
- package/dist/src/cli/rpc.d.ts +43 -2
- package/dist/src/cli/rpc.d.ts.map +1 -1
- package/dist/src/cli/rpc.js +176 -23
- package/dist/src/cli/rpc.js.map +1 -1
- package/dist/src/cli/run.d.ts +8 -1
- package/dist/src/cli/run.d.ts.map +1 -1
- package/dist/src/cli/run.js +24 -7
- package/dist/src/cli/run.js.map +1 -1
- package/dist/src/cli/shared.d.ts +4 -3
- package/dist/src/cli/shared.d.ts.map +1 -1
- package/dist/src/cli/shared.js +3 -4
- package/dist/src/cli/shared.js.map +1 -1
- package/dist/src/cli/shutdown.d.ts +4 -2
- package/dist/src/cli/shutdown.d.ts.map +1 -1
- package/dist/src/cli/shutdown.js +4 -2
- package/dist/src/cli/shutdown.js.map +1 -1
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +12 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/core/structured-output.d.ts +2 -0
- package/dist/src/core/structured-output.d.ts.map +1 -1
- package/dist/src/core/structured-output.js +1 -0
- package/dist/src/core/structured-output.js.map +1 -1
- package/dist/src/lib/system-reminder.d.ts +14 -0
- package/dist/src/lib/system-reminder.d.ts.map +1 -0
- package/dist/src/lib/system-reminder.js +53 -0
- package/dist/src/lib/system-reminder.js.map +1 -0
- package/dist/src/lib/walk-ancestors.d.ts +9 -0
- package/dist/src/lib/walk-ancestors.d.ts.map +1 -0
- package/dist/src/lib/walk-ancestors.js +28 -0
- package/dist/src/lib/walk-ancestors.js.map +1 -0
- package/dist/src/memory/observational-prompts.d.ts.map +1 -1
- package/dist/src/memory/observational-prompts.js +2 -1
- package/dist/src/memory/observational-prompts.js.map +1 -1
- package/dist/src/memory/observational.d.ts +31 -4
- package/dist/src/memory/observational.d.ts.map +1 -1
- package/dist/src/memory/observational.js +43 -4
- package/dist/src/memory/observational.js.map +1 -1
- package/dist/src/model-resolution/catalog.d.ts +2 -2
- package/dist/src/model-resolution/catalog.d.ts.map +1 -1
- package/dist/src/model-resolution/catalog.js +61 -33
- package/dist/src/model-resolution/catalog.js.map +1 -1
- package/dist/src/model-resolution/duet-gateway.d.ts +3 -3
- package/dist/src/model-resolution/duet-gateway.d.ts.map +1 -1
- package/dist/src/model-resolution/duet-gateway.js +119 -19
- package/dist/src/model-resolution/duet-gateway.js.map +1 -1
- package/dist/src/model-resolution/model-gateway.d.ts.map +1 -0
- package/dist/src/{cli → model-resolution}/model-gateway.js +10 -6
- package/dist/src/model-resolution/model-gateway.js.map +1 -0
- package/dist/src/model-resolution/resolver.d.ts +11 -4
- package/dist/src/model-resolution/resolver.d.ts.map +1 -1
- package/dist/src/model-resolution/resolver.js +39 -8
- package/dist/src/model-resolution/resolver.js.map +1 -1
- package/dist/src/model-routing/advisor-transcript.d.ts +36 -0
- package/dist/src/model-routing/advisor-transcript.d.ts.map +1 -0
- package/dist/src/model-routing/advisor-transcript.js +103 -0
- package/dist/src/model-routing/advisor-transcript.js.map +1 -0
- package/dist/src/model-routing/advisor.d.ts +27 -0
- package/dist/src/model-routing/advisor.d.ts.map +1 -0
- package/dist/src/model-routing/advisor.js +20 -0
- package/dist/src/model-routing/advisor.js.map +1 -0
- package/dist/src/model-routing/classifier.d.ts +57 -0
- package/dist/src/model-routing/classifier.d.ts.map +1 -0
- package/dist/src/model-routing/classifier.js +63 -0
- package/dist/src/model-routing/classifier.js.map +1 -0
- package/dist/src/model-routing/loader.d.ts +48 -0
- package/dist/src/model-routing/loader.d.ts.map +1 -0
- package/dist/src/model-routing/loader.js +79 -0
- package/dist/src/model-routing/loader.js.map +1 -0
- package/dist/src/model-routing/prompts.d.ts +22 -0
- package/dist/src/model-routing/prompts.d.ts.map +1 -0
- package/dist/src/model-routing/prompts.js +87 -0
- package/dist/src/model-routing/prompts.js.map +1 -0
- package/dist/src/model-routing/resolve.d.ts +40 -0
- package/dist/src/model-routing/resolve.d.ts.map +1 -0
- package/dist/src/model-routing/resolve.js +76 -0
- package/dist/src/model-routing/resolve.js.map +1 -0
- package/dist/src/model-routing/router.d.ts +149 -0
- package/dist/src/model-routing/router.d.ts.map +1 -0
- package/dist/src/model-routing/router.js +235 -0
- package/dist/src/model-routing/router.js.map +1 -0
- package/dist/src/model-routing/step-triggers.d.ts +27 -0
- package/dist/src/model-routing/step-triggers.d.ts.map +1 -0
- package/dist/src/model-routing/step-triggers.js +20 -0
- package/dist/src/model-routing/step-triggers.js.map +1 -0
- package/dist/src/model-routing/table.d.ts +126 -0
- package/dist/src/model-routing/table.d.ts.map +1 -0
- package/dist/src/model-routing/table.js +351 -0
- package/dist/src/model-routing/table.js.map +1 -0
- package/dist/src/session/session.d.ts +40 -23
- package/dist/src/session/session.d.ts.map +1 -1
- package/dist/src/session/session.js +173 -97
- package/dist/src/session/session.js.map +1 -1
- package/dist/src/tasks/quiescence.d.ts +13 -0
- package/dist/src/tasks/quiescence.d.ts.map +1 -0
- package/dist/src/tasks/quiescence.js +11 -0
- package/dist/src/tasks/quiescence.js.map +1 -0
- package/dist/src/tasks/task-manager.d.ts +101 -0
- package/dist/src/tasks/task-manager.d.ts.map +1 -0
- package/dist/src/tasks/task-manager.js +311 -0
- package/dist/src/tasks/task-manager.js.map +1 -0
- package/dist/src/tasks/types.d.ts +85 -0
- package/dist/src/tasks/types.d.ts.map +1 -0
- package/dist/src/tasks/types.js +2 -0
- package/dist/src/tasks/types.js.map +1 -0
- package/dist/src/tui/app.d.ts +1 -1
- package/dist/src/tui/app.d.ts.map +1 -1
- package/dist/src/tui/app.js +12 -2
- package/dist/src/tui/app.js.map +1 -1
- package/dist/src/tui/initial-prompt.d.ts.map +1 -1
- package/dist/src/tui/initial-prompt.js +0 -3
- package/dist/src/tui/initial-prompt.js.map +1 -1
- package/dist/src/tui/session-subscription.d.ts +3 -0
- package/dist/src/tui/session-subscription.d.ts.map +1 -1
- package/dist/src/tui/session-subscription.js +29 -5
- package/dist/src/tui/session-subscription.js.map +1 -1
- package/dist/src/tui/sidebar.d.ts +3 -0
- package/dist/src/tui/sidebar.d.ts.map +1 -1
- package/dist/src/tui/sidebar.js +19 -3
- package/dist/src/tui/sidebar.js.map +1 -1
- package/dist/src/tui/slash-commands.d.ts +12 -9
- package/dist/src/tui/slash-commands.d.ts.map +1 -1
- package/dist/src/tui/slash-commands.js +48 -10
- package/dist/src/tui/slash-commands.js.map +1 -1
- package/dist/src/tui/status-controller.d.ts +14 -9
- package/dist/src/tui/status-controller.d.ts.map +1 -1
- package/dist/src/tui/status-controller.js +26 -7
- package/dist/src/tui/status-controller.js.map +1 -1
- package/dist/src/tui/task-lane-renderer.d.ts +30 -0
- package/dist/src/tui/task-lane-renderer.d.ts.map +1 -0
- package/dist/src/tui/task-lane-renderer.js +93 -0
- package/dist/src/tui/task-lane-renderer.js.map +1 -0
- package/dist/src/tui/task-tree.d.ts +47 -0
- package/dist/src/tui/task-tree.d.ts.map +1 -0
- package/dist/src/tui/task-tree.js +190 -0
- package/dist/src/tui/task-tree.js.map +1 -0
- package/dist/src/tui/tool-formatters.js +3 -0
- package/dist/src/tui/tool-formatters.js.map +1 -1
- package/dist/src/turn-runner/agent-events.d.ts.map +1 -1
- package/dist/src/turn-runner/agent-events.js +1 -0
- package/dist/src/turn-runner/agent-events.js.map +1 -1
- package/dist/src/turn-runner/duration.d.ts +2 -2
- package/dist/src/turn-runner/duration.js +3 -3
- package/dist/src/turn-runner/duration.js.map +1 -1
- package/dist/src/turn-runner/prompts.d.ts +5 -1
- package/dist/src/turn-runner/prompts.d.ts.map +1 -1
- package/dist/src/turn-runner/prompts.js +30 -6
- package/dist/src/turn-runner/prompts.js.map +1 -1
- package/dist/src/turn-runner/runtime-clock.d.ts +20 -0
- package/dist/src/turn-runner/runtime-clock.d.ts.map +1 -0
- package/dist/src/turn-runner/runtime-clock.js +38 -0
- package/dist/src/turn-runner/runtime-clock.js.map +1 -0
- package/dist/src/turn-runner/shell-state-handle.d.ts +0 -3
- package/dist/src/turn-runner/shell-state-handle.d.ts.map +1 -1
- package/dist/src/turn-runner/shell-state-handle.js +5 -55
- package/dist/src/turn-runner/shell-state-handle.js.map +1 -1
- package/dist/src/turn-runner/skill-context.d.ts +6 -7
- package/dist/src/turn-runner/skill-context.d.ts.map +1 -1
- package/dist/src/turn-runner/skill-context.js +10 -10
- package/dist/src/turn-runner/skill-context.js.map +1 -1
- package/dist/src/turn-runner/skills.d.ts.map +1 -1
- package/dist/src/turn-runner/skills.js +2 -22
- package/dist/src/turn-runner/skills.js.map +1 -1
- package/dist/src/turn-runner/state-compaction.d.ts +7 -5
- package/dist/src/turn-runner/state-compaction.d.ts.map +1 -1
- package/dist/src/turn-runner/state-compaction.js +69 -10
- package/dist/src/turn-runner/state-compaction.js.map +1 -1
- package/dist/src/turn-runner/state-machine-decisions.d.ts +135 -0
- package/dist/src/turn-runner/state-machine-decisions.d.ts.map +1 -0
- package/dist/src/turn-runner/state-machine-decisions.js +443 -0
- package/dist/src/turn-runner/state-machine-decisions.js.map +1 -0
- package/dist/src/turn-runner/state-machine-session.d.ts +13 -28
- package/dist/src/turn-runner/state-machine-session.d.ts.map +1 -1
- package/dist/src/turn-runner/state-machine-session.js +18 -55
- package/dist/src/turn-runner/state-machine-session.js.map +1 -1
- package/dist/src/turn-runner/subagent.d.ts +156 -0
- package/dist/src/turn-runner/subagent.d.ts.map +1 -0
- package/dist/src/turn-runner/subagent.js +164 -0
- package/dist/src/turn-runner/subagent.js.map +1 -0
- package/dist/src/turn-runner/task-tools.d.ts +76 -0
- package/dist/src/turn-runner/task-tools.d.ts.map +1 -0
- package/dist/src/turn-runner/task-tools.js +370 -0
- package/dist/src/turn-runner/task-tools.js.map +1 -0
- package/dist/src/turn-runner/tools.d.ts +65 -17
- package/dist/src/turn-runner/tools.d.ts.map +1 -1
- package/dist/src/turn-runner/tools.js +173 -59
- package/dist/src/turn-runner/tools.js.map +1 -1
- package/dist/src/turn-runner/turn-runner.d.ts +198 -134
- package/dist/src/turn-runner/turn-runner.d.ts.map +1 -1
- package/dist/src/turn-runner/turn-runner.js +1302 -713
- package/dist/src/turn-runner/turn-runner.js.map +1 -1
- package/dist/src/turn-runner/usage-accounting.d.ts +4 -0
- package/dist/src/turn-runner/usage-accounting.d.ts.map +1 -1
- package/dist/src/turn-runner/usage-accounting.js +19 -0
- package/dist/src/turn-runner/usage-accounting.js.map +1 -1
- package/dist/src/types/config.d.ts +9 -1
- package/dist/src/types/config.d.ts.map +1 -1
- package/dist/src/types/config.js +2 -1
- package/dist/src/types/config.js.map +1 -1
- package/dist/src/types/protocol.d.ts +110 -30
- package/dist/src/types/protocol.d.ts.map +1 -1
- package/dist/src/types/state-machine.d.ts +10 -12
- package/dist/src/types/state-machine.d.ts.map +1 -1
- package/dist/src/types/state-machine.js.map +1 -1
- package/package.json +4 -4
- package/dist/src/cli/model-gateway.d.ts.map +0 -1
- package/dist/src/cli/model-gateway.js.map +0 -1
- package/dist/src/turn-runner/state-machine-controller.d.ts +0 -140
- package/dist/src/turn-runner/state-machine-controller.d.ts.map +0 -1
- package/dist/src/turn-runner/state-machine-controller.js +0 -501
- package/dist/src/turn-runner/state-machine-controller.js.map +0 -1
- /package/dist/src/{cli → model-resolution}/model-gateway.d.ts +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ThinkingLevel } from "@earendil-works/pi-ai";
|
|
2
|
+
import { type LanguageModelUsage } from "ai";
|
|
3
|
+
/** Inputs for one advisor generation after catalog shorthand resolution. */
|
|
4
|
+
export interface CallAdvisorInput {
|
|
5
|
+
/** Curated executor transcript sent as advisor-call content. */
|
|
6
|
+
transcriptText: string;
|
|
7
|
+
/** Gateway-native `provider/model` id, already resolved by the composition site. */
|
|
8
|
+
modelName: string;
|
|
9
|
+
/** Portable reasoning effort forwarded through AI SDK 7's top-level option. */
|
|
10
|
+
thinkingLevel: ThinkingLevel;
|
|
11
|
+
/** Cancels the advisor request with the parent tool execution. */
|
|
12
|
+
signal?: AbortSignal;
|
|
13
|
+
}
|
|
14
|
+
/** Compact text returned to the executor after an advisor consultation. */
|
|
15
|
+
export interface AdvisorResult {
|
|
16
|
+
/** Compact strategic guidance returned to the executor tool. */
|
|
17
|
+
advice: string;
|
|
18
|
+
/** Provider-reported token usage for pricing and live turn attribution. */
|
|
19
|
+
usage: LanguageModelUsage;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Run a plain text advisor call through the shared gateway constructor. No
|
|
23
|
+
* provider options are supplied, so this path opts into neither prompt
|
|
24
|
+
* caching nor any provider-specific request behavior.
|
|
25
|
+
*/
|
|
26
|
+
export declare function callAdvisor(input: CallAdvisorInput): Promise<AdvisorResult>;
|
|
27
|
+
//# sourceMappingURL=advisor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advisor.d.ts","sourceRoot":"","sources":["../../../src/model-routing/advisor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,IAAI,CAAC;AAI3D,4EAA4E;AAC5E,MAAM,WAAW,gBAAgB;IAC/B,gEAAgE;IAChE,cAAc,EAAE,MAAM,CAAC;IACvB,oFAAoF;IACpF,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,aAAa,EAAE,aAAa,CAAC;IAC7B,kEAAkE;IAClE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,KAAK,EAAE,kBAAkB,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAWjF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { generateText } from "ai";
|
|
2
|
+
import { createDuetModelGateway } from "../model-resolution/model-gateway.js";
|
|
3
|
+
import { ADVISOR_SYSTEM_PROMPT } from "./prompts.js";
|
|
4
|
+
/**
|
|
5
|
+
* Run a plain text advisor call through the shared gateway constructor. No
|
|
6
|
+
* provider options are supplied, so this path opts into neither prompt
|
|
7
|
+
* caching nor any provider-specific request behavior.
|
|
8
|
+
*/
|
|
9
|
+
export async function callAdvisor(input) {
|
|
10
|
+
const gateway = createDuetModelGateway();
|
|
11
|
+
const result = await generateText({
|
|
12
|
+
model: gateway(input.modelName),
|
|
13
|
+
system: ADVISOR_SYSTEM_PROMPT,
|
|
14
|
+
prompt: input.transcriptText,
|
|
15
|
+
reasoning: input.thinkingLevel,
|
|
16
|
+
abortSignal: input.signal,
|
|
17
|
+
});
|
|
18
|
+
return { advice: result.text, usage: result.usage };
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=advisor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advisor.js","sourceRoot":"","sources":["../../../src/model-routing/advisor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAA2B,MAAM,IAAI,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAsBrD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAuB;IACvD,MAAM,OAAO,GAAG,sBAAsB,EAAE,CAAC;IAEzC,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC;QAChC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;QAC/B,MAAM,EAAE,qBAAqB;QAC7B,MAAM,EAAE,KAAK,CAAC,cAAc;QAC5B,SAAS,EAAE,KAAK,CAAC,aAAa;QAC9B,WAAW,EAAE,KAAK,CAAC,MAAM;KAC1B,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ThinkingLevel, Usage } from "@earendil-works/pi-ai";
|
|
2
|
+
import type { TierDefinition } from "./table.js";
|
|
3
|
+
/**
|
|
4
|
+
* The runtime milestone that requested a classification. Owned here — where
|
|
5
|
+
* the concept originates — and consumed by the router, the protocol event,
|
|
6
|
+
* and the CLI probe, so the union can never drift across layers.
|
|
7
|
+
*/
|
|
8
|
+
export type RouteTrigger = "turn_start" | "cadence" | "advisor" | "step_trigger" | "compaction";
|
|
9
|
+
/** Lean routing facts supplied at a turn boundary or intra-turn milestone. */
|
|
10
|
+
export interface ClassifierInput {
|
|
11
|
+
/** Virtual tier whose complete route set is being classified in one call. */
|
|
12
|
+
tierName: string;
|
|
13
|
+
/** Tier rules shown to the classifier; concrete targets remain hidden. */
|
|
14
|
+
tier: TierDefinition;
|
|
15
|
+
/** Administrator-authored routing and cache-preference policy. */
|
|
16
|
+
guidance: string;
|
|
17
|
+
/** Current concrete target and selecting route, when continuity is possible. */
|
|
18
|
+
currentTarget?: string;
|
|
19
|
+
/** Bounded summary of the preceding turn, used only to judge task continuity. */
|
|
20
|
+
prevTurnHint?: string;
|
|
21
|
+
/** Bounded description of what changed in the most recent agent step. */
|
|
22
|
+
lastStepDelta?: string;
|
|
23
|
+
/** Whether the pending input includes images; the router handles capability after classification. */
|
|
24
|
+
hasImages: boolean;
|
|
25
|
+
/** Event that requested classification, for interpreting sparse cadence/advisor context. */
|
|
26
|
+
trigger: RouteTrigger;
|
|
27
|
+
}
|
|
28
|
+
/** Pure system/user prompt pair consumed by the structured-output classifier call. */
|
|
29
|
+
export interface ClassifierMessages {
|
|
30
|
+
/** Stable classifier policy. */
|
|
31
|
+
systemPrompt: string;
|
|
32
|
+
/** Tier rules plus the lean, request-specific routing facts. */
|
|
33
|
+
prompt: string;
|
|
34
|
+
}
|
|
35
|
+
/** Options for the live structured-output route decision. */
|
|
36
|
+
export interface ClassifyRouteOptions {
|
|
37
|
+
/** Classifier model reference resolved by the caller's composition layer. */
|
|
38
|
+
model: string;
|
|
39
|
+
/** Reasoning effort configured for the classifier target in the routing table. */
|
|
40
|
+
thinkingLevel?: ThinkingLevel;
|
|
41
|
+
/** Cancels the provider request when its owning turn is interrupted. */
|
|
42
|
+
signal?: AbortSignal;
|
|
43
|
+
/** Receives classifier token and cost usage for attribution. */
|
|
44
|
+
onUsage?: (usage: Usage) => void;
|
|
45
|
+
}
|
|
46
|
+
/** A classifier choice that still names policy, not a concrete execution target. */
|
|
47
|
+
export interface ClassifierDecision {
|
|
48
|
+
/** Existing route name selected from the supplied tier. */
|
|
49
|
+
route: string;
|
|
50
|
+
/** One-sentence explanation returned by the classifier. */
|
|
51
|
+
rationale: string;
|
|
52
|
+
}
|
|
53
|
+
/** Build the complete lean classifier request without reading runtime state. */
|
|
54
|
+
export declare function buildClassifierMessages(input: ClassifierInput): ClassifierMessages;
|
|
55
|
+
/** Classify one tier in one model call and reject any route outside that tier. */
|
|
56
|
+
export declare function classifyRoute(input: ClassifierInput, options: ClassifyRouteOptions): Promise<ClassifierDecision>;
|
|
57
|
+
//# sourceMappingURL=classifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classifier.d.ts","sourceRoot":"","sources":["../../../src/model-routing/classifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AASlE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAwBjD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,cAAc,GAAG,YAAY,CAAC;AAEhG,8EAA8E;AAC9E,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,IAAI,EAAE,cAAc,CAAC;IACrB,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qGAAqG;IACrG,SAAS,EAAE,OAAO,CAAC;IACnB,4FAA4F;IAC5F,OAAO,EAAE,YAAY,CAAC;CACvB;AAED,sFAAsF;AACtF,MAAM,WAAW,kBAAkB;IACjC,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,6DAA6D;AAC7D,MAAM,WAAW,oBAAoB;IACnC,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,wEAAwE;IACxE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,gEAAgE;IAChE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,oFAAoF;AACpF,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;CACnB;AAUD,gFAAgF;AAChF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,eAAe,GAAG,kBAAkB,CAkBlF;AAED,kFAAkF;AAClF,wBAAsB,aAAa,CACjC,KAAK,EAAE,eAAe,EACtB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CAiB7B"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import dedent from "dedent";
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
import * as structuredOutput from "../core/structured-output.js";
|
|
4
|
+
import { CLASSIFIER_SYSTEM_PROMPT, renderCacheContinuity, renderClassifierRules, } from "./prompts.js";
|
|
5
|
+
const CONTEXT_HINT_LIMIT = 1_000;
|
|
6
|
+
function classifierResultTool(routeNames) {
|
|
7
|
+
return {
|
|
8
|
+
name: "select_route",
|
|
9
|
+
description: "Select exactly one existing route for the agent's next work.",
|
|
10
|
+
parameters: Type.Object({
|
|
11
|
+
route: Type.Union(routeNames.map((name) => Type.Literal(name)), { description: "Exactly one route name from AVAILABLE ROUTES." }),
|
|
12
|
+
rationale: Type.String({
|
|
13
|
+
minLength: 1,
|
|
14
|
+
description: "One sentence explaining why this route matches the current work.",
|
|
15
|
+
}),
|
|
16
|
+
}, { additionalProperties: false }),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function boundedHint(value) {
|
|
20
|
+
if (!value?.trim())
|
|
21
|
+
return "Not provided.";
|
|
22
|
+
const normalized = value.trim();
|
|
23
|
+
return normalized.length <= CONTEXT_HINT_LIMIT
|
|
24
|
+
? normalized
|
|
25
|
+
: `${normalized.slice(0, CONTEXT_HINT_LIMIT)}…`;
|
|
26
|
+
}
|
|
27
|
+
/** Build the complete lean classifier request without reading runtime state. */
|
|
28
|
+
export function buildClassifierMessages(input) {
|
|
29
|
+
const continuity = renderCacheContinuity(input.currentTarget);
|
|
30
|
+
return {
|
|
31
|
+
systemPrompt: CLASSIFIER_SYSTEM_PROMPT,
|
|
32
|
+
prompt: dedent `
|
|
33
|
+
${renderClassifierRules(input.tierName, input.tier, input.guidance)}
|
|
34
|
+
|
|
35
|
+
CLASSIFICATION CONTEXT:
|
|
36
|
+
Trigger: ${input.trigger}
|
|
37
|
+
Images present: ${input.hasImages ? "yes" : "no"}
|
|
38
|
+
${continuity}
|
|
39
|
+
Previous-turn hint: ${boundedHint(input.prevTurnHint)}
|
|
40
|
+
Current request / last-step delta: ${boundedHint(input.lastStepDelta)}
|
|
41
|
+
|
|
42
|
+
Pick exactly one name from AVAILABLE ROUTES and give a one-sentence rationale.
|
|
43
|
+
`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** Classify one tier in one model call and reject any route outside that tier. */
|
|
47
|
+
export async function classifyRoute(input, options) {
|
|
48
|
+
const messages = buildClassifierMessages(input);
|
|
49
|
+
const result = await structuredOutput.generateStructuredOutput({
|
|
50
|
+
model: options.model,
|
|
51
|
+
tool: classifierResultTool(Object.keys(input.tier.routes)),
|
|
52
|
+
systemPrompt: messages.systemPrompt,
|
|
53
|
+
prompt: messages.prompt,
|
|
54
|
+
...(options.thinkingLevel ? { callOptions: { reasoningEffort: options.thinkingLevel } } : {}),
|
|
55
|
+
signal: options.signal,
|
|
56
|
+
onUsage: options.onUsage,
|
|
57
|
+
});
|
|
58
|
+
if (!Object.hasOwn(input.tier.routes, result.route)) {
|
|
59
|
+
throw new Error(`Classifier selected unknown route "${result.route}" for tier "${input.tierName}".`);
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=classifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classifier.js","sourceRoot":"","sources":["../../../src/model-routing/classifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type RoutingCatalogAdapter, type RoutingTable } from "./table.js";
|
|
2
|
+
/** Options for loading the optional project-local routing table. */
|
|
3
|
+
export interface LoadRoutingTableOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Directory the discovery walk starts from. Candidates are
|
|
6
|
+
* `<ancestor>/.duet/models.json` for cwd and every parent up to the
|
|
7
|
+
* filesystem root (home excluded from the walk), then `~/.duet/models.json`
|
|
8
|
+
* as the global fallback — the same project-then-global scoping skills
|
|
9
|
+
* discovery uses. The nearest existing file wins outright as a complete
|
|
10
|
+
* replacement; an invalid winner fails loudly rather than falling through.
|
|
11
|
+
*/
|
|
12
|
+
cwd: string;
|
|
13
|
+
/** Concrete catalog used for collision, dangling-target, and vision validation. */
|
|
14
|
+
catalogAdapter: RoutingCatalogAdapter;
|
|
15
|
+
/** Home directory override for tests; defaults to the real home. */
|
|
16
|
+
homeDir?: string;
|
|
17
|
+
}
|
|
18
|
+
/** Provenance attached to the active routing table. */
|
|
19
|
+
export type LoadedRoutingTable = {
|
|
20
|
+
table: RoutingTable;
|
|
21
|
+
source: "built-in";
|
|
22
|
+
} | {
|
|
23
|
+
table: RoutingTable;
|
|
24
|
+
source: "file";
|
|
25
|
+
path: string;
|
|
26
|
+
};
|
|
27
|
+
/** Options for writing the built-in table to a project for customization. */
|
|
28
|
+
export interface ExportRoutingTableOptions {
|
|
29
|
+
/** Project directory where `.duet/models.json` should be written. */
|
|
30
|
+
cwd: string;
|
|
31
|
+
/** Allows replacement of an existing file when explicitly set. */
|
|
32
|
+
force: boolean;
|
|
33
|
+
}
|
|
34
|
+
/** Result of exporting the built-in routing table. */
|
|
35
|
+
export interface ExportedRoutingTable {
|
|
36
|
+
/** Absolute or cwd-relative path, matching the supplied cwd, of the written file. */
|
|
37
|
+
path: string;
|
|
38
|
+
/** The complete built-in replacement serialized to the file. */
|
|
39
|
+
table: RoutingTable;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Load the nearest `.duet/models.json` as a complete replacement, or use the
|
|
43
|
+
* built-in table when no override exists anywhere on the discovery path.
|
|
44
|
+
*/
|
|
45
|
+
export declare function loadRoutingTable(options: LoadRoutingTableOptions): Promise<LoadedRoutingTable>;
|
|
46
|
+
/** Export the complete built-in table as deterministic, two-space-indented JSON. */
|
|
47
|
+
export declare function exportRoutingTable(options: ExportRoutingTableOptions): Promise<ExportedRoutingTable>;
|
|
48
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/model-routing/loader.ts"],"names":[],"mappings":"AAKA,OAAO,EAIL,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AAIpB,oEAAoE;AACpE,MAAM,WAAW,uBAAuB;IACtC;;;;;;;OAOG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,mFAAmF;IACnF,cAAc,EAAE,qBAAqB,CAAC;IACtC,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,uDAAuD;AACvD,MAAM,MAAM,kBAAkB,GAC1B;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC3C;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,6EAA6E;AAC7E,MAAM,WAAW,yBAAyB;IACxC,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,sDAAsD;AACtD,MAAM,WAAW,oBAAoB;IACnC,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,KAAK,EAAE,YAAY,CAAC;CACrB;AA0BD;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CA8B7B;AAED,oFAAoF;AACpF,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,oBAAoB,CAAC,CAgB/B"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { walkAncestors } from "../lib/walk-ancestors.js";
|
|
5
|
+
import { Value } from "typebox/value";
|
|
6
|
+
import { BUILT_IN_ROUTING_TABLE, RoutingTableSchema, validateRoutingTable, } from "./table.js";
|
|
7
|
+
const ROUTING_TABLE_RELATIVE_PATH = join(".duet", "models.json");
|
|
8
|
+
function isMissingFile(error) {
|
|
9
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
10
|
+
}
|
|
11
|
+
function assertSchema(value, path) {
|
|
12
|
+
if (Value.Check(RoutingTableSchema, value))
|
|
13
|
+
return;
|
|
14
|
+
const details = [...Value.Errors(RoutingTableSchema, value)]
|
|
15
|
+
.map((error) => `${error.instancePath || "/"}: ${error.message}`)
|
|
16
|
+
.join("; ");
|
|
17
|
+
throw new Error(`Invalid routing table at ${path}: ${details}`);
|
|
18
|
+
}
|
|
19
|
+
function assertDomain(table, path, catalogAdapter) {
|
|
20
|
+
const issues = validateRoutingTable(table, catalogAdapter);
|
|
21
|
+
if (issues.length === 0)
|
|
22
|
+
return;
|
|
23
|
+
throw new Error(`Invalid routing table at ${path}:\n${issues.map((issue) => `- ${issue.path}: ${issue.message}`).join("\n")}`);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Load the nearest `.duet/models.json` as a complete replacement, or use the
|
|
27
|
+
* built-in table when no override exists anywhere on the discovery path.
|
|
28
|
+
*/
|
|
29
|
+
export async function loadRoutingTable(options) {
|
|
30
|
+
const home = options.homeDir ?? homedir();
|
|
31
|
+
const candidates = [
|
|
32
|
+
...walkAncestors(options.cwd, home).map((dir) => join(dir, ROUTING_TABLE_RELATIVE_PATH)),
|
|
33
|
+
join(home, ROUTING_TABLE_RELATIVE_PATH),
|
|
34
|
+
];
|
|
35
|
+
for (const path of candidates) {
|
|
36
|
+
let contents;
|
|
37
|
+
try {
|
|
38
|
+
contents = await readFile(path, "utf8");
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if (isMissingFile(error))
|
|
42
|
+
continue;
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
let parsed;
|
|
46
|
+
try {
|
|
47
|
+
parsed = JSON.parse(contents);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
51
|
+
throw new Error(`Failed to parse routing table at ${path}: ${detail}`, { cause: error });
|
|
52
|
+
}
|
|
53
|
+
assertSchema(parsed, path);
|
|
54
|
+
assertDomain(parsed, path, options.catalogAdapter);
|
|
55
|
+
return { table: parsed, source: "file", path };
|
|
56
|
+
}
|
|
57
|
+
assertDomain(BUILT_IN_ROUTING_TABLE, "built-in routing table", options.catalogAdapter);
|
|
58
|
+
return { table: BUILT_IN_ROUTING_TABLE, source: "built-in" };
|
|
59
|
+
}
|
|
60
|
+
/** Export the complete built-in table as deterministic, two-space-indented JSON. */
|
|
61
|
+
export async function exportRoutingTable(options) {
|
|
62
|
+
const directory = join(options.cwd, ".duet");
|
|
63
|
+
const path = join(options.cwd, ROUTING_TABLE_RELATIVE_PATH);
|
|
64
|
+
await mkdir(directory, { recursive: true });
|
|
65
|
+
const contents = `${JSON.stringify(BUILT_IN_ROUTING_TABLE, null, 2)}\n`;
|
|
66
|
+
try {
|
|
67
|
+
await writeFile(path, contents, { encoding: "utf8", flag: options.force ? "w" : "wx" });
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
71
|
+
throw new Error(`Routing table already exists at ${path}; pass force to overwrite it.`, {
|
|
72
|
+
cause: error,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
return { path, table: BUILT_IN_ROUTING_TABLE };
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/model-routing/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,GAGrB,MAAM,YAAY,CAAC;AAEpB,MAAM,2BAA2B,GAAG,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;AAwCjE,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC9E,CAAC;AAED,SAAS,YAAY,CAAC,KAAc,EAAE,IAAY;IAChD,IAAI,KAAK,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC;QAAE,OAAO;IACnD,MAAM,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;SACzD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,YAAY,IAAI,GAAG,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;SAChE,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,YAAY,CACnB,KAAmB,EACnB,IAAY,EACZ,cAAqC;IAErC,MAAM,MAAM,GAAG,oBAAoB,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;IAC3D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAChC,MAAM,IAAI,KAAK,CACb,4BAA4B,IAAI,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC9G,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAgC;IAEhC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,EAAE,CAAC;IAC1C,MAAM,UAAU,GAAG;QACjB,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;QACxF,IAAI,CAAC,IAAI,EAAE,2BAA2B,CAAC;KACxC,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,QAAgB,CAAC;QACrB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,aAAa,CAAC,KAAK,CAAC;gBAAE,SAAS;YACnC,MAAM,KAAK,CAAC;QACd,CAAC;QAED,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACtE,MAAM,IAAI,KAAK,CAAC,oCAAoC,IAAI,KAAK,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3F,CAAC;QACD,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC3B,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;QACnD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACjD,CAAC;IAED,YAAY,CAAC,sBAAsB,EAAE,wBAAwB,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACvF,OAAO,EAAE,KAAK,EAAE,sBAAsB,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AAC/D,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAkC;IAElC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;IAC5D,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,sBAAsB,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IACxE,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACzE,MAAM,IAAI,KAAK,CAAC,mCAAmC,IAAI,+BAA+B,EAAE;gBACtF,KAAK,EAAE,KAAK;aACb,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { TierDefinition } from "./table.js";
|
|
2
|
+
/** Identifies the measured classifier prompt in scorecard output. */
|
|
3
|
+
export declare const CLASSIFIER_PROMPT_VERSION = "model-router-classifier-v3";
|
|
4
|
+
/** Stable classifier behavior shared by the probe CLI and runtime router. */
|
|
5
|
+
export declare const CLASSIFIER_SYSTEM_PROMPT: string;
|
|
6
|
+
/** Executor-facing guidance for the no-parameter advisor consultation tool. */
|
|
7
|
+
export declare const ASK_ADVISOR_TOOL_DESCRIPTION: string;
|
|
8
|
+
/**
|
|
9
|
+
* Executor-facing system-prompt layer injected alongside the ask_advisor tool.
|
|
10
|
+
* Anthropic's advisor documentation is explicit that the tool description
|
|
11
|
+
* alone under-triggers on hard tasks and that consistent consult timing comes
|
|
12
|
+
* from executor system-prompt steering; live acceptance runs confirmed it
|
|
13
|
+
* (four consecutive positive-case misses on description-only guidance).
|
|
14
|
+
*/
|
|
15
|
+
export declare const ADVISOR_EXECUTOR_GUIDANCE_LAYER: string;
|
|
16
|
+
/** Instructions owned by the advisor call, separate from the executor's quoted prompt. */
|
|
17
|
+
export declare const ADVISOR_SYSTEM_PROMPT: string;
|
|
18
|
+
/** Continuity framing for the classifier: cache preference when a target is active. */
|
|
19
|
+
export declare function renderCacheContinuity(currentTarget: string | undefined): string;
|
|
20
|
+
/** Render every route in one tier for a single all-entries classifier decision. */
|
|
21
|
+
export declare function renderClassifierRules(tierName: string, tier: TierDefinition, guidance: string): string;
|
|
22
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/model-routing/prompts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,qEAAqE;AACrE,eAAO,MAAM,yBAAyB,+BAA+B,CAAC;AAEtE,6EAA6E;AAC7E,eAAO,MAAM,wBAAwB,QAapC,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,4BAA4B,QASxC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,+BAA+B,QAe3C,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,qBAAqB,QAOjC,CAAC;AAEF,uFAAuF;AACvF,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQ/E;AAED,mFAAmF;AACnF,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,cAAc,EACpB,QAAQ,EAAE,MAAM,GACf,MAAM,CAaR"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import dedent from "dedent";
|
|
2
|
+
/** Identifies the measured classifier prompt in scorecard output. */
|
|
3
|
+
export const CLASSIFIER_PROMPT_VERSION = "model-router-classifier-v3";
|
|
4
|
+
/** Stable classifier behavior shared by the probe CLI and runtime router. */
|
|
5
|
+
export const CLASSIFIER_SYSTEM_PROMPT = dedent `
|
|
6
|
+
You are a model-route classifier. Choose the single route that best matches the work the agent
|
|
7
|
+
should do next, using only the supplied route names and descriptions.
|
|
8
|
+
|
|
9
|
+
Return exactly one existing route name through the required tool, plus a one-sentence rationale.
|
|
10
|
+
Never invent, rename, combine, or return a concrete model name. Treat administrator guidance as
|
|
11
|
+
additional routing policy.
|
|
12
|
+
|
|
13
|
+
Route for the current kind of work, not merely the topic or the input capabilities it needs.
|
|
14
|
+
Vision fallback or graceful degradation is handled by the router after classification. A route
|
|
15
|
+
change discards the current model's prompt cache, so prefer the current route/model while the
|
|
16
|
+
kind of work remains materially the same. Switch when the work clearly changes kind; cache
|
|
17
|
+
continuity must not keep a genuinely wrong route.
|
|
18
|
+
`;
|
|
19
|
+
/** Executor-facing guidance for the no-parameter advisor consultation tool. */
|
|
20
|
+
export const ASK_ADVISOR_TOOL_DESCRIPTION = dedent `
|
|
21
|
+
Ask a senior advisor to review your full progress so far and recommend what to do next. The
|
|
22
|
+
advisor sees the curated in-progress session transcript; this tool takes no parameters.
|
|
23
|
+
|
|
24
|
+
You must call it before substantive work when the task has consequential architecture choices,
|
|
25
|
+
conflicting constraints, or important unknowns; when you are stuck; before changing your
|
|
26
|
+
approach; or before declaring a complex task complete. Do not call it for routine, local,
|
|
27
|
+
obvious work where strategic review would not change the next action. Use the advice as
|
|
28
|
+
strategic input, then verify and act on it with your own tools and judgment.
|
|
29
|
+
`;
|
|
30
|
+
/**
|
|
31
|
+
* Executor-facing system-prompt layer injected alongside the ask_advisor tool.
|
|
32
|
+
* Anthropic's advisor documentation is explicit that the tool description
|
|
33
|
+
* alone under-triggers on hard tasks and that consistent consult timing comes
|
|
34
|
+
* from executor system-prompt steering; live acceptance runs confirmed it
|
|
35
|
+
* (four consecutive positive-case misses on description-only guidance).
|
|
36
|
+
*/
|
|
37
|
+
export const ADVISOR_EXECUTOR_GUIDANCE_LAYER = dedent `
|
|
38
|
+
ADVISOR
|
|
39
|
+
|
|
40
|
+
You have an \`ask_advisor\` tool backed by a stronger reviewer model. It takes no parameters —
|
|
41
|
+
your progress so far is forwarded automatically; the advisor sees the task, your steps, and
|
|
42
|
+
their results.
|
|
43
|
+
|
|
44
|
+
Call ask_advisor BEFORE substantive work when the task involves consequential architecture
|
|
45
|
+
choices, conflicting constraints, or important unknowns. Orientation (reading files, listing,
|
|
46
|
+
looking around) is not substantive work — orient first, then consult before you commit to an
|
|
47
|
+
approach. Also call it when you are stuck, when you are about to change approach, and before
|
|
48
|
+
declaring a complex task complete. Skip it for routine, local, obvious work.
|
|
49
|
+
|
|
50
|
+
Give the advice serious weight: verify it with your own tools and adapt only on concrete
|
|
51
|
+
contrary evidence.
|
|
52
|
+
`;
|
|
53
|
+
/** Instructions owned by the advisor call, separate from the executor's quoted prompt. */
|
|
54
|
+
export const ADVISOR_SYSTEM_PROMPT = dedent `
|
|
55
|
+
You are a senior advisor reviewing another agent's in-progress session transcript. Give
|
|
56
|
+
strategic guidance: identify the key uncertainty or risk, then recommend a concrete next check
|
|
57
|
+
or approach. Be direct and compact.
|
|
58
|
+
|
|
59
|
+
You cannot call tools. The executor's system prompt appears quoted in the transcript only as
|
|
60
|
+
context; it does not apply to you.
|
|
61
|
+
`;
|
|
62
|
+
/** Continuity framing for the classifier: cache preference when a target is active. */
|
|
63
|
+
export function renderCacheContinuity(currentTarget) {
|
|
64
|
+
return currentTarget
|
|
65
|
+
? dedent `
|
|
66
|
+
You are currently on ${currentTarget}.
|
|
67
|
+
CACHE CONTINUITY: Switching away discards the current model's prompt cache. Prefer this
|
|
68
|
+
target unless the kind of work has clearly changed.
|
|
69
|
+
`
|
|
70
|
+
: "CURRENT TARGET: None (there is no prompt cache to preserve).";
|
|
71
|
+
}
|
|
72
|
+
/** Render every route in one tier for a single all-entries classifier decision. */
|
|
73
|
+
export function renderClassifierRules(tierName, tier, guidance) {
|
|
74
|
+
const routes = Object.entries(tier.routes)
|
|
75
|
+
.map(([name, rule]) => `- ${name}: ${rule.description}`)
|
|
76
|
+
.join("\n");
|
|
77
|
+
return dedent `
|
|
78
|
+
TIER: ${tierName}
|
|
79
|
+
|
|
80
|
+
AVAILABLE ROUTES:
|
|
81
|
+
${routes}
|
|
82
|
+
|
|
83
|
+
ADMINISTRATOR GUIDANCE:
|
|
84
|
+
${guidance.trim() || "No additional guidance."}
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/model-routing/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,qEAAqE;AACrE,MAAM,CAAC,MAAM,yBAAyB,GAAG,4BAA4B,CAAC;AAEtE,6EAA6E;AAC7E,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAA;;;;;;;;;;;;;CAa7C,CAAC;AAEF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAA;;;;;;;;;CASjD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,MAAM,CAAA;;;;;;;;;;;;;;;CAepD,CAAC;AAEF,0FAA0F;AAC1F,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAA;;;;;;;CAO1C,CAAC;AAEF,uFAAuF;AACvF,MAAM,UAAU,qBAAqB,CAAC,aAAiC;IACrE,OAAO,aAAa;QAClB,CAAC,CAAC,MAAM,CAAA;+BACmB,aAAa;;;OAGrC;QACH,CAAC,CAAC,8DAA8D,CAAC;AACrE,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,qBAAqB,CACnC,QAAgB,EAChB,IAAoB,EACpB,QAAgB;IAEhB,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;SACvC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;SACvD,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,OAAO,MAAM,CAAA;YACH,QAAQ;;;MAGd,MAAM;;;MAGN,QAAQ,CAAC,IAAI,EAAE,IAAI,yBAAyB;GAC/C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ThinkingLevel } from "@earendil-works/pi-ai";
|
|
2
|
+
import type { RoutingTable } from "./table.js";
|
|
3
|
+
/** Request facts that can change an otherwise deterministic route selection. */
|
|
4
|
+
export interface RouteContext {
|
|
5
|
+
/** Whether the pending model input contains one or more images. */
|
|
6
|
+
hasImages: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** Concrete-model capability needed by the pure resolution kernel. */
|
|
9
|
+
export interface RouteResolutionCatalog {
|
|
10
|
+
/** True when the named concrete model accepts image input. */
|
|
11
|
+
modelAcceptsImages(name: string): boolean;
|
|
12
|
+
}
|
|
13
|
+
/** Final concrete target plus the virtual path that selected it. */
|
|
14
|
+
export interface ResolvedTarget {
|
|
15
|
+
/** Virtual tier that owns the final concrete route. */
|
|
16
|
+
tier: string;
|
|
17
|
+
/** Actual route used in the final tier, including general fallthrough. */
|
|
18
|
+
route: string;
|
|
19
|
+
/** Concrete catalog name selected for execution. */
|
|
20
|
+
modelName: string;
|
|
21
|
+
/** Reasoning effort selected by the final route. */
|
|
22
|
+
thinkingLevel: ThinkingLevel;
|
|
23
|
+
/** True when the selected route's image fallback model was applied. */
|
|
24
|
+
visionFallback: boolean;
|
|
25
|
+
/** Ordered virtual tier names visited during recursive resolution. */
|
|
26
|
+
chain: string[];
|
|
27
|
+
}
|
|
28
|
+
type UncheckedTarget = Omit<ResolvedTarget, "visionFallback">;
|
|
29
|
+
/** Non-throwing virtual-chain walk shared by validation and live route resolution. */
|
|
30
|
+
export declare function walkVirtualRoute(table: RoutingTable, startTier: string, requestedRoute: string): {
|
|
31
|
+
cycle?: string[];
|
|
32
|
+
target?: UncheckedTarget;
|
|
33
|
+
chain: string[];
|
|
34
|
+
};
|
|
35
|
+
/** Resolve a virtual tier and classifier route to one concrete model and effort. */
|
|
36
|
+
export declare function resolveRoute(table: RoutingTable, tier: string, route: string, ctx: RouteContext, catalog: RouteResolutionCatalog): ResolvedTarget;
|
|
37
|
+
/** Resolve the general boot route for a selected virtual tier before classification. */
|
|
38
|
+
export declare function resolveTierDefault(table: RoutingTable, tier: string, context: RouteContext, catalog: RouteResolutionCatalog): ResolvedTarget;
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/model-routing/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,gFAAgF;AAChF,MAAM,WAAW,YAAY;IAC3B,mEAAmE;IACnE,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,sEAAsE;AACtE,MAAM,WAAW,sBAAsB;IACrC,8DAA8D;IAC9D,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3C;AAED,oEAAoE;AACpE,MAAM,WAAW,cAAc;IAC7B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,aAAa,EAAE,aAAa,CAAC;IAC7B,uEAAuE;IACvE,cAAc,EAAE,OAAO,CAAC;IACxB,sEAAsE;IACtE,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,KAAK,eAAe,GAAG,IAAI,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;AAE9D,sFAAsF;AACtF,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACrB;IAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CA8BjE;AAwBD,oFAAoF;AACpF,wBAAgB,YAAY,CAC1B,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,YAAY,EACjB,OAAO,EAAE,sBAAsB,GAC9B,cAAc,CAwBhB;AAED,wFAAwF;AACxF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,sBAAsB,GAC9B,cAAc,CAEhB"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** Non-throwing virtual-chain walk shared by validation and live route resolution. */
|
|
2
|
+
export function walkVirtualRoute(table, startTier, requestedRoute) {
|
|
3
|
+
const chain = [];
|
|
4
|
+
let tier = startTier;
|
|
5
|
+
while (true) {
|
|
6
|
+
const repeatedAt = chain.indexOf(tier);
|
|
7
|
+
if (repeatedAt !== -1) {
|
|
8
|
+
return { cycle: [...chain.slice(repeatedAt), tier], chain };
|
|
9
|
+
}
|
|
10
|
+
const definition = table.tiers[tier];
|
|
11
|
+
if (!definition)
|
|
12
|
+
return { chain };
|
|
13
|
+
chain.push(tier);
|
|
14
|
+
const route = Object.hasOwn(definition.routes, requestedRoute) ? requestedRoute : "general";
|
|
15
|
+
const rule = definition.routes[route];
|
|
16
|
+
if (!rule)
|
|
17
|
+
return { chain };
|
|
18
|
+
if (!Object.hasOwn(table.tiers, rule.target.modelName)) {
|
|
19
|
+
return {
|
|
20
|
+
chain,
|
|
21
|
+
target: {
|
|
22
|
+
tier,
|
|
23
|
+
route,
|
|
24
|
+
modelName: rule.target.modelName,
|
|
25
|
+
thinkingLevel: rule.target.thinkingLevel,
|
|
26
|
+
chain,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
tier = rule.target.modelName;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function resolveWithoutVisionGuard(table, startTier, requestedRoute) {
|
|
34
|
+
if (!Object.hasOwn(table.tiers, startTier)) {
|
|
35
|
+
throw new Error(`Unknown virtual model tier "${startTier}".`);
|
|
36
|
+
}
|
|
37
|
+
const result = walkVirtualRoute(table, startTier, requestedRoute);
|
|
38
|
+
if (result.cycle)
|
|
39
|
+
throw new Error(`Virtual model cycle: ${result.cycle.join(" -> ")}.`);
|
|
40
|
+
if (result.target)
|
|
41
|
+
return result.target;
|
|
42
|
+
const tier = result.chain.at(-1) ?? startTier;
|
|
43
|
+
throw new Error(`Tier "${tier}" has neither requested route "${requestedRoute}" nor a general fallback.`);
|
|
44
|
+
}
|
|
45
|
+
function joinChains(initial, fallback) {
|
|
46
|
+
if (initial.at(-1) === fallback[0])
|
|
47
|
+
return [...initial, ...fallback.slice(1)];
|
|
48
|
+
return [...initial, ...fallback];
|
|
49
|
+
}
|
|
50
|
+
/** Resolve a virtual tier and classifier route to one concrete model and effort. */
|
|
51
|
+
export function resolveRoute(table, tier, route, ctx, catalog) {
|
|
52
|
+
const selected = resolveWithoutVisionGuard(table, tier, route);
|
|
53
|
+
if (!ctx.hasImages || catalog.modelAcceptsImages(selected.modelName)) {
|
|
54
|
+
return { ...selected, visionFallback: false };
|
|
55
|
+
}
|
|
56
|
+
const fallbackName = table.tiers[selected.tier].routes[selected.route]?.visionFallbackModelName;
|
|
57
|
+
if (!fallbackName)
|
|
58
|
+
return { ...selected, visionFallback: false };
|
|
59
|
+
const fallback = Object.hasOwn(table.tiers, fallbackName)
|
|
60
|
+
? resolveWithoutVisionGuard(table, fallbackName, selected.route)
|
|
61
|
+
: { ...selected, modelName: fallbackName, chain: [] };
|
|
62
|
+
if (!catalog.modelAcceptsImages(fallback.modelName)) {
|
|
63
|
+
throw new Error(`Vision fallback "${fallbackName}" for route "${selected.route}" resolves to text-only model "${fallback.modelName}".`);
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
...fallback,
|
|
67
|
+
thinkingLevel: selected.thinkingLevel,
|
|
68
|
+
visionFallback: true,
|
|
69
|
+
chain: joinChains(selected.chain, fallback.chain),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** Resolve the general boot route for a selected virtual tier before classification. */
|
|
73
|
+
export function resolveTierDefault(table, tier, context, catalog) {
|
|
74
|
+
return resolveRoute(table, tier, "general", context, catalog);
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/model-routing/resolve.ts"],"names":[],"mappings":"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"}
|