Short description
On OMP, dreamer.pi / historian.pi models are ignored and tasks silently run on OMP's default model
What happened?
On OMP, if the config only has pi blocks (the plugin falls back from omp to pi), dreamer tasks and the historian run on OMP's default model instead of the configured one. There's no warning, and doctor reports everything PASS.
Config (trimmed):
Expected: /ctx-dream curate runs on gpt-6-luna.
Actual: it runs on claude-opus-5-5, which is my OMP modelRoles.default. dream_runs reports the task as completed, so nothing looks wrong unless you check provider usage. From my provider's request log, two manual curate runs (main session requests filtered out; input = uncached + cache write + cache read):
time model input output
15:11:40 claude-opus-5-5 8529 577
15:16:21 claude-opus-5-5 8889 1192
15:16:27 claude-opus-5-5 10189 498
After renaming pi to omp in both places (nothing else changed), the same command:
time model input output
15:21:50 gpt-6-luna 4392 643
15:21:55 gpt-6-luna 5079 148
I think this is the cause:
sampleLiveConfig (packages/plugin/src/config/live-run-config.ts) walks every path in LIVE_RELOAD_CONFIG_PATHS, and for each parent segment it does target[part] = copy, creating {} when the parent doesn't exist. Since the list includes dreamer.omp.model, dreamer.omp.tasks, historian.omp.model etc., the sampled config always ends up with dreamer.omp = { model: undefined, tasks: undefined, ... } even when the user never wrote an omp block.
Then resolveHarnessBlock does
harness === "omp" ? container?.omp ?? container?.pi : container?.[harness]
and the empty object wins over pi, so no model is resolved and the child falls back to the host default.
I checked it by running the bundled functions against my config: with pi blocks, after sampleLiveConfig both curate's and the historian's model come back undefined; with omp blocks they resolve to luna / sonnet. So the historian is probably affected too. I only confirmed curate end to end through request logs. The code is unchanged on master as of today.
Possible fixes, either one would do:
- in
sampleLiveConfig, skip a path when the fresh value is undefined instead of creating the parent chain, or
- in
resolveHarnessBlock, only take omp when it actually has keys.
Workaround: use "omp" instead of "pi" for the historian / dreamer blocks.
Repro: put only pi blocks with a non-default model in the config, run /ctx-dream curate in OMP, and check which model the provider actually receives.
Diagnostics
Output of `npx @cortexkit/magic-context@0.46.1 doctor --issue --harness omp --report <file>` (taken after switching to the `omp` workaround; it was all PASS before as well):
- Magic Context CLI: 0.46.1
- PASS: OMP 18.8.6 detected at ~/.bun/bin/omp
- PASS: @cortexkit/pi-magic-context 0.46.1 is enabled
- PASS: Plugin exposes an OMP/Pi extension manifest
- PASS: OMP native compaction is disabled
- PASS: OMP automatic memory backend is disabled
- PASS: OMP agent directory resolved to ~/.omp/agent
- PASS: Magic Context config parses: ~/.config/cortexkit/magic-context.jsonc
- PASS: Magic Context runtime config loads successfully
- INFO: Shared storage: ~/.local/share/cortexkit/magic-context (source: platform default)
- PASS: SQLite integrity_check: ok
- PASS: Background maintenance completed its last pass
Plugin version
0.46.1
OpenCode version
N/A (Oh My Pi 18.8.6)
Platform
macOS arm64
Client
Pi
Log output (optional)
Short description
On OMP,
dreamer.pi/historian.pimodels are ignored and tasks silently run on OMP's default modelWhat happened?
On OMP, if the config only has
piblocks (the plugin falls back fromomptopi), dreamer tasks and the historian run on OMP's default model instead of the configured one. There's no warning, anddoctorreports everything PASS.Config (trimmed):
{ "historian": { "pi": { "model": "claude-sonnet-5-5" } }, "dreamer": { "pi": { "model": "claude-sonnet-5-5", "tasks": { "curate": { "model": "gpt-6-luna" } } } } }Expected:
/ctx-dream curateruns ongpt-6-luna.Actual: it runs on
claude-opus-5-5, which is my OMPmodelRoles.default.dream_runsreports the task as completed, so nothing looks wrong unless you check provider usage. From my provider's request log, two manual curate runs (main session requests filtered out; input = uncached + cache write + cache read):After renaming
pitoompin both places (nothing else changed), the same command:I think this is the cause:
sampleLiveConfig(packages/plugin/src/config/live-run-config.ts) walks every path inLIVE_RELOAD_CONFIG_PATHS, and for each parent segment it doestarget[part] = copy, creating{}when the parent doesn't exist. Since the list includesdreamer.omp.model,dreamer.omp.tasks,historian.omp.modeletc., the sampled config always ends up withdreamer.omp = { model: undefined, tasks: undefined, ... }even when the user never wrote anompblock.Then
resolveHarnessBlockdoesand the empty object wins over
pi, so no model is resolved and the child falls back to the host default.I checked it by running the bundled functions against my config: with
piblocks, aftersampleLiveConfigboth curate's and the historian's model come backundefined; withompblocks they resolve to luna / sonnet. So the historian is probably affected too. I only confirmed curate end to end through request logs. The code is unchanged on master as of today.Possible fixes, either one would do:
sampleLiveConfig, skip a path when the fresh value isundefinedinstead of creating the parent chain, orresolveHarnessBlock, only takeompwhen it actually has keys.Workaround: use
"omp"instead of"pi"for thehistorian/dreamerblocks.Repro: put only
piblocks with a non-default model in the config, run/ctx-dream curatein OMP, and check which model the provider actually receives.Diagnostics
Plugin version
0.46.1
OpenCode version
N/A (Oh My Pi 18.8.6)
Platform
macOS arm64
Client
Pi
Log output (optional)