Skip to content

Commit 4e79d8f

Browse files
feat: toast_duration_ms = 0 disables toasts; README config links
Follow-up to the cherry-picked PR #92 (toast_duration_ms, by Csaba Kertesz): - toast_duration_ms now accepts 0 = disable Magic Context toasts entirely (schema min 1000 → 0). showToast() skips when the effective duration is non-positive, so a config of 0 suppresses routine toasts while explicit positive per-call overrides (e.g. restart-required) still show. Both TUI toast routes (direct + server-pushed drain) funnel through showToast, so the one gate covers both. Regenerated assets/magic-context.schema.json + the docs config reference; updated CONFIGURATION.md. - Replaced PR #92's module-level `mock.module("../../hooks/magic-context")` in create-session-hooks.test.ts — Bun's mock.module is process-global and mock.restore() does not undo it, so it leaked into hook.test.ts and failed 12 of its hook-shape assertions in the full suite (the file passed alone). Fixed by extracting the pure buildMagicContextHookConfig() mapping and testing that directly — no mock, no leak (also a cleaner unit, portable to the future Rust MC module). +1 toast=0 passthrough test. - README: added Docs (docs.cortexkit.io/magic-context) and Configuration links to the nav row, and pointed the Configuration section at both CONFIGURATION.md and the docs-site configuration reference. Gate: plugin 2240/0, schema/config-parity green, dashboard config-parity 10/0. Co-authored-by: Alfonso [Magic Context] <288211368+alfonso-magic-context@users.noreply.github.com>
1 parent 2981b81 commit 4e79d8f

8 files changed

Lines changed: 78 additions & 65 deletions

File tree

CONFIGURATION.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ Higher-tier models with longer cache windows benefit from a longer TTL. Setting
113113
| `ctx_reduce_enabled` | `boolean` | `true` | When `false`, hides `ctx_reduce` tool, disables all nudges/reminders, and strips reduction guidance from prompts. Heuristic cleanup, compartments, memory, and search still work. Useful for testing whether automatic cleanup alone is sufficient. |
114114
| `cache_ttl` | `string` or `object` | `"5m"` | Time after a response before applying pending ops. String or per-model map. |
115115
| `protected_tags` | `number` (1–100) | `20` | Last N active tags immune from immediate dropping. |
116-
| `toast_duration_ms` | `number` (1000–60000) | `5000` | TUI toast lifetime for Magic Context notifications in milliseconds. Increase this if toasts disappear too quickly. |
116+
| `toast_duration_ms` | `number` (0–60000) | `5000` | TUI toast lifetime for Magic Context notifications in milliseconds. Increase this if toasts disappear too quickly, or set to `0` to disable Magic Context toasts entirely. |
117117
| `execute_threshold_percentage` | `number` (20–80) or `object` | `65` | Context usage that forces queued ops to execute. Capped at 80% max for cache safety. Supports per-model map. |
118118
| `execute_threshold_tokens` | `object` (per-model map) || **Optional absolute-tokens variant of `execute_threshold_percentage`.** Per-model map (e.g. `{ "default": 150000, "github-copilot/gpt-5.2-codex": 40000 }`). When set for a model, overrides the percentage-based threshold for that model. Clamped to `80% × context_limit` with a warn log. Requires a resolvable context limit — falls through to percentage if unavailable. See below. |
119119
| `clear_reasoning_age` | `number` | `50` | Clear thinking/reasoning blocks older than N tags. |

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
<a href="#-capture">Capture</a> ·
2727
<a href="#-consolidate">Consolidate</a> ·
2828
<a href="#-recall">Recall</a> ·
29+
<a href="https://docs.cortexkit.io/magic-context">Docs</a> ·
30+
<a href="./CONFIGURATION.md">Configuration</a> ·
2931
<a href="https://discord.gg/DSa65w8wuf">💬 Discord</a>
3032
</p>
3133

@@ -239,7 +241,7 @@ It reads directly from Magic Context's SQLite database. No extra server, no API.
239241

240242
## Configuration
241243

