@cortexkit/opencode-magic-context 0.22.0 → 0.22.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/README.md +10 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/schema/agent-overrides.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +15 -0
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-identity.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-openai.d.ts +6 -0
- package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-probe.d.ts +5 -0
- package/dist/features/magic-context/memory/embedding-probe.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/cache.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +195 -104
- package/dist/plugin/event.d.ts +10 -0
- package/dist/plugin/event.d.ts.map +1 -1
- package/dist/shared/announcement.d.ts +16 -0
- package/dist/shared/announcement.d.ts.map +1 -1
- package/dist/shared/models-dev-cache.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/shared/announcement.test.ts +23 -7
- package/src/shared/announcement.ts +24 -1
- package/src/shared/conflict-detector.test.ts +15 -2
- package/src/shared/conflict-fixer.test.ts +5 -1
- package/src/shared/models-dev-cache.test.ts +72 -4
- package/src/shared/models-dev-cache.ts +47 -8
- package/src/shared/opencode-compaction-detector.test.ts +10 -2
- package/src/shared/rpc-client.test.ts +5 -1
package/README.md
CHANGED
|
@@ -244,6 +244,16 @@ Settings live in `magic-context.jsonc`. Everything has sensible defaults; projec
|
|
|
244
244
|
|
|
245
245
|
All durable state lives in a local SQLite database under the shared CortexKit store (`~/.local/share/cortexkit/magic-context/context.db`, XDG-equivalent on Windows; legacy OpenCode-folder databases are migrated forward on first boot). If the database can't be opened, Magic Context disables itself and notifies you. Memories are keyed to a **stable project identity** derived from the repo, so they follow a project across worktrees, clones, and forks rather than being tied to a directory path.
|
|
246
246
|
|
|
247
|
+
Magic Context also writes to a few other locations:
|
|
248
|
+
|
|
249
|
+
| Path | What | Persistence |
|
|
250
|
+
|---|---|---|
|
|
251
|
+
| `~/.local/share/cortexkit/magic-context/context.db` | SQLite database — tags, compartments, memories, all durable state (XDG-equivalent on Windows) | **Must persist.** Losing it loses your memory/history. |
|
|
252
|
+
| `~/.local/share/cortexkit/magic-context/models/` | Local embedding model cache (~90 MB `Xenova/all-MiniLM-L6-v2` ONNX), downloaded on first use when local embeddings are enabled | Should persist, else re-downloaded each run. Not used when `memory.enabled: false` or an `openai_compatible`/`ollama` embedding backend is configured. |
|
|
253
|
+
| `${TMPDIR}/opencode/magic-context/magic-context.log` (`pi/` for Pi) | Diagnostic log | Disposable. |
|
|
254
|
+
|
|
255
|
+
**Sandboxed / ephemeral environments (Docker, CI, disposable containers):** mount the `~/.local/share/cortexkit/magic-context/` directory on a persistent volume so the database and model cache survive between runs. If only the model cache is ephemeral, the model is simply re-downloaded; if the database is ephemeral, memory and history don't accumulate. To avoid the ~90 MB model download entirely, set `memory.enabled: false` or point `embedding` at a remote `openai_compatible`/`ollama` backend.
|
|
256
|
+
|
|
247
257
|
---
|
|
248
258
|
|
|
249
259
|
## Star History
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,kBAAkB,EAA4B,MAAM,wBAAwB,CAAC;AAG3F,MAAM,WAAW,wBAAyB,SAAQ,kBAAkB;IAChE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CACZ,MAAM,EACN;QACI,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,OAAO,CAAC;KACrB,CACJ,CAAC;CACL;AAmBD,MAAM,MAAM,WAAW,GACjB,IAAI,GACJ,0BAA0B,GAC1B,uBAAuB,GACvB,iBAAiB,GACjB,sBAAsB,CAAC;AAE7B,MAAM,WAAW,kBAAkB;IAC/B,MAAM,EAAE,wBAAwB,GAAG;QAAE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACjE,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE;QACL,UAAU,EAAE,WAAW,CAAC;QACxB,aAAa,EAAE,WAAW,CAAC;KAC9B,CAAC;IACF,oBAAoB,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9F,qBAAqB,EAAE,MAAM,EAAE,CAAC;CACnC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,kBAAkB,EAA4B,MAAM,wBAAwB,CAAC;AAG3F,MAAM,WAAW,wBAAyB,SAAQ,kBAAkB;IAChE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CACZ,MAAM,EACN;QACI,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,OAAO,CAAC;KACrB,CACJ,CAAC;CACL;AAmBD,MAAM,MAAM,WAAW,GACjB,IAAI,GACJ,0BAA0B,GAC1B,uBAAuB,GACvB,iBAAiB,GACjB,sBAAsB,CAAC;AAE7B,MAAM,WAAW,kBAAkB;IAC/B,MAAM,EAAE,wBAAwB,GAAG;QAAE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACjE,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE;QACL,UAAU,EAAE,WAAW,CAAC;QACxB,aAAa,EAAE,WAAW,CAAC;KAC9B,CAAC;IACF,oBAAoB,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9F,qBAAqB,EAAE,MAAM,EAAE,CAAC;CACnC;AAwQD,wBAAgB,gBAAgB,CAC5B,SAAS,EAAE,MAAM,GAClB,wBAAwB,GAAG;IAAE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CA2E1D;AAgDD,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,CAuE9E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-overrides.d.ts","sourceRoot":"","sources":["../../../src/config/schema/agent-overrides.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,iCAAiC,+CAAgD,CAAC;AAgB/F,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"agent-overrides.d.ts","sourceRoot":"","sources":["../../../src/config/schema/agent-overrides.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,iCAAiC,+CAAgD,CAAC;AAgB/F,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4BpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export declare const DEFAULT_NUDGE_INTERVAL_TOKENS = 10000;
|
|
3
3
|
export declare const DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65;
|
|
4
|
+
export declare const EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 80% for cache safety: a single large agent step can overflow the context window before Magic Context can compact between turns, forcing OpenCode's native compaction (hard to recover from). 80% also leaves headroom below the 85%/95% emergency bands. Use a value between 20 and 80.";
|
|
4
5
|
export declare const DEFAULT_HISTORIAN_TIMEOUT_MS = 300000;
|
|
5
6
|
export declare const DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15;
|
|
6
7
|
export declare const DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2";
|
|
@@ -241,10 +242,14 @@ export declare const EmbeddingConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
241
242
|
model: z.ZodOptional<z.ZodString>;
|
|
242
243
|
endpoint: z.ZodOptional<z.ZodString>;
|
|
243
244
|
api_key: z.ZodOptional<z.ZodString>;
|
|
245
|
+
input_type: z.ZodOptional<z.ZodString>;
|
|
246
|
+
truncate: z.ZodOptional<z.ZodString>;
|
|
244
247
|
}, z.core.$strip>, z.ZodTransform<{
|
|
245
248
|
provider: "local";
|
|
246
249
|
model: string;
|
|
247
250
|
} | {
|
|
251
|
+
truncate?: string | undefined;
|
|
252
|
+
input_type?: string | undefined;
|
|
248
253
|
api_key?: string | undefined;
|
|
249
254
|
provider: "openai-compatible";
|
|
250
255
|
model: string;
|
|
@@ -257,6 +262,8 @@ export declare const EmbeddingConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
257
262
|
model?: string | undefined;
|
|
258
263
|
endpoint?: string | undefined;
|
|
259
264
|
api_key?: string | undefined;
|
|
265
|
+
input_type?: string | undefined;
|
|
266
|
+
truncate?: string | undefined;
|
|
260
267
|
}>>;
|
|
261
268
|
export type EmbeddingConfig = z.infer<typeof EmbeddingConfigSchema>;
|
|
262
269
|
export interface MagicContextConfig {
|
|
@@ -560,10 +567,14 @@ export declare const MagicContextConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
560
567
|
model: z.ZodOptional<z.ZodString>;
|
|
561
568
|
endpoint: z.ZodOptional<z.ZodString>;
|
|
562
569
|
api_key: z.ZodOptional<z.ZodString>;
|
|
570
|
+
input_type: z.ZodOptional<z.ZodString>;
|
|
571
|
+
truncate: z.ZodOptional<z.ZodString>;
|
|
563
572
|
}, z.core.$strip>, z.ZodTransform<{
|
|
564
573
|
provider: "local";
|
|
565
574
|
model: string;
|
|
566
575
|
} | {
|
|
576
|
+
truncate?: string | undefined;
|
|
577
|
+
input_type?: string | undefined;
|
|
567
578
|
api_key?: string | undefined;
|
|
568
579
|
provider: "openai-compatible";
|
|
569
580
|
model: string;
|
|
@@ -576,6 +587,8 @@ export declare const MagicContextConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
576
587
|
model?: string | undefined;
|
|
577
588
|
endpoint?: string | undefined;
|
|
578
589
|
api_key?: string | undefined;
|
|
590
|
+
input_type?: string | undefined;
|
|
591
|
+
truncate?: string | undefined;
|
|
579
592
|
}>>>;
|
|
580
593
|
temporal_awareness: z.ZodDefault<z.ZodBoolean>;
|
|
581
594
|
caveman_text_compression: z.ZodDefault<z.ZodObject<{
|
|
@@ -692,6 +705,8 @@ export declare const MagicContextConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
692
705
|
provider: "local";
|
|
693
706
|
model: string;
|
|
694
707
|
} | {
|
|
708
|
+
truncate?: string | undefined;
|
|
709
|
+
input_type?: string | undefined;
|
|
695
710
|
api_key?: string | undefined;
|
|
696
711
|
provider: "openai-compatible";
|
|
697
712
|
model: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"magic-context.d.ts","sourceRoot":"","sources":["../../../src/config/schema/magic-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,6BAA6B,QAAS,CAAC;AACpD,eAAO,MAAM,oCAAoC,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"magic-context.d.ts","sourceRoot":"","sources":["../../../src/config/schema/magic-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,6BAA6B,QAAS,CAAC;AACpD,eAAO,MAAM,oCAAoC,KAAK,CAAC;AAOvD,eAAO,MAAM,6BAA6B,2TACkR,CAAC;AAC7T,eAAO,MAAM,4BAA4B,SAAU,CAAC;AACpD,eAAO,MAAM,iCAAiC,OAAO,CAAC;AACtD,eAAO,MAAM,6BAA6B,4BAA4B,CAAC;AAEvE,eAAO,MAAM,aAAa,iFAMhB,CAAC;AAEX,eAAO,MAAM,kBAAkB;;;;;;EAAwB,CAAC;AACxD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,qBAAqB,EAAE,YAAY,EAK/C,CAAC;AAEF;;iEAEiE;AACjE,eAAO,MAAM,qBAAqB;;;;;;;GAEnB,CAAC;AAChB,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,wDAAwD;AACxD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0E/B,CAAC;AACF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAMpB,CAAC;AACd,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC;AAE/E;;;;2CAI2C;AAC3C,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAUrB,CAAC;AACd,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC;AAkDjF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuBhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,MAAM,WAAW,kBAAkB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB;8EAC0E;IAC1E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;oFAEgF;IAChF,kBAAkB,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACpE,qBAAqB,EAAE,MAAM,CAAC;IAC9B,4BAA4B,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACvF;;uGAEmG;IACnG,wBAAwB,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IACxF,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,yBAAyB,EAAE,MAAM,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;IAClC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,sBAAsB,EAAE;QACpB,OAAO,EAAE,OAAO,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,uEAAuE;IACvE,MAAM,EAAE;QACJ,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;KACxB,CAAC;IACF;;;;;;;OAOG;IACH,uBAAuB,EAAE;QACrB,4EAA4E;QAC5E,OAAO,EAAE,OAAO,CAAC;QACjB;;;;;;;WAOG;QACH,eAAe,EAAE,MAAM,EAAE,CAAC;KAC7B,CAAC;IACF;;2EAEuE;IACvE,kBAAkB,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;;;;;OAaG;IACH,wBAAwB,EAAE;QACtB,OAAO,EAAE,OAAO,CAAC;QACjB,oEAAoE;QACpE,SAAS,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,SAAS,EAAE,eAAe,CAAC;IAC3B,MAAM,EAAE;QACJ,OAAO,EAAE,OAAO,CAAC;QACjB,uBAAuB,EAAE,MAAM,CAAC;QAChC,YAAY,EAAE,OAAO,CAAC;QACtB,mCAAmC,EAAE,MAAM,CAAC;QAC5C;;;;;;uCAM+B;QAC/B,WAAW,EAAE;YACT,OAAO,EAAE,OAAO,CAAC;YACjB,qEAAqE;YACrE,eAAe,EAAE,MAAM,CAAC;YACxB,sEAAsE;YACtE,gBAAgB,EAAE,MAAM,CAAC;SAC5B,CAAC;QACF;;;;mCAI2B;QAC3B,mBAAmB,EAAE;YACjB,OAAO,EAAE,OAAO,CAAC;YACjB,8CAA8C;YAC9C,UAAU,EAAE,MAAM,CAAC;YACnB,mEAAmE;YACnE,WAAW,EAAE,MAAM,CAAC;SACvB,CAAC;KACL,CAAC;IACF,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC7B;AAED,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8S/B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embedding-identity.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/memory/embedding-identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAQ5E;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"embedding-identity.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/memory/embedding-identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAQ5E;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CA0B5E"}
|
|
@@ -3,6 +3,10 @@ interface OpenAICompatibleEmbeddingProviderOptions {
|
|
|
3
3
|
endpoint?: string;
|
|
4
4
|
model?: string;
|
|
5
5
|
apiKey?: string;
|
|
6
|
+
/** Optional `input_type` body field (e.g. NVIDIA NIM 'query'/'passage'). */
|
|
7
|
+
inputType?: string;
|
|
8
|
+
/** Optional `truncate` body field (e.g. NVIDIA NIM 'NONE'/'START'/'END'). */
|
|
9
|
+
truncate?: string;
|
|
6
10
|
}
|
|
7
11
|
type CircuitState = "closed" | "open" | "half_open";
|
|
8
12
|
export declare class OpenAICompatibleEmbeddingProvider implements EmbeddingProvider {
|
|
@@ -10,6 +14,8 @@ export declare class OpenAICompatibleEmbeddingProvider implements EmbeddingProvi
|
|
|
10
14
|
private readonly endpoint;
|
|
11
15
|
private readonly model;
|
|
12
16
|
private readonly apiKey;
|
|
17
|
+
private readonly inputType;
|
|
18
|
+
private readonly truncate;
|
|
13
19
|
private initialized;
|
|
14
20
|
private failureTimes;
|
|
15
21
|
private circuitOpenUntil;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embedding-openai.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/memory/embedding-openai.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,UAAU,wCAAwC;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"embedding-openai.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/memory/embedding-openai.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,UAAU,wCAAwC;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAyCD,KAAK,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAEpD,qBAAa,iCAAkC,YAAW,iBAAiB;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,WAAW,CAAS;IAI5B,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B;;sDAEkD;IAClD,OAAO,CAAC,qBAAqB,CAAS;gBAE1B,OAAO,EAAE,wCAAwC;IAcvD,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAc9B,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAKvE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC;IAkJnF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAI9B,QAAQ,IAAI,OAAO;IAInB;;;;;;;;OAQG;IACH,OAAO,CAAC,wBAAwB;IAsBhC,OAAO,CAAC,aAAa;IAiCrB,OAAO,CAAC,aAAa;IAUrB,gBAAgB,IAAI,YAAY;IAQhC,gBAAgB,IAAI,MAAM;IAG1B,aAAa,IAAI,IAAI;CAMxB"}
|
|
@@ -43,6 +43,11 @@ export interface EmbeddingProbeOptions {
|
|
|
43
43
|
endpoint: string;
|
|
44
44
|
model: string;
|
|
45
45
|
apiKey?: string;
|
|
46
|
+
/** Optional `input_type` body field — required by some providers (NVIDIA NIM)
|
|
47
|
+
* for the probe to succeed. Omitted from the body when unset. */
|
|
48
|
+
inputType?: string;
|
|
49
|
+
/** Optional `truncate` body field (e.g. NVIDIA NIM). Omitted when unset. */
|
|
50
|
+
truncate?: string;
|
|
46
51
|
/** Milliseconds before aborting the request. Defaults to 10000. */
|
|
47
52
|
timeoutMs?: number;
|
|
48
53
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embedding-probe.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/memory/embedding-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,MAAM,qBAAqB,GAC3B;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACjE;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,MAAM,WAAW,qBAAqB;IAClC;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAKD;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CACxC,OAAO,EAAE,qBAAqB,GAC/B,OAAO,CAAC,qBAAqB,CAAC,
|
|
1
|
+
{"version":3,"file":"embedding-probe.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/memory/embedding-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,MAAM,qBAAqB,GAC3B;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACjE;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,MAAM,WAAW,qBAAqB;IAClC;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;sEACkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAKD;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CACxC,OAAO,EAAE,qBAAqB,GAC/B,OAAO,CAAC,qBAAqB,CAAC,CAsFhC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/memory/embedding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAG5E,OAAO,KAAK,EAAE,QAAQ,EAAkC,MAAM,wBAAwB,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAOvD,YAAY,EACR,iBAAiB,EACjB,oCAAoC,GACvC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACH,sCAAsC,EACtC,iCAAiC,EACjC,oBAAoB,EACpB,mBAAmB,EACnB,iCAAiC,EACjC,2BAA2B,EAC3B,oCAAoC,EACpC,gCAAgC,EAChC,0BAA0B,EAC1B,0BAA0B,GAC7B,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/memory/embedding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAG5E,OAAO,KAAK,EAAE,QAAQ,EAAkC,MAAM,wBAAwB,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAOvD,YAAY,EACR,iBAAiB,EACjB,oCAAoC,GACvC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACH,sCAAsC,EACtC,iCAAiC,EACjC,oBAAoB,EACpB,mBAAmB,EACnB,iCAAiC,EACjC,2BAA2B,EAC3B,oCAAoC,EACpC,gCAAgC,EAChC,0BAA0B,EAC1B,0BAA0B,GAC7B,MAAM,+BAA+B,CAAC;AA0FvC,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAoBjE;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO7D;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAWhG;AAED,wBAAsB,UAAU,CAC5B,KAAK,EAAE,MAAM,EAAE,EACf,MAAM,CAAC,EAAE,WAAW,GACrB,OAAO,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC,CAelC;AAED,wBAAsB,uBAAuB,CACzC,EAAE,EAAE,QAAQ,EACZ,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,eAAe,EACvB,SAAS,SAAK,GACf,OAAO,CAAC,MAAM,CAAC,CAEjB;AAgBD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,0BAA0B,CAC5C,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,eAAe,EACvB,SAAS,SAAK,GACf,OAAO,CAAC,MAAM,CAAC,CAsEjB;AAED,8CAA8C;AAC9C,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAmDD,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAE5B,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAS3D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/hooks/auto-update-checker/cache.ts"],"names":[],"mappings":"AAmBA,UAAU,wBAAwB;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CAC3B;
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/hooks/auto-update-checker/cache.ts"],"names":[],"mappings":"AAmBA,UAAU,wBAAwB;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CAC3B;AAoHD,wBAAgB,qBAAqB,CACjC,sBAAsB,GAAE,MAAM,GAAG,IAAyC,GAC3E,wBAAwB,GAAG,IAAI,CA2CjC;AAED,wBAAgB,oBAAoB,CAChC,OAAO,EAAE,MAAM,EACf,WAAW,GAAE,MAAqB,EAClC,sBAAsB,GAAE,MAAM,GAAG,IAAyC,GAC3E,MAAM,GAAG,IAAI,CAyBf;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CACnC,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAO,GAC3D,OAAO,CAAC,OAAO,CAAC,CAgDlB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-resolvers.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/event-resolvers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAQ5E,KAAK,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEtD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,GAAG,CAAC,EAAE;IAAE,EAAE,CAAC,EAAE,eAAe,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD,MAAM,CAoBR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACtC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,GAAG,CAAC,EAAE;IAAE,EAAE,CAAC,EAAE,eAAe,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD,MAAM,GAAG,SAAS,CAwBpB;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAiB9F;AAED,KAAK,sBAAsB,GAAG,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC;AACvF,KAAK,4BAA4B,GAC3B;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAAE,GAC5D,SAAS,CAAC;AAEhB,MAAM,WAAW,uBAAuB;IACpC;oDACgD;IAChD,YAAY,CAAC,EAAE,4BAA4B,CAAC;IAC5C;yDACqD;IACrD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,QAAQ,CAAC;AAE3D,MAAM,WAAW,sBAAsB;IACnC,yFAAyF;IACzF,UAAU,EAAE,MAAM,CAAC;IACnB,kGAAkG;IAClG,IAAI,EAAE,oBAAoB,CAAC;IAC3B,6FAA6F;IAC7F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sGAAsG;IACtG,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AA8CD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CACzC,MAAM,EAAE,sBAAsB,EAC9B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,uBAAuB,GAClC,sBAAsB,
|
|
1
|
+
{"version":3,"file":"event-resolvers.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/event-resolvers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAQ5E,KAAK,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEtD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,GAAG,CAAC,EAAE;IAAE,EAAE,CAAC,EAAE,eAAe,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD,MAAM,CAoBR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACtC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,GAAG,CAAC,EAAE;IAAE,EAAE,CAAC,EAAE,eAAe,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD,MAAM,GAAG,SAAS,CAwBpB;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAiB9F;AAED,KAAK,sBAAsB,GAAG,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC;AACvF,KAAK,4BAA4B,GAC3B;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAAE,GAC5D,SAAS,CAAC;AAEhB,MAAM,WAAW,uBAAuB;IACpC;oDACgD;IAChD,YAAY,CAAC,EAAE,4BAA4B,CAAC;IAC5C;yDACqD;IACrD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,QAAQ,CAAC;AAE3D,MAAM,WAAW,sBAAsB;IACnC,yFAAyF;IACzF,UAAU,EAAE,MAAM,CAAC;IACnB,kGAAkG;IAClG,IAAI,EAAE,oBAAoB,CAAC;IAC3B,6FAA6F;IAC7F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sGAAsG;IACtG,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AA8CD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CACzC,MAAM,EAAE,sBAAsB,EAC9B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,uBAAuB,GAClC,sBAAsB,CA8FxB;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACnC,MAAM,EAAE,sBAAsB,EAC9B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,uBAAuB,GAClC,MAAM,CAER;AA2BD,wBAAgB,eAAe,CAC3B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,GAC5B,MAAM,GAAG,SAAS,CAMpB;AAED,wBAAgB,gBAAgB,CAC5B,UAAU,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAC/D,MAAM,GAAG,SAAS,CAmBpB"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AA6ClD,QAAA,MAAM,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AA6ClD,QAAA,MAAM,MAAM,EAAE,MA4gBb,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -14818,25 +14818,25 @@ var init_agent_overrides = __esm(() => {
|
|
|
14818
14818
|
external_directory: PermissionValueSchema.optional()
|
|
14819
14819
|
}).optional();
|
|
14820
14820
|
AgentOverrideConfigSchema = exports_external.object({
|
|
14821
|
-
model: exports_external.string().optional(),
|
|
14822
|
-
temperature: exports_external.number().min(0).max(2).optional(),
|
|
14823
|
-
top_p: exports_external.number().min(0).max(1).optional(),
|
|
14824
|
-
prompt: exports_external.string().optional(),
|
|
14825
|
-
tools: exports_external.record(exports_external.string(), exports_external.boolean()).optional(),
|
|
14826
|
-
disable: exports_external.boolean().optional(),
|
|
14827
|
-
description: exports_external.string().optional(),
|
|
14828
|
-
mode: exports_external.enum(["subagent", "primary", "all"]).optional(),
|
|
14829
|
-
color: exports_external.string().regex(/^#[0-9A-Fa-f]{6}$/).optional(),
|
|
14830
|
-
maxSteps: exports_external.number().optional(),
|
|
14831
|
-
permission: PermissionSchema,
|
|
14832
|
-
maxTokens: exports_external.number().optional(),
|
|
14833
|
-
variant: exports_external.string().optional(),
|
|
14834
|
-
fallback_models: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional()
|
|
14821
|
+
model: exports_external.string().optional().describe("Primary model ID (e.g. 'claude-sonnet-4-6')"),
|
|
14822
|
+
temperature: exports_external.number().min(0).max(2).optional().describe("Sampling temperature (0-2)"),
|
|
14823
|
+
top_p: exports_external.number().min(0).max(1).optional().describe("Nucleus sampling top_p (0-1)"),
|
|
14824
|
+
prompt: exports_external.string().optional().describe("Additional system prompt text"),
|
|
14825
|
+
tools: exports_external.record(exports_external.string(), exports_external.boolean()).optional().describe("Tool enable/disable overrides"),
|
|
14826
|
+
disable: exports_external.boolean().optional().describe("Disable this agent"),
|
|
14827
|
+
description: exports_external.string().optional().describe("Agent description"),
|
|
14828
|
+
mode: exports_external.enum(["subagent", "primary", "all"]).optional().describe("Agent mode (subagent, primary, or all)"),
|
|
14829
|
+
color: exports_external.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe("Hex color for the agent (e.g. '#a1b2c3')"),
|
|
14830
|
+
maxSteps: exports_external.number().optional().describe("Maximum tool-call steps per invocation"),
|
|
14831
|
+
permission: PermissionSchema.describe("Per-tool permission overrides"),
|
|
14832
|
+
maxTokens: exports_external.number().optional().describe("Maximum output tokens"),
|
|
14833
|
+
variant: exports_external.string().optional().describe("OpenCode reasoning variant (e.g. for extended thinking)"),
|
|
14834
|
+
fallback_models: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional().describe("Fallback model IDs if primary is unavailable")
|
|
14835
14835
|
});
|
|
14836
14836
|
});
|
|
14837
14837
|
|
|
14838
14838
|
// src/config/schema/magic-context.ts
|
|
14839
|
-
var DEFAULT_NUDGE_INTERVAL_TOKENS = 1e4, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65, DEFAULT_HISTORIAN_TIMEOUT_MS = 300000, DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15, DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2", DREAMER_TASKS, DreamingTaskSchema, DEFAULT_DREAMER_TASKS, PiThinkingLevelSchema, DreamerConfigSchema, SidekickConfigSchema, HistorianConfigSchema, BaseEmbeddingConfigSchema, EmbeddingConfigSchema, MagicContextConfigSchema;
|
|
14839
|
+
var DEFAULT_NUDGE_INTERVAL_TOKENS = 1e4, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65, EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 80% for cache safety: a single large agent step can overflow the context window before Magic Context can compact between turns, forcing OpenCode's native compaction (hard to recover from). 80% also leaves headroom below the 85%/95% emergency bands. Use a value between 20 and 80.", DEFAULT_HISTORIAN_TIMEOUT_MS = 300000, DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15, DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2", DREAMER_TASKS, DreamingTaskSchema, DEFAULT_DREAMER_TASKS, PiThinkingLevelSchema, DreamerConfigSchema, SidekickConfigSchema, HistorianConfigSchema, BaseEmbeddingConfigSchema, EmbeddingConfigSchema, MagicContextConfigSchema;
|
|
14840
14840
|
var init_magic_context = __esm(() => {
|
|
14841
14841
|
init_zod();
|
|
14842
14842
|
init_agent_overrides();
|
|
@@ -14856,36 +14856,38 @@ var init_magic_context = __esm(() => {
|
|
|
14856
14856
|
];
|
|
14857
14857
|
PiThinkingLevelSchema = exports_external.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional();
|
|
14858
14858
|
DreamerConfigSchema = AgentOverrideConfigSchema.merge(exports_external.object({
|
|
14859
|
-
schedule: exports_external.string().default("02:00-06:00"),
|
|
14860
|
-
max_runtime_minutes: exports_external.number().min(10).default(120),
|
|
14861
|
-
tasks: exports_external.array(DreamingTaskSchema).default(DEFAULT_DREAMER_TASKS),
|
|
14862
|
-
task_timeout_minutes: exports_external.number().min(5).default(20),
|
|
14863
|
-
inject_docs: exports_external.boolean().default(true),
|
|
14859
|
+
schedule: exports_external.string().default("02:00-06:00").describe("Scheduled window for overnight dreaming (e.g. '02:00-06:00')"),
|
|
14860
|
+
max_runtime_minutes: exports_external.number().min(10).default(120).describe("Maximum runtime per dream session in minutes"),
|
|
14861
|
+
tasks: exports_external.array(DreamingTaskSchema).default(DEFAULT_DREAMER_TASKS).describe("Tasks to run during dreaming, in order"),
|
|
14862
|
+
task_timeout_minutes: exports_external.number().min(5).default(20).describe("Minutes allocated per task before moving to next"),
|
|
14863
|
+
inject_docs: exports_external.boolean().default(true).describe("Inject ARCHITECTURE.md and STRUCTURE.md into system prompt"),
|
|
14864
14864
|
user_memories: exports_external.object({
|
|
14865
|
-
enabled: exports_external.boolean().default(true),
|
|
14866
|
-
promotion_threshold: exports_external.number().min(2).max(20).default(3)
|
|
14867
|
-
}).default({ enabled: true, promotion_threshold: 3 }),
|
|
14865
|
+
enabled: exports_external.boolean().default(true).describe("Enable user memory extraction and promotion (default: true)"),
|
|
14866
|
+
promotion_threshold: exports_external.number().min(2).max(20).default(3).describe("Minimum candidate observations before dreamer considers promotion (default: 3)")
|
|
14867
|
+
}).default({ enabled: true, promotion_threshold: 3 }).describe("User memory pipeline: historian extracts behavior observations from each compartment run; dreamer reviews recurring patterns and promotes them to stable user memories injected into all sessions as <user-profile>. Requires dreamer to not be disabled for promotion to actually happen. Graduated from experimental in v0.14. Default: enabled."),
|
|
14868
14868
|
pin_key_files: exports_external.object({
|
|
14869
|
-
enabled: exports_external.boolean().default(false),
|
|
14870
|
-
token_budget: exports_external.number().min(2000).max(30000).default(1e4),
|
|
14871
|
-
min_reads: exports_external.number().min(2).max(20).default(4)
|
|
14872
|
-
}).default({ enabled: false, token_budget: 1e4, min_reads: 4 }),
|
|
14873
|
-
thinking_level: PiThinkingLevelSchema
|
|
14869
|
+
enabled: exports_external.boolean().default(false).describe("Enable key file pinning (default: false)"),
|
|
14870
|
+
token_budget: exports_external.number().min(2000).max(30000).default(1e4).describe("Total token budget for all pinned key files (min: 2000, max: 30000, default: 10000)"),
|
|
14871
|
+
min_reads: exports_external.number().min(2).max(20).default(4).describe("Minimum full-read count before a file is considered for pinning (min: 2, default: 4)")
|
|
14872
|
+
}).default({ enabled: false, token_budget: 1e4, min_reads: 4 }).describe("Pin frequently-read key files into the system prompt so the agent doesn't need to re-read them after context drops. Dreamer identifies key files per session based on read patterns. Requires dreamer to not be disabled for selection to happen. Graduated from experimental in v0.14. Default: disabled."),
|
|
14873
|
+
thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level for dreamer subagent invocations. See historian.thinking_level.")
|
|
14874
14874
|
}));
|
|
14875
14875
|
SidekickConfigSchema = AgentOverrideConfigSchema.extend({
|
|
14876
|
-
timeout_ms: exports_external.number().default(30000),
|
|
14877
|
-
system_prompt: exports_external.string().optional(),
|
|
14878
|
-
thinking_level: PiThinkingLevelSchema
|
|
14876
|
+
timeout_ms: exports_external.number().default(30000).describe("Timeout for sidekick calls in milliseconds"),
|
|
14877
|
+
system_prompt: exports_external.string().optional().describe("Custom system prompt for sidekick"),
|
|
14878
|
+
thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level for sidekick subagent invocations. See historian.thinking_level.")
|
|
14879
14879
|
}).optional();
|
|
14880
14880
|
HistorianConfigSchema = AgentOverrideConfigSchema.extend({
|
|
14881
|
-
two_pass: exports_external.boolean().default(false),
|
|
14882
|
-
thinking_level: PiThinkingLevelSchema
|
|
14881
|
+
two_pass: exports_external.boolean().default(false).describe("Run a second editor pass over historian output to clean low-signal U: lines and cross-compartment duplicates. Adds ~1 extra API call and ~1.3x cost per historian run. Useful for models without extended thinking support. (default: false)"),
|
|
14882
|
+
thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level passed as --thinking <level> to Pi historian subagent invocations. Required when using reasoning models (e.g. github-copilot/gpt-5.4) because Pi's default thinking-level resolution can pick a value the provider rejects. OpenCode users set variant instead. Valid: off | minimal | low | medium | high | xhigh")
|
|
14883
14883
|
}).optional();
|
|
14884
14884
|
BaseEmbeddingConfigSchema = exports_external.object({
|
|
14885
|
-
provider: exports_external.enum(["local", "openai-compatible", "off"]).default("local"),
|
|
14886
|
-
model: exports_external.string().optional(),
|
|
14887
|
-
endpoint: exports_external.string().optional(),
|
|
14888
|
-
api_key: exports_external.string().optional()
|
|
14885
|
+
provider: exports_external.enum(["local", "openai-compatible", "off"]).default("local").describe("Embedding provider. 'local' uses Xenova/all-MiniLM-L6-v2, 'openai-compatible' requires endpoint and model, 'off' disables embeddings."),
|
|
14886
|
+
model: exports_external.string().optional().describe("Embedding model name. Required for openai-compatible, ignored for local."),
|
|
14887
|
+
endpoint: exports_external.string().optional().describe("API endpoint URL. Required when provider is openai-compatible."),
|
|
14888
|
+
api_key: exports_external.string().optional().describe("API key for remote embedding provider (optional)"),
|
|
14889
|
+
input_type: exports_external.string().optional().describe("Optional input_type sent in the embedding request body. Required by some openai-compatible providers (e.g. NVIDIA NIM expects 'query' or 'passage'). Omitted from the request when unset."),
|
|
14890
|
+
truncate: exports_external.string().optional().describe("Optional truncate mode sent in the embedding request body (e.g. NVIDIA NIM accepts 'NONE' | 'START' | 'END'). Omitted from the request when unset.")
|
|
14889
14891
|
}).superRefine((data, ctx) => {
|
|
14890
14892
|
if (data.provider === "openai-compatible" && !data.endpoint?.trim()) {
|
|
14891
14893
|
ctx.addIssue({
|
|
@@ -14911,76 +14913,80 @@ var init_magic_context = __esm(() => {
|
|
|
14911
14913
|
}
|
|
14912
14914
|
if (data.provider === "openai-compatible") {
|
|
14913
14915
|
const apiKey = data.api_key?.trim();
|
|
14916
|
+
const inputType = data.input_type?.trim();
|
|
14917
|
+
const truncate = data.truncate?.trim();
|
|
14914
14918
|
return {
|
|
14915
14919
|
provider: "openai-compatible",
|
|
14916
14920
|
model: data.model?.trim() ?? "",
|
|
14917
14921
|
endpoint: data.endpoint?.trim() ?? "",
|
|
14918
|
-
...apiKey ? { api_key: apiKey } : {}
|
|
14922
|
+
...apiKey ? { api_key: apiKey } : {},
|
|
14923
|
+
...inputType ? { input_type: inputType } : {},
|
|
14924
|
+
...truncate ? { truncate } : {}
|
|
14919
14925
|
};
|
|
14920
14926
|
}
|
|
14921
14927
|
return { provider: "off" };
|
|
14922
14928
|
});
|
|
14923
14929
|
MagicContextConfigSchema = exports_external.object({
|
|
14924
|
-
enabled: exports_external.boolean().default(true),
|
|
14925
|
-
auto_update: exports_external.boolean().optional(),
|
|
14926
|
-
ctx_reduce_enabled: exports_external.boolean().default(true),
|
|
14927
|
-
historian: HistorianConfigSchema,
|
|
14928
|
-
dreamer: DreamerConfigSchema.optional(),
|
|
14929
|
-
cache_ttl: exports_external.union([exports_external.string(), exports_external.object({ default: exports_external.string() }).catchall(exports_external.string())]).default("5m"),
|
|
14930
|
-
nudge_interval_tokens: exports_external.number().min(1000).default(DEFAULT_NUDGE_INTERVAL_TOKENS),
|
|
14930
|
+
enabled: exports_external.boolean().default(true).describe("Enable magic context (default: true)"),
|
|
14931
|
+
auto_update: exports_external.boolean().optional().describe("Enable automatic npm self-update checks for the OpenCode plugin. Security: USER-only in config loader, so hostile project configs cannot suppress updates."),
|
|
14932
|
+
ctx_reduce_enabled: exports_external.boolean().default(true).describe("When false, ctx_reduce tool is hidden, all nudges disabled, and prompt guidance about ctx_reduce stripped. Heuristic cleanup, compartments, memory, and other features still work. (default: true)"),
|
|
14933
|
+
historian: HistorianConfigSchema.describe("Historian agent configuration (model, fallback_models, variant, temperature, maxTokens, permission, two_pass, etc.)"),
|
|
14934
|
+
dreamer: DreamerConfigSchema.optional().describe("Dreamer agent + scheduling configuration (model, fallback_models, disable, schedule, tasks, etc.)"),
|
|
14935
|
+
cache_ttl: exports_external.union([exports_external.string(), exports_external.object({ default: exports_external.string() }).catchall(exports_external.string())]).default("5m").describe('Cache TTL: string (e.g. "5m") or per-model object ({ default: "5m", "model-id": "10m" })'),
|
|
14936
|
+
nudge_interval_tokens: exports_external.number().min(1000).default(DEFAULT_NUDGE_INTERVAL_TOKENS).describe("Minimum token growth between low-priority rolling nudges (default: DEFAULT_NUDGE_INTERVAL_TOKENS)"),
|
|
14931
14937
|
execute_threshold_percentage: exports_external.union([
|
|
14932
|
-
exports_external.number().min(20).max(80),
|
|
14933
|
-
exports_external.object({ default: exports_external.number().min(20).max(80) }).catchall(exports_external.number().min(20).max(80))
|
|
14934
|
-
]).default(DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE),
|
|
14938
|
+
exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE),
|
|
14939
|
+
exports_external.object({ default: exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE) }).catchall(exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE))
|
|
14940
|
+
]).default(DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE).describe('Context percentage that forces queued operations to execute. Number or per-model object ({ default: 65, "provider/model": 45 }). Values above 80 are rejected because the runtime caps at 80% for cache safety (MAX_EXECUTE_THRESHOLD). Default: DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE'),
|
|
14935
14941
|
execute_threshold_tokens: exports_external.object({
|
|
14936
14942
|
default: exports_external.number().min(5000).max(2000000).optional()
|
|
14937
|
-
}).catchall(exports_external.number().min(5000).max(2000000)).optional(),
|
|
14938
|
-
protected_tags: exports_external.number().min(1).max(100).optional(),
|
|
14939
|
-
auto_drop_tool_age: exports_external.number().min(10).default(100),
|
|
14940
|
-
drop_tool_structure: exports_external.boolean().default(true),
|
|
14941
|
-
clear_reasoning_age: exports_external.number().min(10).default(50),
|
|
14942
|
-
iteration_nudge_threshold: exports_external.number().min(5).default(15),
|
|
14943
|
-
history_budget_percentage: exports_external.number().min(0.05).max(0.5).default(DEFAULT_HISTORY_BUDGET_PERCENTAGE),
|
|
14944
|
-
historian_timeout_ms: exports_external.number().min(60000).default(DEFAULT_HISTORIAN_TIMEOUT_MS),
|
|
14943
|
+
}).catchall(exports_external.number().min(5000).max(2000000)).optional().describe("Absolute token thresholds per model. When matched, overrides execute_threshold_percentage for that model. Accepts `default` for all models or per-model keys. Values above 80% × context_limit are clamped with a warning log. Min 5_000, max 2_000_000."),
|
|
14944
|
+
protected_tags: exports_external.number().min(1).max(100).optional().describe("Number of recent tags to protect from dropping (min: 1, max: 100, default: 20)"),
|
|
14945
|
+
auto_drop_tool_age: exports_external.number().min(10).default(100).describe("Auto-drop tool outputs older than N tags during queue execution (default: 100)"),
|
|
14946
|
+
drop_tool_structure: exports_external.boolean().default(true).describe("When true, dropped tool parts are fully removed instead of truncated in place (default: true)"),
|
|
14947
|
+
clear_reasoning_age: exports_external.number().min(10).default(50).describe("Clear reasoning/thinking blocks older than N tags (default: 50)"),
|
|
14948
|
+
iteration_nudge_threshold: exports_external.number().min(5).default(15).describe("Number of consecutive assistant messages without user input to trigger iteration nudge (default: 15)"),
|
|
14949
|
+
history_budget_percentage: exports_external.number().min(0.05).max(0.5).default(DEFAULT_HISTORY_BUDGET_PERCENTAGE).describe("Fraction of usable context (context_limit × execute_threshold) reserved for the session history block (default: 0.15)"),
|
|
14950
|
+
historian_timeout_ms: exports_external.number().min(60000).default(DEFAULT_HISTORIAN_TIMEOUT_MS).describe("Timeout for each historian prompt call in milliseconds (default: 300000)"),
|
|
14945
14951
|
commit_cluster_trigger: exports_external.object({
|
|
14946
|
-
enabled: exports_external.boolean().default(true),
|
|
14947
|
-
min_clusters: exports_external.number().min(1).default(3)
|
|
14948
|
-
}).default({ enabled: true, min_clusters: 3 }),
|
|
14952
|
+
enabled: exports_external.boolean().default(true).describe("Enable commit-cluster based historian triggering (default: true)"),
|
|
14953
|
+
min_clusters: exports_external.number().min(1).default(3).describe("Minimum commit clusters required to trigger historian (min: 1, default: 3)")
|
|
14954
|
+
}).default({ enabled: true, min_clusters: 3 }).describe("Commit-cluster trigger: fire historian when enough commit clusters accumulate in the unsummarized tail"),
|
|
14949
14955
|
system_prompt_injection: exports_external.object({
|
|
14950
|
-
enabled: exports_external.boolean().default(true),
|
|
14951
|
-
skip_signatures: exports_external.array(exports_external.string()).default(["<!-- magic-context: skip -->"])
|
|
14956
|
+
enabled: exports_external.boolean().default(true).describe("When false, NO injection happens for ANY agent — global escape hatch. (default: true)"),
|
|
14957
|
+
skip_signatures: exports_external.array(exports_external.string()).default(["<!-- magic-context: skip -->"]).describe(`Substring opt-out list. If the agent's system prompt contains any of these strings, skip ALL Magic Context injection for that call. Default "<!-- magic-context: skip -->" is meant to be added inside a user's custom agent prompt to opt that agent out.`)
|
|
14952
14958
|
}).default({
|
|
14953
14959
|
enabled: true,
|
|
14954
14960
|
skip_signatures: ["<!-- magic-context: skip -->"]
|
|
14955
|
-
}),
|
|
14961
|
+
}).describe("Controls whether and where Magic Context augments the system prompt. Lets users opt specific agents out of the Magic Context guidance and the surrounding project-docs / user-profile / key-files blocks. OpenCode's internal hidden agents — title, summary, and compaction — are always skipped automatically."),
|
|
14956
14962
|
sqlite: exports_external.object({
|
|
14957
|
-
cache_size_mb: exports_external.number().min(2).max(2048).default(64),
|
|
14958
|
-
mmap_size_mb: exports_external.number().min(0).max(8192).default(0)
|
|
14959
|
-
}).default({ cache_size_mb: 64, mmap_size_mb: 0 }),
|
|
14963
|
+
cache_size_mb: exports_external.number().min(2).max(2048).default(64).describe("Page-cache size in MiB per connection (PRAGMA cache_size). Larger keeps more hot pages resident, cutting re-reads on repeated full-table scans. (min 2, max 2048, default 64)"),
|
|
14964
|
+
mmap_size_mb: exports_external.number().min(0).max(8192).default(0).describe("Memory-mapped I/O size in MiB (PRAGMA mmap_size). 0 disables mmap (SQLite default). Raising it can cut read overhead on large DBs at the cost of address space. (min 0, max 8192, default 0)")
|
|
14965
|
+
}).default({ cache_size_mb: 64, mmap_size_mb: 0 }).describe("SQLite connection tuning for Magic Context's own context.db. These are per-connection PRAGMAs applied at open; they do not change the schema or what is stored."),
|
|
14960
14966
|
embedding: EmbeddingConfigSchema.default({
|
|
14961
14967
|
provider: "local",
|
|
14962
14968
|
model: DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
14963
|
-
}),
|
|
14964
|
-
temporal_awareness: exports_external.boolean().default(true),
|
|
14969
|
+
}).describe("Embedding provider configuration"),
|
|
14970
|
+
temporal_awareness: exports_external.boolean().default(true).describe('Inject wall-clock gap markers (<!-- +Xm -->) between user messages where > 5 min elapsed since the previous message, and add start/end date attributes on compartments. Gives the agent a sense of session pacing and "how long ago" across multi-day sessions. Graduated from experimental.temporal_awareness; default: true (set false to opt out).'),
|
|
14965
14971
|
caveman_text_compression: exports_external.object({
|
|
14966
|
-
enabled: exports_external.boolean().default(false),
|
|
14967
|
-
min_chars: exports_external.number().min(100).max(1e4).default(500)
|
|
14968
|
-
}).default({ enabled: false, min_chars: 500 }),
|
|
14972
|
+
enabled: exports_external.boolean().default(false).describe("Apply deterministic caveman-style text compression to old conversation text. Only active when ctx_reduce_enabled=false. Compresses user/assistant text in oldest-first tiers: ultra (oldest 20%), full, lite, untouched (newest 40%)."),
|
|
14973
|
+
min_chars: exports_external.number().min(100).max(1e4).default(500).describe("Text parts shorter than this (characters) stay untouched. Min 100, max 10000. Default: 500.")
|
|
14974
|
+
}).default({ enabled: false, min_chars: 500 }).describe("Age-tier caveman compression for long user/assistant text parts. Only active when ctx_reduce_enabled is false. Oldest 20% of eligible tags (outside protected tail) go to ultra, next 20% to full, next 20% to lite, newest 40% untouched. Graduated from experimental.caveman_text_compression; opt-in, default off (lossy)."),
|
|
14969
14975
|
memory: exports_external.object({
|
|
14970
|
-
enabled: exports_external.boolean().default(true),
|
|
14971
|
-
injection_budget_tokens: exports_external.number().min(500).max(20000).default(4000),
|
|
14972
|
-
auto_promote: exports_external.boolean().default(true),
|
|
14973
|
-
retrieval_count_promotion_threshold: exports_external.number().min(1).default(3),
|
|
14976
|
+
enabled: exports_external.boolean().default(true).describe("Enable cross-session memory (default: true)"),
|
|
14977
|
+
injection_budget_tokens: exports_external.number().min(500).max(20000).default(4000).describe("Token budget for memory injection on session start (min: 500, max: 20000, default: 4000)"),
|
|
14978
|
+
auto_promote: exports_external.boolean().default(true).describe("Automatically promote eligible session facts into memory (default: true)"),
|
|
14979
|
+
retrieval_count_promotion_threshold: exports_external.number().min(1).default(3).describe("retrieval_count threshold for promoting memory to permanent status (min: 1, default: 3)"),
|
|
14974
14980
|
auto_search: exports_external.object({
|
|
14975
|
-
enabled: exports_external.boolean().default(true),
|
|
14976
|
-
score_threshold: exports_external.number().min(0.3).max(0.95).default(0.6),
|
|
14977
|
-
min_prompt_chars: exports_external.number().min(5).max(500).default(20)
|
|
14978
|
-
}).default({ enabled: true, score_threshold: 0.6, min_prompt_chars: 20 }),
|
|
14981
|
+
enabled: exports_external.boolean().default(true).describe("Automatically append a compact <ctx-search-hint> to eligible user messages when relevant memories, conversation, or commits are found. Graduated from experimental.auto_search; on by default (set false to opt out). Independent of memory.enabled."),
|
|
14982
|
+
score_threshold: exports_external.number().min(0.3).max(0.95).default(0.6).describe("Top hit score must exceed this threshold for the hint to fire (min: 0.3, max: 0.95, default: 0.60)"),
|
|
14983
|
+
min_prompt_chars: exports_external.number().min(5).max(500).default(20).describe("Skip hint when user message is shorter than this (min: 5, max: 500, default: 20)")
|
|
14984
|
+
}).default({ enabled: true, score_threshold: 0.6, min_prompt_chars: 20 }).describe("Auto-search hint: transform-time ctx_search on each new user message; when the top hit clears the threshold, append a compact <ctx-search-hint> block of vague fragments to that user message. Does NOT inject full content. Graduated from experimental.auto_search; enabled by default (set enabled: false to opt out). Independent of memory.enabled."),
|
|
14979
14985
|
git_commit_indexing: exports_external.object({
|
|
14980
|
-
enabled: exports_external.boolean().default(false),
|
|
14981
|
-
since_days: exports_external.number().min(7).max(3650).default(365),
|
|
14982
|
-
max_commits: exports_external.number().min(100).max(20000).default(2000)
|
|
14983
|
-
}).default({ enabled: false, since_days: 365, max_commits: 2000 })
|
|
14986
|
+
enabled: exports_external.boolean().default(false).describe("Index HEAD git commits for ctx_search (git_commit source). Graduated from experimental.git_commit_indexing; opt-in, default off. Independent of memory.enabled."),
|
|
14987
|
+
since_days: exports_external.number().min(7).max(3650).default(365).describe("Days of HEAD history to index (min: 7, max: 3650, default: 365)"),
|
|
14988
|
+
max_commits: exports_external.number().min(100).max(20000).default(2000).describe("Max commits kept per project; oldest evicted (min: 100, max: 20000, default: 2000)")
|
|
14989
|
+
}).default({ enabled: false, since_days: 365, max_commits: 2000 }).describe("Index git commit messages from HEAD into ctx_search. Commits become a 4th searchable source alongside memories and session history. Graduated from experimental.git_commit_indexing; opt-in, default off (per-project embedding cost). Independent of memory.enabled.")
|
|
14984
14990
|
}).default({
|
|
14985
14991
|
enabled: true,
|
|
14986
14992
|
injection_budget_tokens: 4000,
|
|
@@ -14988,8 +14994,8 @@ var init_magic_context = __esm(() => {
|
|
|
14988
14994
|
retrieval_count_promotion_threshold: 3,
|
|
14989
14995
|
auto_search: { enabled: true, score_threshold: 0.6, min_prompt_chars: 20 },
|
|
14990
14996
|
git_commit_indexing: { enabled: false, since_days: 365, max_commits: 2000 }
|
|
14991
|
-
}),
|
|
14992
|
-
sidekick: SidekickConfigSchema
|
|
14997
|
+
}).describe("Cross-session memory configuration"),
|
|
14998
|
+
sidekick: SidekickConfigSchema.describe("Optional sidekick agent configuration for session-start memory retrieval")
|
|
14993
14999
|
}).transform((data) => {
|
|
14994
15000
|
return {
|
|
14995
15001
|
...data,
|
|
@@ -163633,7 +163639,8 @@ function getEmbeddingProviderIdentity(config2) {
|
|
|
163633
163639
|
provider: "openai-compatible",
|
|
163634
163640
|
model: config2.model.trim(),
|
|
163635
163641
|
endpoint: normalizeEndpoint(config2.endpoint),
|
|
163636
|
-
apiKeyPresent: Boolean(config2.api_key?.trim())
|
|
163642
|
+
apiKeyPresent: Boolean(config2.api_key?.trim()),
|
|
163643
|
+
inputType: config2.input_type?.trim() || ""
|
|
163637
163644
|
} : {
|
|
163638
163645
|
provider: "local",
|
|
163639
163646
|
model: config2.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
@@ -164002,6 +164009,8 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
164002
164009
|
endpoint;
|
|
164003
164010
|
model;
|
|
164004
164011
|
apiKey;
|
|
164012
|
+
inputType;
|
|
164013
|
+
truncate;
|
|
164005
164014
|
initialized = false;
|
|
164006
164015
|
failureTimes = [];
|
|
164007
164016
|
circuitOpenUntil = 0;
|
|
@@ -164011,6 +164020,8 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
164011
164020
|
this.endpoint = normalizeEndpoint2(options.endpoint);
|
|
164012
164021
|
this.model = options.model?.trim() ?? "";
|
|
164013
164022
|
this.apiKey = options.apiKey?.trim() ?? "";
|
|
164023
|
+
this.inputType = options.inputType?.trim() ?? "";
|
|
164024
|
+
this.truncate = options.truncate?.trim() ?? "";
|
|
164014
164025
|
this.modelId = getEmbeddingProviderIdentity({
|
|
164015
164026
|
provider: "openai-compatible",
|
|
164016
164027
|
endpoint: this.endpoint,
|
|
@@ -164067,7 +164078,9 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
164067
164078
|
},
|
|
164068
164079
|
body: JSON.stringify({
|
|
164069
164080
|
model: this.model,
|
|
164070
|
-
input: texts
|
|
164081
|
+
input: texts,
|
|
164082
|
+
...this.inputType ? { input_type: this.inputType } : {},
|
|
164083
|
+
...this.truncate ? { truncate: this.truncate } : {}
|
|
164071
164084
|
}),
|
|
164072
164085
|
signal: internalController.signal
|
|
164073
164086
|
});
|
|
@@ -164590,7 +164603,9 @@ function createProvider2(config2) {
|
|
|
164590
164603
|
return new OpenAICompatibleEmbeddingProvider({
|
|
164591
164604
|
endpoint: config2.endpoint,
|
|
164592
164605
|
model: config2.model,
|
|
164593
|
-
apiKey: config2.api_key
|
|
164606
|
+
apiKey: config2.api_key,
|
|
164607
|
+
inputType: config2.input_type,
|
|
164608
|
+
truncate: config2.truncate
|
|
164594
164609
|
});
|
|
164595
164610
|
}
|
|
164596
164611
|
return new LocalEmbeddingProvider(config2.model);
|
|
@@ -164788,18 +164803,32 @@ async function refreshModelLimitsFromApi(client) {
|
|
|
164788
164803
|
}
|
|
164789
164804
|
}
|
|
164790
164805
|
function getModelsDevContextLimit(providerID, modelID) {
|
|
164791
|
-
const key = `${providerID}/${modelID}`;
|
|
164792
|
-
if (apiCache) {
|
|
164793
|
-
const fromApi = apiCache.get(key)?.limit;
|
|
164794
|
-
if (typeof fromApi === "number")
|
|
164795
|
-
return fromApi;
|
|
164796
|
-
}
|
|
164797
164806
|
const now = Date.now();
|
|
164798
164807
|
if (!fileCache || now - fileLastAttempt > RELOAD_INTERVAL_MS) {
|
|
164799
164808
|
fileLastAttempt = now;
|
|
164800
164809
|
fileCache = loadModelsDevMetadataFromFile();
|
|
164801
164810
|
}
|
|
164802
|
-
|
|
164811
|
+
const fromApi = lookupLimitWithTagFallback(apiCache, providerID, modelID);
|
|
164812
|
+
const fromFile = lookupLimitWithTagFallback(fileCache, providerID, modelID);
|
|
164813
|
+
if (typeof fromApi === "number" && typeof fromFile === "number") {
|
|
164814
|
+
return Math.max(fromApi, fromFile);
|
|
164815
|
+
}
|
|
164816
|
+
return fromApi ?? fromFile;
|
|
164817
|
+
}
|
|
164818
|
+
function lookupLimitWithTagFallback(cache, providerID, modelID) {
|
|
164819
|
+
if (!cache)
|
|
164820
|
+
return;
|
|
164821
|
+
const exact = cache.get(`${providerID}/${modelID}`)?.limit;
|
|
164822
|
+
if (typeof exact === "number")
|
|
164823
|
+
return exact;
|
|
164824
|
+
const colonIdx = modelID.lastIndexOf(":");
|
|
164825
|
+
if (colonIdx > 0) {
|
|
164826
|
+
const baseModel = modelID.slice(0, colonIdx);
|
|
164827
|
+
const fallback = cache.get(`${providerID}/${baseModel}`)?.limit;
|
|
164828
|
+
if (typeof fallback === "number")
|
|
164829
|
+
return fallback;
|
|
164830
|
+
}
|
|
164831
|
+
return;
|
|
164803
164832
|
}
|
|
164804
164833
|
var RELOAD_INTERVAL_MS, apiCache = null, apiLoadedAt = 0, fileCache = null, fileLastAttempt = 0;
|
|
164805
164834
|
var init_models_dev_cache = __esm(() => {
|
|
@@ -171440,7 +171469,12 @@ function markAnnouncementSeen(version2) {
|
|
|
171440
171469
|
function shouldShowAnnouncement() {
|
|
171441
171470
|
if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0)
|
|
171442
171471
|
return false;
|
|
171443
|
-
|
|
171472
|
+
const lastVersion = readLastAnnouncedVersion();
|
|
171473
|
+
if (!lastVersion) {
|
|
171474
|
+
markAnnouncementSeen(ANNOUNCEMENT_VERSION);
|
|
171475
|
+
return false;
|
|
171476
|
+
}
|
|
171477
|
+
return lastVersion !== ANNOUNCEMENT_VERSION;
|
|
171444
171478
|
}
|
|
171445
171479
|
var ANNOUNCEMENT_VERSION = "0.22.0", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
|
|
171446
171480
|
var init_announcement = __esm(() => {
|
|
@@ -171905,10 +171939,19 @@ function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
171905
171939
|
const defaults = MagicContextConfigSchema.parse({});
|
|
171906
171940
|
const warnings = [];
|
|
171907
171941
|
const errorPaths = new Set;
|
|
171942
|
+
const customMessagesByKey = new Map;
|
|
171943
|
+
const GENERIC_ZOD_PREFIXES = ["Too big", "Too small", "Invalid input", "Invalid", "Expected"];
|
|
171908
171944
|
for (const issue2 of parsed.error.issues) {
|
|
171909
171945
|
const topKey = issue2.path[0];
|
|
171910
171946
|
if (topKey !== undefined) {
|
|
171911
|
-
|
|
171947
|
+
const key = String(topKey);
|
|
171948
|
+
errorPaths.add(key);
|
|
171949
|
+
const msg = issue2.message;
|
|
171950
|
+
if (msg && !GENERIC_ZOD_PREFIXES.some((p) => msg.startsWith(p))) {
|
|
171951
|
+
if (!customMessagesByKey.has(key)) {
|
|
171952
|
+
customMessagesByKey.set(key, msg);
|
|
171953
|
+
}
|
|
171954
|
+
}
|
|
171912
171955
|
}
|
|
171913
171956
|
}
|
|
171914
171957
|
const patched = { ...rawConfig };
|
|
@@ -171921,7 +171964,8 @@ function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
171921
171964
|
} else {
|
|
171922
171965
|
delete patched[key];
|
|
171923
171966
|
const defaultVal = defaults[key];
|
|
171924
|
-
|
|
171967
|
+
const reason = customMessagesByKey.get(key);
|
|
171968
|
+
warnings.push(`"${key}": invalid value (${redactConfigValue(rawConfig[key])}), using default ${JSON.stringify(defaultVal)}.${reason ? ` ${reason}` : ""}`);
|
|
171925
171969
|
}
|
|
171926
171970
|
}
|
|
171927
171971
|
const retryMigrated = migrateLegacyExperimental(patched, preMigrationWarnings);
|
|
@@ -173154,9 +173198,18 @@ function removeInstalledPackage(installDir, packageName) {
|
|
|
173154
173198
|
const packageDir = join9(installDir, "node_modules", packageName);
|
|
173155
173199
|
if (!existsSync9(packageDir))
|
|
173156
173200
|
return false;
|
|
173157
|
-
|
|
173158
|
-
|
|
173159
|
-
|
|
173201
|
+
try {
|
|
173202
|
+
rmSync(packageDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
173203
|
+
log(`[auto-update-checker] Package removed: ${packageDir}`);
|
|
173204
|
+
return true;
|
|
173205
|
+
} catch (err) {
|
|
173206
|
+
const code = err.code;
|
|
173207
|
+
if (code === "EBUSY" || code === "EPERM" || code === "ENOTEMPTY") {
|
|
173208
|
+
warn2(`[auto-update-checker] Could not remove ${packageDir} (${code}); the file is locked by the running process. Continuing — npm install will overwrite it in place.`);
|
|
173209
|
+
return false;
|
|
173210
|
+
}
|
|
173211
|
+
throw err;
|
|
173212
|
+
}
|
|
173160
173213
|
}
|
|
173161
173214
|
function resolveInstallContext(runtimePackageJsonPath = getCurrentRuntimePackageJsonPath()) {
|
|
173162
173215
|
if (runtimePackageJsonPath) {
|
|
@@ -175821,6 +175874,14 @@ function createEventHandler(args) {
|
|
|
175821
175874
|
return async (input) => {
|
|
175822
175875
|
await args.autoUpdateChecker?.(input);
|
|
175823
175876
|
await args.magicContext?.event?.(input);
|
|
175877
|
+
if (args.onInstanceDisposed && input.event?.type === "server.instance.disposed") {
|
|
175878
|
+
const directory = input.event.properties?.directory;
|
|
175879
|
+
if (typeof directory === "string") {
|
|
175880
|
+
try {
|
|
175881
|
+
await args.onInstanceDisposed(directory);
|
|
175882
|
+
} catch {}
|
|
175883
|
+
}
|
|
175884
|
+
}
|
|
175824
175885
|
};
|
|
175825
175886
|
}
|
|
175826
175887
|
|
|
@@ -175966,8 +176027,21 @@ function resolveExecuteThresholdDetail(config2, modelKey, fallback, options) {
|
|
|
175966
176027
|
if (!Number.isFinite(resolved) || resolved < 0) {
|
|
175967
176028
|
resolved = fallback;
|
|
175968
176029
|
}
|
|
176030
|
+
const cappedPercentage = Math.min(resolved, MAX_EXECUTE_THRESHOLD);
|
|
176031
|
+
if (cappedPercentage < resolved) {
|
|
176032
|
+
const dedupeKey = `pct|${options?.sessionId ?? "__global__"}|${modelKey ?? "__default__"}|${resolved}`;
|
|
176033
|
+
if (!clampWarnSeen.has(dedupeKey)) {
|
|
176034
|
+
clampWarnSeen.add(dedupeKey);
|
|
176035
|
+
const msg = `execute_threshold clamped ${resolved}% → ${MAX_EXECUTE_THRESHOLD}% for ${modelKey ?? "default"} (capped for cache safety; a large step can overflow before compaction, and 80% stays below the 85%/95% emergency bands)`;
|
|
176036
|
+
if (options?.sessionId) {
|
|
176037
|
+
sessionLog(options.sessionId, `WARN: ${msg}`);
|
|
176038
|
+
} else {
|
|
176039
|
+
log(`[magic-context] WARN: ${msg}`);
|
|
176040
|
+
}
|
|
176041
|
+
}
|
|
176042
|
+
}
|
|
175969
176043
|
return {
|
|
175970
|
-
percentage:
|
|
176044
|
+
percentage: cappedPercentage,
|
|
175971
176045
|
mode: "percentage",
|
|
175972
176046
|
matchedKey
|
|
175973
176047
|
};
|
|
@@ -185041,6 +185115,8 @@ var plugin = async (ctx) => {
|
|
|
185041
185115
|
}
|
|
185042
185116
|
}
|
|
185043
185117
|
const storageDir = getMagicContextStorageDir();
|
|
185118
|
+
let rpcServer = null;
|
|
185119
|
+
let stopDreamTimerRegistration;
|
|
185044
185120
|
if (pluginConfig.enabled) {
|
|
185045
185121
|
const dreamerRunnable = isDreamerRunnable(pluginConfig);
|
|
185046
185122
|
const timerRegistration = {
|
|
@@ -185066,8 +185142,8 @@ var plugin = async (ctx) => {
|
|
|
185066
185142
|
} : undefined,
|
|
185067
185143
|
ensureRegistered: ensureProjectRegisteredFromOpenCodeDirectory
|
|
185068
185144
|
};
|
|
185069
|
-
await startDreamScheduleTimer(timerRegistration);
|
|
185070
|
-
|
|
185145
|
+
stopDreamTimerRegistration = await startDreamScheduleTimer(timerRegistration);
|
|
185146
|
+
rpcServer = new MagicContextRpcServer(storageDir, ctx.directory);
|
|
185071
185147
|
registerRpcHandlers(rpcServer, {
|
|
185072
185148
|
directory: ctx.directory,
|
|
185073
185149
|
config: pluginConfig,
|
|
@@ -185121,6 +185197,7 @@ var plugin = async (ctx) => {
|
|
|
185121
185197
|
} catch {}
|
|
185122
185198
|
}
|
|
185123
185199
|
let lastChatContext = null;
|
|
185200
|
+
const ownProjectIdentity = resolveProjectIdentity(ctx.directory);
|
|
185124
185201
|
return {
|
|
185125
185202
|
tool: tools5,
|
|
185126
185203
|
event: createEventHandler({
|
|
@@ -185129,7 +185206,21 @@ var plugin = async (ctx) => {
|
|
|
185129
185206
|
autoUpdate: pluginConfig.auto_update !== false,
|
|
185130
185207
|
signal: autoUpdateAbort.signal,
|
|
185131
185208
|
storageDir
|
|
185132
|
-
})
|
|
185209
|
+
}),
|
|
185210
|
+
onInstanceDisposed: (disposedDirectory) => {
|
|
185211
|
+
if (resolveProjectIdentity(disposedDirectory) !== ownProjectIdentity)
|
|
185212
|
+
return;
|
|
185213
|
+
try {
|
|
185214
|
+
autoUpdateAbort.abort();
|
|
185215
|
+
} catch {}
|
|
185216
|
+
try {
|
|
185217
|
+
stopDreamTimerRegistration?.();
|
|
185218
|
+
} catch {}
|
|
185219
|
+
try {
|
|
185220
|
+
rpcServer?.stop();
|
|
185221
|
+
} catch {}
|
|
185222
|
+
log("[magic-context] instance disposed — stopped RPC server, dream timer, auto-update");
|
|
185223
|
+
}
|
|
185133
185224
|
}),
|
|
185134
185225
|
"experimental.chat.messages.transform": createMessagesTransformHandler({
|
|
185135
185226
|
magicContext: hooks.magicContext
|
package/dist/plugin/event.d.ts
CHANGED
|
@@ -7,6 +7,16 @@ export declare function createEventHandler(args: {
|
|
|
7
7
|
autoUpdateChecker?: ((input: {
|
|
8
8
|
event: import("@opencode-ai/sdk").Event;
|
|
9
9
|
}) => Promise<void>) | null;
|
|
10
|
+
/**
|
|
11
|
+
* Orderly cleanup for THIS plugin instance when OpenCode disposes it. Fires
|
|
12
|
+
* on the SDK `server.instance.disposed` event; the callback receives the
|
|
13
|
+
* disposed instance's `directory` so the caller can match it against its own
|
|
14
|
+
* `ctx.directory` (OpenCode Desktop runs multiple instances in one process,
|
|
15
|
+
* each disposed independently, so a dispose for a different directory must
|
|
16
|
+
* not tear down this instance's resources). Best-effort: failures are
|
|
17
|
+
* swallowed so a cleanup error never propagates into OpenCode's event loop.
|
|
18
|
+
*/
|
|
19
|
+
onInstanceDisposed?: (directory: string) => void | Promise<void>;
|
|
10
20
|
}): (input: {
|
|
11
21
|
event: import("@opencode-ai/sdk").Event;
|
|
12
22
|
}) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/plugin/event.ts"],"names":[],"mappings":"AAAA,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,YAAY,EAAE;QACV,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE;YAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,KAAK,CAAA;SAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACjF,GAAG,IAAI,CAAC;IACT,iBAAiB,CAAC,EACZ,CAAC,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,KAAK,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GACvE,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/plugin/event.ts"],"names":[],"mappings":"AAAA,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,YAAY,EAAE;QACV,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE;YAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,KAAK,CAAA;SAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACjF,GAAG,IAAI,CAAC;IACT,iBAAiB,CAAC,EACZ,CAAC,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,KAAK,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GACvE,IAAI,CAAC;IACX;;;;;;;;OAQG;IACH,kBAAkB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpE,GAAG,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,KAAK,CAAA;CAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAgBxE"}
|
|
@@ -50,6 +50,22 @@ export declare function markAnnouncementSeen(version: string): void;
|
|
|
50
50
|
* True when the configured `ANNOUNCEMENT_VERSION` has not yet been dismissed
|
|
51
51
|
* AND there is at least one feature to show. Used by both the TUI dialog path
|
|
52
52
|
* and the Desktop ignored-message fallback.
|
|
53
|
+
*
|
|
54
|
+
* First-run / sandbox handling: when NO state file exists yet, we seed it to the
|
|
55
|
+
* current `ANNOUNCEMENT_VERSION` and return false instead of announcing. This
|
|
56
|
+
* covers two cases that previously spammed the dialog (issue #99):
|
|
57
|
+
* - Fresh installs: a brand-new user shouldn't be shown a changelog of release
|
|
58
|
+
* bullets they have no context for — they need onboarding, not patch notes.
|
|
59
|
+
* - Ephemeral/sandbox environments (Docker, CI, disposable dev containers)
|
|
60
|
+
* where the storage dir is wiped between launches: without the seed, the
|
|
61
|
+
* missing file made the announcement re-show on every single startup.
|
|
62
|
+
* Real upgrades still announce exactly once: an existing user already has a
|
|
63
|
+
* state file at the prior version, so the version mismatch shows the dialog and
|
|
64
|
+
* dismissing it advances the file to the current version.
|
|
65
|
+
*
|
|
66
|
+
* The seed is a deliberate write side-effect on the "no file" branch — folding
|
|
67
|
+
* it here (rather than a separate startup call) makes every caller path (plugin
|
|
68
|
+
* startup, Pi startup, TUI rpc pull) consistent with no ordering dependency.
|
|
53
69
|
*/
|
|
54
70
|
export declare function shouldShowAnnouncement(): boolean;
|
|
55
71
|
//# sourceMappingURL=announcement.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"announcement.d.ts","sourceRoot":"","sources":["../../src/shared/announcement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAE7C;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC,MAAM,CAMvD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,qDAAqD,CAAC;AAQtF;;;;;;GAMG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAQjD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAS1D;AAED
|
|
1
|
+
{"version":3,"file":"announcement.d.ts","sourceRoot":"","sources":["../../src/shared/announcement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAE7C;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC,MAAM,CAMvD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,qDAAqD,CAAC;AAQtF;;;;;;GAMG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAQjD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAS1D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAUhD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models-dev-cache.d.ts","sourceRoot":"","sources":["../../src/shared/models-dev-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;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;AA+LD;;;;;;;;;;GAUG;AACH,wBAAsB,yBAAyB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkDzF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"models-dev-cache.d.ts","sourceRoot":"","sources":["../../src/shared/models-dev-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;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;AA+LD;;;;;;;;;;GAUG;AACH,wBAAsB,yBAAyB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkDzF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAqBhG;AAkCD,4CAA4C;AAC5C,wBAAgB,mBAAmB,IAAI,IAAI,CAK1C;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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/opencode-magic-context",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenCode plugin for Magic Context — cross-session memory and context management",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@huggingface/transformers": "^4.1.0",
|
|
44
|
-
"@opencode-ai/plugin": "^1.
|
|
45
|
-
"@opencode-ai/sdk": "^1.
|
|
44
|
+
"@opencode-ai/plugin": "^1.15.13",
|
|
45
|
+
"@opencode-ai/sdk": "^1.15.13",
|
|
46
46
|
"ai-tokenizer": "^1.0.6",
|
|
47
47
|
"comment-json": "^4.2.5",
|
|
48
48
|
"zod": "^4.1.8"
|
|
@@ -69,6 +69,6 @@
|
|
|
69
69
|
"tui"
|
|
70
70
|
],
|
|
71
71
|
"peerDependencies": {
|
|
72
|
-
"@opencode-ai/plugin": ">=1.
|
|
72
|
+
"@opencode-ai/plugin": ">=1.15.0"
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -8,8 +8,11 @@ import * as path from "node:path";
|
|
|
8
8
|
* `getMagicContextStorageDir()`. The behavior we test:
|
|
9
9
|
* 1. `markAnnouncementSeen` then `readLastAnnouncedVersion` round-trips
|
|
10
10
|
* 2. `shouldShowAnnouncement` returns false after a matching mark
|
|
11
|
-
* 3. `shouldShowAnnouncement` returns true after a non-matching mark
|
|
12
|
-
* 4.
|
|
11
|
+
* 3. `shouldShowAnnouncement` returns true after a non-matching (older) mark
|
|
12
|
+
* 4. `shouldShowAnnouncement` seeds state + returns false on first run / wiped
|
|
13
|
+
* sandbox (no prior file), so fresh installs and ephemeral envs aren't
|
|
14
|
+
* spammed with a changelog (issue #99)
|
|
15
|
+
* 5. Empty-version inputs are no-ops (don't crash, don't write garbage)
|
|
13
16
|
*
|
|
14
17
|
* We isolate writes by pointing `XDG_DATA_HOME` at a temp dir before requiring
|
|
15
18
|
* the module fresh per test, since the module captures the storage path at
|
|
@@ -32,7 +35,8 @@ afterEach(() => {
|
|
|
32
35
|
process.env.XDG_DATA_HOME = originalXdg;
|
|
33
36
|
}
|
|
34
37
|
try {
|
|
35
|
-
|
|
38
|
+
// maxRetries/retryDelay ride out transient EBUSY/EPERM on Windows.
|
|
39
|
+
fs.rmSync(tmpRoot, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
36
40
|
} catch {
|
|
37
41
|
// best-effort
|
|
38
42
|
}
|
|
@@ -110,9 +114,14 @@ describe("shouldShowAnnouncement gating", () => {
|
|
|
110
114
|
expect(shouldShowAnnouncement()).toBe(false);
|
|
111
115
|
});
|
|
112
116
|
|
|
113
|
-
test("returns
|
|
117
|
+
test("seeds state and returns false on first run / wiped sandbox (issue #99)", async () => {
|
|
114
118
|
const mod = await import(`./announcement?t=${Date.now()}-none`);
|
|
115
|
-
const {
|
|
119
|
+
const {
|
|
120
|
+
ANNOUNCEMENT_VERSION,
|
|
121
|
+
ANNOUNCEMENT_FEATURES,
|
|
122
|
+
shouldShowAnnouncement,
|
|
123
|
+
readLastAnnouncedVersion,
|
|
124
|
+
} = mod;
|
|
116
125
|
|
|
117
126
|
if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0) {
|
|
118
127
|
// When empty, the gate is always false regardless of state
|
|
@@ -120,8 +129,15 @@ describe("shouldShowAnnouncement gating", () => {
|
|
|
120
129
|
return;
|
|
121
130
|
}
|
|
122
131
|
|
|
123
|
-
// No mark
|
|
124
|
-
|
|
132
|
+
// No mark exists yet (fresh install or ephemeral/wiped sandbox). The
|
|
133
|
+
// gate must NOT announce — it seeds the state to the current version and
|
|
134
|
+
// returns false, so first-run users and disposable containers are never
|
|
135
|
+
// spammed with a changelog they have no context for.
|
|
136
|
+
expect(readLastAnnouncedVersion()).toBe("");
|
|
137
|
+
expect(shouldShowAnnouncement()).toBe(false);
|
|
138
|
+
// The seed was written, so a subsequent check stays quiet too.
|
|
139
|
+
expect(readLastAnnouncedVersion()).toBe(ANNOUNCEMENT_VERSION);
|
|
140
|
+
expect(shouldShowAnnouncement()).toBe(false);
|
|
125
141
|
});
|
|
126
142
|
|
|
127
143
|
test("returns true when a different (older) version is marked", async () => {
|
|
@@ -89,8 +89,31 @@ export function markAnnouncementSeen(version: string): void {
|
|
|
89
89
|
* True when the configured `ANNOUNCEMENT_VERSION` has not yet been dismissed
|
|
90
90
|
* AND there is at least one feature to show. Used by both the TUI dialog path
|
|
91
91
|
* and the Desktop ignored-message fallback.
|
|
92
|
+
*
|
|
93
|
+
* First-run / sandbox handling: when NO state file exists yet, we seed it to the
|
|
94
|
+
* current `ANNOUNCEMENT_VERSION` and return false instead of announcing. This
|
|
95
|
+
* covers two cases that previously spammed the dialog (issue #99):
|
|
96
|
+
* - Fresh installs: a brand-new user shouldn't be shown a changelog of release
|
|
97
|
+
* bullets they have no context for — they need onboarding, not patch notes.
|
|
98
|
+
* - Ephemeral/sandbox environments (Docker, CI, disposable dev containers)
|
|
99
|
+
* where the storage dir is wiped between launches: without the seed, the
|
|
100
|
+
* missing file made the announcement re-show on every single startup.
|
|
101
|
+
* Real upgrades still announce exactly once: an existing user already has a
|
|
102
|
+
* state file at the prior version, so the version mismatch shows the dialog and
|
|
103
|
+
* dismissing it advances the file to the current version.
|
|
104
|
+
*
|
|
105
|
+
* The seed is a deliberate write side-effect on the "no file" branch — folding
|
|
106
|
+
* it here (rather than a separate startup call) makes every caller path (plugin
|
|
107
|
+
* startup, Pi startup, TUI rpc pull) consistent with no ordering dependency.
|
|
92
108
|
*/
|
|
93
109
|
export function shouldShowAnnouncement(): boolean {
|
|
94
110
|
if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0) return false;
|
|
95
|
-
|
|
111
|
+
const lastVersion = readLastAnnouncedVersion();
|
|
112
|
+
if (!lastVersion) {
|
|
113
|
+
// No prior state: fresh install or wiped sandbox. Seed to current and
|
|
114
|
+
// skip the announcement so we never pester first-run / ephemeral envs.
|
|
115
|
+
markAnnouncementSeen(ANNOUNCEMENT_VERSION);
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return lastVersion !== ANNOUNCEMENT_VERSION;
|
|
96
119
|
}
|
|
@@ -46,8 +46,21 @@ describe("detectConflicts", () => {
|
|
|
46
46
|
else process.env[k] = v;
|
|
47
47
|
}
|
|
48
48
|
// Test directories live under tmpdir(); cleanup is best-effort.
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
try {
|
|
50
|
+
rmSync(projectDir, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
51
|
+
} catch {
|
|
52
|
+
/* Ignore EBUSY on Windows */
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
rmSync(userConfigDir, {
|
|
56
|
+
recursive: true,
|
|
57
|
+
force: true,
|
|
58
|
+
maxRetries: 10,
|
|
59
|
+
retryDelay: 100,
|
|
60
|
+
});
|
|
61
|
+
} catch {
|
|
62
|
+
/* Ignore EBUSY on Windows */
|
|
63
|
+
}
|
|
51
64
|
});
|
|
52
65
|
|
|
53
66
|
function writeProjectConfig(plugins: Array<string | [string, unknown]>): void {
|
|
@@ -38,7 +38,11 @@ describe("fixConflicts", () => {
|
|
|
38
38
|
if (value === undefined) delete process.env[key];
|
|
39
39
|
else process.env[key] = value;
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
try {
|
|
42
|
+
rmSync(root, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
43
|
+
} catch {
|
|
44
|
+
/* Ignore EBUSY on Windows */
|
|
45
|
+
}
|
|
42
46
|
});
|
|
43
47
|
|
|
44
48
|
it("preserves JSONC comments and tuple plugin entries while removing canonical DCP", () => {
|
|
@@ -39,7 +39,11 @@ describe("models-dev-cache", () => {
|
|
|
39
39
|
if (v === undefined) delete process.env[k];
|
|
40
40
|
else process.env[k] = v;
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
try {
|
|
43
|
+
rmSync(tempDir, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
44
|
+
} catch {
|
|
45
|
+
/* Ignore EBUSY on Windows */
|
|
46
|
+
}
|
|
43
47
|
clearModelsDevCache();
|
|
44
48
|
});
|
|
45
49
|
|
|
@@ -234,7 +238,7 @@ describe("models-dev-cache", () => {
|
|
|
234
238
|
expect(getModelsDevContextLimit("anthropic", "claude-4")).toBeUndefined();
|
|
235
239
|
});
|
|
236
240
|
|
|
237
|
-
test("
|
|
241
|
+
test("takes the larger limit when both layers know the model (API larger)", async () => {
|
|
238
242
|
// Seed file layer with one value.
|
|
239
243
|
const opencodeDir = join(tempDir, "opencode");
|
|
240
244
|
mkdirSync(opencodeDir, { recursive: true });
|
|
@@ -248,7 +252,7 @@ describe("models-dev-cache", () => {
|
|
|
248
252
|
// Sanity: file layer returns 100000 before API refresh.
|
|
249
253
|
expect(getModelsDevContextLimit("anthropic", "claude-4")).toBe(100000);
|
|
250
254
|
|
|
251
|
-
// Mock client providing
|
|
255
|
+
// Mock client providing a LARGER value via API.
|
|
252
256
|
const mockClient = {
|
|
253
257
|
config: {
|
|
254
258
|
providers: async () => ({
|
|
@@ -267,7 +271,7 @@ describe("models-dev-cache", () => {
|
|
|
267
271
|
};
|
|
268
272
|
await refreshModelLimitsFromApi(mockClient);
|
|
269
273
|
|
|
270
|
-
// API value wins.
|
|
274
|
+
// Larger (API) value wins.
|
|
271
275
|
expect(getModelsDevContextLimit("anthropic", "claude-4")).toBe(1000000);
|
|
272
276
|
|
|
273
277
|
const state = getModelsDevCacheState();
|
|
@@ -275,6 +279,70 @@ describe("models-dev-cache", () => {
|
|
|
275
279
|
expect(state.apiCount).toBe(1);
|
|
276
280
|
});
|
|
277
281
|
|
|
282
|
+
test("file value wins when the live API reports a smaller (wrong) limit (issue #117)", async () => {
|
|
283
|
+
// The ollama-cloud scenario: models.dev has the correct large window, but
|
|
284
|
+
// ollama reports its tiny default num_ctx via the live /config/providers
|
|
285
|
+
// API. The larger, correct file value must win so pressure isn't bogus.
|
|
286
|
+
const opencodeDir = join(tempDir, "opencode");
|
|
287
|
+
mkdirSync(opencodeDir, { recursive: true });
|
|
288
|
+
writeFileSync(
|
|
289
|
+
join(opencodeDir, "models.json"),
|
|
290
|
+
JSON.stringify({
|
|
291
|
+
"ollama-cloud": {
|
|
292
|
+
models: { "deepseek-v4-pro": { limit: { context: 1048576 } } },
|
|
293
|
+
},
|
|
294
|
+
}),
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
const mockClient = {
|
|
298
|
+
config: {
|
|
299
|
+
providers: async () => ({
|
|
300
|
+
data: {
|
|
301
|
+
providers: [
|
|
302
|
+
{
|
|
303
|
+
id: "ollama-cloud",
|
|
304
|
+
models: {
|
|
305
|
+
// Bogus tiny default num_ctx from ollama.
|
|
306
|
+
"deepseek-v4-pro": { limit: { context: 8192 } },
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
],
|
|
310
|
+
},
|
|
311
|
+
}),
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
await refreshModelLimitsFromApi(mockClient);
|
|
315
|
+
|
|
316
|
+
// Larger (file/models.dev) value wins, not the tiny live-API value.
|
|
317
|
+
expect(getModelsDevContextLimit("ollama-cloud", "deepseek-v4-pro")).toBe(1048576);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("matches a tagged ollama model against its tag-less models.dev entry (issue #117)", () => {
|
|
321
|
+
// ollama invokes cloud models with a tag (deepseek-v4-pro:cloud) while
|
|
322
|
+
// models.dev stores them tag-less (deepseek-v4-pro).
|
|
323
|
+
const opencodeDir = join(tempDir, "opencode");
|
|
324
|
+
mkdirSync(opencodeDir, { recursive: true });
|
|
325
|
+
writeFileSync(
|
|
326
|
+
join(opencodeDir, "models.json"),
|
|
327
|
+
JSON.stringify({
|
|
328
|
+
"ollama-cloud": {
|
|
329
|
+
models: {
|
|
330
|
+
"deepseek-v4-pro": { limit: { context: 1048576 } },
|
|
331
|
+
// A legitimately-tagged model must still match exactly.
|
|
332
|
+
"gemma3:27b": { limit: { context: 131072 } },
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
}),
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
// Tagged invocation falls back to the tag-less entry.
|
|
339
|
+
expect(getModelsDevContextLimit("ollama-cloud", "deepseek-v4-pro:cloud")).toBe(1048576);
|
|
340
|
+
// Exact tagged match still wins (no wrongful collapse).
|
|
341
|
+
expect(getModelsDevContextLimit("ollama-cloud", "gemma3:27b")).toBe(131072);
|
|
342
|
+
// Unknown tagged model with no tag-less base stays undefined.
|
|
343
|
+
expect(getModelsDevContextLimit("ollama-cloud", "nonexistent:cloud")).toBeUndefined();
|
|
344
|
+
});
|
|
345
|
+
|
|
278
346
|
test("refreshModelLimitsFromApi tolerates empty/malformed responses", async () => {
|
|
279
347
|
// Undefined data.
|
|
280
348
|
await refreshModelLimitsFromApi({
|
|
@@ -298,19 +298,58 @@ export async function refreshModelLimitsFromApi(client: OpencodeClientLike): Pro
|
|
|
298
298
|
* Returns `undefined` if neither layer knows the model.
|
|
299
299
|
*/
|
|
300
300
|
export function getModelsDevContextLimit(providerID: string, modelID: string): number | undefined {
|
|
301
|
-
const key = `${providerID}/${modelID}`;
|
|
302
|
-
|
|
303
|
-
if (apiCache) {
|
|
304
|
-
const fromApi = apiCache.get(key)?.limit;
|
|
305
|
-
if (typeof fromApi === "number") return fromApi;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
301
|
const now = Date.now();
|
|
309
302
|
if (!fileCache || now - fileLastAttempt > RELOAD_INTERVAL_MS) {
|
|
310
303
|
fileLastAttempt = now;
|
|
311
304
|
fileCache = loadModelsDevMetadataFromFile();
|
|
312
305
|
}
|
|
313
|
-
|
|
306
|
+
|
|
307
|
+
const fromApi = lookupLimitWithTagFallback(apiCache, providerID, modelID);
|
|
308
|
+
const fromFile = lookupLimitWithTagFallback(fileCache, providerID, modelID);
|
|
309
|
+
|
|
310
|
+
// When BOTH layers know the model, take the LARGER limit. Providers never
|
|
311
|
+
// under-report their real window, so a suspiciously small value — e.g.
|
|
312
|
+
// ollama reporting its default `num_ctx` (4k/8k) for a cloud model via the
|
|
313
|
+
// live `/config/providers` API — must not override the correct, larger
|
|
314
|
+
// models.dev value. A genuinely smaller real limit (provider actually
|
|
315
|
+
// rejects at N) is captured separately via the overflow-detection path
|
|
316
|
+
// (detectedContextLimit), not here. (issue #117)
|
|
317
|
+
if (typeof fromApi === "number" && typeof fromFile === "number") {
|
|
318
|
+
return Math.max(fromApi, fromFile);
|
|
319
|
+
}
|
|
320
|
+
return fromApi ?? fromFile;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Look up a model's limit in one cache layer, with an ollama-style tag-suffix
|
|
325
|
+
* fallback.
|
|
326
|
+
*
|
|
327
|
+
* models.dev stores some models WITH a colon tag (e.g. `gemma3:27b`,
|
|
328
|
+
* `deepseek-v3.1:671b`) and ollama-cloud base models WITHOUT one
|
|
329
|
+
* (`deepseek-v4-pro`). But ollama invokes cloud models with a tag at runtime
|
|
330
|
+
* (`deepseek-v4-pro:cloud`), so OpenCode reports the tagged id. An exact-only
|
|
331
|
+
* match therefore misses → falls back to the 128k default → wrong pressure
|
|
332
|
+
* denominator (issue #117).
|
|
333
|
+
*
|
|
334
|
+
* Strategy: exact match first (never collapses a legitimately-tagged model),
|
|
335
|
+
* then retry once with the last `:tag` segment stripped.
|
|
336
|
+
*/
|
|
337
|
+
function lookupLimitWithTagFallback(
|
|
338
|
+
cache: Map<string, CachedModelMetadata> | null,
|
|
339
|
+
providerID: string,
|
|
340
|
+
modelID: string,
|
|
341
|
+
): number | undefined {
|
|
342
|
+
if (!cache) return undefined;
|
|
343
|
+
const exact = cache.get(`${providerID}/${modelID}`)?.limit;
|
|
344
|
+
if (typeof exact === "number") return exact;
|
|
345
|
+
|
|
346
|
+
const colonIdx = modelID.lastIndexOf(":");
|
|
347
|
+
if (colonIdx > 0) {
|
|
348
|
+
const baseModel = modelID.slice(0, colonIdx);
|
|
349
|
+
const fallback = cache.get(`${providerID}/${baseModel}`)?.limit;
|
|
350
|
+
if (typeof fallback === "number") return fallback;
|
|
351
|
+
}
|
|
352
|
+
return undefined;
|
|
314
353
|
}
|
|
315
354
|
|
|
316
355
|
/** Clear in-memory caches (for testing). */
|
|
@@ -18,7 +18,11 @@ describe("opencode-compaction-detector", () => {
|
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
afterEach(() => {
|
|
21
|
-
|
|
21
|
+
try {
|
|
22
|
+
rmSync(tmpDir, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
23
|
+
} catch {
|
|
24
|
+
/* Ignore EBUSY on Windows */
|
|
25
|
+
}
|
|
22
26
|
delete process.env.OPENCODE_DISABLE_AUTOCOMPACT;
|
|
23
27
|
});
|
|
24
28
|
|
|
@@ -30,7 +34,11 @@ describe("opencode-compaction-detector", () => {
|
|
|
30
34
|
const result = isOpenCodeAutoCompactionEnabled(emptyDir);
|
|
31
35
|
|
|
32
36
|
expect(result).toBe(true);
|
|
33
|
-
|
|
37
|
+
try {
|
|
38
|
+
rmSync(emptyDir, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
39
|
+
} catch {
|
|
40
|
+
/* Ignore EBUSY on Windows */
|
|
41
|
+
}
|
|
34
42
|
});
|
|
35
43
|
});
|
|
36
44
|
|
|
@@ -20,7 +20,11 @@ afterEach(async () => {
|
|
|
20
20
|
await server.close();
|
|
21
21
|
}
|
|
22
22
|
for (const dir of tempDirs.splice(0)) {
|
|
23
|
-
|
|
23
|
+
try {
|
|
24
|
+
rmSync(dir, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
25
|
+
} catch {
|
|
26
|
+
/* Ignore EBUSY on Windows */
|
|
27
|
+
}
|
|
24
28
|
}
|
|
25
29
|
});
|
|
26
30
|
|