@kenkaiiii/ggcoder 5.25.0 → 5.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/agent-notifications.d.ts +62 -0
- package/dist/core/agent-notifications.d.ts.map +1 -0
- package/dist/core/agent-notifications.js +92 -0
- package/dist/core/agent-notifications.js.map +1 -0
- package/dist/core/agent-notifications.test.d.ts +2 -0
- package/dist/core/agent-notifications.test.d.ts.map +1 -0
- package/dist/core/agent-notifications.test.js +97 -0
- package/dist/core/agent-notifications.test.js.map +1 -0
- package/dist/core/agent-session-model-switch.test.d.ts +2 -0
- package/dist/core/agent-session-model-switch.test.d.ts.map +1 -0
- package/dist/core/agent-session-model-switch.test.js +161 -0
- package/dist/core/agent-session-model-switch.test.js.map +1 -0
- package/dist/core/agent-session-notifications.test.d.ts +2 -0
- package/dist/core/agent-session-notifications.test.d.ts.map +1 -0
- package/dist/core/agent-session-notifications.test.js +114 -0
- package/dist/core/agent-session-notifications.test.js.map +1 -0
- package/dist/core/agent-session.d.ts +55 -6
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +172 -25
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/event-bus.d.ts +6 -0
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js +7 -0
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/process-manager-notifications.test.d.ts +2 -0
- package/dist/core/process-manager-notifications.test.d.ts.map +1 -0
- package/dist/core/process-manager-notifications.test.js +113 -0
- package/dist/core/process-manager-notifications.test.js.map +1 -0
- package/dist/core/process-manager.d.ts +29 -0
- package/dist/core/process-manager.d.ts.map +1 -1
- package/dist/core/process-manager.js +123 -0
- package/dist/core/process-manager.js.map +1 -1
- package/dist/core/session-manager.d.ts +3 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +2 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/steering.d.ts +12 -0
- package/dist/core/steering.d.ts.map +1 -1
- package/dist/core/steering.js +16 -0
- package/dist/core/steering.js.map +1 -1
- package/dist/core/subagent-manager.d.ts +13 -0
- package/dist/core/subagent-manager.d.ts.map +1 -1
- package/dist/core/subagent-manager.js +30 -0
- package/dist/core/subagent-manager.js.map +1 -1
- package/dist/core/subagent-manager.test.js +16 -0
- package/dist/core/subagent-manager.test.js.map +1 -1
- package/dist/modes/json-mode.d.ts.map +1 -1
- package/dist/modes/json-mode.js +5 -0
- package/dist/modes/json-mode.js.map +1 -1
- package/dist/modes/subagent-worker-mode.d.ts.map +1 -1
- package/dist/modes/subagent-worker-mode.js +3 -1
- package/dist/modes/subagent-worker-mode.js.map +1 -1
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/subagent-control.d.ts.map +1 -1
- package/dist/tools/subagent-control.js +6 -2
- package/dist/tools/subagent-control.js.map +1 -1
- package/dist/tools/subagent-shared.d.ts +6 -0
- package/dist/tools/subagent-shared.d.ts.map +1 -1
- package/dist/tools/subagent-shared.js +6 -0
- package/dist/tools/subagent-shared.js.map +1 -1
- package/dist/tools/task-output.d.ts.map +1 -1
- package/dist/tools/task-output.js +3 -1
- package/dist/tools/task-output.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded push queue for out-of-band events the agent should learn about
|
|
3
|
+
* without spending a turn asking — a spawned child finishing, a background
|
|
4
|
+
* build making progress or exiting.
|
|
5
|
+
*
|
|
6
|
+
* The queue is deliberately lossy. Only the LATEST entry per `(kind, id)`
|
|
7
|
+
* survives, because a stale "build is 40% through" line is worthless next to
|
|
8
|
+
* "build exited 1", and a parent that spawned five children needs five facts,
|
|
9
|
+
* not fifty. Terminal entries supersede pending non-terminal ones for the same
|
|
10
|
+
* id and cannot themselves be superseded by a later non-terminal update, so a
|
|
11
|
+
* completion can never be overwritten by a straggling progress tick.
|
|
12
|
+
*
|
|
13
|
+
* Every bound here protects the same thing: injected bytes per drain. These
|
|
14
|
+
* notifications ride the steering path into live context, so an unbounded
|
|
15
|
+
* queue would silently eat the context window it is meant to save.
|
|
16
|
+
*/
|
|
17
|
+
/** Notification source. Extended as new push producers are added. */
|
|
18
|
+
export type NotificationKind = "subagent" | "process";
|
|
19
|
+
export interface AgentNotification {
|
|
20
|
+
kind: NotificationKind;
|
|
21
|
+
/** Producer-scoped identity (agent id, process id). Dedupe key with `kind`. */
|
|
22
|
+
id: string;
|
|
23
|
+
/** Bounded, human-readable one-liner. Never raw output. */
|
|
24
|
+
text: string;
|
|
25
|
+
/** True once the producer reached a final state (child done, process exited). */
|
|
26
|
+
terminal: boolean;
|
|
27
|
+
/** Unix epoch ms of the most recent update for this `(kind, id)`. */
|
|
28
|
+
updatedAt: number;
|
|
29
|
+
}
|
|
30
|
+
/** Max characters retained for a single notification's text. */
|
|
31
|
+
export declare const NOTIFICATION_MAX_CHARS = 512;
|
|
32
|
+
/** Max characters returned by one `drain()`, across all notifications. */
|
|
33
|
+
export declare const NOTIFICATION_DRAIN_MAX_CHARS = 1024;
|
|
34
|
+
/**
|
|
35
|
+
* FIFO with latest-only dedupe by `(kind, id)`. Insertion order is preserved
|
|
36
|
+
* across updates: an entry that is updated keeps its original queue position,
|
|
37
|
+
* so a chatty producer cannot starve an older, quieter one out of a drain.
|
|
38
|
+
*/
|
|
39
|
+
export declare class AgentNotificationQueue {
|
|
40
|
+
private entries;
|
|
41
|
+
private static key;
|
|
42
|
+
/**
|
|
43
|
+
* Record the latest state for one producer. Returns false when the update
|
|
44
|
+
* was dropped because a terminal entry for the same id already exists.
|
|
45
|
+
*/
|
|
46
|
+
enqueue(kind: NotificationKind, id: string, text: string, options?: {
|
|
47
|
+
terminal?: boolean;
|
|
48
|
+
}): boolean;
|
|
49
|
+
/** Number of notifications currently waiting. */
|
|
50
|
+
get size(): number;
|
|
51
|
+
/** Discard any pending notification for one producer (e.g. on reap). */
|
|
52
|
+
clear(kind: NotificationKind, id: string): void;
|
|
53
|
+
/** Discard everything (e.g. between runs). */
|
|
54
|
+
clearAll(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Take pending notifications, oldest first, up to the per-drain char budget.
|
|
57
|
+
* Taken entries are removed; entries that did not fit stay queued for the
|
|
58
|
+
* next drain rather than being dropped.
|
|
59
|
+
*/
|
|
60
|
+
drain(): AgentNotification[];
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=agent-notifications.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-notifications.d.ts","sourceRoot":"","sources":["../../src/core/agent-notifications.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,qEAAqE;AACrE,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,SAAS,CAAC;AAEtD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,gBAAgB,CAAC;IACvB,+EAA+E;IAC/E,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,QAAQ,EAAE,OAAO,CAAC;IAClB,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,gEAAgE;AAChE,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,0EAA0E;AAC1E,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAOjD;;;;GAIG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,OAAO,CAAwC;IAEvD,OAAO,CAAC,MAAM,CAAC,GAAG;IAIlB;;;OAGG;IACH,OAAO,CACL,IAAI,EAAE,gBAAgB,EACtB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAO,GACnC,OAAO;IAgBV,iDAAiD;IACjD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,wEAAwE;IACxE,KAAK,CAAC,IAAI,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAI/C,8CAA8C;IAC9C,QAAQ,IAAI,IAAI;IAIhB;;;;OAIG;IACH,KAAK,IAAI,iBAAiB,EAAE;CAmB7B"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded push queue for out-of-band events the agent should learn about
|
|
3
|
+
* without spending a turn asking — a spawned child finishing, a background
|
|
4
|
+
* build making progress or exiting.
|
|
5
|
+
*
|
|
6
|
+
* The queue is deliberately lossy. Only the LATEST entry per `(kind, id)`
|
|
7
|
+
* survives, because a stale "build is 40% through" line is worthless next to
|
|
8
|
+
* "build exited 1", and a parent that spawned five children needs five facts,
|
|
9
|
+
* not fifty. Terminal entries supersede pending non-terminal ones for the same
|
|
10
|
+
* id and cannot themselves be superseded by a later non-terminal update, so a
|
|
11
|
+
* completion can never be overwritten by a straggling progress tick.
|
|
12
|
+
*
|
|
13
|
+
* Every bound here protects the same thing: injected bytes per drain. These
|
|
14
|
+
* notifications ride the steering path into live context, so an unbounded
|
|
15
|
+
* queue would silently eat the context window it is meant to save.
|
|
16
|
+
*/
|
|
17
|
+
/** Max characters retained for a single notification's text. */
|
|
18
|
+
export const NOTIFICATION_MAX_CHARS = 512;
|
|
19
|
+
/** Max characters returned by one `drain()`, across all notifications. */
|
|
20
|
+
export const NOTIFICATION_DRAIN_MAX_CHARS = 1024;
|
|
21
|
+
function truncate(text, maxChars) {
|
|
22
|
+
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
23
|
+
return collapsed.length <= maxChars ? collapsed : `${collapsed.slice(0, maxChars - 1)}\u2026`;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* FIFO with latest-only dedupe by `(kind, id)`. Insertion order is preserved
|
|
27
|
+
* across updates: an entry that is updated keeps its original queue position,
|
|
28
|
+
* so a chatty producer cannot starve an older, quieter one out of a drain.
|
|
29
|
+
*/
|
|
30
|
+
export class AgentNotificationQueue {
|
|
31
|
+
entries = new Map();
|
|
32
|
+
static key(kind, id) {
|
|
33
|
+
return `${kind}:${id}`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Record the latest state for one producer. Returns false when the update
|
|
37
|
+
* was dropped because a terminal entry for the same id already exists.
|
|
38
|
+
*/
|
|
39
|
+
enqueue(kind, id, text, options = {}) {
|
|
40
|
+
const terminal = options.terminal === true;
|
|
41
|
+
const key = AgentNotificationQueue.key(kind, id);
|
|
42
|
+
const existing = this.entries.get(key);
|
|
43
|
+
// A completion is the last word — a late progress tick must not erase it.
|
|
44
|
+
if (existing?.terminal && !terminal)
|
|
45
|
+
return false;
|
|
46
|
+
this.entries.set(key, {
|
|
47
|
+
kind,
|
|
48
|
+
id,
|
|
49
|
+
text: truncate(text, NOTIFICATION_MAX_CHARS),
|
|
50
|
+
terminal,
|
|
51
|
+
updatedAt: Date.now(),
|
|
52
|
+
});
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
/** Number of notifications currently waiting. */
|
|
56
|
+
get size() {
|
|
57
|
+
return this.entries.size;
|
|
58
|
+
}
|
|
59
|
+
/** Discard any pending notification for one producer (e.g. on reap). */
|
|
60
|
+
clear(kind, id) {
|
|
61
|
+
this.entries.delete(AgentNotificationQueue.key(kind, id));
|
|
62
|
+
}
|
|
63
|
+
/** Discard everything (e.g. between runs). */
|
|
64
|
+
clearAll() {
|
|
65
|
+
this.entries.clear();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Take pending notifications, oldest first, up to the per-drain char budget.
|
|
69
|
+
* Taken entries are removed; entries that did not fit stay queued for the
|
|
70
|
+
* next drain rather than being dropped.
|
|
71
|
+
*/
|
|
72
|
+
drain() {
|
|
73
|
+
const taken = [];
|
|
74
|
+
let budget = NOTIFICATION_DRAIN_MAX_CHARS;
|
|
75
|
+
for (const [key, entry] of this.entries) {
|
|
76
|
+
if (entry.text.length > budget) {
|
|
77
|
+
// Nothing taken yet and even one entry overflows: take it truncated
|
|
78
|
+
// rather than deadlocking the queue on an oversized head.
|
|
79
|
+
if (taken.length === 0) {
|
|
80
|
+
taken.push({ ...entry, text: truncate(entry.text, budget) });
|
|
81
|
+
this.entries.delete(key);
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
budget -= entry.text.length;
|
|
86
|
+
taken.push(entry);
|
|
87
|
+
this.entries.delete(key);
|
|
88
|
+
}
|
|
89
|
+
return taken;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=agent-notifications.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-notifications.js","sourceRoot":"","sources":["../../src/core/agent-notifications.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-notifications.test.d.ts","sourceRoot":"","sources":["../../src/core/agent-notifications.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { AgentNotificationQueue, NOTIFICATION_DRAIN_MAX_CHARS, NOTIFICATION_MAX_CHARS, } from "./agent-notifications.js";
|
|
3
|
+
describe("AgentNotificationQueue", () => {
|
|
4
|
+
it("drains in insertion order and clears itself", () => {
|
|
5
|
+
const q = new AgentNotificationQueue();
|
|
6
|
+
q.enqueue("subagent", "a", "first");
|
|
7
|
+
q.enqueue("subagent", "b", "second");
|
|
8
|
+
expect(q.drain().map((n) => n.text)).toEqual(["first", "second"]);
|
|
9
|
+
expect(q.size).toBe(0);
|
|
10
|
+
expect(q.drain()).toEqual([]);
|
|
11
|
+
});
|
|
12
|
+
it("keeps only the latest entry per (kind, id)", () => {
|
|
13
|
+
const q = new AgentNotificationQueue();
|
|
14
|
+
q.enqueue("process", "p1", "10% done");
|
|
15
|
+
q.enqueue("process", "p1", "90% done");
|
|
16
|
+
const drained = q.drain();
|
|
17
|
+
expect(drained).toHaveLength(1);
|
|
18
|
+
expect(drained[0].text).toBe("90% done");
|
|
19
|
+
});
|
|
20
|
+
it("keys dedupe by kind as well as id", () => {
|
|
21
|
+
const q = new AgentNotificationQueue();
|
|
22
|
+
q.enqueue("process", "1", "process one");
|
|
23
|
+
q.enqueue("subagent", "1", "child one");
|
|
24
|
+
expect(q.drain()).toHaveLength(2);
|
|
25
|
+
});
|
|
26
|
+
it("preserves queue position when an entry is updated", () => {
|
|
27
|
+
const q = new AgentNotificationQueue();
|
|
28
|
+
q.enqueue("process", "p1", "old");
|
|
29
|
+
q.enqueue("process", "p2", "other");
|
|
30
|
+
q.enqueue("process", "p1", "new");
|
|
31
|
+
expect(q.drain().map((n) => n.text)).toEqual(["new", "other"]);
|
|
32
|
+
});
|
|
33
|
+
it("lets a terminal entry supersede a pending progress entry", () => {
|
|
34
|
+
const q = new AgentNotificationQueue();
|
|
35
|
+
q.enqueue("process", "p1", "still building");
|
|
36
|
+
expect(q.enqueue("process", "p1", "exited 0", { terminal: true })).toBe(true);
|
|
37
|
+
const drained = q.drain();
|
|
38
|
+
expect(drained).toHaveLength(1);
|
|
39
|
+
expect(drained[0]).toMatchObject({ text: "exited 0", terminal: true });
|
|
40
|
+
});
|
|
41
|
+
it("refuses to overwrite a terminal entry with a late progress tick", () => {
|
|
42
|
+
const q = new AgentNotificationQueue();
|
|
43
|
+
q.enqueue("process", "p1", "exited 1", { terminal: true });
|
|
44
|
+
expect(q.enqueue("process", "p1", "50% done")).toBe(false);
|
|
45
|
+
expect(q.drain()[0]).toMatchObject({ text: "exited 1", terminal: true });
|
|
46
|
+
});
|
|
47
|
+
it("allows a terminal entry to replace an earlier terminal entry", () => {
|
|
48
|
+
const q = new AgentNotificationQueue();
|
|
49
|
+
q.enqueue("subagent", "a", "failed", { terminal: true });
|
|
50
|
+
q.enqueue("subagent", "a", "done", { terminal: true });
|
|
51
|
+
expect(q.drain()[0].text).toBe("done");
|
|
52
|
+
});
|
|
53
|
+
it("caps a single notification at NOTIFICATION_MAX_CHARS", () => {
|
|
54
|
+
const q = new AgentNotificationQueue();
|
|
55
|
+
q.enqueue("subagent", "a", "x".repeat(NOTIFICATION_MAX_CHARS * 3));
|
|
56
|
+
const [entry] = q.drain();
|
|
57
|
+
expect(entry.text.length).toBe(NOTIFICATION_MAX_CHARS);
|
|
58
|
+
expect(entry.text.endsWith("\u2026")).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
it("collapses whitespace so multi-line output cannot inflate a notification", () => {
|
|
61
|
+
const q = new AgentNotificationQueue();
|
|
62
|
+
q.enqueue("process", "p1", " build\n\n failed \t badly ");
|
|
63
|
+
expect(q.drain()[0].text).toBe("build failed badly");
|
|
64
|
+
});
|
|
65
|
+
it("caps one drain at NOTIFICATION_DRAIN_MAX_CHARS and requeues the rest", () => {
|
|
66
|
+
const q = new AgentNotificationQueue();
|
|
67
|
+
for (let i = 0; i < 6; i++)
|
|
68
|
+
q.enqueue("subagent", `a${i}`, "y".repeat(NOTIFICATION_MAX_CHARS));
|
|
69
|
+
const first = q.drain();
|
|
70
|
+
const firstChars = first.reduce((sum, n) => sum + n.text.length, 0);
|
|
71
|
+
expect(firstChars).toBeLessThanOrEqual(NOTIFICATION_DRAIN_MAX_CHARS);
|
|
72
|
+
expect(first).toHaveLength(2);
|
|
73
|
+
// Nothing is lost — the remainder waits for the next drain.
|
|
74
|
+
expect(q.size).toBe(4);
|
|
75
|
+
});
|
|
76
|
+
it("never deadlocks on an oversized head entry", () => {
|
|
77
|
+
const q = new AgentNotificationQueue();
|
|
78
|
+
// Two max-size entries fill the drain budget exactly; add a third.
|
|
79
|
+
q.enqueue("subagent", "a", "y".repeat(NOTIFICATION_MAX_CHARS));
|
|
80
|
+
q.enqueue("subagent", "b", "y".repeat(NOTIFICATION_MAX_CHARS));
|
|
81
|
+
q.enqueue("subagent", "c", "z".repeat(NOTIFICATION_MAX_CHARS));
|
|
82
|
+
expect(q.drain()).toHaveLength(2);
|
|
83
|
+
const rest = q.drain();
|
|
84
|
+
expect(rest).toHaveLength(1);
|
|
85
|
+
expect(q.size).toBe(0);
|
|
86
|
+
});
|
|
87
|
+
it("clears a single producer and everything", () => {
|
|
88
|
+
const q = new AgentNotificationQueue();
|
|
89
|
+
q.enqueue("process", "p1", "a");
|
|
90
|
+
q.enqueue("process", "p2", "b");
|
|
91
|
+
q.clear("process", "p1");
|
|
92
|
+
expect(q.size).toBe(1);
|
|
93
|
+
q.clearAll();
|
|
94
|
+
expect(q.size).toBe(0);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=agent-notifications.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-notifications.test.js","sourceRoot":"","sources":["../../src/core/agent-notifications.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-session-model-switch.test.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-model-switch.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A mid-session model switch must be replayable state, not a silent mutation:
|
|
3
|
+
* recorded as a durable marker, injected as its own trailing message, and — the
|
|
4
|
+
* expensive part — kept OFF the cached system prefix so the next turn still
|
|
5
|
+
* reads from cache.
|
|
6
|
+
*/
|
|
7
|
+
import fs from "node:fs/promises";
|
|
8
|
+
import os from "node:os";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
11
|
+
import { useFakeHome } from "../test-support/fake-home.js";
|
|
12
|
+
const agentLoopMock = vi.hoisted(() => vi.fn());
|
|
13
|
+
vi.mock("@kenkaiiii/gg-agent", async () => {
|
|
14
|
+
const actual = await vi.importActual("@kenkaiiii/gg-agent");
|
|
15
|
+
return { ...actual, agentLoop: agentLoopMock };
|
|
16
|
+
});
|
|
17
|
+
vi.mock("./mcp/index.js", async () => {
|
|
18
|
+
const actual = await vi.importActual("./mcp/index.js");
|
|
19
|
+
return {
|
|
20
|
+
...actual,
|
|
21
|
+
MCPClientManager: vi.fn(function MCPClientManagerMock() {
|
|
22
|
+
return { connectAll: vi.fn(async () => []), dispose: vi.fn(async () => { }) };
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
let restoreHome;
|
|
27
|
+
let tempHome;
|
|
28
|
+
let tempProject;
|
|
29
|
+
const CACHE_MARKER = "<!-- uncached -->";
|
|
30
|
+
beforeEach(async () => {
|
|
31
|
+
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "agent-switch-home-"));
|
|
32
|
+
tempProject = await fs.mkdtemp(path.join(os.tmpdir(), "agent-switch-project-"));
|
|
33
|
+
restoreHome = useFakeHome(tempHome);
|
|
34
|
+
agentLoopMock.mockReset();
|
|
35
|
+
await fs.mkdir(path.join(tempHome, ".gg"), { recursive: true });
|
|
36
|
+
await fs.writeFile(path.join(tempHome, ".gg", "auth.json"), JSON.stringify({
|
|
37
|
+
anthropic: { accessToken: "t", refreshToken: "t", expiresAt: Date.now() + 3_600_000 },
|
|
38
|
+
openai: { accessToken: "t", refreshToken: "t", expiresAt: Date.now() + 3_600_000 },
|
|
39
|
+
}));
|
|
40
|
+
});
|
|
41
|
+
afterEach(async () => {
|
|
42
|
+
restoreHome?.();
|
|
43
|
+
await Promise.all([
|
|
44
|
+
fs.rm(tempHome, { recursive: true, force: true }),
|
|
45
|
+
fs.rm(tempProject, { recursive: true, force: true }),
|
|
46
|
+
]);
|
|
47
|
+
vi.clearAllMocks();
|
|
48
|
+
});
|
|
49
|
+
async function createSession() {
|
|
50
|
+
const { AgentSession } = await import("./agent-session.js");
|
|
51
|
+
const session = new AgentSession({
|
|
52
|
+
provider: "openai",
|
|
53
|
+
model: "gpt-5.6-sol",
|
|
54
|
+
// Repo cwd so the bundled agent definitions register spawn_agent — the
|
|
55
|
+
// Sol/Ultra orchestration block only renders when that tool exists, and it
|
|
56
|
+
// is the model-dependent prompt content this test is about.
|
|
57
|
+
cwd: process.cwd(),
|
|
58
|
+
systemPrompt: "stable role prompt",
|
|
59
|
+
thinkingLevel: "ultra",
|
|
60
|
+
transient: true,
|
|
61
|
+
selfCorrectionHooks: false,
|
|
62
|
+
});
|
|
63
|
+
await session.initialize();
|
|
64
|
+
// A conversation must already exist for the switch note to have a job.
|
|
65
|
+
session
|
|
66
|
+
.getMessages()
|
|
67
|
+
.push({ role: "user", content: "start the work" }, { role: "assistant", content: "on it" });
|
|
68
|
+
return session;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* System-prompt bytes that carry cache_control. Mirrors the provider split in
|
|
72
|
+
* gg-ai `transform.ts`: everything before the marker, trimmed at the end.
|
|
73
|
+
*/
|
|
74
|
+
function cachedPrefix(content) {
|
|
75
|
+
const index = content.indexOf(CACHE_MARKER);
|
|
76
|
+
return (index === -1 ? content : content.slice(0, index)).trimEnd();
|
|
77
|
+
}
|
|
78
|
+
describe("AgentSession model switch", () => {
|
|
79
|
+
it("keeps the cached system prefix byte-identical across a switch", async () => {
|
|
80
|
+
const session = await createSession();
|
|
81
|
+
try {
|
|
82
|
+
const before = String(session.getMessages()[0].content);
|
|
83
|
+
// Sol/Ultra guidance is live, so the switch really does change the prompt.
|
|
84
|
+
expect(before).toContain(CACHE_MARKER);
|
|
85
|
+
expect(before).toContain("Proactively use spawn_agent");
|
|
86
|
+
await session.switchModel("openai", "gpt-5.5-codex");
|
|
87
|
+
const after = String(session.getMessages()[0].content);
|
|
88
|
+
expect(cachedPrefix(after)).toBe(cachedPrefix(before));
|
|
89
|
+
// Model-dependent guidance followed the model, out of the cached region.
|
|
90
|
+
expect(after).not.toContain("Proactively use spawn_agent");
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
await session.dispose();
|
|
94
|
+
}
|
|
95
|
+
}, 30_000);
|
|
96
|
+
it("appends the switch as its own trailing message", async () => {
|
|
97
|
+
const session = await createSession();
|
|
98
|
+
try {
|
|
99
|
+
await session.switchModel("openai", "gpt-5.5-codex");
|
|
100
|
+
const messages = session.getMessages();
|
|
101
|
+
const last = messages[messages.length - 1];
|
|
102
|
+
expect(last.role).toBe("user");
|
|
103
|
+
expect(String(last.content)).toContain("gpt-5.6-sol");
|
|
104
|
+
expect(String(last.content)).toContain("gpt-5.5-codex");
|
|
105
|
+
// Cross-provider switches name the provider on both sides.
|
|
106
|
+
await session.switchModel("anthropic", "claude-test");
|
|
107
|
+
expect(String(session.getMessages().at(-1).content)).toContain("anthropic/claude-test");
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
await session.dispose();
|
|
111
|
+
}
|
|
112
|
+
}, 30_000);
|
|
113
|
+
it("records a replayable model_switch marker", async () => {
|
|
114
|
+
const session = await createSession();
|
|
115
|
+
try {
|
|
116
|
+
await session.switchModel("openai", "gpt-5.5-codex");
|
|
117
|
+
const markers = session.getAppMarkers().filter((m) => m.kind === "model_switch");
|
|
118
|
+
expect(markers).toHaveLength(1);
|
|
119
|
+
expect(markers[0].data).toMatchObject({
|
|
120
|
+
from: "gpt-5.6-sol",
|
|
121
|
+
to: "gpt-5.5-codex",
|
|
122
|
+
provider: "openai",
|
|
123
|
+
fromProvider: "openai",
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
await session.dispose();
|
|
128
|
+
}
|
|
129
|
+
}, 30_000);
|
|
130
|
+
it("does nothing when the model did not actually change", async () => {
|
|
131
|
+
const session = await createSession();
|
|
132
|
+
try {
|
|
133
|
+
const before = [...session.getMessages()];
|
|
134
|
+
await session.switchModel("openai", "gpt-5.6-sol");
|
|
135
|
+
expect(session.getMessages()).toHaveLength(before.length);
|
|
136
|
+
expect(session.getAppMarkers().filter((m) => m.kind === "model_switch")).toHaveLength(0);
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
await session.dispose();
|
|
140
|
+
}
|
|
141
|
+
}, 30_000);
|
|
142
|
+
it("does not break tool pairing when a switch lands mid tool call", async () => {
|
|
143
|
+
const session = await createSession();
|
|
144
|
+
try {
|
|
145
|
+
session.getMessages().push({
|
|
146
|
+
role: "assistant",
|
|
147
|
+
content: [{ type: "tool_call", id: "t1", name: "read", args: {} }],
|
|
148
|
+
});
|
|
149
|
+
const count = session.getMessages().length;
|
|
150
|
+
await session.switchModel("openai", "gpt-5.5-codex");
|
|
151
|
+
// No user message may sit between tool_use and its tool_result.
|
|
152
|
+
expect(session.getMessages()).toHaveLength(count);
|
|
153
|
+
// The switch is still recorded durably.
|
|
154
|
+
expect(session.getAppMarkers().filter((m) => m.kind === "model_switch")).toHaveLength(1);
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
await session.dispose();
|
|
158
|
+
}
|
|
159
|
+
}, 30_000);
|
|
160
|
+
});
|
|
161
|
+
//# sourceMappingURL=agent-session-model-switch.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-session-model-switch.test.js","sourceRoot":"","sources":["../../src/core/agent-session-model-switch.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-session-notifications.test.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-notifications.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pushed notifications must reach the model on the steering path — a finished
|
|
3
|
+
* child or an exited background build should arrive on its own, without the
|
|
4
|
+
* agent spending a turn on wait_agent/task_output, and without displacing
|
|
5
|
+
* anything the user queued.
|
|
6
|
+
*/
|
|
7
|
+
import fs from "node:fs/promises";
|
|
8
|
+
import os from "node:os";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
11
|
+
import { useFakeHome } from "../test-support/fake-home.js";
|
|
12
|
+
import { NOTIFICATION_DRAIN_MAX_CHARS } from "./agent-notifications.js";
|
|
13
|
+
import { NOTIFICATION_PREFIX, STEERING_PREFIX } from "./steering.js";
|
|
14
|
+
const agentLoopMock = vi.hoisted(() => vi.fn());
|
|
15
|
+
vi.mock("@kenkaiiii/gg-agent", async () => {
|
|
16
|
+
const actual = await vi.importActual("@kenkaiiii/gg-agent");
|
|
17
|
+
return { ...actual, agentLoop: agentLoopMock };
|
|
18
|
+
});
|
|
19
|
+
vi.mock("./mcp/index.js", async () => {
|
|
20
|
+
const actual = await vi.importActual("./mcp/index.js");
|
|
21
|
+
return {
|
|
22
|
+
...actual,
|
|
23
|
+
MCPClientManager: vi.fn(function MCPClientManagerMock() {
|
|
24
|
+
return { connectAll: vi.fn(async () => []), dispose: vi.fn(async () => { }) };
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
let restoreHome;
|
|
29
|
+
let tmpHome;
|
|
30
|
+
let tmpProject;
|
|
31
|
+
beforeEach(async () => {
|
|
32
|
+
tmpHome = await fs.mkdtemp(path.join(os.tmpdir(), "agent-session-notify-home-"));
|
|
33
|
+
tmpProject = await fs.mkdtemp(path.join(os.tmpdir(), "agent-session-notify-project-"));
|
|
34
|
+
restoreHome = useFakeHome(tmpHome);
|
|
35
|
+
agentLoopMock.mockReset();
|
|
36
|
+
await fs.mkdir(path.join(tmpHome, ".gg"), { recursive: true });
|
|
37
|
+
await fs.writeFile(path.join(tmpHome, ".gg", "auth.json"), JSON.stringify({
|
|
38
|
+
anthropic: {
|
|
39
|
+
accessToken: "test",
|
|
40
|
+
refreshToken: "test",
|
|
41
|
+
expiresAt: Date.now() + 3_600_000,
|
|
42
|
+
},
|
|
43
|
+
}), "utf-8");
|
|
44
|
+
});
|
|
45
|
+
afterEach(async () => {
|
|
46
|
+
restoreHome?.();
|
|
47
|
+
await fs.rm(tmpHome, { recursive: true, force: true });
|
|
48
|
+
await fs.rm(tmpProject, { recursive: true, force: true });
|
|
49
|
+
vi.clearAllMocks();
|
|
50
|
+
});
|
|
51
|
+
async function makeSession() {
|
|
52
|
+
const { AgentSession } = await import("./agent-session.js");
|
|
53
|
+
const session = new AgentSession({
|
|
54
|
+
provider: "anthropic",
|
|
55
|
+
model: "claude-test",
|
|
56
|
+
cwd: tmpProject,
|
|
57
|
+
systemPrompt: "test system prompt",
|
|
58
|
+
transient: true,
|
|
59
|
+
});
|
|
60
|
+
await session.initialize();
|
|
61
|
+
const internals = session;
|
|
62
|
+
return { session, internals };
|
|
63
|
+
}
|
|
64
|
+
describe("AgentSession pushed notifications", () => {
|
|
65
|
+
it("injects queued notifications as one framed steering message", async () => {
|
|
66
|
+
const { session, internals } = await makeSession();
|
|
67
|
+
try {
|
|
68
|
+
internals.notifications.enqueue("subagent", "a1", 'Child agent "one" is completed.', {
|
|
69
|
+
terminal: true,
|
|
70
|
+
});
|
|
71
|
+
internals.notifications.enqueue("process", "p1", "Build exited 0.", { terminal: true });
|
|
72
|
+
const messages = internals.getHookSteeringMessages();
|
|
73
|
+
expect(messages).toHaveLength(1);
|
|
74
|
+
const content = messages[0].content;
|
|
75
|
+
expect(content.startsWith(NOTIFICATION_PREFIX)).toBe(true);
|
|
76
|
+
expect(content).toContain('Child agent "one" is completed.');
|
|
77
|
+
expect(content).toContain("Build exited 0.");
|
|
78
|
+
expect(content.length).toBeLessThanOrEqual(NOTIFICATION_PREFIX.length + NOTIFICATION_DRAIN_MAX_CHARS + 8);
|
|
79
|
+
// Consumed exactly once — a second poll must not re-inject them.
|
|
80
|
+
expect(internals.getHookSteeringMessages()).toBeNull();
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
await session.dispose();
|
|
84
|
+
}
|
|
85
|
+
}, 15_000);
|
|
86
|
+
it("never displaces user steering — both ride out in the same batch", async () => {
|
|
87
|
+
const { session, internals } = await makeSession();
|
|
88
|
+
try {
|
|
89
|
+
session.queueMessage("also check the tests");
|
|
90
|
+
internals.notifications.enqueue("subagent", "a1", 'Child agent "one" is completed.', {
|
|
91
|
+
terminal: true,
|
|
92
|
+
});
|
|
93
|
+
const messages = internals.getHookSteeringMessages();
|
|
94
|
+
expect(messages).toHaveLength(2);
|
|
95
|
+
// User steering first: it is an instruction, the notification is a fact.
|
|
96
|
+
expect(messages[0].content).toBe(`${STEERING_PREFIX}also check the tests`);
|
|
97
|
+
expect(messages[1].content).toContain(NOTIFICATION_PREFIX);
|
|
98
|
+
expect(session.getQueuedCount()).toBe(0);
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
await session.dispose();
|
|
102
|
+
}
|
|
103
|
+
}, 15_000);
|
|
104
|
+
it("returns null when nothing is pending", async () => {
|
|
105
|
+
const { session, internals } = await makeSession();
|
|
106
|
+
try {
|
|
107
|
+
expect(internals.getHookSteeringMessages()).toBeNull();
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
await session.dispose();
|
|
111
|
+
}
|
|
112
|
+
}, 15_000);
|
|
113
|
+
});
|
|
114
|
+
//# sourceMappingURL=agent-session-notifications.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-session-notifications.test.js","sourceRoot":"","sources":["../../src/core/agent-session-notifications.test.ts"],"names":[],"mappings":"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"}
|