242-
Settings live in `magic-context.jsonc`. Everything has sensible defaults; project config merges on top of user-wide settings. See **[CONFIGURATION.md](./CONFIGURATION.md)** for the full reference: cache TTL tuning, per-model execute thresholds, historian and dreamer model selection, embedding providers, and memory settings.
244+
Settings live in `magic-context.jsonc`. Everything has sensible defaults; project config merges on top of user-wide settings. For the full referencecache TTL tuning, per-model execute thresholds, historian and dreamer model selection, embedding providers, and memory settings — see **[CONFIGURATION.md](./CONFIGURATION.md)** or the **[configuration reference on docs.cortexkit.io](https://docs.cortexkit.io/magic-context/reference/configuration/)**.
243245

244246
**Config locations** (merged in order, project overrides user):
245247
1. `<project-root>/magic-context.jsonc`

assets/magic-context.schema.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,9 +478,9 @@
478478
},
479479
"toast_duration_ms": {
480480
"default": 5000,
481-
"description": "TUI toast lifetime in milliseconds for Magic Context notifications (min: 1000, max: 60000, default: 5000)",
481+
"description": "TUI toast lifetime in milliseconds for Magic Context notifications. Set to 0 to disable Magic Context toasts entirely (min: 0, max: 60000, default: 5000)",
482482
"type": "number",
483-
"minimum": 1000,
483+
"minimum": 0,
484484
"maximum": 60000
485485
},
486486
"execute_threshold_percentage": {

packages/docs/src/content/docs/reference/configuration.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,9 @@ Behavior tuning most installs never need to touch.
192192
| `sqlite` | object || 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. |
193193
| `sqlite.cache_size_mb` | number (2–2048) | `64` | 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) |
194194
| `sqlite.mmap_size_mb` | number (0–8192) | `0` | 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) |
195+
196+
## Other
197+
198+
| Key | Type | Default | Description |
199+
|---|---|---|---|
200+
| `toast_duration_ms` | number (0–60000) | `5000` | TUI toast lifetime in milliseconds for Magic Context notifications. Set to 0 to disable Magic Context toasts entirely (min: 0, max: 60000, default: 5000) |

