diff --git a/packages/core/src/mcp/guidance.ts b/packages/core/src/mcp/guidance.ts index b647bda4bf..89f48bf219 100644 --- a/packages/core/src/mcp/guidance.ts +++ b/packages/core/src/mcp/guidance.ts @@ -31,23 +31,10 @@ const update = (previous: ReadonlyArray, current: ReadonlyArray server.server, (before, after) => before.instructions !== after.instructions, ) - const items = [ - ...diff.added.map((server) => ({ - key: server.server, - description: "MCP server instructions", - action: "added" as const, - })), - ...diff.removed.map((server) => ({ - key: server.server, - description: "MCP server instructions", - action: "removed" as const, - })), - ...diff.changed.map((server) => ({ - key: server.current.server, - description: "MCP server instructions", - action: "updated" as const, - })), - ] + const items = SystemContext.diffItems(diff, (server) => ({ + key: server.server, + description: "MCP server instructions", + })) // Additions and removals render as small deltas; anything else restates the full list. if (diff.changed.length > 0 || (diff.added.length === 0 && diff.removed.length === 0)) return { diff --git a/packages/core/src/reference/guidance.ts b/packages/core/src/reference/guidance.ts index 84458cf0da..3632a9060b 100644 --- a/packages/core/src/reference/guidance.ts +++ b/packages/core/src/reference/guidance.ts @@ -35,23 +35,10 @@ const update = (previous: ReadonlyArray, current: ReadonlyA (reference) => reference.name, (before, after) => before.path !== after.path || before.description !== after.description, ) - const items = [ - ...diff.added.map((reference) => ({ - key: reference.name, - description: reference.description ?? reference.path, - action: "added" as const, - })), - ...diff.removed.map((reference) => ({ - key: reference.name, - description: reference.description ?? reference.path, - action: "removed" as const, - })), - ...diff.changed.map((reference) => ({ - key: reference.current.name, - description: reference.current.description ?? reference.current.path, - action: "updated" as const, - })), - ] + const items = SystemContext.diffItems(diff, (reference) => ({ + key: reference.name, + description: reference.description ?? reference.path, + })) // Additions and removals render as small deltas; anything else restates the full list. if (diff.changed.length > 0 || (diff.added.length === 0 && diff.removed.length === 0)) return { diff --git a/packages/core/src/skill/guidance.ts b/packages/core/src/skill/guidance.ts index 5ff1918e2d..d249b101d2 100644 --- a/packages/core/src/skill/guidance.ts +++ b/packages/core/src/skill/guidance.ts @@ -37,15 +37,7 @@ const update = (previous: ReadonlyArray, current: ReadonlyArray skill.name, (before, after) => before.description !== after.description, ) - const items = [ - ...diff.added.map((skill) => ({ key: skill.name, description: skill.description, action: "added" as const })), - ...diff.removed.map((skill) => ({ key: skill.name, description: skill.description, action: "removed" as const })), - ...diff.changed.map((skill) => ({ - key: skill.current.name, - description: skill.current.description, - action: "updated" as const, - })), - ] + const items = SystemContext.diffItems(diff, (skill) => ({ key: skill.name, description: skill.description })) // Additions and removals render as small deltas; anything else restates the full list. if (diff.changed.length > 0 || (diff.added.length === 0 && diff.removed.length === 0)) return { diff --git a/packages/core/src/system-context/index.ts b/packages/core/src/system-context/index.ts index 0b486f705f..a9b3a60a44 100644 --- a/packages/core/src/system-context/index.ts +++ b/packages/core/src/system-context/index.ts @@ -117,7 +117,6 @@ export class DuplicateKeyError extends Schema.TaggedErrorClass /** Restates the model's belief from a last-applied value when the source cannot be observed. */ readonly recall: (stored: AppliedSource) => string | undefined @@ -150,7 +149,6 @@ export function make(source: Source): SystemContext { return context([ { key: source.key, - description, recall: (stored) => Option.match(decode(stored.value), { onNone: () => undefined, @@ -163,8 +161,9 @@ export function make(source: Source): SystemContext { description, applied: { value: encode(value), - description, - ...(source.removed ? { removed: requireText(source.key, "removal", source.removed(value)) } : {}), + ...(source.removed + ? { description, removed: requireText(source.key, "removal", source.removed(value)) } + : {}), }, baseline: () => baseline(value), update: (previous) => @@ -206,6 +205,17 @@ export function diffByKey( } } +export function diffItems( + diff: ReturnType>, + item: (value: A) => { readonly key: string; readonly description: string }, +): ReadonlyArray { + return [ + ...diff.added.map((value) => ({ ...item(value), action: "added" as const })), + ...diff.removed.map((value) => ({ ...item(value), action: "removed" as const })), + ...diff.changed.map((value) => ({ ...item(value.current), action: "updated" as const })), + ] +} + /** Combines contexts in order and rejects duplicate source keys immediately. */ export function combine(values: ReadonlyArray): SystemContext { const sources = values.flatMap((value) => value[ContextTypeId]) diff --git a/packages/core/test/system-context/index.test.ts b/packages/core/test/system-context/index.test.ts index c0409ce464..3d1d003eee 100644 --- a/packages/core/test/system-context/index.test.ts +++ b/packages/core/test/system-context/index.test.ts @@ -62,7 +62,7 @@ describe("SystemContext", () => { text: "Today's date is 2026-06-03.\n\nDirectory: /repo", applied: { "core/date": { value: "2026-06-03", description: "Current date", removed: "The date was removed." }, - "core/location": { value: "/repo", description: "Description for core/location" }, + "core/location": { value: "/repo" }, }, }) expect(loads).toBe(1) @@ -123,7 +123,7 @@ describe("SystemContext", () => { _tag: "Updated", text: "Available skill: effect", updates: [{ key: key("core/skills"), description: "Description for core/skills", action: "added" }], - applied: { "core/skills": { value: "effect", description: "Description for core/skills" } }, + applied: { "core/skills": { value: "effect" } }, }) }), ) @@ -182,7 +182,7 @@ describe("SystemContext", () => { text: "effect", updates: [{ key: key("core/skills"), description: "Description for core/skills", action: "added" }], applied: { - "core/skills": { value: "effect", description: "Description for core/skills" }, + "core/skills": { value: "effect" }, "core/date": { value: "2026-06-04" }, }, }) @@ -221,7 +221,7 @@ describe("SystemContext", () => { _tag: "Updated", text: "2026-06-04", updates: [{ key: key("core/date"), description: "Description for core/date", action: "updated" }], - applied: { "core/date": { value: "2026-06-04", description: "Description for core/date" } }, + applied: { "core/date": { value: "2026-06-04" } }, }) }), ) @@ -250,8 +250,8 @@ describe("SystemContext", () => { { key: key("core/location"), description: "Description for core/location", action: "updated" }, ], applied: { - "core/date": { value: "2026-06-04", description: "Description for core/date" }, - "core/location": { value: "/repo", description: "Description for core/location" }, + "core/date": { value: "2026-06-04" }, + "core/location": { value: "/repo" }, }, }) }), @@ -274,7 +274,7 @@ describe("SystemContext", () => { expect(yield* SystemContext.rebaseline(context, { "core/date": { value: "2026-06-03" } })).toEqual({ text: "2026-06-04", - applied: { "core/date": { value: "2026-06-04", description: "Current date" } }, + applied: { "core/date": { value: "2026-06-04" } }, }) expect(loads).toBe(1) }), @@ -298,7 +298,7 @@ describe("SystemContext", () => { ).toEqual({ text: "2026-06-04\n\nInstructions: contents", applied: { - "core/date": { value: "2026-06-04", description: "Description for core/date" }, + "core/date": { value: "2026-06-04" }, "core/remote": { value: "contents", removed: "Instructions removed" }, }, }) @@ -349,6 +349,21 @@ describe("SystemContext", () => { }, ], }) + expect( + SystemContext.diffItems( + SystemContext.diffByKey( + previous, + current, + (value) => value.name, + (before, after) => before.description !== after.description, + ), + (value) => ({ key: value.name, description: value.description }), + ), + ).toEqual([ + { key: "writing", description: "Write prose", action: "added" }, + { key: "retired", description: "Old", action: "removed" }, + { key: "effect", description: "Build with Effect v4", action: "updated" }, + ]) }), ) @@ -375,7 +390,7 @@ describe("SystemContext", () => { items: [{ key: "effect", description: "Build with Effect", action: "updated" }], }, ], - applied: { "core/skills": { value: "new", description: "Available skills" } }, + applied: { "core/skills": { value: "new" } }, }) }), )