@cortexkit/opencode-magic-context 0.17.2 → 0.18.0
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/dist/features/magic-context/dreamer/runner.d.ts +15 -0
- package/dist/features/magic-context/dreamer/runner.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +14 -0
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts +1 -0
- package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta.d.ts +1 -1
- package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +1 -1
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/types.d.ts +1 -0
- package/dist/features/magic-context/types.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts +2 -0
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +2 -0
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-compressor.d.ts +1 -0
- package/dist/hooks/magic-context/compartment-runner-compressor.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts +7 -0
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +2 -0
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/todo-view.d.ts +102 -0
- package/dist/hooks/magic-context/todo-view.d.ts.map +1 -0
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +1 -0
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-message-helpers.d.ts +22 -0
- package/dist/hooks/magic-context/transform-message-helpers.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +2 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.js +626 -178
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts +2 -1
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/model-suggestion-retry.d.ts +37 -0
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/models-dev-cache.d.ts.map +1 -1
- package/dist/shared/resolve-fallbacks.d.ts +32 -0
- package/dist/shared/resolve-fallbacks.d.ts.map +1 -0
- package/dist/shared/tag-transcript.d.ts.map +1 -1
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/shared/index.ts +1 -0
- package/src/shared/model-suggestion-retry.test.ts +251 -0
- package/src/shared/model-suggestion-retry.ts +194 -6
- package/src/shared/models-dev-cache.ts +7 -7
- package/src/shared/resolve-fallbacks.test.ts +136 -0
- package/src/shared/resolve-fallbacks.ts +76 -0
- package/src/shared/tag-transcript.ts +3 -2
- package/src/tui/index.tsx +114 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dream-timer.d.ts","sourceRoot":"","sources":["../../src/plugin/dream-timer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dream-timer.d.ts","sourceRoot":"","sources":["../../src/plugin/dream-timer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAWrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C;;;;;GAKG;AACH,UAAU,mBAAmB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,OAAO,CAAC;IACvB,wBAAwB,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,uBAAuB,CAAC,EAAE;QACtB,OAAO,EAAE,OAAO,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,iBAAiB,CAAC,EAAE;QAChB,OAAO,EAAE,OAAO,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;KACvB,CAAC;CACL;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,mBAAmB,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAuD3F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-session-hooks.d.ts","sourceRoot":"","sources":["../../../src/plugin/hooks/create-session-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAU7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;IACvC,gBAAgB,EAAE,gBAAgB,CAAC;CACtC;;;;;;qBAqDyvJ,CAAC;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"create-session-hooks.d.ts","sourceRoot":"","sources":["../../../src/plugin/hooks/create-session-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAU7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;IACvC,gBAAgB,EAAE,gBAAgB,CAAC;CACtC;;;;;;qBAqDyvJ,CAAC;;;;;;;;;;;;qBAAzyD,CAAC;mBAAyB,CAAC;iBAAuB,CAAC;iBAAuB,CAAC;0BAAc,CAAC;uBAAiB,CAAC;;;;;;0BAAmxqB,CAAC;;;;;;EADj1wB"}
|
|
@@ -6,8 +6,9 @@ import type { MagicContextConfig } from "../config/schema/magic-context";
|
|
|
6
6
|
import { type ContextDatabase as Database } from "../features/magic-context/storage";
|
|
7
7
|
import type { LiveSessionState } from "../hooks/magic-context/live-session-state";
|
|
8
8
|
import type { MagicContextRpcServer } from "../shared/rpc-server";
|
|
9
|
-
import type { SidebarSnapshot } from "../shared/rpc-types";
|
|
9
|
+
import type { SidebarSnapshot, StatusDetail } from "../shared/rpc-types";
|
|
10
10
|
export declare function buildSidebarSnapshot(db: Database, sessionId: string, directory: string, liveSessionState?: LiveSessionState, injectionBudgetTokens?: number): SidebarSnapshot;
|
|
11
|
+
export declare function buildStatusDetail(db: Database, sessionId: string, directory: string, modelKey?: string, config?: Record<string, unknown>, liveSessionState?: LiveSessionState, injectionBudgetTokens?: number): StatusDetail;
|
|
11
12
|
/**
|
|
12
13
|
* Register all RPC handlers on the server.
|
|
13
14
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-handlers.d.ts","sourceRoot":"","sources":["../../src/plugin/rpc-handlers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAGzE,OAAO,EAAE,KAAK,eAAe,IAAI,QAAQ,EAAgB,MAAM,mCAAmC,CAAC;AAQnG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AASlF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"rpc-handlers.d.ts","sourceRoot":"","sources":["../../src/plugin/rpc-handlers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAGzE,OAAO,EAAE,KAAK,eAAe,IAAI,QAAQ,EAAgB,MAAM,mCAAmC,CAAC;AAQnG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AASlF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAmDzE,wBAAgB,oBAAoB,CAChC,EAAE,EAAE,QAAQ,EACZ,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,qBAAqB,CAAC,EAAE,MAAM,GAC/B,eAAe,CAySjB;AAED,wBAAgB,iBAAiB,CAC7B,EAAE,EAAE,QAAQ,EACZ,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,qBAAqB,CAAC,EAAE,MAAM,GAC/B,YAAY,CAkKd;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,SAAS,EAAE,qBAAqB,EAChC,IAAI,EAAE;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,EAAE,gBAAgB,CAAC;CACtC,GACF,IAAI,CAoIN"}
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC"}
|
|
@@ -19,6 +19,29 @@ export interface PromptRetryOptions {
|
|
|
19
19
|
timeoutMs?: number;
|
|
20
20
|
/** External abort signal — cancels the in-flight LLM prompt immediately when aborted */
|
|
21
21
|
signal?: AbortSignal;
|
|
22
|
+
/**
|
|
23
|
+
* Ordered list of "provider/modelID" alternates to try if the primary call
|
|
24
|
+
* (and its single-suggestion retry) fails. Empty / undefined = no fallback
|
|
25
|
+
* iteration (legacy behavior).
|
|
26
|
+
*
|
|
27
|
+
* Fallback policy:
|
|
28
|
+
* - Each fallback gets the FULL `timeoutMs` budget (per-attempt, not total).
|
|
29
|
+
* - Suggestion-retry runs inside each attempt (so "did you mean X?" errors
|
|
30
|
+
* still self-heal at the primary AND at each fallback).
|
|
31
|
+
* - Iteration stops immediately on abort/timeout/context-overflow errors —
|
|
32
|
+
* fallbacks won't help and the caller's emergency-recovery path needs
|
|
33
|
+
* to handle these.
|
|
34
|
+
* - On all-failed, the LAST error is thrown (matches legacy behavior when
|
|
35
|
+
* `fallbackModels` is empty).
|
|
36
|
+
*/
|
|
37
|
+
fallbackModels?: readonly string[];
|
|
38
|
+
/**
|
|
39
|
+
* Identifier for structured logging (e.g. "dreamer:consolidate",
|
|
40
|
+
* "historian", "compressor", "sidekick"). Helps correlate fallback
|
|
41
|
+
* attempts to a specific call site in `magic-context.log`. Defaults to
|
|
42
|
+
* "subagent" if not provided.
|
|
43
|
+
*/
|
|
44
|
+
callContext?: string;
|
|
22
45
|
}
|
|
23
46
|
export interface ModelSuggestionInfo {
|
|
24
47
|
providerID: string;
|
|
@@ -26,6 +49,20 @@ export interface ModelSuggestionInfo {
|
|
|
26
49
|
suggestion: string;
|
|
27
50
|
}
|
|
28
51
|
export declare function parseModelSuggestion(error: unknown): ModelSuggestionInfo | null;
|
|
52
|
+
/**
|
|
53
|
+
* Run an OpenCode subagent prompt with model fallback support.
|
|
54
|
+
*
|
|
55
|
+
* Attempts the configured primary model first (whatever `args.body.model` or
|
|
56
|
+
* the registered agent default resolves to), then iterates through
|
|
57
|
+
* `options.fallbackModels` if provided. Each attempt internally retries once on
|
|
58
|
+
* the SDK's "model not found, did you mean X?" suggestion. Aborts, timeouts,
|
|
59
|
+
* and context-overflow errors short-circuit the fallback loop because retrying
|
|
60
|
+
* the same prompt against another model won't help.
|
|
61
|
+
*
|
|
62
|
+
* Behavior with `fallbackModels` empty/undefined is identical to the pre-v0.18
|
|
63
|
+
* single-suggestion retry — fully backward-compatible for callers that haven't
|
|
64
|
+
* been updated to thread a chain.
|
|
65
|
+
*/
|
|
29
66
|
export declare function promptSyncWithModelSuggestionRetry(client: Client, args: PromptArgs, options?: PromptRetryOptions): Promise<void>;
|
|
30
67
|
export {};
|
|
31
68
|
//# sourceMappingURL=model-suggestion-retry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-suggestion-retry.d.ts","sourceRoot":"","sources":["../../src/shared/model-suggestion-retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"model-suggestion-retry.d.ts","sourceRoot":"","sources":["../../src/shared/model-suggestion-retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAM7D,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEtD,KAAK,UAAU,GAAG;IACd,KAAK,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B,CAAC;AAEF,KAAK,UAAU,GAAG;IACd,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B,CAAC;AAEF,MAAM,WAAW,kBAAkB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACtB;AAiBD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CA4C/E;AAuID;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kCAAkC,CACpD,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,kBAAuB,GACjC,OAAO,CAAC,IAAI,CAAC,CAgFf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models-dev-cache.d.ts","sourceRoot":"","sources":["../../src/shared/models-dev-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;
|
|
1
|
+
{"version":3,"file":"models-dev-cache.d.ts","sourceRoot":"","sources":["../../src/shared/models-dev-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAUH,UAAU,kBAAkB;IACxB,MAAM,EAAE;QACJ,SAAS,EAAE,MAAM,OAAO,CAAC;YAAE,IAAI,CAAC,EAAE;gBAAE,SAAS,CAAC,EAAE,OAAO,CAAA;aAAE,CAAA;SAAE,CAAC,CAAC;KAChE,CAAC;CACL;AA2MD;;;;;;;;;;GAUG;AACH,wBAAsB,yBAAyB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmEzF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAchG;AAED,4CAA4C;AAC5C,wBAAgB,mBAAmB,IAAI,IAAI,CAO1C;AAED,oDAAoD;AACpD,wBAAgB,sBAAsB,IAAI;IACtC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACrB,CAOA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the final fallback model list to attempt for an OpenCode subagent
|
|
3
|
+
* call.
|
|
4
|
+
*
|
|
5
|
+
* Policy (decided 2026-05-10):
|
|
6
|
+
* - If user configured explicit `fallback_models` in their magic-context.jsonc
|
|
7
|
+
* for this agent: use ONLY those. Respects user intent, no surprise
|
|
8
|
+
* providers.
|
|
9
|
+
* - If user did NOT configure any: fall back to the plugin's builtin
|
|
10
|
+
* provider-agnostic chain (`AGENT_MODEL_REQUIREMENTS`).
|
|
11
|
+
*
|
|
12
|
+
* The returned list does NOT include the primary model — it's the ordered
|
|
13
|
+
* list of *alternates* to try after the primary fails. Each entry is
|
|
14
|
+
* "provider/modelID" form.
|
|
15
|
+
*
|
|
16
|
+
* Duplicates and empty strings are filtered. Entries that don't match the
|
|
17
|
+
* "provider/modelID" shape (must contain a "/" with non-empty parts) are
|
|
18
|
+
* also dropped — defensive guard against malformed user config.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveFallbackChain(agentName: string, userFallbacks: readonly string[] | string | undefined): string[];
|
|
21
|
+
/**
|
|
22
|
+
* Parse a "provider/modelID" string into the OpenCode `model` object shape.
|
|
23
|
+
* Returns null on invalid input.
|
|
24
|
+
*
|
|
25
|
+
* Note: only splits on the FIRST "/" — modelID can legitimately contain slashes
|
|
26
|
+
* (e.g. `lemonade/GLM-4.7-Flash-GGUF/main`).
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseProviderModel(spec: string): {
|
|
29
|
+
providerID: string;
|
|
30
|
+
modelID: string;
|
|
31
|
+
} | null;
|
|
32
|
+
//# sourceMappingURL=resolve-fallbacks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-fallbacks.d.ts","sourceRoot":"","sources":["../../src/shared/resolve-fallbacks.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAChC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,GACtD,MAAM,EAAE,CAUV;AA2BD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAO/F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag-transcript.d.ts","sourceRoot":"","sources":["../../src/shared/tag-transcript.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAGzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAM/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,cAAc,CAAC;AAE/D,MAAM,WAAW,oBAAoB;IACjC;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACnC;AAyDD,wBAAgB,aAAa,CACzB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,eAAe,EACnB,OAAO,GAAE,oBAAyB,GACnC,mBAAmB,
|
|
1
|
+
{"version":3,"file":"tag-transcript.d.ts","sourceRoot":"","sources":["../../src/shared/tag-transcript.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAGzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAM/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,cAAc,CAAC;AAE/D,MAAM,WAAW,oBAAoB;IACjC;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACnC;AAyDD,wBAAgB,aAAa,CACzB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,eAAe,EACnB,OAAO,GAAE,oBAAyB,GACnC,mBAAmB,CAqKrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-memory/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAQ,MAAM,qBAAqB,CAAC;AAsBhE,OAAO,EAIH,KAAK,iBAAiB,EACzB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-memory/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAQ,MAAM,qBAAqB,CAAC;AAsBhE,OAAO,EAIH,KAAK,iBAAiB,EACzB,MAAM,SAAS,CAAC;AA8djB,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAI5F"}
|
package/package.json
CHANGED
package/src/shared/index.ts
CHANGED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { describe, expect, mock, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { promptSyncWithModelSuggestionRetry } from "./model-suggestion-retry";
|
|
4
|
+
|
|
5
|
+
type PromptCall = {
|
|
6
|
+
body: { model?: { providerID: string; modelID: string } };
|
|
7
|
+
signal?: AbortSignal;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
function createClient(prompt: ReturnType<typeof mock>) {
|
|
11
|
+
return {
|
|
12
|
+
session: {
|
|
13
|
+
prompt,
|
|
14
|
+
},
|
|
15
|
+
} as never;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function createArgs(model?: { providerID: string; modelID: string }) {
|
|
19
|
+
return {
|
|
20
|
+
path: { id: "ses-test" },
|
|
21
|
+
body: model ? { model } : {},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe("promptSyncWithModelSuggestionRetry", () => {
|
|
26
|
+
test("primary succeeds, no fallback iteration", async () => {
|
|
27
|
+
const prompt = mock(async () => ({}));
|
|
28
|
+
const client = createClient(prompt);
|
|
29
|
+
|
|
30
|
+
await promptSyncWithModelSuggestionRetry(client, createArgs(), {
|
|
31
|
+
fallbackModels: ["anthropic/claude-sonnet-4-6"],
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
expect(prompt).toHaveBeenCalledTimes(1);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("primary succeeds with no fallbacks configured", async () => {
|
|
38
|
+
const prompt = mock(async () => ({}));
|
|
39
|
+
const client = createClient(prompt);
|
|
40
|
+
|
|
41
|
+
await promptSyncWithModelSuggestionRetry(client, createArgs());
|
|
42
|
+
|
|
43
|
+
expect(prompt).toHaveBeenCalledTimes(1);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("primary fails, fallback[0] succeeds", async () => {
|
|
47
|
+
const prompt = mock(async () => {
|
|
48
|
+
if (prompt.mock.calls.length === 1) throw new Error("primary failed");
|
|
49
|
+
return {};
|
|
50
|
+
});
|
|
51
|
+
const client = createClient(prompt);
|
|
52
|
+
|
|
53
|
+
await promptSyncWithModelSuggestionRetry(client, createArgs(), {
|
|
54
|
+
fallbackModels: ["anthropic/claude-sonnet-4-6"],
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(prompt).toHaveBeenCalledTimes(2);
|
|
58
|
+
expect((prompt.mock.calls[1]?.[0] as PromptCall).body.model).toEqual({
|
|
59
|
+
providerID: "anthropic",
|
|
60
|
+
modelID: "claude-sonnet-4-6",
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("primary fails, fallback[0] fails, fallback[1] succeeds", async () => {
|
|
65
|
+
const prompt = mock(async () => {
|
|
66
|
+
if (prompt.mock.calls.length <= 2)
|
|
67
|
+
throw new Error(`failed ${prompt.mock.calls.length}`);
|
|
68
|
+
return {};
|
|
69
|
+
});
|
|
70
|
+
const client = createClient(prompt);
|
|
71
|
+
|
|
72
|
+
await promptSyncWithModelSuggestionRetry(client, createArgs(), {
|
|
73
|
+
fallbackModels: ["anthropic/claude-sonnet-4-6", "google/gemini-3-flash"],
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
expect(prompt).toHaveBeenCalledTimes(3);
|
|
77
|
+
expect((prompt.mock.calls[2]?.[0] as PromptCall).body.model).toEqual({
|
|
78
|
+
providerID: "google",
|
|
79
|
+
modelID: "gemini-3-flash",
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("all attempts fail throws the last fallback error", async () => {
|
|
84
|
+
const primaryError = new Error("primary failed");
|
|
85
|
+
const firstFallbackError = new Error("fallback 0 failed");
|
|
86
|
+
const lastFallbackError = new Error("fallback 1 failed");
|
|
87
|
+
const errors = [primaryError, firstFallbackError, lastFallbackError];
|
|
88
|
+
const prompt = mock(async () => {
|
|
89
|
+
throw errors[prompt.mock.calls.length - 1];
|
|
90
|
+
});
|
|
91
|
+
const client = createClient(prompt);
|
|
92
|
+
|
|
93
|
+
await expect(
|
|
94
|
+
promptSyncWithModelSuggestionRetry(client, createArgs(), {
|
|
95
|
+
fallbackModels: ["anthropic/claude-sonnet-4-6", "google/gemini-3-flash"],
|
|
96
|
+
}),
|
|
97
|
+
).rejects.toBe(lastFallbackError);
|
|
98
|
+
expect(prompt).toHaveBeenCalledTimes(3);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("abort signal short-circuits", async () => {
|
|
102
|
+
const controller = new AbortController();
|
|
103
|
+
controller.abort();
|
|
104
|
+
const prompt = mock(async () => {
|
|
105
|
+
throw new Error("provider noticed abort");
|
|
106
|
+
});
|
|
107
|
+
const client = createClient(prompt);
|
|
108
|
+
|
|
109
|
+
await expect(
|
|
110
|
+
promptSyncWithModelSuggestionRetry(client, createArgs(), {
|
|
111
|
+
signal: controller.signal,
|
|
112
|
+
fallbackModels: ["anthropic/claude-sonnet-4-6"],
|
|
113
|
+
}),
|
|
114
|
+
).rejects.toThrow("prompt aborted by external signal");
|
|
115
|
+
// Pre-aborted signal MUST short-circuit before any upstream prompt
|
|
116
|
+
// call — Audit Finding #1 hardening. No round-trip wasted on a
|
|
117
|
+
// request the caller has already cancelled.
|
|
118
|
+
expect(prompt).toHaveBeenCalledTimes(0);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("AbortError name short-circuits", async () => {
|
|
122
|
+
const abortError = new Error("aborted by provider");
|
|
123
|
+
abortError.name = "AbortError";
|
|
124
|
+
const prompt = mock(async () => {
|
|
125
|
+
throw abortError;
|
|
126
|
+
});
|
|
127
|
+
const client = createClient(prompt);
|
|
128
|
+
|
|
129
|
+
await expect(
|
|
130
|
+
promptSyncWithModelSuggestionRetry(client, createArgs(), {
|
|
131
|
+
fallbackModels: ["anthropic/claude-sonnet-4-6"],
|
|
132
|
+
}),
|
|
133
|
+
).rejects.toBe(abortError);
|
|
134
|
+
expect(prompt).toHaveBeenCalledTimes(1);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("timeout short-circuits", async () => {
|
|
138
|
+
const timeoutError = new Error("prompt timed out after 5000ms");
|
|
139
|
+
const prompt = mock(async () => {
|
|
140
|
+
throw timeoutError;
|
|
141
|
+
});
|
|
142
|
+
const client = createClient(prompt);
|
|
143
|
+
|
|
144
|
+
await expect(
|
|
145
|
+
promptSyncWithModelSuggestionRetry(client, createArgs(), {
|
|
146
|
+
fallbackModels: ["anthropic/claude-sonnet-4-6"],
|
|
147
|
+
}),
|
|
148
|
+
).rejects.toBe(timeoutError);
|
|
149
|
+
expect(prompt).toHaveBeenCalledTimes(1);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("context overflow short-circuits", async () => {
|
|
153
|
+
const overflowError = new Error("prompt is too long: 50000 tokens > 32000");
|
|
154
|
+
const prompt = mock(async () => {
|
|
155
|
+
throw overflowError;
|
|
156
|
+
});
|
|
157
|
+
const client = createClient(prompt);
|
|
158
|
+
|
|
159
|
+
await expect(
|
|
160
|
+
promptSyncWithModelSuggestionRetry(client, createArgs(), {
|
|
161
|
+
fallbackModels: ["anthropic/claude-sonnet-4-6"],
|
|
162
|
+
}),
|
|
163
|
+
).rejects.toBe(overflowError);
|
|
164
|
+
expect(prompt).toHaveBeenCalledTimes(1);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("suggestion retry within attempt succeeds", async () => {
|
|
168
|
+
const suggestionError = new Error("model not found");
|
|
169
|
+
suggestionError.name = "ProviderModelNotFoundError";
|
|
170
|
+
Object.assign(suggestionError, {
|
|
171
|
+
data: {
|
|
172
|
+
providerID: "anthropic",
|
|
173
|
+
modelID: "claude-sonnet-4-6",
|
|
174
|
+
suggestions: ["claude-sonnet-4-7"],
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
const prompt = mock(async () => {
|
|
178
|
+
if (prompt.mock.calls.length === 1) throw suggestionError;
|
|
179
|
+
return {};
|
|
180
|
+
});
|
|
181
|
+
const client = createClient(prompt);
|
|
182
|
+
|
|
183
|
+
await promptSyncWithModelSuggestionRetry(
|
|
184
|
+
client,
|
|
185
|
+
createArgs({ providerID: "anthropic", modelID: "claude-sonnet-4-6" }),
|
|
186
|
+
{ fallbackModels: ["google/gemini-3-flash"] },
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
expect(prompt).toHaveBeenCalledTimes(2);
|
|
190
|
+
expect((prompt.mock.calls[1]?.[0] as PromptCall).body.model).toEqual({
|
|
191
|
+
providerID: "anthropic",
|
|
192
|
+
modelID: "claude-sonnet-4-7",
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test("invalid fallback specs are skipped", async () => {
|
|
197
|
+
const prompt = mock(async () => {
|
|
198
|
+
if (prompt.mock.calls.length === 1) throw new Error("primary failed");
|
|
199
|
+
return {};
|
|
200
|
+
});
|
|
201
|
+
const client = createClient(prompt);
|
|
202
|
+
|
|
203
|
+
await promptSyncWithModelSuggestionRetry(client, createArgs(), {
|
|
204
|
+
fallbackModels: ["no-slash", "/leading", "valid/model"],
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
expect(prompt).toHaveBeenCalledTimes(2);
|
|
208
|
+
expect((prompt.mock.calls[1]?.[0] as PromptCall).body.model).toEqual({
|
|
209
|
+
providerID: "valid",
|
|
210
|
+
modelID: "model",
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test("iteration order respected", async () => {
|
|
215
|
+
const prompt = mock(async () => {
|
|
216
|
+
throw new Error(`failed ${prompt.mock.calls.length}`);
|
|
217
|
+
});
|
|
218
|
+
const client = createClient(prompt);
|
|
219
|
+
|
|
220
|
+
await expect(
|
|
221
|
+
promptSyncWithModelSuggestionRetry(client, createArgs(), {
|
|
222
|
+
fallbackModels: [
|
|
223
|
+
"anthropic/claude-sonnet-4-6",
|
|
224
|
+
"google/gemini-3-flash",
|
|
225
|
+
"openrouter/qwen3-coder",
|
|
226
|
+
],
|
|
227
|
+
}),
|
|
228
|
+
).rejects.toThrow("failed 4");
|
|
229
|
+
|
|
230
|
+
expect(prompt).toHaveBeenCalledTimes(4);
|
|
231
|
+
expect(prompt.mock.calls.map((call) => (call[0] as PromptCall).body.model)).toEqual([
|
|
232
|
+
undefined,
|
|
233
|
+
{ providerID: "anthropic", modelID: "claude-sonnet-4-6" },
|
|
234
|
+
{ providerID: "google", modelID: "gemini-3-flash" },
|
|
235
|
+
{ providerID: "openrouter", modelID: "qwen3-coder" },
|
|
236
|
+
]);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test("empty fallbackModels = legacy", async () => {
|
|
240
|
+
const originalError = new Error("primary failed without suggestion");
|
|
241
|
+
const prompt = mock(async () => {
|
|
242
|
+
throw originalError;
|
|
243
|
+
});
|
|
244
|
+
const client = createClient(prompt);
|
|
245
|
+
|
|
246
|
+
await expect(
|
|
247
|
+
promptSyncWithModelSuggestionRetry(client, createArgs(), { fallbackModels: [] }),
|
|
248
|
+
).rejects.toBe(originalError);
|
|
249
|
+
expect(prompt).toHaveBeenCalledTimes(1);
|
|
250
|
+
});
|
|
251
|
+
});
|