@cortexkit/opencode-magic-context 0.33.0 → 0.34.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/config/agent-disable.d.ts +22 -0
- package/dist/config/agent-disable.d.ts.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/project-security.d.ts +7 -0
- package/dist/config/project-security.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +144 -24
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/config/transform-mode.d.ts +2 -0
- package/dist/config/transform-mode.d.ts.map +1 -1
- package/dist/{conflict-warning-hook-bwa99a04.js → conflict-warning-hook-fvpfvt0w.js} +1 -1
- package/dist/{derive-budgets-e9j09sjr.js → derive-budgets-9crp0cvd.js} +1 -1
- package/dist/features/builtin-commands/commands.d.ts +1 -1
- package/dist/features/builtin-commands/commands.d.ts.map +1 -1
- package/dist/features/magic-context/compaction-marker.d.ts +106 -0
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts +0 -2
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-registry.d.ts +0 -1
- package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
- package/dist/features/magic-context/fail-closed-block.d.ts +10 -0
- package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/index.d.ts +2 -2
- package/dist/features/magic-context/git-commits/index.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts +0 -2
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/storage-git-commits.d.ts +0 -13
- package/dist/features/magic-context/git-commits/storage-git-commits.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-local.d.ts +7 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts +1 -2
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
- package/dist/features/magic-context/memory/memory-migration.d.ts +0 -6
- package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
- package/dist/features/magic-context/memory/project-identity.d.ts +2 -6
- package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +0 -1
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory.d.ts +1 -6
- package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
- package/dist/features/magic-context/memory/verification-paths.d.ts +0 -1
- package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
- package/dist/features/magic-context/mural/render-mural.d.ts.map +1 -1
- package/dist/features/magic-context/mural/storage-mural.d.ts +0 -1
- package/dist/features/magic-context/mural/storage-mural.d.ts.map +1 -1
- package/dist/features/magic-context/overflow-detection.d.ts +8 -1
- package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts +16 -2
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/scheduler.d.ts.map +1 -1
- package/dist/features/magic-context/schema-fence-probe.d.ts +28 -0
- package/dist/features/magic-context/schema-fence-probe.d.ts.map +1 -0
- package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/capabilities.d.ts +0 -2
- package/dist/features/magic-context/smart-notes/capabilities.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/compiler.d.ts +0 -1
- package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/types.d.ts +0 -16
- package/dist/features/magic-context/smart-notes/types.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts +35 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +38 -5
- package/dist/features/magic-context/storage-meta-persisted.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/user-memory/review-user-memories.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/storage-user-memory.d.ts +0 -2
- package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/types.d.ts +0 -3
- package/dist/hooks/auto-update-checker/types.d.ts.map +1 -1
- package/dist/hooks/magic-context/boundary-execution.d.ts +1 -1
- package/dist/hooks/magic-context/boundary-execution.d.ts.map +1 -1
- package/dist/hooks/magic-context/cache-busting-signals.d.ts +1 -1
- package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
- package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
- package/dist/hooks/magic-context/child-session-spawn.d.ts +26 -0
- package/dist/hooks/magic-context/child-session-spawn.d.ts.map +1 -0
- 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/compaction-marker-manager.d.ts +49 -0
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-off-transition.d.ts +96 -0
- package/dist/hooks/magic-context/compaction-off-transition.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-parser.d.ts +12 -0
- package/dist/hooks/magic-context/compartment-parser.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts +2 -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-mapping.d.ts +0 -12
- package/dist/hooks/magic-context/compartment-runner-mapping.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-trigger.d.ts +12 -5
- package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
- package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +47 -1
- package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
- package/dist/hooks/magic-context/emergency-drop.d.ts +2 -2
- package/dist/hooks/magic-context/event-handler.d.ts +7 -0
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-resolvers.d.ts +13 -21
- package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +2 -0
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts +1 -1
- package/dist/hooks/magic-context/historian-prompt.generated.d.ts +1 -1
- package/dist/hooks/magic-context/historian-prompt.generated.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts +1 -0
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +11 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +18 -0
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
- package/dist/hooks/magic-context/rust-mode-transform.d.ts +3 -0
- package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/send-session-notification.d.ts +20 -1
- package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
- package/dist/hooks/magic-context/sentinel.d.ts +39 -0
- package/dist/hooks/magic-context/sentinel.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-drop-target.d.ts +19 -0
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +3 -0
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +30 -0
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +27 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/{index-kxz4tn6m.js → index-56yjaeb2.js} +56 -4
- package/dist/{index-bmkea2dq.js → index-b563sga5.js} +40 -287
- package/dist/{index-y1c9tcm3.js → index-cn960ffd.js} +101 -20
- package/dist/{index-k5y60ymm.js → index-dtas91s5.js} +27 -6
- package/dist/index-fcyvznch.js +279 -0
- package/dist/{index-63dq2g4d.js → index-ry8rh8cv.js} +138 -24
- package/dist/{index-h86twgsp.js → index-s0mdn690.js} +2113 -1067
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1356 -627
- package/dist/plugin/embedding-bootstrap.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +19 -8
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/messages-transform.d.ts +10 -0
- package/dist/plugin/messages-transform.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts +3 -7
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/plugin/tool-registry.d.ts +8 -0
- package/dist/plugin/tool-registry.d.ts.map +1 -1
- package/dist/{recomp-orchestrator-yh7pepvx.js → recomp-orchestrator-8e82vmvb.js} +6 -5
- package/dist/send-session-notification-6njqewzk.js +20 -0
- package/dist/shared/conflict-detector.d.ts +38 -1
- package/dist/shared/conflict-detector.d.ts.map +1 -1
- package/dist/shared/conflict-fixer.d.ts +18 -1
- package/dist/shared/conflict-fixer.d.ts.map +1 -1
- package/dist/shared/context-limit-provenance.d.ts +3 -0
- package/dist/shared/context-limit-provenance.d.ts.map +1 -0
- package/dist/shared/escalation-bands.d.ts +9 -0
- package/dist/shared/escalation-bands.d.ts.map +1 -0
- package/dist/shared/format-threshold.d.ts +1 -1
- package/dist/shared/models-dev-cache.d.ts +29 -3
- package/dist/shared/models-dev-cache.d.ts.map +1 -1
- package/dist/shared/rpc-server.d.ts.map +1 -1
- package/dist/shared/rpc-types.d.ts +46 -1
- package/dist/shared/rpc-types.d.ts.map +1 -1
- package/dist/shared/sqlite.d.ts +9 -4
- package/dist/shared/sqlite.d.ts.map +1 -1
- package/dist/shared/storage-permissions.d.ts +5 -0
- package/dist/shared/storage-permissions.d.ts.map +1 -0
- package/dist/{storage-meta-session-1phy0b1z.js → storage-meta-session-xt41zbw4.js} +2 -1
- package/dist/{task-config-dn9k9szr.js → task-config-5nx3qfz8.js} +1 -2
- package/dist/tui/compaction-off.d.ts +13 -0
- package/dist/tui/compaction-off.d.ts.map +1 -0
- package/dist/tui/data/context-db.d.ts.map +1 -1
- package/dist/tui-compiled/compaction-off.d.ts +13 -0
- package/dist/tui-compiled/compaction-off.d.ts.map +1 -0
- package/dist/tui-compiled/data/context-db.d.ts.map +1 -1
- package/package.json +8 -3
- package/src/agents/dreamer.ts +68 -0
- package/src/agents/hidden-agent-registrations.ts +331 -0
- package/src/agents/historian.ts +3 -0
- package/src/agents/language-directive.test.ts +138 -0
- package/src/agents/language-directive.ts +121 -0
- package/src/agents/magic-context-prompt.language.test.ts +35 -0
- package/src/agents/magic-context-prompt.test.ts +292 -0
- package/src/agents/magic-context-prompt.ts +182 -0
- package/src/agents/permissions.test.ts +252 -0
- package/src/agents/permissions.ts +186 -0
- package/src/agents/sidekick.ts +1 -0
- package/src/agents/smart-note-compiler.ts +1 -0
- package/src/config/agent-disable.ts +106 -0
- package/src/config/compaction-accessor-guard.test.ts +82 -0
- package/src/config/compaction-backcompat.test.ts +52 -0
- package/src/config/index.test.ts +904 -0
- package/src/config/index.ts +601 -0
- package/src/config/migrate-config-location.test.ts +332 -0
- package/src/config/migrate-config-location.ts +635 -0
- package/src/config/migrate-dreamer-v2.test.ts +287 -0
- package/src/config/migrate-dreamer-v2.ts +336 -0
- package/src/config/migrate-experimental.ts +159 -0
- package/src/config/project-security.test.ts +366 -0
- package/src/config/project-security.ts +588 -0
- package/src/config/prune-config-leaf.test.ts +78 -0
- package/src/config/prune-config-leaf.ts +68 -0
- package/src/config/removed-config-keys.test.ts +116 -0
- package/src/config/schema/agent-overrides.ts +45 -0
- package/src/config/schema/magic-context.test.ts +358 -0
- package/src/config/schema/magic-context.ts +1002 -0
- package/src/config/transform-mode.test.ts +62 -0
- package/src/config/transform-mode.ts +34 -0
- package/src/config/variable.test.ts +323 -0
- package/src/config/variable.ts +192 -0
- package/src/features/magic-context/defaults.ts +1 -0
- package/src/features/magic-context/dreamer/cron.ts +243 -0
- package/src/features/magic-context/dreamer/task-registry.ts +104 -0
- package/src/shared/conflict-detector.test.ts +251 -1
- package/src/shared/conflict-detector.ts +84 -5
- package/src/shared/conflict-fixer.test.ts +309 -0
- package/src/shared/conflict-fixer.ts +82 -5
- package/src/shared/context-limit-provenance.ts +6 -0
- package/src/shared/escalation-bands.test.ts +23 -0
- package/src/shared/escalation-bands.ts +18 -0
- package/src/shared/format-threshold.ts +1 -1
- package/src/shared/models-dev-cache.test.ts +171 -0
- package/src/shared/models-dev-cache.ts +195 -38
- package/src/shared/rpc-server.ts +27 -18
- package/src/shared/rpc-types.ts +46 -1
- package/src/shared/sqlite.ts +13 -33
- package/src/shared/storage-permissions.ts +20 -0
- package/src/tui/compaction-off.test.ts +56 -0
- package/src/tui/compaction-off.ts +29 -0
- package/src/tui/data/context-db.ts +6 -0
- package/src/tui/index.tsx +113 -65
- package/src/tui/slots/sidebar-content.tsx +139 -83
- package/src/tui-compiled/compaction-off.ts +29 -0
- package/src/tui-compiled/data/context-db.ts +6 -0
- package/src/tui-compiled/index.tsx +558 -455
- package/src/tui-compiled/slots/sidebar-content.tsx +237 -161
- package/dist/config/schema.d.ts +0 -3
- package/dist/config/schema.d.ts.map +0 -1
- package/dist/features/magic-context/plugin-messages.d.ts +0 -75
- package/dist/features/magic-context/plugin-messages.d.ts.map +0 -1
- package/dist/hooks/magic-context/compartment-runner-state-xml.d.ts +0 -21
- package/dist/hooks/magic-context/compartment-runner-state-xml.d.ts.map +0 -1
- package/dist/index-anhrfygk.js +0 -57
- package/dist/send-session-notification-tghq9gnh.js +0 -11
- package/dist/shared/opencode-compaction-detector.d.ts +0 -2
- package/dist/shared/opencode-compaction-detector.d.ts.map +0 -1
- package/dist/shared/transcript-opencode.d.ts +0 -71
- package/dist/shared/transcript-opencode.d.ts.map +0 -1
- package/dist/tools/index.d.ts +0 -6
- package/dist/tools/index.d.ts.map +0 -1
- package/src/shared/opencode-compaction-detector.test.ts +0 -239
- package/src/shared/opencode-compaction-detector.ts +0 -81
- package/src/shared/transcript-opencode.ts +0 -302
- /package/dist/{index-v7fmc1s2.js → index-ygcng9t8.js} +0 -0
|
@@ -0,0 +1,1002 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { isValidLanguageCode } from "../../agents/language-directive";
|
|
4
|
+
import { DEFAULT_PROTECTED_TAGS } from "../../features/magic-context/defaults";
|
|
5
|
+
import { isValidCron } from "../../features/magic-context/dreamer/cron";
|
|
6
|
+
import type {
|
|
7
|
+
AGENTIC_DREAM_TASKS,
|
|
8
|
+
DreamTaskName,
|
|
9
|
+
} from "../../features/magic-context/dreamer/task-registry";
|
|
10
|
+
import { AgentOverrideConfigSchema } from "./agent-overrides";
|
|
11
|
+
|
|
12
|
+
export const DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65;
|
|
13
|
+
// Output reservation now removes generation capacity from the usable window.
|
|
14
|
+
// The 90% cap leaves roughly 10% of that safe input budget for mid-turn growth;
|
|
15
|
+
// escalation derives above the effective threshold and the 95% wall stays fixed.
|
|
16
|
+
export const EXECUTE_THRESHOLD_CAP_MESSAGE =
|
|
17
|
+
"execute_threshold is capped at 90% for cache safety: output capacity is reserved from the usable context window, and the remaining 10% absorbs mid-turn growth before the absolute 95% emergency wall. Use a value between 20 and 90.";
|
|
18
|
+
export const DEFAULT_HISTORIAN_TIMEOUT_MS = 300_000;
|
|
19
|
+
export const DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15;
|
|
20
|
+
|
|
21
|
+
export const DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2";
|
|
22
|
+
|
|
23
|
+
// Re-exported from the (DB-free) task registry so the schema and the runtime
|
|
24
|
+
// scheduler share ONE source of truth for task names. DreamingTask remains the
|
|
25
|
+
// agentic tasks (those driven by buildDreamTaskPrompt); CANONICAL_DREAM_TASKS
|
|
26
|
+
// is the full task set used for per-task scheduling config.
|
|
27
|
+
export type DreamingTask = (typeof AGENTIC_DREAM_TASKS)[number];
|
|
28
|
+
|
|
29
|
+
/** Valid thinking levels for Pi subagents. Maps to Pi's --thinking CLI flag.
|
|
30
|
+
* Off: disable reasoning. Minimal/low/medium/high/xhigh/max: increasing reasoning depth.
|
|
31
|
+
* `max` was added in Pi 0.83.0.
|
|
32
|
+
* Pi-only — OpenCode uses `variant` in agent config instead. */
|
|
33
|
+
export const PiThinkingLevelSchema = z
|
|
34
|
+
.enum(["off", "minimal", "low", "medium", "high", "xhigh", "max"])
|
|
35
|
+
.optional();
|
|
36
|
+
export type PiThinkingLevel = z.infer<typeof PiThinkingLevelSchema>;
|
|
37
|
+
|
|
38
|
+
/** Pi-only child-process controls. This block is intentionally optional so an
|
|
39
|
+
* absent allowlist preserves Pi's normal extension discovery behavior. */
|
|
40
|
+
export const PiConfigSchema = z
|
|
41
|
+
.object({
|
|
42
|
+
subagent_extensions: z
|
|
43
|
+
.array(z.string().trim().min(1))
|
|
44
|
+
.optional()
|
|
45
|
+
.describe(
|
|
46
|
+
"User-only allowlist of Pi extensions for Magic Context subagent children. When set, children use --no-extensions and load only these entries (plus Magic Context's scoped child extension where applicable). Relative paths resolve from ~/.pi/agent, matching Pi's settings.json package location. Unset preserves normal Pi extension discovery.",
|
|
47
|
+
),
|
|
48
|
+
})
|
|
49
|
+
.optional();
|
|
50
|
+
export type PiConfig = NonNullable<z.infer<typeof PiConfigSchema>>;
|
|
51
|
+
|
|
52
|
+
/** A 5-field cron expression, or "" to disable the task. */
|
|
53
|
+
const CronScheduleSchema = z
|
|
54
|
+
.string()
|
|
55
|
+
.refine((s) => s.trim() === "" || isValidCron(s), {
|
|
56
|
+
message:
|
|
57
|
+
'Invalid schedule: use a 5-field cron expression (e.g. "0 3 * * *" for 3am daily, "0 3 * * 0" for Sunday 3am, "0 */6 * * *" every 6h) or "" to disable.',
|
|
58
|
+
})
|
|
59
|
+
.describe('5-field cron schedule (e.g. "0 3 * * *"), or "" to disable this task.');
|
|
60
|
+
|
|
61
|
+
/** Per-task scheduling + model config. Model/fallback/thinking inherit the
|
|
62
|
+
* dreamer-level defaults when omitted. Task-specific params (promotion_threshold)
|
|
63
|
+
* are optional and only meaningful for their owning task. */
|
|
64
|
+
const DreamTaskBaseConfigSchema = z.object({
|
|
65
|
+
schedule: CronScheduleSchema.default(""),
|
|
66
|
+
model: z.string().optional().describe("Per-task model override (inherits dreamer.model)"),
|
|
67
|
+
fallback_models: z
|
|
68
|
+
.union([z.string(), z.array(z.string())])
|
|
69
|
+
.optional()
|
|
70
|
+
.describe("Per-task fallback chain (inherits dreamer.fallback_models)"),
|
|
71
|
+
thinking_level: PiThinkingLevelSchema.describe("Pi only: per-task thinking level"),
|
|
72
|
+
timeout_minutes: z
|
|
73
|
+
.number()
|
|
74
|
+
.min(5)
|
|
75
|
+
.default(20)
|
|
76
|
+
.describe("Minutes allowed for this task before it is aborted"),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const PromotionThresholdSchema = z
|
|
80
|
+
.number()
|
|
81
|
+
.min(2)
|
|
82
|
+
.max(20)
|
|
83
|
+
.optional()
|
|
84
|
+
.describe(
|
|
85
|
+
"review-user-memories: min candidate observations before promotion is considered (default: 3)",
|
|
86
|
+
);
|
|
87
|
+
const PrimerPromotionThresholdSchema = z
|
|
88
|
+
.number()
|
|
89
|
+
.min(2)
|
|
90
|
+
.max(20)
|
|
91
|
+
.optional()
|
|
92
|
+
.describe(
|
|
93
|
+
"promote-primers: min recurring source days before promotion is considered (default: 2)",
|
|
94
|
+
);
|
|
95
|
+
export const DreamTaskConfigSchema = DreamTaskBaseConfigSchema.extend({
|
|
96
|
+
promotion_threshold: PromotionThresholdSchema,
|
|
97
|
+
});
|
|
98
|
+
const ReviewUserMemoriesTaskConfigSchema = DreamTaskBaseConfigSchema.extend({
|
|
99
|
+
promotion_threshold: PromotionThresholdSchema,
|
|
100
|
+
});
|
|
101
|
+
const PromotePrimersTaskConfigSchema = DreamTaskBaseConfigSchema.extend({
|
|
102
|
+
promotion_threshold: PrimerPromotionThresholdSchema,
|
|
103
|
+
});
|
|
104
|
+
export type DreamTaskConfig = z.infer<typeof DreamTaskConfigSchema>;
|
|
105
|
+
|
|
106
|
+
/** Default schedule per task. Preserves v1 behavior: verify runs nightly;
|
|
107
|
+
* curate runs weekly; classify runs daily after curation; maintain-docs
|
|
108
|
+
* defaults OFF (it was not in the v1 default list); the two promoted
|
|
109
|
+
* post-phases run nightly and are gated. */
|
|
110
|
+
const DEFAULT_TASK_SCHEDULES: Record<DreamTaskName, string> = {
|
|
111
|
+
// map-memories is a one-time-style backfill (gate: unmapped memories exist).
|
|
112
|
+
// Default nightly so it drains the pool then no-ops once everything is mapped.
|
|
113
|
+
"map-memories": "0 2 * * *",
|
|
114
|
+
verify: "0 3 * * *",
|
|
115
|
+
"verify-broad": "0 4 * * 0",
|
|
116
|
+
curate: "0 4 * * 0",
|
|
117
|
+
// Daily trickle: chunks are small (~40 memories), so after the initial
|
|
118
|
+
// backfill the per-memory cue compression is cheap to run every night.
|
|
119
|
+
"compress-cues": "0 4 * * *",
|
|
120
|
+
"classify-memories": "0 6 * * *",
|
|
121
|
+
retrospective: "0 5 * * *",
|
|
122
|
+
"maintain-docs": "",
|
|
123
|
+
"evaluate-smart-notes": "0 3 * * *",
|
|
124
|
+
"review-user-memories": "0 3 * * *",
|
|
125
|
+
"promote-primers": "0 3 * * *",
|
|
126
|
+
"refresh-primers": "0 3 * * *",
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
function defaultTaskConfig(task: DreamTaskName): z.input<typeof DreamTaskConfigSchema> {
|
|
130
|
+
const base: z.input<typeof DreamTaskConfigSchema> = { schedule: DEFAULT_TASK_SCHEDULES[task] };
|
|
131
|
+
if (task === "review-user-memories") base.promotion_threshold = 3;
|
|
132
|
+
if (task === "promote-primers") base.promotion_threshold = 2;
|
|
133
|
+
return base;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// `.default()` in Zod 4 wants the OUTPUT shape; the function form lets us derive
|
|
137
|
+
// it by parsing the (partial) input default so timeout_minutes etc. fill in.
|
|
138
|
+
/** The `tasks` record: one entry per canonical task, each defaulting to its
|
|
139
|
+
* v1-behavior-preserving schedule. Written explicitly (not via fromEntries) so
|
|
140
|
+
* the inferred type stays a precise per-key object. */
|
|
141
|
+
export const DreamTasksSchema = z
|
|
142
|
+
.object({
|
|
143
|
+
"map-memories": DreamTaskBaseConfigSchema.default(() =>
|
|
144
|
+
DreamTaskBaseConfigSchema.parse(defaultTaskConfig("map-memories")),
|
|
145
|
+
),
|
|
146
|
+
verify: DreamTaskBaseConfigSchema.default(() =>
|
|
147
|
+
DreamTaskBaseConfigSchema.parse(defaultTaskConfig("verify")),
|
|
148
|
+
),
|
|
149
|
+
"verify-broad": DreamTaskBaseConfigSchema.default(() =>
|
|
150
|
+
DreamTaskBaseConfigSchema.parse(defaultTaskConfig("verify-broad")),
|
|
151
|
+
),
|
|
152
|
+
curate: DreamTaskBaseConfigSchema.default(() =>
|
|
153
|
+
DreamTaskBaseConfigSchema.parse(defaultTaskConfig("curate")),
|
|
154
|
+
),
|
|
155
|
+
"compress-cues": DreamTaskBaseConfigSchema.default(() =>
|
|
156
|
+
DreamTaskBaseConfigSchema.parse(defaultTaskConfig("compress-cues")),
|
|
157
|
+
),
|
|
158
|
+
"classify-memories": DreamTaskBaseConfigSchema.default(() =>
|
|
159
|
+
DreamTaskBaseConfigSchema.parse(defaultTaskConfig("classify-memories")),
|
|
160
|
+
),
|
|
161
|
+
retrospective: DreamTaskBaseConfigSchema.default(() =>
|
|
162
|
+
DreamTaskBaseConfigSchema.parse(defaultTaskConfig("retrospective")),
|
|
163
|
+
),
|
|
164
|
+
"maintain-docs": DreamTaskBaseConfigSchema.default(() =>
|
|
165
|
+
DreamTaskBaseConfigSchema.parse(defaultTaskConfig("maintain-docs")),
|
|
166
|
+
),
|
|
167
|
+
"evaluate-smart-notes": DreamTaskBaseConfigSchema.default(() =>
|
|
168
|
+
DreamTaskBaseConfigSchema.parse(defaultTaskConfig("evaluate-smart-notes")),
|
|
169
|
+
),
|
|
170
|
+
"review-user-memories": ReviewUserMemoriesTaskConfigSchema.default(() =>
|
|
171
|
+
ReviewUserMemoriesTaskConfigSchema.parse(defaultTaskConfig("review-user-memories")),
|
|
172
|
+
),
|
|
173
|
+
"promote-primers": PromotePrimersTaskConfigSchema.default(() =>
|
|
174
|
+
PromotePrimersTaskConfigSchema.parse(defaultTaskConfig("promote-primers")),
|
|
175
|
+
),
|
|
176
|
+
"refresh-primers": DreamTaskBaseConfigSchema.default(() =>
|
|
177
|
+
DreamTaskBaseConfigSchema.parse(defaultTaskConfig("refresh-primers")),
|
|
178
|
+
),
|
|
179
|
+
})
|
|
180
|
+
.describe(
|
|
181
|
+
"Per-task scheduling + model config. Each task has its own cron schedule and may override the dreamer-level model.",
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
/** Combined dreamer agent + per-task scheduling configuration (Dreamer v2). */
|
|
185
|
+
export const DreamerConfigSchema = AgentOverrideConfigSchema.merge(
|
|
186
|
+
z.object({
|
|
187
|
+
tasks: DreamTasksSchema.default(() => DreamTasksSchema.parse({})),
|
|
188
|
+
inject_docs: z
|
|
189
|
+
.boolean()
|
|
190
|
+
.default(true)
|
|
191
|
+
.describe(
|
|
192
|
+
"Inject ARCHITECTURE.md and STRUCTURE.md into the m[0] `<project-docs>` block (default true)",
|
|
193
|
+
),
|
|
194
|
+
thinking_level: PiThinkingLevelSchema.describe(
|
|
195
|
+
"Pi only: default thinking level for dreamer subagent invocations. See historian.thinking_level.",
|
|
196
|
+
),
|
|
197
|
+
}),
|
|
198
|
+
);
|
|
199
|
+
export type DreamerConfig = z.infer<typeof DreamerConfigSchema>;
|
|
200
|
+
|
|
201
|
+
export const SidekickConfigSchema = AgentOverrideConfigSchema.extend({
|
|
202
|
+
timeout_ms: z.number().default(30000).describe("Timeout for sidekick calls in milliseconds"),
|
|
203
|
+
system_prompt: z.string().optional().describe("Custom system prompt for sidekick"),
|
|
204
|
+
thinking_level: PiThinkingLevelSchema.describe(
|
|
205
|
+
"Pi only: explicit thinking level for sidekick subagent invocations. See historian.thinking_level.",
|
|
206
|
+
),
|
|
207
|
+
}).optional();
|
|
208
|
+
export type SidekickConfig = NonNullable<z.infer<typeof SidekickConfigSchema>>;
|
|
209
|
+
|
|
210
|
+
/** Historian agent configuration — includes all agent overrides plus two_pass mode.
|
|
211
|
+
* Two-pass mode runs a second editor pass after the initial historian pass to clean
|
|
212
|
+
* up low-signal U: lines and cross-compartment duplicates. Recommended for models
|
|
213
|
+
* without extended thinking; not needed for Claude Sonnet/Opus when reasoning is
|
|
214
|
+
* enabled via OpenCode variant config. */
|
|
215
|
+
export const HistorianConfigSchema = AgentOverrideConfigSchema.extend({
|
|
216
|
+
two_pass: z
|
|
217
|
+
.boolean()
|
|
218
|
+
.default(false)
|
|
219
|
+
.describe(
|
|
220
|
+
"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)",
|
|
221
|
+
),
|
|
222
|
+
thinking_level: PiThinkingLevelSchema.describe(
|
|
223
|
+
"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 | max",
|
|
224
|
+
),
|
|
225
|
+
disallowed_tools: z
|
|
226
|
+
.array(z.enum(["*", "read", "aft_outline", "aft_zoom", "aft_search"]))
|
|
227
|
+
.default([])
|
|
228
|
+
.describe(
|
|
229
|
+
'OpenCode only. Tools to REMOVE from the historian\'s default allow-list [read, aft_outline, aft_zoom, aft_search]. Applies to both historian and historian-editor agents. Use ["*"] to strip all tool definitions from the model request — this prevents weak instruction-following models (e.g. mistral-small-latest) from entering tool-calling loops. Individual tool names remove just that tool. Note: a user-supplied historian.permission override can re-allow a tool that disallowed_tools removed — disallowed_tools sets the baseline, permission overrides take precedence. (default: [])',
|
|
230
|
+
),
|
|
231
|
+
}).optional();
|
|
232
|
+
export type HistorianConfig = NonNullable<z.infer<typeof HistorianConfigSchema>>;
|
|
233
|
+
|
|
234
|
+
const EmbeddingFallbackProviderSchema = z.enum(["local", "openai-compatible", "off"]);
|
|
235
|
+
|
|
236
|
+
function expandConfigPath(value: string): string {
|
|
237
|
+
const trimmed = value.trim();
|
|
238
|
+
if (trimmed === "~") return homedir();
|
|
239
|
+
if (trimmed.startsWith("~/")) return `${homedir()}/${trimmed.slice(2)}`;
|
|
240
|
+
return trimmed;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const BaseEmbeddingConfigSchema = z
|
|
244
|
+
.object({
|
|
245
|
+
provider: z
|
|
246
|
+
.enum(["local", "openai-compatible", "off", "synapse"])
|
|
247
|
+
.default("local")
|
|
248
|
+
.describe(
|
|
249
|
+
"Embedding provider. 'local' uses Xenova/all-MiniLM-L6-v2, 'openai-compatible' requires endpoint and model, 'synapse' uses the certified local Synapse lane with an explicit fallback provider, and 'off' disables embeddings.",
|
|
250
|
+
),
|
|
251
|
+
fallback_provider: EmbeddingFallbackProviderSchema.optional().describe(
|
|
252
|
+
"Fallback provider for the Synapse lane. Required when provider is 'synapse'; local, openai-compatible, and off are valid.",
|
|
253
|
+
),
|
|
254
|
+
model: z
|
|
255
|
+
.string()
|
|
256
|
+
.optional()
|
|
257
|
+
.describe("Embedding model name. Required for openai-compatible, ignored for local."),
|
|
258
|
+
endpoint: z
|
|
259
|
+
.string()
|
|
260
|
+
.optional()
|
|
261
|
+
.describe("API endpoint URL. Required when provider is openai-compatible."),
|
|
262
|
+
api_key: z.string().optional().describe("API key for remote embedding provider (optional)"),
|
|
263
|
+
input_type: z
|
|
264
|
+
.string()
|
|
265
|
+
.optional()
|
|
266
|
+
.describe(
|
|
267
|
+
"Default input_type for stored/indexed (passage) embeddings in the request body. Required by some openai-compatible providers (e.g. NVIDIA NIM). Omitted from the request when unset.",
|
|
268
|
+
),
|
|
269
|
+
query_input_type: z
|
|
270
|
+
.string()
|
|
271
|
+
.optional()
|
|
272
|
+
.describe(
|
|
273
|
+
"Optional input_type for query (search) embeddings on asymmetric models (e.g. NVIDIA NIM 'query'). When unset, query embeddings use embedding.input_type. Passage/stored content always uses embedding.input_type.",
|
|
274
|
+
),
|
|
275
|
+
truncate: z
|
|
276
|
+
.string()
|
|
277
|
+
.optional()
|
|
278
|
+
.describe(
|
|
279
|
+
"Optional truncate mode sent in the embedding request body (e.g. NVIDIA NIM accepts 'NONE' | 'START' | 'END'). Omitted from the request when unset.",
|
|
280
|
+
),
|
|
281
|
+
max_input_tokens: z
|
|
282
|
+
.number()
|
|
283
|
+
.int()
|
|
284
|
+
.positive()
|
|
285
|
+
.optional()
|
|
286
|
+
.describe(
|
|
287
|
+
"Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted.",
|
|
288
|
+
),
|
|
289
|
+
local_dtype: z
|
|
290
|
+
.enum([
|
|
291
|
+
"auto",
|
|
292
|
+
"fp32",
|
|
293
|
+
"fp16",
|
|
294
|
+
"q8",
|
|
295
|
+
"int8",
|
|
296
|
+
"uint8",
|
|
297
|
+
"q4",
|
|
298
|
+
"bnb4",
|
|
299
|
+
"q4f16",
|
|
300
|
+
"q2",
|
|
301
|
+
"q2f16",
|
|
302
|
+
"q1",
|
|
303
|
+
"q1f16",
|
|
304
|
+
])
|
|
305
|
+
.optional()
|
|
306
|
+
.describe(
|
|
307
|
+
"Local provider only: ONNX model dtype passed to the transformers.js feature-extraction pipeline. Accepts the @huggingface/transformers DataType strings (auto, fp32, fp16, q8, int8, uint8, q4, bnb4, q4f16, q2, q2f16, q1, q1f16). Omitted keeps today's behavior (fp32). A non-default value changes the produced vectors and folds into the embedding model identity, so switching dtype re-embeds rather than mixing vector spaces. Useful for selecting a quantized variant (e.g. q8) of a larger multilingual model to cut memory and CPU cost; see issue #259.",
|
|
308
|
+
),
|
|
309
|
+
})
|
|
310
|
+
.superRefine((data, ctx) => {
|
|
311
|
+
const validationProvider =
|
|
312
|
+
data.provider === "synapse" ? data.fallback_provider : data.provider;
|
|
313
|
+
if (validationProvider === "openai-compatible" && !data.endpoint?.trim()) {
|
|
314
|
+
ctx.addIssue({
|
|
315
|
+
code: "custom",
|
|
316
|
+
path: ["endpoint"],
|
|
317
|
+
message: "endpoint is required when embedding.provider is openai-compatible",
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (validationProvider === "openai-compatible" && !data.model?.trim()) {
|
|
322
|
+
ctx.addIssue({
|
|
323
|
+
code: "custom",
|
|
324
|
+
path: ["model"],
|
|
325
|
+
message: "model is required when embedding.provider is openai-compatible",
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
export const EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
|
|
331
|
+
if (data.provider === "synapse") {
|
|
332
|
+
const model = data.model?.trim();
|
|
333
|
+
const endpoint = data.endpoint?.trim();
|
|
334
|
+
const apiKey = data.api_key?.trim();
|
|
335
|
+
const inputType = data.input_type?.trim();
|
|
336
|
+
const queryInputType = data.query_input_type?.trim();
|
|
337
|
+
const truncate = data.truncate?.trim();
|
|
338
|
+
return {
|
|
339
|
+
provider: "synapse" as const,
|
|
340
|
+
...(data.fallback_provider ? { fallback_provider: data.fallback_provider } : {}),
|
|
341
|
+
...(model ? { model } : {}),
|
|
342
|
+
...(endpoint ? { endpoint } : {}),
|
|
343
|
+
...(apiKey ? { api_key: apiKey } : {}),
|
|
344
|
+
...(inputType ? { input_type: inputType } : {}),
|
|
345
|
+
...(queryInputType ? { query_input_type: queryInputType } : {}),
|
|
346
|
+
...(truncate ? { truncate } : {}),
|
|
347
|
+
...(data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}),
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (data.provider === "local") {
|
|
352
|
+
return {
|
|
353
|
+
provider: "local" as const,
|
|
354
|
+
model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
355
|
+
...(data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}),
|
|
356
|
+
// local_dtype is spread CONDITIONALLY: omitting it when unset keeps
|
|
357
|
+
// the identity byte-identical for the common no-dtype config, so
|
|
358
|
+
// adding this field does not force a global re-embed — only configs
|
|
359
|
+
// that actually set a dtype get a new identity (and under per-model
|
|
360
|
+
// coexistence even that just coexists + lazily GCs, never a
|
|
361
|
+
// destructive wipe). Mirrors the truncate fold pattern.
|
|
362
|
+
...(data.local_dtype ? { local_dtype: data.local_dtype } : {}),
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (data.provider === "openai-compatible") {
|
|
367
|
+
const apiKey = data.api_key?.trim();
|
|
368
|
+
const inputType = data.input_type?.trim();
|
|
369
|
+
const queryInputType = data.query_input_type?.trim();
|
|
370
|
+
const truncate = data.truncate?.trim();
|
|
371
|
+
return {
|
|
372
|
+
provider: "openai-compatible" as const,
|
|
373
|
+
model: data.model?.trim() ?? "",
|
|
374
|
+
endpoint: data.endpoint?.trim() ?? "",
|
|
375
|
+
...(apiKey ? { api_key: apiKey } : {}),
|
|
376
|
+
...(inputType ? { input_type: inputType } : {}),
|
|
377
|
+
...(queryInputType ? { query_input_type: queryInputType } : {}),
|
|
378
|
+
...(truncate ? { truncate } : {}),
|
|
379
|
+
...(data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}),
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return { provider: "off" as const };
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
export type EmbeddingConfig = z.infer<typeof EmbeddingConfigSchema>;
|
|
387
|
+
export type EmbeddingFallbackProvider = z.infer<typeof EmbeddingFallbackProviderSchema>;
|
|
388
|
+
|
|
389
|
+
export interface SubcConfig {
|
|
390
|
+
connection_file: string;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export interface ShadowEmbeddingConfig {
|
|
394
|
+
enabled: boolean;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export interface ExperimentalMuralConfig {
|
|
398
|
+
enabled: boolean;
|
|
399
|
+
/** The CUE COMPRESSOR model for the compress-cues dreamer task (the mural is
|
|
400
|
+
* now rendered deterministically, so this no longer names an author model). */
|
|
401
|
+
model?: string;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export interface ExperimentalConfig {
|
|
405
|
+
mural: ExperimentalMuralConfig;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export interface MagicContextConfig {
|
|
409
|
+
enabled: boolean;
|
|
410
|
+
/** User-level setting that lets a session started exactly in the canonical home directory use a deterministic directory identity. */
|
|
411
|
+
allow_home_project: boolean;
|
|
412
|
+
experimental: ExperimentalConfig;
|
|
413
|
+
/** Selects the runtime implementation for this project. Rust mode is experimental and requires user-level subc configuration. */
|
|
414
|
+
transform_mode: "ts" | "rust";
|
|
415
|
+
/** Auto-update the cached OpenCode plugin wrapper when a newer npm version is available.
|
|
416
|
+
* USER config only; project configs cannot disable it. Default: true. */
|
|
417
|
+
auto_update?: boolean;
|
|
418
|
+
/** Output language for generated Magic Context prose. USER config only. */
|
|
419
|
+
language?: string;
|
|
420
|
+
historian?: HistorianConfig;
|
|
421
|
+
dreamer?: DreamerConfig;
|
|
422
|
+
cache_ttl: string | { default: string; [modelKey: string]: string };
|
|
423
|
+
/** User-only output-token reservation override. Zero disables reservation. */
|
|
424
|
+
output_reserve?: number | { default: number; [modelKey: string]: number };
|
|
425
|
+
/** TUI toast lifetime in milliseconds for Magic Context notifications. Default: 5000. */
|
|
426
|
+
toast_duration_ms?: number;
|
|
427
|
+
execute_threshold_percentage: number | { default: number; [modelKey: string]: number };
|
|
428
|
+
/** Absolute token thresholds per model. When set for a given model (or via `default`),
|
|
429
|
+
* this overrides `execute_threshold_percentage` for that model. Useful for hard caps
|
|
430
|
+
* matching provider input limits. Values above 90% × context_limit are clamped with a warning. */
|
|
431
|
+
execute_threshold_tokens?: { default?: number; [modelKey: string]: number | undefined };
|
|
432
|
+
protected_tags: number;
|
|
433
|
+
clear_reasoning_age: number;
|
|
434
|
+
history_budget_percentage: number;
|
|
435
|
+
historian_timeout_ms: number;
|
|
436
|
+
commit_cluster_trigger: {
|
|
437
|
+
enabled: boolean;
|
|
438
|
+
min_clusters: number;
|
|
439
|
+
};
|
|
440
|
+
/** Per-connection SQLite tuning for Magic Context's own context.db. */
|
|
441
|
+
sqlite: {
|
|
442
|
+
cache_size_mb: number;
|
|
443
|
+
mmap_size_mb: number;
|
|
444
|
+
};
|
|
445
|
+
/**
|
|
446
|
+
* Keep shared-storage permissions under an external operator's control.
|
|
447
|
+
* USER config only; project configs cannot weaken local data privacy.
|
|
448
|
+
*/
|
|
449
|
+
storage: {
|
|
450
|
+
enforce_private_permissions: boolean;
|
|
451
|
+
};
|
|
452
|
+
/**
|
|
453
|
+
* Controls whether and where Magic Context augments the system prompt
|
|
454
|
+
* (`## Magic Context` guidance, `<project-docs>`, `<user-profile>`,
|
|
455
|
+
* sticky date) inside `experimental.chat.system.transform`.
|
|
456
|
+
*
|
|
457
|
+
* Internal OpenCode hidden agents (title, summary, compaction) are
|
|
458
|
+
* always skipped automatically — that's a separate code path.
|
|
459
|
+
*/
|
|
460
|
+
system_prompt_injection: {
|
|
461
|
+
/** When false, NO injection happens for ANY agent — global escape hatch. */
|
|
462
|
+
enabled: boolean;
|
|
463
|
+
/**
|
|
464
|
+
* If the agent's system prompt contains any of these substrings,
|
|
465
|
+
* skip ALL Magic Context injection for that call. Lets users opt
|
|
466
|
+
* specific agents out (e.g. read-only QA agents that deny our
|
|
467
|
+
* `ctx_*` tools and don't need the guidance). The default marker
|
|
468
|
+
* `<!-- magic-context: skip -->` is meant to be added inside the
|
|
469
|
+
* user's custom agent prompt.
|
|
470
|
+
*/
|
|
471
|
+
skip_signatures: string[];
|
|
472
|
+
};
|
|
473
|
+
/** Inject elapsed-time markers between user messages and date ranges on
|
|
474
|
+
* compartments so the agent has a wall-clock sense of the session.
|
|
475
|
+
* Graduated from `experimental.temporal_awareness`; default: true. */
|
|
476
|
+
temporal_awareness: boolean;
|
|
477
|
+
/** Debug: when true, keep the child sessions Magic Context spawns for its
|
|
478
|
+
* own subagents (historian, dreamer, sidekick, memory-migration) instead
|
|
479
|
+
* of deleting them on success. For short-term inspection/data collection;
|
|
480
|
+
* kept sessions accumulate until manually cleared. Default false. */
|
|
481
|
+
keep_subagents: boolean;
|
|
482
|
+
/**
|
|
483
|
+
* When true (default), deterministic inoperability (schema fence, storage
|
|
484
|
+
* open/migration failure) blocks the primary-session transform with a loud
|
|
485
|
+
* recovery error instead of silently falling through to native compaction.
|
|
486
|
+
* USER config only — project tier cannot set this. Not recommended to disable.
|
|
487
|
+
*/
|
|
488
|
+
fail_closed_blocking: boolean;
|
|
489
|
+
/**
|
|
490
|
+
* Compaction-off mode gate. When `enabled` is false Magic Context stops
|
|
491
|
+
* managing the context window and keeps only its knowledge layer, letting
|
|
492
|
+
* the harness's native compaction (or nothing) own the window. USER config
|
|
493
|
+
* only — project tier `compaction.enabled` is stripped for security.
|
|
494
|
+
* Boot-resolved: changing it requires a process restart.
|
|
495
|
+
*/
|
|
496
|
+
compaction: {
|
|
497
|
+
enabled: boolean;
|
|
498
|
+
};
|
|
499
|
+
/** Pi-only controls for Magic Context's OpenCode-parity todowrite surface. */
|
|
500
|
+
todowrite: {
|
|
501
|
+
enabled: boolean;
|
|
502
|
+
overlay: boolean;
|
|
503
|
+
};
|
|
504
|
+
/** Pi-only child-process extension controls. */
|
|
505
|
+
pi?: PiConfig;
|
|
506
|
+
/** Content-aware reclaim of tool output that a later call supersedes, added
|
|
507
|
+
* to the normal age-based auto-drop: superseded todowrite/ctx_reduce/meta
|
|
508
|
+
* outputs are dropped, and older edits to a file are compressed to a marker
|
|
509
|
+
* that keeps only the filePath. Only runs on a transform pass that is
|
|
510
|
+
* already rewriting the messages, so it never triggers a prompt-cache miss
|
|
511
|
+
* on its own; when off, the messages sent to the model are byte-identical to
|
|
512
|
+
* the age-based-only behavior. Experimental, opt-in, default off until cache
|
|
513
|
+
* stability is proven. */
|
|
514
|
+
smart_drops: boolean;
|
|
515
|
+
/**
|
|
516
|
+
* Age-tier caveman compression for long user/assistant text parts.
|
|
517
|
+
* Graduated from `experimental.caveman_text_compression`; opt-in, default off.
|
|
518
|
+
*
|
|
519
|
+
* Active only for primary sessions when enabled; never for subagents.
|
|
520
|
+
* Buckets eligible (outside-protected-tail) messages into four age
|
|
521
|
+
* tiers by tag position — oldest 20% → ultra, next 20% → full,
|
|
522
|
+
* next 20% → lite, newest 40% → untouched — and rewrites the text
|
|
523
|
+
* part in place.
|
|
524
|
+
* Always compresses from the original source (source_contents), so
|
|
525
|
+
* tier shifts produce the same result as if the target depth were
|
|
526
|
+
* applied directly to the original text.
|
|
527
|
+
*
|
|
528
|
+
* Disabled by default because it rewrites agent-visible history.
|
|
529
|
+
*/
|
|
530
|
+
caveman_text_compression: {
|
|
531
|
+
enabled: boolean;
|
|
532
|
+
/** Text parts shorter than this (characters) are left untouched. */
|
|
533
|
+
min_chars: number;
|
|
534
|
+
};
|
|
535
|
+
embedding: EmbeddingConfig;
|
|
536
|
+
/** User-only connection settings for the Synapse daemon. */
|
|
537
|
+
subc?: SubcConfig;
|
|
538
|
+
/** Developer-only Synapse shadow lane switch. */
|
|
539
|
+
shadow_embedding?: ShadowEmbeddingConfig;
|
|
540
|
+
memory: {
|
|
541
|
+
enabled: boolean;
|
|
542
|
+
injection_budget_tokens: number;
|
|
543
|
+
auto_promote: boolean;
|
|
544
|
+
retrieval_count_promotion_threshold: number;
|
|
545
|
+
/** Appends a compact hint to new user messages when ctx_search finds
|
|
546
|
+
* highly-related memories, conversation, or git commits. Does NOT
|
|
547
|
+
* inject full content — just vague fragments that nudge the agent to
|
|
548
|
+
* run ctx_search for full context if relevant. Graduated from
|
|
549
|
+
* `experimental.auto_search`; enabled by default. Independent of
|
|
550
|
+
* `memory.enabled` — it can still surface conversation/git hints when
|
|
551
|
+
* the memory store is off. */
|
|
552
|
+
auto_search: {
|
|
553
|
+
enabled: boolean;
|
|
554
|
+
/** Top hit score must exceed this threshold for the hint to fire. */
|
|
555
|
+
score_threshold: number;
|
|
556
|
+
/** Minimum user message length in characters (skip short prompts). */
|
|
557
|
+
min_prompt_chars: number;
|
|
558
|
+
};
|
|
559
|
+
/** Index git commit messages from HEAD into a new ctx_search source so
|
|
560
|
+
* agents can recall recent regressions, fixes, and decisions from
|
|
561
|
+
* commit history without running git log manually. Graduated from
|
|
562
|
+
* `experimental.git_commit_indexing`; opt-in, default off. Independent
|
|
563
|
+
* of `memory.enabled`. */
|
|
564
|
+
git_commit_indexing: {
|
|
565
|
+
enabled: boolean;
|
|
566
|
+
/** Days of history to index (default: 365) */
|
|
567
|
+
since_days: number;
|
|
568
|
+
/** Max commits kept per project; oldest evicted (default: 2000) */
|
|
569
|
+
max_commits: number;
|
|
570
|
+
};
|
|
571
|
+
};
|
|
572
|
+
sidekick?: SidekickConfig;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
export const MagicContextConfigSchema = z
|
|
576
|
+
.object({
|
|
577
|
+
enabled: z.boolean().default(true).describe("Enable magic context (default: true)"),
|
|
578
|
+
allow_home_project: z
|
|
579
|
+
.boolean()
|
|
580
|
+
.default(false)
|
|
581
|
+
.describe(
|
|
582
|
+
"Allow Magic Context sessions launched from the exact canonical home directory. The home session uses its deterministic dir: identity so pre-gate memories reconnect. USER-LEVEL ONLY: project config is ignored. The home identity is excluded from registry seed exports, never resolves descendants by containment, and cannot join a workspace.",
|
|
583
|
+
),
|
|
584
|
+
experimental: z
|
|
585
|
+
.object({
|
|
586
|
+
mural: z
|
|
587
|
+
.object({
|
|
588
|
+
enabled: z.boolean().default(false),
|
|
589
|
+
model: z
|
|
590
|
+
.string()
|
|
591
|
+
.trim()
|
|
592
|
+
.min(1)
|
|
593
|
+
.optional()
|
|
594
|
+
.describe(
|
|
595
|
+
"Model for the compress-cues task that compresses each memory into a mural cue. The mural image itself is rendered deterministically (no author model).",
|
|
596
|
+
),
|
|
597
|
+
})
|
|
598
|
+
.default({ enabled: false })
|
|
599
|
+
.describe(
|
|
600
|
+
"Experimental mural: a single deterministically-rendered image of project memories that did not fit the context budget. Cues are compressed per-memory by the compress-cues dreamer task.",
|
|
601
|
+
),
|
|
602
|
+
})
|
|
603
|
+
.default({ mural: { enabled: false } })
|
|
604
|
+
.describe(
|
|
605
|
+
"Experimental feature switches. User and project configuration are both accepted.",
|
|
606
|
+
),
|
|
607
|
+
transform_mode: z
|
|
608
|
+
.enum(["ts", "rust"])
|
|
609
|
+
.default("ts")
|
|
610
|
+
.describe(
|
|
611
|
+
'Experimental: routes the entire Magic Context runtime for the project through the ck-mc Rust module over subc (requires user-level `subc` config); "ts" is the current TypeScript pipeline.',
|
|
612
|
+
),
|
|
613
|
+
auto_update: z
|
|
614
|
+
.boolean()
|
|
615
|
+
.optional()
|
|
616
|
+
.describe(
|
|
617
|
+
"Enable automatic npm self-update checks for the OpenCode plugin. Security: USER-only in config loader, so hostile project configs cannot suppress updates.",
|
|
618
|
+
),
|
|
619
|
+
language: z
|
|
620
|
+
.string()
|
|
621
|
+
.trim()
|
|
622
|
+
.toLowerCase()
|
|
623
|
+
.refine(
|
|
624
|
+
(s) => isValidLanguageCode(s),
|
|
625
|
+
'language must be a 2-letter ISO 639-1 code (e.g. "tr", "es", "de")',
|
|
626
|
+
)
|
|
627
|
+
.optional()
|
|
628
|
+
.describe(
|
|
629
|
+
"Output language for Magic Context's generated content and guidance, as a " +
|
|
630
|
+
'2-letter ISO 639-1 code (e.g. "tr", "es", "de", "ja", "pt"). When set, the ' +
|
|
631
|
+
"historian, dreamer, sidekick, and the agent-guidance block instruct the model to " +
|
|
632
|
+
"write its PROSE in this language while keeping all structural tokens (XML tags, " +
|
|
633
|
+
"the five memory category names, code identifiers, file paths) in English. " +
|
|
634
|
+
"USER-LEVEL ONLY (ignored in project config for security). Unset = today's " +
|
|
635
|
+
"behavior (model mirrors the conversation; English scaffolding). Changing it " +
|
|
636
|
+
"triggers one cache re-materialization; existing compartments/memories keep their " +
|
|
637
|
+
"original language until naturally rewritten.",
|
|
638
|
+
),
|
|
639
|
+
historian: HistorianConfigSchema.describe(
|
|
640
|
+
"Historian agent configuration (model, fallback_models, variant, temperature, maxTokens, permission, two_pass, etc.)",
|
|
641
|
+
),
|
|
642
|
+
dreamer: DreamerConfigSchema.optional().describe(
|
|
643
|
+
"Dreamer agent + scheduling configuration (model, fallback_models, disable, schedule, tasks, etc.)",
|
|
644
|
+
),
|
|
645
|
+
cache_ttl: z
|
|
646
|
+
.union([z.string(), z.object({ default: z.string() }).catchall(z.string())])
|
|
647
|
+
.default("5m")
|
|
648
|
+
.describe(
|
|
649
|
+
'Cache TTL: string (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "model-id": "10m" }). Set to "never" for lanes kept warm by an external keepwarm proxy — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time.',
|
|
650
|
+
),
|
|
651
|
+
output_reserve: z
|
|
652
|
+
.union([
|
|
653
|
+
z.number().min(0),
|
|
654
|
+
z.object({ default: z.number().min(0) }).catchall(z.number().min(0)),
|
|
655
|
+
])
|
|
656
|
+
.optional()
|
|
657
|
+
.describe(
|
|
658
|
+
'User-only output-token reservation override. Number or per-model object ({ default: 16384, "provider/model": 8192 }); 0 disables reservation. When unset, Magic Context reserves the catalog output limit (capped at 25% of context) for shared-window providers and keeps proven separate-quota Google/Gemini windows unchanged.',
|
|
659
|
+
),
|
|
660
|
+
toast_duration_ms: z
|
|
661
|
+
.number()
|
|
662
|
+
.min(0)
|
|
663
|
+
.max(60_000)
|
|
664
|
+
.default(5_000)
|
|
665
|
+
.describe(
|
|
666
|
+
"TUI toast lifetime in milliseconds for Magic Context notifications. Set to 0 to disable Magic Context toasts entirely (min: 0, max: 60000, default: 5000)",
|
|
667
|
+
),
|
|
668
|
+
execute_threshold_percentage: z
|
|
669
|
+
.union([
|
|
670
|
+
z.number().min(20).max(90, EXECUTE_THRESHOLD_CAP_MESSAGE),
|
|
671
|
+
z
|
|
672
|
+
.object({ default: z.number().min(20).max(90, EXECUTE_THRESHOLD_CAP_MESSAGE) })
|
|
673
|
+
.catchall(z.number().min(20).max(90, EXECUTE_THRESHOLD_CAP_MESSAGE)),
|
|
674
|
+
])
|
|
675
|
+
.default(DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE)
|
|
676
|
+
.describe(
|
|
677
|
+
'Context percentage that forces queued operations to execute. Number or per-model object ({ default: 65, "provider/model": 45 }). Values above 90 are rejected because the runtime caps at 90% of the output-reserved safe window (MAX_EXECUTE_THRESHOLD). Default: DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE',
|
|
678
|
+
),
|
|
679
|
+
execute_threshold_tokens: z
|
|
680
|
+
.object({
|
|
681
|
+
default: z.number().min(5_000).max(2_000_000).optional(),
|
|
682
|
+
})
|
|
683
|
+
.catchall(z.number().min(5_000).max(2_000_000))
|
|
684
|
+
.optional()
|
|
685
|
+
.describe(
|
|
686
|
+
"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 90% × context_limit are clamped with a warning log. Min 5_000, max 2_000_000.",
|
|
687
|
+
),
|
|
688
|
+
protected_tags: z
|
|
689
|
+
.number()
|
|
690
|
+
.min(1)
|
|
691
|
+
.max(100)
|
|
692
|
+
.optional()
|
|
693
|
+
.describe(
|
|
694
|
+
"Number of recent tags to protect from dropping (min: 1, max: 100, default: 20)",
|
|
695
|
+
),
|
|
696
|
+
clear_reasoning_age: z
|
|
697
|
+
.number()
|
|
698
|
+
.min(10)
|
|
699
|
+
.default(50)
|
|
700
|
+
.describe("Clear reasoning/thinking blocks older than N tags (default: 50)"),
|
|
701
|
+
history_budget_percentage: z
|
|
702
|
+
.number()
|
|
703
|
+
.min(0.05)
|
|
704
|
+
.max(0.5)
|
|
705
|
+
.default(DEFAULT_HISTORY_BUDGET_PERCENTAGE)
|
|
706
|
+
.describe(
|
|
707
|
+
"Fraction of usable context (context_limit × execute_threshold) reserved for the session history block (default: 0.15)",
|
|
708
|
+
),
|
|
709
|
+
historian_timeout_ms: z
|
|
710
|
+
.number()
|
|
711
|
+
.min(60_000)
|
|
712
|
+
.default(DEFAULT_HISTORIAN_TIMEOUT_MS)
|
|
713
|
+
.describe("Timeout for each historian prompt call in milliseconds (default: 300000)"),
|
|
714
|
+
commit_cluster_trigger: z
|
|
715
|
+
.object({
|
|
716
|
+
enabled: z
|
|
717
|
+
.boolean()
|
|
718
|
+
.default(true)
|
|
719
|
+
.describe("Enable commit-cluster based historian triggering (default: true)"),
|
|
720
|
+
min_clusters: z
|
|
721
|
+
.number()
|
|
722
|
+
.min(1)
|
|
723
|
+
.default(3)
|
|
724
|
+
.describe(
|
|
725
|
+
"Minimum commit clusters required to trigger historian (min: 1, default: 3)",
|
|
726
|
+
),
|
|
727
|
+
})
|
|
728
|
+
.default({ enabled: true, min_clusters: 3 })
|
|
729
|
+
.describe(
|
|
730
|
+
"Commit-cluster trigger: fire historian when enough commit clusters accumulate in the unsummarized tail",
|
|
731
|
+
),
|
|
732
|
+
system_prompt_injection: z
|
|
733
|
+
.object({
|
|
734
|
+
enabled: z
|
|
735
|
+
.boolean()
|
|
736
|
+
.default(true)
|
|
737
|
+
.describe(
|
|
738
|
+
"When false, NO injection happens for ANY agent — global escape hatch. (default: true)",
|
|
739
|
+
),
|
|
740
|
+
skip_signatures: z
|
|
741
|
+
.array(z.string())
|
|
742
|
+
.default(["<!-- magic-context: skip -->"])
|
|
743
|
+
.describe(
|
|
744
|
+
"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.",
|
|
745
|
+
),
|
|
746
|
+
})
|
|
747
|
+
.default({
|
|
748
|
+
enabled: true,
|
|
749
|
+
skip_signatures: ["<!-- magic-context: skip -->"],
|
|
750
|
+
})
|
|
751
|
+
.describe(
|
|
752
|
+
"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 blocks. OpenCode's internal hidden agents — title, summary, and compaction — are always skipped automatically.",
|
|
753
|
+
),
|
|
754
|
+
// v2: the LLM compressor was removed — deterministic decay-tier rendering
|
|
755
|
+
// (decay-render.ts) replaces it, so there are no compressor knobs. A
|
|
756
|
+
// leftover `compressor` block in an existing config is silently ignored
|
|
757
|
+
// (the schema strips unknown keys).
|
|
758
|
+
sqlite: z
|
|
759
|
+
.object({
|
|
760
|
+
cache_size_mb: z
|
|
761
|
+
.number()
|
|
762
|
+
.min(2)
|
|
763
|
+
.max(2048)
|
|
764
|
+
.default(64)
|
|
765
|
+
.describe(
|
|
766
|
+
"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)",
|
|
767
|
+
),
|
|
768
|
+
mmap_size_mb: z
|
|
769
|
+
.number()
|
|
770
|
+
.min(0)
|
|
771
|
+
.max(8192)
|
|
772
|
+
.default(0)
|
|
773
|
+
.describe(
|
|
774
|
+
"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)",
|
|
775
|
+
),
|
|
776
|
+
})
|
|
777
|
+
.default({ cache_size_mb: 64, mmap_size_mb: 0 })
|
|
778
|
+
.describe(
|
|
779
|
+
"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.",
|
|
780
|
+
),
|
|
781
|
+
storage: z
|
|
782
|
+
.object({
|
|
783
|
+
enforce_private_permissions: z
|
|
784
|
+
.boolean()
|
|
785
|
+
.default(true)
|
|
786
|
+
.describe(
|
|
787
|
+
"When true (default), Magic Context creates and re-tightens its storage directories to owner-only 0700 and storage files to owner-only 0600. Set false only for a deliberate trusted-group deployment whose operator manages directory, database, WAL/SHM, cache, and RPC file permissions externally; Magic Context then never chmods or supplies restrictive creation modes. USER-LEVEL ONLY — ignored in project config for security. On Windows, POSIX chmod modes are already meaningless, so this setting is a no-op.",
|
|
788
|
+
),
|
|
789
|
+
})
|
|
790
|
+
.default({ enforce_private_permissions: true })
|
|
791
|
+
.describe(
|
|
792
|
+
"Storage permission policy. The default keeps session content and memories owner-private. Disabling enforcement is for trusted shared-group storage managed externally; every group member able to read the storage can read all stored session content and memories.",
|
|
793
|
+
),
|
|
794
|
+
embedding: EmbeddingConfigSchema.default({
|
|
795
|
+
provider: "local",
|
|
796
|
+
model: DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
797
|
+
}).describe("Embedding provider configuration"),
|
|
798
|
+
subc: z
|
|
799
|
+
.object({
|
|
800
|
+
connection_file: z
|
|
801
|
+
.string()
|
|
802
|
+
.trim()
|
|
803
|
+
.min(1)
|
|
804
|
+
.transform(expandConfigPath)
|
|
805
|
+
.describe("Path to the owner-only subc connection file."),
|
|
806
|
+
})
|
|
807
|
+
.optional()
|
|
808
|
+
.describe("User-only Synapse daemon connection settings."),
|
|
809
|
+
shadow_embedding: z
|
|
810
|
+
.object({
|
|
811
|
+
enabled: z
|
|
812
|
+
.boolean()
|
|
813
|
+
.default(false)
|
|
814
|
+
.describe("Developer-only Synapse shadow embedding lane switch."),
|
|
815
|
+
})
|
|
816
|
+
.default({ enabled: false })
|
|
817
|
+
.describe("Developer-only Synapse shadow embedding lane."),
|
|
818
|
+
temporal_awareness: z
|
|
819
|
+
.boolean()
|
|
820
|
+
.default(true)
|
|
821
|
+
.describe(
|
|
822
|
+
'Inject wall-clock gap markers (<!-- +Xm -->) between user messages where > 5 min elapsed since the previous message, and add compact date ranges to compartment headings. 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).',
|
|
823
|
+
),
|
|
824
|
+
keep_subagents: z
|
|
825
|
+
.boolean()
|
|
826
|
+
.default(false)
|
|
827
|
+
.describe(
|
|
828
|
+
"Debug: keep the child sessions Magic Context spawns for its own subagents (historian, dreamer, sidekick, memory-migration) instead of deleting them on success. Useful for short-term inspection/data collection — their full transcript (prompt, tool calls, token usage, output) stays in the host session store. Kept sessions accumulate until manually cleared; leave false for normal use. Requires a restart to take effect.",
|
|
829
|
+
),
|
|
830
|
+
fail_closed_blocking: z
|
|
831
|
+
.boolean()
|
|
832
|
+
.default(true)
|
|
833
|
+
.describe(
|
|
834
|
+
"When Magic Context cannot operate (schema fence mismatch, storage open/migration failure), block the primary-session prompt with a loud recovery error instead of silently degrading to native compaction. Default true. Set false only to restore the old degrade-silently behavior (not recommended). USER-LEVEL ONLY — ignored in project config for security. Requires a restart.",
|
|
835
|
+
),
|
|
836
|
+
compaction: z
|
|
837
|
+
.object({
|
|
838
|
+
enabled: z
|
|
839
|
+
.boolean()
|
|
840
|
+
.default(true)
|
|
841
|
+
.describe(
|
|
842
|
+
"When false, Magic Context stops managing the context window and keeps its knowledge layer: memory and docs/user-profile/key-files injection through additive m[0]/m[1], raw-message FTS indexing, dreamer, notes, ctx_search, ctx_expand, ctx_memory, and /ctx-embed remain available. MC's historian/compartment preparation, tagging, markers, pruning, folding, drops, strips, splicing, synthetic context-management todos, temporal markers, nudges, and fail-closed blocking stop; ctx_expand remains a knowledge-surface tool. fail_closed_blocking is inert: a transform failure passes the input messages through without blocking or cancelling. This setting does not enable native compaction: OpenCode's compaction.auto / compaction.prune or Pi's equivalent owns the window, or nothing does. MC's compaction.enabled in magic-context.jsonc is distinct from OpenCode's compaction.auto / compaction.prune in opencode.jsonc; they are different files and different owners. On the first turn after disabling, a long session may trigger one native compaction cycle; MC removes only its own marker boundary, leaves native boundaries and stored compartments intact, and does no pre-trimming mitigation. Marker cleanup is lazy per session, so an unresumed session is cleaned when it is next resumed. If compaction is enabled again, run /ctx-wrapup when the historian is runnable to catch up. OpenCode peer verification against v1.18.4 confirms native compaction covers child sessions: subagents receive additive memory/docs injection and no MC reclaim in this mode, so keep subagent tasks small or leave compaction.enabled on for long subagent runs. If transform_mode is rust, compaction-off resolves to the TypeScript transform and emits one frozen boot warning because there is no Rust reduced-mode contract. This is boot-resolved and requires a process restart; project-tier compaction.enabled is stripped so a cloned repository cannot disable the user's setting. The sidebar reports raw usage as Context: <pct>% · native compaction or Context: <pct>% · no active compaction and does not show an MC execute-threshold fill. /ctx-wrapup, /ctx-recomp, /ctx-flush, and /ctx-session-upgrade refuse without context-management side effects; /ctx-embed remains functional. Raw content hidden by a native boundary before Magic Context's first pass is not retroactively indexed.",
|
|
843
|
+
),
|
|
844
|
+
})
|
|
845
|
+
.default({ enabled: true })
|
|
846
|
+
.describe(
|
|
847
|
+
"Compaction-off mode gate. Default true (MC manages the context window as today). Set compaction.enabled=false to keep the knowledge layer while letting native compaction (or nothing) own the window. Boot-resolved; requires a restart to change.",
|
|
848
|
+
),
|
|
849
|
+
todowrite: z
|
|
850
|
+
.object({
|
|
851
|
+
enabled: z
|
|
852
|
+
.boolean()
|
|
853
|
+
.default(true)
|
|
854
|
+
.describe(
|
|
855
|
+
"Pi only: register Magic Context's todowrite task-list tool. Disable if you use your own todo extension. OpenCode ships its own built-in todowrite; this setting has no effect there.",
|
|
856
|
+
),
|
|
857
|
+
overlay: z
|
|
858
|
+
.boolean()
|
|
859
|
+
.default(true)
|
|
860
|
+
.describe(
|
|
861
|
+
"Pi only: show the persistent todo overlay above the editor while tasks are active.",
|
|
862
|
+
),
|
|
863
|
+
})
|
|
864
|
+
.default({ enabled: true, overlay: true })
|
|
865
|
+
.describe(
|
|
866
|
+
"Pi-only todowrite tool and overlay controls. Pi registers tools and widgets at extension boot, so changing this after /cd requires /reload or restart.",
|
|
867
|
+
),
|
|
868
|
+
pi: PiConfigSchema.describe(
|
|
869
|
+
"Pi-only child-process extension controls. This setting is user-level only; project configuration cannot choose which extensions a user's subagent children load.",
|
|
870
|
+
),
|
|
871
|
+
smart_drops: z
|
|
872
|
+
.boolean()
|
|
873
|
+
.default(false)
|
|
874
|
+
.describe(
|
|
875
|
+
"Content-aware reclaim of provably-superseded tool output, layered on the existing execute-pass auto-drop. When on: superseded todowrite (keep newest 1), spent ctx_reduce (keep newest 5), and zero-value meta (bash_status, bash_kill, ctx_note read/dismiss) outputs are dropped; older edits to a file are compressed to a filePath-preserving marker while the newest edit per file stays full. Only acts on passes already busting the cache, so it never originates a cache bust. Honors the protected-tag reserve. Experimental: opt-in, default off until cache stability is proven; when off the wire is byte-identical to the positional-only reclaim. Requires a restart.",
|
|
876
|
+
),
|
|
877
|
+
caveman_text_compression: z
|
|
878
|
+
.object({
|
|
879
|
+
enabled: z
|
|
880
|
+
.boolean()
|
|
881
|
+
.default(false)
|
|
882
|
+
.describe(
|
|
883
|
+
"Apply deterministic caveman-style text compression to old conversation text. Active for primary sessions when enabled; never for subagents. Compresses user/assistant text in oldest-first tiers: ultra (oldest 20%), full, lite, untouched (newest 40%).",
|
|
884
|
+
),
|
|
885
|
+
min_chars: z
|
|
886
|
+
.number()
|
|
887
|
+
.min(100)
|
|
888
|
+
.max(10000)
|
|
889
|
+
.default(500)
|
|
890
|
+
.describe(
|
|
891
|
+
"Text parts shorter than this (characters) stay untouched. Min 100, max 10000. Default: 500.",
|
|
892
|
+
),
|
|
893
|
+
})
|
|
894
|
+
.default({ enabled: false, min_chars: 500 })
|
|
895
|
+
.describe(
|
|
896
|
+
"Age-tier caveman compression for long user/assistant text parts. Active for primary sessions when enabled; never for subagents. 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).",
|
|
897
|
+
),
|
|
898
|
+
memory: z
|
|
899
|
+
.object({
|
|
900
|
+
enabled: z
|
|
901
|
+
.boolean()
|
|
902
|
+
.default(true)
|
|
903
|
+
.describe("Enable cross-session memory (default: true)"),
|
|
904
|
+
injection_budget_tokens: z
|
|
905
|
+
.number()
|
|
906
|
+
.min(500)
|
|
907
|
+
.max(20000)
|
|
908
|
+
.default(4000)
|
|
909
|
+
.describe(
|
|
910
|
+
"Token budget for memory injection on session start (min: 500, max: 20000, default: 4000)",
|
|
911
|
+
),
|
|
912
|
+
auto_promote: z
|
|
913
|
+
.boolean()
|
|
914
|
+
.default(true)
|
|
915
|
+
.describe(
|
|
916
|
+
"Automatically promote eligible session facts into memory (default: true)",
|
|
917
|
+
),
|
|
918
|
+
retrieval_count_promotion_threshold: z
|
|
919
|
+
.number()
|
|
920
|
+
.min(1)
|
|
921
|
+
.default(3)
|
|
922
|
+
.describe(
|
|
923
|
+
"retrieval_count threshold for promoting memory to permanent status (min: 1, default: 3)",
|
|
924
|
+
),
|
|
925
|
+
auto_search: z
|
|
926
|
+
.object({
|
|
927
|
+
enabled: z
|
|
928
|
+
.boolean()
|
|
929
|
+
.default(true)
|
|
930
|
+
.describe(
|
|
931
|
+
"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.",
|
|
932
|
+
),
|
|
933
|
+
score_threshold: z
|
|
934
|
+
.number()
|
|
935
|
+
.min(0.3)
|
|
936
|
+
.max(0.95)
|
|
937
|
+
.default(0.6)
|
|
938
|
+
.describe(
|
|
939
|
+
"Top hit score must exceed this threshold for the hint to fire (min: 0.3, max: 0.95, default: 0.60)",
|
|
940
|
+
),
|
|
941
|
+
min_prompt_chars: z
|
|
942
|
+
.number()
|
|
943
|
+
.min(5)
|
|
944
|
+
.max(500)
|
|
945
|
+
.default(20)
|
|
946
|
+
.describe(
|
|
947
|
+
"Skip hint when user message is shorter than this (min: 5, max: 500, default: 20)",
|
|
948
|
+
),
|
|
949
|
+
})
|
|
950
|
+
.default({ enabled: true, score_threshold: 0.6, min_prompt_chars: 20 })
|
|
951
|
+
.describe(
|
|
952
|
+
"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.",
|
|
953
|
+
),
|
|
954
|
+
git_commit_indexing: z
|
|
955
|
+
.object({
|
|
956
|
+
enabled: z
|
|
957
|
+
.boolean()
|
|
958
|
+
.default(false)
|
|
959
|
+
.describe(
|
|
960
|
+
"Index HEAD git commits for ctx_search (git_commit source). Graduated from experimental.git_commit_indexing; opt-in, default off. Independent of memory.enabled.",
|
|
961
|
+
),
|
|
962
|
+
since_days: z
|
|
963
|
+
.number()
|
|
964
|
+
.min(7)
|
|
965
|
+
.max(3650)
|
|
966
|
+
.default(365)
|
|
967
|
+
.describe(
|
|
968
|
+
"Days of HEAD history to index (min: 7, max: 3650, default: 365)",
|
|
969
|
+
),
|
|
970
|
+
max_commits: z
|
|
971
|
+
.number()
|
|
972
|
+
.min(100)
|
|
973
|
+
.max(20000)
|
|
974
|
+
.default(2000)
|
|
975
|
+
.describe(
|
|
976
|
+
"Max commits kept per project; oldest evicted (min: 100, max: 20000, default: 2000)",
|
|
977
|
+
),
|
|
978
|
+
})
|
|
979
|
+
.default({ enabled: false, since_days: 365, max_commits: 2000 })
|
|
980
|
+
.describe(
|
|
981
|
+
"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.",
|
|
982
|
+
),
|
|
983
|
+
})
|
|
984
|
+
.default({
|
|
985
|
+
enabled: true,
|
|
986
|
+
injection_budget_tokens: 4000,
|
|
987
|
+
auto_promote: true,
|
|
988
|
+
retrieval_count_promotion_threshold: 3,
|
|
989
|
+
auto_search: { enabled: true, score_threshold: 0.6, min_prompt_chars: 20 },
|
|
990
|
+
git_commit_indexing: { enabled: false, since_days: 365, max_commits: 2000 },
|
|
991
|
+
})
|
|
992
|
+
.describe("Cross-session memory configuration"),
|
|
993
|
+
sidekick: SidekickConfigSchema.describe(
|
|
994
|
+
"Optional sidekick agent configuration for session-start memory retrieval",
|
|
995
|
+
),
|
|
996
|
+
})
|
|
997
|
+
.transform((data): MagicContextConfig => {
|
|
998
|
+
return {
|
|
999
|
+
...data,
|
|
1000
|
+
protected_tags: data.protected_tags ?? DEFAULT_PROTECTED_TAGS,
|
|
1001
|
+
};
|
|
1002
|
+
});
|