@code-yeongyu/senpi-agent-core 2026.8.1 → 2026.8.3
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/harness/agent-harness.d.ts +14 -3
- package/dist/harness/agent-harness.d.ts.map +1 -1
- package/dist/harness/agent-harness.js +156 -67
- package/dist/harness/agent-harness.js.map +1 -1
- package/dist/harness/session/array-session-reader.d.ts +3 -0
- package/dist/harness/session/array-session-reader.d.ts.map +1 -0
- package/dist/harness/session/array-session-reader.js +70 -0
- package/dist/harness/session/array-session-reader.js.map +1 -0
- package/dist/harness/session/fork.d.ts +4 -0
- package/dist/harness/session/fork.d.ts.map +1 -0
- package/dist/harness/session/fork.js +22 -0
- package/dist/harness/session/fork.js.map +1 -0
- package/dist/harness/session/jsonl-store.d.ts +13 -0
- package/dist/harness/session/jsonl-store.d.ts.map +1 -0
- package/dist/harness/session/jsonl-store.js +304 -0
- package/dist/harness/session/jsonl-store.js.map +1 -0
- package/dist/harness/session/keyed-operation-queue.d.ts +17 -0
- package/dist/harness/session/keyed-operation-queue.d.ts.map +1 -0
- package/dist/harness/session/keyed-operation-queue.js +60 -0
- package/dist/harness/session/keyed-operation-queue.js.map +1 -0
- package/dist/harness/session/memory-store.d.ts +6 -0
- package/dist/harness/session/memory-store.d.ts.map +1 -0
- package/dist/harness/session/memory-store.js +107 -0
- package/dist/harness/session/memory-store.js.map +1 -0
- package/dist/harness/session/repository.d.ts +28 -0
- package/dist/harness/session/repository.d.ts.map +1 -0
- package/dist/harness/session/repository.js +61 -0
- package/dist/harness/session/repository.js.map +1 -0
- package/dist/harness/session/search-backend.d.ts +8 -0
- package/dist/harness/session/search-backend.d.ts.map +1 -0
- package/dist/harness/session/search-backend.js +22 -0
- package/dist/harness/session/search-backend.js.map +1 -0
- package/dist/harness/session/session.d.ts +6 -10
- package/dist/harness/session/session.d.ts.map +1 -1
- package/dist/harness/session/session.js +154 -77
- package/dist/harness/session/session.js.map +1 -1
- package/dist/harness/types.d.ts +49 -23
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/proxy.js +1 -1
- package/dist/proxy.js.map +1 -1
- package/package.json +4 -4
- package/dist/harness/session/jsonl-repo.d.ts +0 -26
- package/dist/harness/session/jsonl-repo.d.ts.map +0 -1
- package/dist/harness/session/jsonl-repo.js +0 -100
- package/dist/harness/session/jsonl-repo.js.map +0 -1
- package/dist/harness/session/jsonl-storage.d.ts +0 -42
- package/dist/harness/session/jsonl-storage.d.ts.map +0 -1
- package/dist/harness/session/jsonl-storage.js +0 -286
- package/dist/harness/session/jsonl-storage.js.map +0 -1
- package/dist/harness/session/memory-repo.d.ts +0 -18
- package/dist/harness/session/memory-repo.d.ts.map +0 -1
- package/dist/harness/session/memory-repo.js +0 -44
- package/dist/harness/session/memory-repo.js.map +0 -1
- package/dist/harness/session/memory-storage.d.ts +0 -33
- package/dist/harness/session/memory-storage.d.ts.map +0 -1
- package/dist/harness/session/memory-storage.js +0 -163
- package/dist/harness/session/memory-storage.js.map +0 -1
- package/dist/harness/session/repo-utils.d.ts +0 -11
- package/dist/harness/session/repo-utils.d.ts.map +0 -1
- package/dist/harness/session/repo-utils.js +0 -39
- package/dist/harness/session/repo-utils.js.map +0 -1
|
@@ -5,8 +5,10 @@ export declare class AgentHarness<TContext extends object | undefined = undefine
|
|
|
5
5
|
private session;
|
|
6
6
|
readonly models: Models;
|
|
7
7
|
private phase;
|
|
8
|
-
private
|
|
9
|
-
private
|
|
8
|
+
private activeAbortController?;
|
|
9
|
+
private readonly activeTasks;
|
|
10
|
+
private shutdownPromise?;
|
|
11
|
+
private isShutdown;
|
|
10
12
|
private pendingSessionWrites;
|
|
11
13
|
private model;
|
|
12
14
|
private thinkingLevel;
|
|
@@ -24,6 +26,7 @@ export declare class AgentHarness<TContext extends object | undefined = undefine
|
|
|
24
26
|
private nextTurnQueue;
|
|
25
27
|
private handlers;
|
|
26
28
|
constructor(options: AgentHarnessOptions<TContext, TSkill, TPromptTemplate, TTool>);
|
|
29
|
+
private assertNotShutDown;
|
|
27
30
|
private getHandlers;
|
|
28
31
|
private emitOwn;
|
|
29
32
|
private emitAny;
|
|
@@ -32,7 +35,9 @@ export declare class AgentHarness<TContext extends object | undefined = undefine
|
|
|
32
35
|
private emitBeforeProviderRequest;
|
|
33
36
|
private emitBeforeProviderPayload;
|
|
34
37
|
private emitQueueUpdate;
|
|
35
|
-
private
|
|
38
|
+
private startOperation;
|
|
39
|
+
private track;
|
|
40
|
+
private waitForTasks;
|
|
36
41
|
private resolveToolContext;
|
|
37
42
|
private bindToolContext;
|
|
38
43
|
private createTurnState;
|
|
@@ -74,8 +79,10 @@ export declare class AgentHarness<TContext extends object | undefined = undefine
|
|
|
74
79
|
setThinkingLevel(level: ThinkingLevel): Promise<void>;
|
|
75
80
|
getTools(): TTool[];
|
|
76
81
|
setTools(tools: TTool[], activeToolNames?: string[]): Promise<void>;
|
|
82
|
+
private applyTools;
|
|
77
83
|
getActiveTools(): TTool[];
|
|
78
84
|
setActiveTools(toolNames: string[]): Promise<void>;
|
|
85
|
+
private applyActiveTools;
|
|
79
86
|
getSteeringMode(): QueueMode;
|
|
80
87
|
setSteeringMode(mode: QueueMode): Promise<void>;
|
|
81
88
|
getFollowUpMode(): QueueMode;
|
|
@@ -84,6 +91,10 @@ export declare class AgentHarness<TContext extends object | undefined = undefine
|
|
|
84
91
|
setResources(resources: AgentHarnessResources<TSkill, TPromptTemplate>): Promise<void>;
|
|
85
92
|
getStreamOptions(): AgentHarnessStreamOptions;
|
|
86
93
|
setStreamOptions(streamOptions: AgentHarnessStreamOptions): Promise<void>;
|
|
94
|
+
/** Permanently stop this harness instance without deleting its durable session. */
|
|
95
|
+
requestShutdown(): void;
|
|
96
|
+
/** Waits for work active when shutdown was requested to settle. */
|
|
97
|
+
waitForShutdown(): Promise<void>;
|
|
87
98
|
abort(): Promise<AbortResult>;
|
|
88
99
|
waitForIdle(): Promise<void>;
|
|
89
100
|
subscribe(listener: (event: AgentHarnessEvent<TSkill, TPromptTemplate>, signal?: AbortSignal) => Promise<void> | void): () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-harness.d.ts","sourceRoot":"","sources":["../../src/harness/agent-harness.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,gBAAgB,EAErB,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,MAAM,EAIX,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAIX,YAAY,EAEZ,SAAS,EAET,aAAa,EACb,MAAM,aAAa,CAAC;AAMrB,OAAO,KAAK,EACX,WAAW,EACX,iBAAiB,EACjB,0BAA0B,EAC1B,mBAAmB,EACnB,oBAAoB,EAEpB,qBAAqB,EACrB,yBAAyB,EAGzB,gBAAgB,EAEhB,aAAa,EACb,kBAAkB,EAElB,cAAc,EAEd,KAAK,EACL,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-harness.d.ts","sourceRoot":"","sources":["../../src/harness/agent-harness.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,gBAAgB,EAErB,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,MAAM,EAIX,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAIX,YAAY,EAEZ,SAAS,EAET,aAAa,EACb,MAAM,aAAa,CAAC;AAMrB,OAAO,KAAK,EACX,WAAW,EACX,iBAAiB,EACjB,0BAA0B,EAC1B,mBAAmB,EACnB,oBAAoB,EAEpB,qBAAqB,EACrB,yBAAyB,EAGzB,gBAAgB,EAEhB,aAAa,EACb,kBAAkB,EAElB,cAAc,EAEd,KAAK,EACL,MAAM,YAAY,CAAC;AAgJpB,qBAAa,YAAY,CACxB,QAAQ,SAAS,MAAM,GAAG,SAAS,GAAG,SAAS,EAC/C,MAAM,SAAS,KAAK,GAAG,KAAK,EAC5B,eAAe,SAAS,cAAc,GAAG,cAAc,EACvD,KAAK,SAAS,gBAAgB,CAAC,QAAQ,CAAC,GAAG,gBAAgB,CAAC,QAAQ,CAAC;IAErE,OAAO,CAAC,OAAO,CAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,qBAAqB,CAAC,CAAkB;IAChD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6C;IACzE,OAAO,CAAC,eAAe,CAAC,CAAgB;IACxC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,YAAY,CAAiF;IACrG,OAAO,CAAC,WAAW,CAAsD;IACzE,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,SAAS,CAAiD;IAClE,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,eAAe,CAAW;IAClC,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,iBAAiB,CAAY;IACrC,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,iBAAiB,CAAY;IACrC,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,QAAQ,CAA+C;IAE/D,YAAY,OAAO,EAAE,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,KAAK,CAAC,EAwBjF;IAED,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,WAAW;YAIL,OAAO;YAUP,OAAO;YAUP,QAAQ;IAmBtB,OAAO,CAAC,cAAc;YASR,yBAAyB;YA0BzB,yBAAyB;YAiBzB,eAAe;IAS7B,OAAO,CAAC,cAAc;YAoBR,KAAK;YAcL,YAAY;YAUZ,kBAAkB;IAOhC,OAAO,CAAC,eAAe;YAOT,eAAe;IAoC7B,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,cAAc;YA8BR,mBAAmB;IAYjC,OAAO,CAAC,gBAAgB;IA+ExB,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,iBAAiB;YAMX,yBAAyB;YA0BzB,gBAAgB;YA6BhB,cAAc;YAcd,WAAW;IAqEnB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAc3F;IAEK,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,sBAAsB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAoBpF;IAEK,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgBrF;IAEK,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAK9E;IAEK,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAKjF;IAEK,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAIjF;IAEK,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAaxD;IAEK,OAAO,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAyDjE;IAEK,YAAY,CACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3G,OAAO,CAAC,kBAAkB,CAAC,CA+F7B;IAED,QAAQ,IAAI,KAAK,CAAC,GAAG,CAAC,CAErB;IAEK,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB/C;IAED,gBAAgB,IAAI,aAAa,CAEhC;IAEK,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB1D;IAED,QAAQ,IAAI,KAAK,EAAE,CAElB;IAEK,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGxE;YAEa,UAAU;IA+BxB,cAAc,IAAI,KAAK,EAAE,CAExB;IAEK,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvD;YAEa,gBAAgB;IAwB9B,eAAe,IAAI,SAAS,CAE3B;IAEK,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpD;IAED,eAAe,IAAI,SAAS,CAE3B;IAEK,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpD;IAED,YAAY,IAAI,qBAAqB,CAAC,MAAM,EAAE,eAAe,CAAC,CAK7D;IAEK,YAAY,CAAC,SAAS,EAAE,qBAAqB,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ3F;IAED,gBAAgB,IAAI,yBAAyB,CAE5C;IAEK,gBAAgB,CAAC,aAAa,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAG9E;IAED,mFAAmF;IACnF,eAAe,IAAI,IAAI,CAStB;IAED,mEAAmE;IACnE,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAK/B;IAEK,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC,CA4BlC;IAEK,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjC;IAED,SAAS,CACR,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GACzG,MAAM,IAAI,CASZ;IAED,EAAE,CAAC,KAAK,SAAS,MAAM,0BAA0B,EAChD,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,CACR,KAAK,EAAE,OAAO,CAAC,oBAAoB,EAAE;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC,KACjD,OAAO,CAAC,0BAA0B,CAAC,KAAK,CAAC,CAAC,GAAG,0BAA0B,CAAC,KAAK,CAAC,GACjF,MAAM,IAAI,CASZ;CACD"}
|
|
@@ -129,6 +129,8 @@ function normalizeHookError(error) {
|
|
|
129
129
|
export class AgentHarness {
|
|
130
130
|
constructor(options) {
|
|
131
131
|
this.phase = "idle";
|
|
132
|
+
this.activeTasks = new Map();
|
|
133
|
+
this.isShutdown = false;
|
|
132
134
|
this.pendingSessionWrites = [];
|
|
133
135
|
this.tools = new Map();
|
|
134
136
|
this.steerQueue = [];
|
|
@@ -156,6 +158,10 @@ export class AgentHarness {
|
|
|
156
158
|
this.steeringQueueMode = options.steeringMode ?? "one-at-a-time";
|
|
157
159
|
this.followUpQueueMode = options.followUpMode ?? "one-at-a-time";
|
|
158
160
|
}
|
|
161
|
+
assertNotShutDown() {
|
|
162
|
+
if (this.isShutdown)
|
|
163
|
+
throw new AgentHarnessError("invalid_state", "AgentHarness has been shut down");
|
|
164
|
+
}
|
|
159
165
|
getHandlers(type) {
|
|
160
166
|
return this.handlers.get(type);
|
|
161
167
|
}
|
|
@@ -253,16 +259,43 @@ export class AgentHarness {
|
|
|
253
259
|
nextTurn: [...this.nextTurnQueue],
|
|
254
260
|
});
|
|
255
261
|
}
|
|
256
|
-
|
|
262
|
+
startOperation() {
|
|
263
|
+
const abortController = new AbortController();
|
|
257
264
|
let finish = () => { };
|
|
258
|
-
this.
|
|
265
|
+
this.activeAbortController = abortController;
|
|
266
|
+
void this.track("operation", () => new Promise((resolve) => {
|
|
259
267
|
finish = resolve;
|
|
260
|
-
});
|
|
261
|
-
return
|
|
262
|
-
|
|
263
|
-
finish()
|
|
268
|
+
}));
|
|
269
|
+
return {
|
|
270
|
+
signal: abortController.signal,
|
|
271
|
+
finish: () => {
|
|
272
|
+
this.activeAbortController = undefined;
|
|
273
|
+
finish();
|
|
274
|
+
},
|
|
264
275
|
};
|
|
265
276
|
}
|
|
277
|
+
async track(kind, operation) {
|
|
278
|
+
let settle = () => { };
|
|
279
|
+
const settled = new Promise((resolve) => {
|
|
280
|
+
settle = resolve;
|
|
281
|
+
});
|
|
282
|
+
this.activeTasks.set(settled, kind);
|
|
283
|
+
try {
|
|
284
|
+
return await operation();
|
|
285
|
+
}
|
|
286
|
+
finally {
|
|
287
|
+
this.activeTasks.delete(settled);
|
|
288
|
+
settle();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
async waitForTasks(kind) {
|
|
292
|
+
while (true) {
|
|
293
|
+
const tasks = [...this.activeTasks].flatMap(([task, taskKind]) => kind === undefined || kind === taskKind ? [task] : []);
|
|
294
|
+
if (tasks.length === 0)
|
|
295
|
+
return;
|
|
296
|
+
await Promise.all(tasks);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
266
299
|
async resolveToolContext() {
|
|
267
300
|
if (typeof this.toolContext === "function") {
|
|
268
301
|
return await this.toolContext();
|
|
@@ -276,6 +309,7 @@ export class AgentHarness {
|
|
|
276
309
|
};
|
|
277
310
|
}
|
|
278
311
|
async createTurnState() {
|
|
312
|
+
this.assertNotShutDown();
|
|
279
313
|
const context = await this.session.buildContext();
|
|
280
314
|
const resources = this.getResources();
|
|
281
315
|
const sessionMetadata = await this.session.getMetadata();
|
|
@@ -469,7 +503,7 @@ export class AgentHarness {
|
|
|
469
503
|
await this.session.appendSessionName(write.name ?? "");
|
|
470
504
|
}
|
|
471
505
|
else if (write.type === "leaf") {
|
|
472
|
-
await this.session.
|
|
506
|
+
await this.session.moveTo(write.targetId);
|
|
473
507
|
}
|
|
474
508
|
this.pendingSessionWrites.shift();
|
|
475
509
|
}
|
|
@@ -512,7 +546,8 @@ export class AgentHarness {
|
|
|
512
546
|
await this.handleAgentEvent({ type: "agent_end", messages: [failureMessage] }, signal);
|
|
513
547
|
return [failureMessage];
|
|
514
548
|
}
|
|
515
|
-
async executeTurn(turnState, text, options) {
|
|
549
|
+
async executeTurn(turnState, text, signal, options) {
|
|
550
|
+
this.assertNotShutDown();
|
|
516
551
|
let activeTurnState = turnState;
|
|
517
552
|
let messages = [createUserMessage(text, options?.images)];
|
|
518
553
|
if (this.nextTurnQueue.length > 0) {
|
|
@@ -533,21 +568,20 @@ export class AgentHarness {
|
|
|
533
568
|
systemPrompt: turnState.systemPrompt,
|
|
534
569
|
resources: turnState.resources,
|
|
535
570
|
});
|
|
571
|
+
this.assertNotShutDown();
|
|
536
572
|
if (beforeResult?.messages)
|
|
537
573
|
messages = [...messages, ...beforeResult.messages];
|
|
538
|
-
const abortController = new AbortController();
|
|
539
574
|
const getTurnState = () => activeTurnState;
|
|
540
575
|
const setTurnState = (nextTurnState) => {
|
|
541
576
|
activeTurnState = nextTurnState;
|
|
542
577
|
};
|
|
543
|
-
this.runAbortController = abortController;
|
|
544
578
|
const runResultPromise = (async () => {
|
|
545
579
|
try {
|
|
546
|
-
return await runAgentLoop(messages, this.createContext(turnState, beforeResult?.systemPrompt), this.createLoopConfig(getTurnState, setTurnState), (event) => this.handleAgentEvent(event,
|
|
580
|
+
return await runAgentLoop(messages, this.createContext(turnState, beforeResult?.systemPrompt), this.createLoopConfig(getTurnState, setTurnState), (event) => this.handleAgentEvent(event, signal), signal, this.createStreamFn(getTurnState));
|
|
547
581
|
}
|
|
548
582
|
catch (error) {
|
|
549
583
|
try {
|
|
550
|
-
return await this.emitRunFailure(activeTurnState.model, error,
|
|
584
|
+
return await this.emitRunFailure(activeTurnState.model, error, signal.aborted, signal);
|
|
551
585
|
}
|
|
552
586
|
catch (failureError) {
|
|
553
587
|
const cause = new AggregateError([toError(error), toError(failureError)], "Agent run failed and failure reporting failed");
|
|
@@ -566,104 +600,110 @@ export class AgentHarness {
|
|
|
566
600
|
throw new AgentHarnessError("invalid_state", "AgentHarness prompt completed without an assistant message");
|
|
567
601
|
}
|
|
568
602
|
finally {
|
|
569
|
-
|
|
570
|
-
await this.flushPendingSessionWrites();
|
|
571
|
-
}
|
|
572
|
-
finally {
|
|
573
|
-
this.runAbortController = undefined;
|
|
574
|
-
}
|
|
603
|
+
await this.flushPendingSessionWrites();
|
|
575
604
|
}
|
|
576
605
|
}
|
|
577
606
|
async prompt(text, options) {
|
|
607
|
+
this.assertNotShutDown();
|
|
578
608
|
if (this.phase !== "idle")
|
|
579
609
|
throw new AgentHarnessError("busy", "AgentHarness is busy");
|
|
580
610
|
this.phase = "turn";
|
|
581
|
-
const
|
|
611
|
+
const operation = this.startOperation();
|
|
582
612
|
try {
|
|
583
613
|
const turnState = await this.createTurnState();
|
|
584
|
-
return await this.executeTurn(turnState, text, options);
|
|
614
|
+
return await this.executeTurn(turnState, text, operation.signal, options);
|
|
585
615
|
}
|
|
586
616
|
catch (error) {
|
|
587
617
|
this.phase = "idle";
|
|
588
618
|
throw normalizeHarnessError(error, "unknown");
|
|
589
619
|
}
|
|
590
620
|
finally {
|
|
591
|
-
|
|
621
|
+
operation.finish();
|
|
592
622
|
}
|
|
593
623
|
}
|
|
594
624
|
async skill(name, additionalInstructions) {
|
|
625
|
+
this.assertNotShutDown();
|
|
595
626
|
if (this.phase !== "idle")
|
|
596
627
|
throw new AgentHarnessError("busy", "AgentHarness is busy");
|
|
597
628
|
this.phase = "turn";
|
|
598
|
-
const
|
|
629
|
+
const operation = this.startOperation();
|
|
599
630
|
try {
|
|
600
631
|
const turnState = await this.createTurnState();
|
|
601
632
|
const skill = (turnState.resources.skills ?? []).find((candidate) => candidate.name === name);
|
|
602
633
|
if (!skill)
|
|
603
634
|
throw new AgentHarnessError("invalid_argument", `Unknown skill: ${name}`);
|
|
604
|
-
return await this.executeTurn(turnState, formatSkillInvocation(skill, additionalInstructions));
|
|
635
|
+
return await this.executeTurn(turnState, formatSkillInvocation(skill, additionalInstructions), operation.signal);
|
|
605
636
|
}
|
|
606
637
|
catch (error) {
|
|
607
638
|
this.phase = "idle";
|
|
608
639
|
throw normalizeHarnessError(error, "unknown");
|
|
609
640
|
}
|
|
610
641
|
finally {
|
|
611
|
-
|
|
642
|
+
operation.finish();
|
|
612
643
|
}
|
|
613
644
|
}
|
|
614
645
|
async promptFromTemplate(name, args = []) {
|
|
646
|
+
this.assertNotShutDown();
|
|
615
647
|
if (this.phase !== "idle")
|
|
616
648
|
throw new AgentHarnessError("busy", "AgentHarness is busy");
|
|
617
649
|
this.phase = "turn";
|
|
618
|
-
const
|
|
650
|
+
const operation = this.startOperation();
|
|
619
651
|
try {
|
|
620
652
|
const turnState = await this.createTurnState();
|
|
621
653
|
const template = (turnState.resources.promptTemplates ?? []).find((candidate) => candidate.name === name);
|
|
622
654
|
if (!template)
|
|
623
655
|
throw new AgentHarnessError("invalid_argument", `Unknown prompt template: ${name}`);
|
|
624
|
-
return await this.executeTurn(turnState, formatPromptTemplateInvocation(template, args));
|
|
656
|
+
return await this.executeTurn(turnState, formatPromptTemplateInvocation(template, args), operation.signal);
|
|
625
657
|
}
|
|
626
658
|
catch (error) {
|
|
627
659
|
this.phase = "idle";
|
|
628
660
|
throw normalizeHarnessError(error, "unknown");
|
|
629
661
|
}
|
|
630
662
|
finally {
|
|
631
|
-
|
|
663
|
+
operation.finish();
|
|
632
664
|
}
|
|
633
665
|
}
|
|
634
666
|
async steer(text, options) {
|
|
667
|
+
this.assertNotShutDown();
|
|
635
668
|
if (this.phase === "idle")
|
|
636
669
|
throw new AgentHarnessError("invalid_state", "Cannot steer while idle");
|
|
637
670
|
this.steerQueue.push(createUserMessage(text, options?.images));
|
|
638
671
|
await this.emitQueueUpdate();
|
|
639
672
|
}
|
|
640
673
|
async followUp(text, options) {
|
|
674
|
+
this.assertNotShutDown();
|
|
641
675
|
if (this.phase === "idle")
|
|
642
676
|
throw new AgentHarnessError("invalid_state", "Cannot follow up while idle");
|
|
643
677
|
this.followUpQueue.push(createUserMessage(text, options?.images));
|
|
644
678
|
await this.emitQueueUpdate();
|
|
645
679
|
}
|
|
646
680
|
async nextTurn(text, options) {
|
|
681
|
+
this.assertNotShutDown();
|
|
647
682
|
this.nextTurnQueue.push(createUserMessage(text, options?.images));
|
|
648
683
|
await this.emitQueueUpdate();
|
|
649
684
|
}
|
|
650
685
|
async appendMessage(message) {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
686
|
+
this.assertNotShutDown();
|
|
687
|
+
return this.track("mutation", async () => {
|
|
688
|
+
try {
|
|
689
|
+
if (this.phase === "idle") {
|
|
690
|
+
await this.session.appendMessage(message);
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
this.pendingSessionWrites.push({ type: "message", message });
|
|
694
|
+
}
|
|
654
695
|
}
|
|
655
|
-
|
|
656
|
-
|
|
696
|
+
catch (error) {
|
|
697
|
+
throw normalizeHarnessError(error, "session");
|
|
657
698
|
}
|
|
658
|
-
}
|
|
659
|
-
catch (error) {
|
|
660
|
-
throw normalizeHarnessError(error, "session");
|
|
661
|
-
}
|
|
699
|
+
});
|
|
662
700
|
}
|
|
663
701
|
async compact(customInstructions) {
|
|
702
|
+
this.assertNotShutDown();
|
|
664
703
|
if (this.phase !== "idle")
|
|
665
704
|
throw new AgentHarnessError("busy", "compact() requires idle harness");
|
|
666
705
|
this.phase = "compaction";
|
|
706
|
+
const operation = this.startOperation();
|
|
667
707
|
try {
|
|
668
708
|
const model = this.model;
|
|
669
709
|
if (!model)
|
|
@@ -680,17 +720,18 @@ export class AgentHarness {
|
|
|
680
720
|
preparation,
|
|
681
721
|
branchEntries,
|
|
682
722
|
customInstructions,
|
|
683
|
-
signal:
|
|
723
|
+
signal: operation.signal,
|
|
684
724
|
});
|
|
685
725
|
if (hookResult?.cancel)
|
|
686
726
|
throw new AgentHarnessError("compaction", "Compaction cancelled");
|
|
687
727
|
const provided = hookResult?.compaction;
|
|
688
728
|
const compactResult = provided
|
|
689
729
|
? { ok: true, value: provided }
|
|
690
|
-
: await compact(preparation, this.models, model, customInstructions,
|
|
730
|
+
: await compact(preparation, this.models, model, customInstructions, operation.signal, this.thinkingLevel, this.retry, this.retryCallbacks("compaction"));
|
|
691
731
|
if (!compactResult.ok)
|
|
692
732
|
throw compactResult.error;
|
|
693
733
|
const result = compactResult.value;
|
|
734
|
+
this.assertNotShutDown();
|
|
694
735
|
const entryId = await this.session.appendCompaction(result.summary, result.firstKeptEntryId, result.tokensBefore, result.details, provided !== undefined, result.usage, result.retainedTail);
|
|
695
736
|
const entry = await this.session.getEntry(entryId);
|
|
696
737
|
if (entry?.type === "compaction") {
|
|
@@ -703,12 +744,15 @@ export class AgentHarness {
|
|
|
703
744
|
}
|
|
704
745
|
finally {
|
|
705
746
|
this.phase = "idle";
|
|
747
|
+
operation.finish();
|
|
706
748
|
}
|
|
707
749
|
}
|
|
708
750
|
async navigateTree(targetId, options) {
|
|
751
|
+
this.assertNotShutDown();
|
|
709
752
|
if (this.phase !== "idle")
|
|
710
753
|
throw new AgentHarnessError("busy", "navigateTree() requires idle harness");
|
|
711
754
|
this.phase = "branch_summary";
|
|
755
|
+
const operation = this.startOperation();
|
|
712
756
|
try {
|
|
713
757
|
const oldLeafId = await this.session.getLeafId();
|
|
714
758
|
if (oldLeafId === targetId)
|
|
@@ -727,8 +771,11 @@ export class AgentHarness {
|
|
|
727
771
|
replaceInstructions: options?.replaceInstructions,
|
|
728
772
|
label: options?.label,
|
|
729
773
|
};
|
|
730
|
-
const
|
|
731
|
-
|
|
774
|
+
const hookResult = await this.emitHook({
|
|
775
|
+
type: "session_before_tree",
|
|
776
|
+
preparation,
|
|
777
|
+
signal: operation.signal,
|
|
778
|
+
});
|
|
732
779
|
if (hookResult?.cancel)
|
|
733
780
|
return { cancelled: true };
|
|
734
781
|
let summaryEntry;
|
|
@@ -742,7 +789,7 @@ export class AgentHarness {
|
|
|
742
789
|
const branchSummary = await generateBranchSummary(entries, {
|
|
743
790
|
models: this.models,
|
|
744
791
|
model,
|
|
745
|
-
signal:
|
|
792
|
+
signal: operation.signal,
|
|
746
793
|
customInstructions: hookResult?.customInstructions ?? options?.customInstructions,
|
|
747
794
|
replaceInstructions: hookResult?.replaceInstructions ?? options?.replaceInstructions,
|
|
748
795
|
retry: this.retry,
|
|
@@ -773,6 +820,7 @@ export class AgentHarness {
|
|
|
773
820
|
else {
|
|
774
821
|
newLeafId = targetId;
|
|
775
822
|
}
|
|
823
|
+
this.assertNotShutDown();
|
|
776
824
|
const summaryId = await this.session.moveTo(newLeafId, summaryText
|
|
777
825
|
? {
|
|
778
826
|
summary: summaryText,
|
|
@@ -800,50 +848,61 @@ export class AgentHarness {
|
|
|
800
848
|
}
|
|
801
849
|
finally {
|
|
802
850
|
this.phase = "idle";
|
|
851
|
+
operation.finish();
|
|
803
852
|
}
|
|
804
853
|
}
|
|
805
854
|
getModel() {
|
|
806
855
|
return this.model;
|
|
807
856
|
}
|
|
808
857
|
async setModel(model) {
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
858
|
+
this.assertNotShutDown();
|
|
859
|
+
return this.track("mutation", async () => {
|
|
860
|
+
try {
|
|
861
|
+
const previousModel = this.model;
|
|
862
|
+
if (this.phase === "idle") {
|
|
863
|
+
await this.session.appendModelChange(model.provider, model.id);
|
|
864
|
+
}
|
|
865
|
+
else {
|
|
866
|
+
this.pendingSessionWrites.push({ type: "model_change", provider: model.provider, modelId: model.id });
|
|
867
|
+
}
|
|
868
|
+
this.model = model;
|
|
869
|
+
await this.emitOwn({ type: "model_update", model, previousModel, source: "set" });
|
|
813
870
|
}
|
|
814
|
-
|
|
815
|
-
|
|
871
|
+
catch (error) {
|
|
872
|
+
throw normalizeHarnessError(error, "session");
|
|
816
873
|
}
|
|
817
|
-
|
|
818
|
-
await this.emitOwn({ type: "model_update", model, previousModel, source: "set" });
|
|
819
|
-
}
|
|
820
|
-
catch (error) {
|
|
821
|
-
throw normalizeHarnessError(error, "session");
|
|
822
|
-
}
|
|
874
|
+
});
|
|
823
875
|
}
|
|
824
876
|
getThinkingLevel() {
|
|
825
877
|
return this.thinkingLevel;
|
|
826
878
|
}
|
|
827
879
|
async setThinkingLevel(level) {
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
880
|
+
this.assertNotShutDown();
|
|
881
|
+
return this.track("mutation", async () => {
|
|
882
|
+
try {
|
|
883
|
+
const previousLevel = this.thinkingLevel;
|
|
884
|
+
if (this.phase === "idle") {
|
|
885
|
+
await this.session.appendThinkingLevelChange(level);
|
|
886
|
+
}
|
|
887
|
+
else {
|
|
888
|
+
this.pendingSessionWrites.push({ type: "thinking_level_change", thinkingLevel: level });
|
|
889
|
+
}
|
|
890
|
+
this.thinkingLevel = level;
|
|
891
|
+
await this.emitOwn({ type: "thinking_level_update", level, previousLevel });
|
|
832
892
|
}
|
|
833
|
-
|
|
834
|
-
|
|
893
|
+
catch (error) {
|
|
894
|
+
throw normalizeHarnessError(error, "session");
|
|
835
895
|
}
|
|
836
|
-
|
|
837
|
-
await this.emitOwn({ type: "thinking_level_update", level, previousLevel });
|
|
838
|
-
}
|
|
839
|
-
catch (error) {
|
|
840
|
-
throw normalizeHarnessError(error, "session");
|
|
841
|
-
}
|
|
896
|
+
});
|
|
842
897
|
}
|
|
843
898
|
getTools() {
|
|
844
899
|
return [...this.tools.values()];
|
|
845
900
|
}
|
|
846
901
|
async setTools(tools, activeToolNames) {
|
|
902
|
+
this.assertNotShutDown();
|
|
903
|
+
return this.track("mutation", () => this.applyTools(tools, activeToolNames));
|
|
904
|
+
}
|
|
905
|
+
async applyTools(tools, activeToolNames) {
|
|
847
906
|
try {
|
|
848
907
|
this.validateUniqueNames(tools.map((tool) => tool.name), "Duplicate tool name(s)");
|
|
849
908
|
const nextTools = new Map(tools.map((tool) => [tool.name, tool]));
|
|
@@ -876,6 +935,10 @@ export class AgentHarness {
|
|
|
876
935
|
return this.activeToolNames.map((name) => this.tools.get(name));
|
|
877
936
|
}
|
|
878
937
|
async setActiveTools(toolNames) {
|
|
938
|
+
this.assertNotShutDown();
|
|
939
|
+
return this.track("mutation", () => this.applyActiveTools(toolNames));
|
|
940
|
+
}
|
|
941
|
+
async applyActiveTools(toolNames) {
|
|
879
942
|
try {
|
|
880
943
|
this.validateToolNames(toolNames);
|
|
881
944
|
const previousToolNames = [...this.tools.keys()];
|
|
@@ -904,12 +967,14 @@ export class AgentHarness {
|
|
|
904
967
|
return this.steeringQueueMode;
|
|
905
968
|
}
|
|
906
969
|
async setSteeringMode(mode) {
|
|
970
|
+
this.assertNotShutDown();
|
|
907
971
|
this.steeringQueueMode = mode;
|
|
908
972
|
}
|
|
909
973
|
getFollowUpMode() {
|
|
910
974
|
return this.followUpQueueMode;
|
|
911
975
|
}
|
|
912
976
|
async setFollowUpMode(mode) {
|
|
977
|
+
this.assertNotShutDown();
|
|
913
978
|
this.followUpQueueMode = mode;
|
|
914
979
|
}
|
|
915
980
|
getResources() {
|
|
@@ -919,6 +984,7 @@ export class AgentHarness {
|
|
|
919
984
|
};
|
|
920
985
|
}
|
|
921
986
|
async setResources(resources) {
|
|
987
|
+
this.assertNotShutDown();
|
|
922
988
|
const previousResources = this.getResources();
|
|
923
989
|
this.resources = {
|
|
924
990
|
skills: resources.skills?.slice(),
|
|
@@ -930,14 +996,35 @@ export class AgentHarness {
|
|
|
930
996
|
return cloneStreamOptions(this.streamOptions);
|
|
931
997
|
}
|
|
932
998
|
async setStreamOptions(streamOptions) {
|
|
999
|
+
this.assertNotShutDown();
|
|
933
1000
|
this.streamOptions = cloneStreamOptions(streamOptions);
|
|
934
1001
|
}
|
|
1002
|
+
/** Permanently stop this harness instance without deleting its durable session. */
|
|
1003
|
+
requestShutdown() {
|
|
1004
|
+
if (this.isShutdown)
|
|
1005
|
+
return;
|
|
1006
|
+
this.isShutdown = true;
|
|
1007
|
+
this.pendingSessionWrites = [];
|
|
1008
|
+
this.steerQueue = [];
|
|
1009
|
+
this.followUpQueue = [];
|
|
1010
|
+
this.nextTurnQueue = [];
|
|
1011
|
+
this.activeAbortController?.abort();
|
|
1012
|
+
this.shutdownPromise = this.waitForTasks();
|
|
1013
|
+
}
|
|
1014
|
+
/** Waits for work active when shutdown was requested to settle. */
|
|
1015
|
+
waitForShutdown() {
|
|
1016
|
+
if (!this.shutdownPromise) {
|
|
1017
|
+
return Promise.reject(new AgentHarnessError("invalid_state", "Shutdown has not been requested"));
|
|
1018
|
+
}
|
|
1019
|
+
return this.shutdownPromise;
|
|
1020
|
+
}
|
|
935
1021
|
async abort() {
|
|
1022
|
+
this.assertNotShutDown();
|
|
936
1023
|
const clearedSteer = [...this.steerQueue];
|
|
937
1024
|
const clearedFollowUp = [...this.followUpQueue];
|
|
938
1025
|
this.steerQueue = [];
|
|
939
1026
|
this.followUpQueue = [];
|
|
940
|
-
this.
|
|
1027
|
+
this.activeAbortController?.abort();
|
|
941
1028
|
const errors = [];
|
|
942
1029
|
try {
|
|
943
1030
|
await this.emitQueueUpdate();
|
|
@@ -964,9 +1051,10 @@ export class AgentHarness {
|
|
|
964
1051
|
return { clearedSteer, clearedFollowUp };
|
|
965
1052
|
}
|
|
966
1053
|
async waitForIdle() {
|
|
967
|
-
await this.
|
|
1054
|
+
await this.waitForTasks("operation");
|
|
968
1055
|
}
|
|
969
1056
|
subscribe(listener) {
|
|
1057
|
+
this.assertNotShutDown();
|
|
970
1058
|
let handlers = this.handlers.get(SUBSCRIBER_EVENT_TYPE);
|
|
971
1059
|
if (!handlers) {
|
|
972
1060
|
handlers = new Set();
|
|
@@ -976,6 +1064,7 @@ export class AgentHarness {
|
|
|
976
1064
|
return () => handlers.delete(listener);
|
|
977
1065
|
}
|
|
978
1066
|
on(type, handler) {
|
|
1067
|
+
this.assertNotShutDown();
|
|
979
1068
|
let handlers = this.handlers.get(type);
|
|
980
1069
|
if (!handlers) {
|
|
981
1070
|
handlers = new Set();
|