packages/plugin/src/config/schema/magic-context.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,11 +392,11 @@ export const MagicContextConfigSchema = z
392392
),
393393
toast_duration_ms: z
394394
.number()
395-
.min(1_000)
395+
.min(0)
396396
.max(60_000)
397397
.default(5_000)
398398
.describe(
399-
"TUI toast lifetime in milliseconds for Magic Context notifications (min: 1000, max: 60000, default: 5000)",
399+
"TUI toast lifetime in milliseconds for Magic Context notifications. Set to 0 to disable Magic Context toasts entirely (min: 0, max: 60000, default: 5000)",
400400
),
401401
execute_threshold_percentage: z
402402
.union([
Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,32 @@
11
/// <reference types="bun-types" />
22

3-
import { beforeEach, describe, expect, it, mock } from "bun:test";
3+
import { describe, expect, it } from "bun:test";
4+
import { buildMagicContextHookConfig } from "./create-session-hooks";
45

5-
const createMagicContextHookMock = mock(() => ({ mocked: true }));
6+
describe("buildMagicContextHookConfig", () => {
7+
it("threads toast_duration_ms into the per-session hook config", () => {
8+
const config = buildMagicContextHookConfig({
9+
enabled: true,
10+
protected_tags: 10,
11+
cache_ttl: "5m",
12+
toast_duration_ms: 30_000,
13+
} as never);
614

7-
mock.module("../../hooks/magic-context", () => ({
8-
createMagicContextHook: createMagicContextHookMock,
9-
}));
10-
11-
describe("createSessionHooks", () => {
12-
beforeEach(() => {
13-
createMagicContextHookMock.mockClear();
15+
expect(config.toast_duration_ms).toBe(30_000);
1416
});
1517

16-
it("threads notification config into the magic-context hook", async () => {
17-
const { createSessionHooks } = await import("./create-session-hooks");
18+
it("passes toast_duration_ms = 0 through unchanged (disables toasts)", () => {
19+
const config = buildMagicContextHookConfig({
20+
enabled: true,
21+
toast_duration_ms: 0,
22+
} as never);
23+
24+
expect(config.toast_duration_ms).toBe(0);
25+
});
1826

19-
createSessionHooks({
20-
ctx: {
21-
client: {},
22-
directory: "/tmp/project",
23-
} as never,
24-
liveSessionState: {
25-
liveModelBySession: new Map(),
26-
variantBySession: new Map(),
27-
agentBySession: new Map(),
28-
},
29-
pluginConfig: {
30-
enabled: true,
31-
protected_tags: 10,
32-
cache_ttl: "5m",
33-
toast_duration_ms: 30_000,
34-
} as never,
35-
});
27+
it("leaves toast_duration_ms undefined when unset (consumer applies default)", () => {
28+
const config = buildMagicContextHookConfig({ enabled: true } as never);
3629

37-
expect(createMagicContextHookMock).toHaveBeenCalledTimes(1);
38-
const args = createMagicContextHookMock.mock.calls[0]?.[0] as {
39-
config?: { toast_duration_ms?: number };
40-
};
41-
expect(args.config?.toast_duration_ms).toBe(30_000);
30+
expect(config.toast_duration_ms).toBeUndefined();
4231
});
4332
});

packages/plugin/src/plugin/hooks/create-session-hooks.ts

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,41 @@ import { createMagicContextHook } from "../../hooks/magic-context";
88
import type { LiveSessionState } from "../../hooks/magic-context/live-session-state";
99
import type { PluginContext } from "../types";
1010

11+
/**
12+
* Map the full plugin config down to the per-session hook config. Pure and
13+
* exported so it can be unit-tested directly — without a module-level
14+
* `mock.module` of the hooks barrel, which in Bun leaks process-globally across
15+
* test files (mock.restore() does not undo it) and corrupts sibling suites that
16+
* import the real hook shape.
17+
*/
18+
export function buildMagicContextHookConfig(pluginConfig: MagicContextPluginConfig) {
19+
return {
20+
protected_tags: pluginConfig.protected_tags ?? DEFAULT_PROTECTED_TAGS,
21+
ctx_reduce_enabled: pluginConfig.ctx_reduce_enabled,
22+
cache_ttl: pluginConfig.cache_ttl,
23+
clear_reasoning_age: pluginConfig.clear_reasoning_age,
24+
toast_duration_ms: pluginConfig.toast_duration_ms,
25+
execute_threshold_percentage:
26+
pluginConfig.execute_threshold_percentage ?? DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE,
27+
execute_threshold_tokens: pluginConfig.execute_threshold_tokens,
28+
historian: pluginConfig.historian,
29+
history_budget_percentage: pluginConfig.history_budget_percentage,
30+
historian_timeout_ms: pluginConfig.historian_timeout_ms,
31+
memory: pluginConfig.memory,
32+
sidekick: pluginConfig.sidekick,
33+
dreamer: pluginConfig.dreamer,
34+
commit_cluster_trigger: pluginConfig.commit_cluster_trigger,
35+
// Issue #53: per-agent system-prompt injection opt-out.
36+
system_prompt_injection: pluginConfig.system_prompt_injection,
37+
// Graduated from experimental.* — temporal_awareness and caveman are
38+
// top-level; auto_search now rides inside `memory` (passed above), and
39+
// git_commit_indexing is consumed at the dream-timer level in index.ts,
40+
// not per-session.
41+
temporal_awareness: pluginConfig.temporal_awareness,
42+
caveman_text_compression: pluginConfig.caveman_text_compression,
43+
};
44+
}
45+
1146
export function createSessionHooks(args: {
1247
ctx: PluginContext;
1348
pluginConfig: MagicContextPluginConfig;
@@ -39,32 +74,7 @@ export function createSessionHooks(args: {
3974
scheduler,
4075
compactionHandler,
4176
liveSessionState,
42-
config: {
43-
protected_tags: pluginConfig.protected_tags ?? DEFAULT_PROTECTED_TAGS,
44-
ctx_reduce_enabled: pluginConfig.ctx_reduce_enabled,
45-
cache_ttl: pluginConfig.cache_ttl,
46-
clear_reasoning_age: pluginConfig.clear_reasoning_age,
47-
toast_duration_ms: pluginConfig.toast_duration_ms,
48-
execute_threshold_percentage:
49-
pluginConfig.execute_threshold_percentage ??
50-
DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE,
51-
execute_threshold_tokens: pluginConfig.execute_threshold_tokens,
52-
historian: pluginConfig.historian,
53-
history_budget_percentage: pluginConfig.history_budget_percentage,
54-
historian_timeout_ms: pluginConfig.historian_timeout_ms,
55-
memory: pluginConfig.memory,
56-
sidekick: pluginConfig.sidekick,
57-
dreamer: pluginConfig.dreamer,
58-
commit_cluster_trigger: pluginConfig.commit_cluster_trigger,
59-
// Issue #53: per-agent system-prompt injection opt-out.
60-
system_prompt_injection: pluginConfig.system_prompt_injection,
61-
// Graduated from experimental.* — temporal_awareness and caveman
62-
// are top-level; auto_search now rides inside `memory` (passed
63-
// above), and git_commit_indexing is consumed at the dream-timer
64-
// level in index.ts, not per-session.
65-
temporal_awareness: pluginConfig.temporal_awareness,
66-
caveman_text_compression: pluginConfig.caveman_text_compression,
67-
},
77+
config: buildMagicContextHookConfig(pluginConfig),
6878
}),
6979
};
7080
}

packages/plugin/src/tui/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ function showToast(
4444
typeof input.durationOverrideMs === "number" && Number.isFinite(input.durationOverrideMs)
4545
? input.durationOverrideMs
4646
: getToastDurationMs()
47+
// toast_duration_ms = 0 disables Magic Context toasts entirely. An explicit
48+
// positive per-call override (e.g. restart-required) still shows; only a
49+
// non-positive effective duration suppresses the toast.
50+
if (!(duration > 0)) {
51+
return
52+
}
4753
api.ui.toast({
4854
message: input.message,
4955
variant: input.variant,

0 commit comments

Comments
 (0)