@elyracode/agent-core 0.1.0
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/README.md +488 -0
- package/dist/agent-loop.d.ts +24 -0
- package/dist/agent-loop.d.ts.map +1 -0
- package/dist/agent-loop.js +479 -0
- package/dist/agent-loop.js.map +1 -0
- package/dist/agent.d.ts +118 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +402 -0
- package/dist/agent.js.map +1 -0
- package/dist/harness/agent-harness.d.ts +78 -0
- package/dist/harness/agent-harness.d.ts.map +1 -0
- package/dist/harness/agent-harness.js +602 -0
- package/dist/harness/agent-harness.js.map +1 -0
- package/dist/harness/compaction/branch-summarization.d.ts +88 -0
- package/dist/harness/compaction/branch-summarization.d.ts.map +1 -0
- package/dist/harness/compaction/branch-summarization.js +243 -0
- package/dist/harness/compaction/branch-summarization.js.map +1 -0
- package/dist/harness/compaction/compaction.d.ts +122 -0
- package/dist/harness/compaction/compaction.d.ts.map +1 -0
- package/dist/harness/compaction/compaction.js +616 -0
- package/dist/harness/compaction/compaction.js.map +1 -0
- package/dist/harness/compaction/utils.d.ts +38 -0
- package/dist/harness/compaction/utils.d.ts.map +1 -0
- package/dist/harness/compaction/utils.js +153 -0
- package/dist/harness/compaction/utils.js.map +1 -0
- package/dist/harness/env/nodejs.d.ts +44 -0
- package/dist/harness/env/nodejs.d.ts.map +1 -0
- package/dist/harness/env/nodejs.js +348 -0
- package/dist/harness/env/nodejs.js.map +1 -0
- package/dist/harness/execution-env.d.ts +4 -0
- package/dist/harness/execution-env.d.ts.map +1 -0
- package/dist/harness/execution-env.js +3 -0
- package/dist/harness/execution-env.js.map +1 -0
- package/dist/harness/messages.d.ts +51 -0
- package/dist/harness/messages.d.ts.map +1 -0
- package/dist/harness/messages.js +102 -0
- package/dist/harness/messages.js.map +1 -0
- package/dist/harness/prompt-templates.d.ts +45 -0
- package/dist/harness/prompt-templates.d.ts.map +1 -0
- package/dist/harness/prompt-templates.js +200 -0
- package/dist/harness/prompt-templates.js.map +1 -0
- package/dist/harness/session/repo/jsonl.d.ts +20 -0
- package/dist/harness/session/repo/jsonl.d.ts.map +1 -0
- package/dist/harness/session/repo/jsonl.js +92 -0
- package/dist/harness/session/repo/jsonl.js.map +1 -0
- package/dist/harness/session/repo/memory.d.ts +18 -0
- package/dist/harness/session/repo/memory.d.ts.map +1 -0
- package/dist/harness/session/repo/memory.js +42 -0
- package/dist/harness/session/repo/memory.js.map +1 -0
- package/dist/harness/session/repo/shared.d.ts +10 -0
- package/dist/harness/session/repo/shared.d.ts.map +1 -0
- package/dist/harness/session/repo/shared.js +31 -0
- package/dist/harness/session/repo/shared.js.map +1 -0
- package/dist/harness/session/session.d.ts +32 -0
- package/dist/harness/session/session.d.ts.map +1 -0
- package/dist/harness/session/session.js +196 -0
- package/dist/harness/session/session.js.map +1 -0
- package/dist/harness/session/storage/jsonl.d.ts +30 -0
- package/dist/harness/session/storage/jsonl.d.ts.map +1 -0
- package/dist/harness/session/storage/jsonl.js +170 -0
- package/dist/harness/session/storage/jsonl.js.map +1 -0
- package/dist/harness/session/storage/memory.d.ts +26 -0
- package/dist/harness/session/storage/memory.d.ts.map +1 -0
- package/dist/harness/session/storage/memory.js +90 -0
- package/dist/harness/session/storage/memory.js.map +1 -0
- package/dist/harness/skills.d.ts +41 -0
- package/dist/harness/skills.d.ts.map +1 -0
- package/dist/harness/skills.js +259 -0
- package/dist/harness/skills.js.map +1 -0
- package/dist/harness/system-prompt.d.ts +3 -0
- package/dist/harness/system-prompt.d.ts.map +1 -0
- package/dist/harness/system-prompt.js +30 -0
- package/dist/harness/system-prompt.js.map +1 -0
- package/dist/harness/types.d.ts +497 -0
- package/dist/harness/types.d.ts.map +1 -0
- package/dist/harness/types.js +16 -0
- package/dist/harness/types.js.map +1 -0
- package/dist/harness/utils/shell-output.d.ts +14 -0
- package/dist/harness/utils/shell-output.d.ts.map +1 -0
- package/dist/harness/utils/shell-output.js +97 -0
- package/dist/harness/utils/shell-output.js.map +1 -0
- package/dist/harness/utils/truncate.d.ts +70 -0
- package/dist/harness/utils/truncate.d.ts.map +1 -0
- package/dist/harness/utils/truncate.js +205 -0
- package/dist/harness/utils/truncate.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/proxy.d.ts +69 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +278 -0
- package/dist/proxy.js.map +1 -0
- package/dist/types.d.ts +386 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { AssistantMessage, ImageContent, Model } from "@elyracode/ai";
|
|
2
|
+
import { Agent, type QueueMode } from "../agent.js";
|
|
3
|
+
import type { AgentMessage, AgentTool, ThinkingLevel } from "../types.js";
|
|
4
|
+
import type { AbortResult, AgentHarnessEvent, AgentHarnessEventResultMap, AgentHarnessOptions, AgentHarnessOwnEvent, AgentHarnessResources, ExecutionEnv, NavigateTreeResult, PromptTemplate, Skill } from "./types.js";
|
|
5
|
+
export declare class AgentHarness<TSkill extends Skill = Skill, TPromptTemplate extends PromptTemplate = PromptTemplate, TTool extends AgentTool = AgentTool> {
|
|
6
|
+
readonly agent: Agent;
|
|
7
|
+
readonly env: ExecutionEnv;
|
|
8
|
+
private session;
|
|
9
|
+
private model;
|
|
10
|
+
private thinkingLevel;
|
|
11
|
+
private activeToolNames;
|
|
12
|
+
private nextTurnQueue;
|
|
13
|
+
private phase;
|
|
14
|
+
private steerQueue;
|
|
15
|
+
private followUpQueue;
|
|
16
|
+
private pendingSessionWrites;
|
|
17
|
+
private resources;
|
|
18
|
+
private systemPrompt;
|
|
19
|
+
private getApiKeyAndHeaders?;
|
|
20
|
+
private tools;
|
|
21
|
+
private listeners;
|
|
22
|
+
private hooks;
|
|
23
|
+
constructor(options: AgentHarnessOptions<TSkill, TPromptTemplate, TTool>);
|
|
24
|
+
private emitOwn;
|
|
25
|
+
private emitAny;
|
|
26
|
+
private emitHook;
|
|
27
|
+
private emitQueueUpdate;
|
|
28
|
+
private createTurnState;
|
|
29
|
+
private applyTurnState;
|
|
30
|
+
private validateToolNames;
|
|
31
|
+
private flushPendingSessionWrites;
|
|
32
|
+
private handleAgentEvent;
|
|
33
|
+
private executeTurn;
|
|
34
|
+
prompt(text: string, options?: {
|
|
35
|
+
images?: ImageContent[];
|
|
36
|
+
}): Promise<AssistantMessage>;
|
|
37
|
+
skill(name: string, additionalInstructions?: string): Promise<AssistantMessage>;
|
|
38
|
+
promptFromTemplate(name: string, args?: string[]): Promise<AssistantMessage>;
|
|
39
|
+
steer(text: string, options?: {
|
|
40
|
+
images?: ImageContent[];
|
|
41
|
+
}): void;
|
|
42
|
+
followUp(text: string, options?: {
|
|
43
|
+
images?: ImageContent[];
|
|
44
|
+
}): void;
|
|
45
|
+
nextTurn(text: string, options?: {
|
|
46
|
+
images?: ImageContent[];
|
|
47
|
+
}): void;
|
|
48
|
+
appendMessage(message: AgentMessage): Promise<void>;
|
|
49
|
+
compact(customInstructions?: string): Promise<{
|
|
50
|
+
summary: string;
|
|
51
|
+
firstKeptEntryId: string;
|
|
52
|
+
tokensBefore: number;
|
|
53
|
+
details?: unknown;
|
|
54
|
+
}>;
|
|
55
|
+
navigateTree(targetId: string, options?: {
|
|
56
|
+
summarize?: boolean;
|
|
57
|
+
customInstructions?: string;
|
|
58
|
+
replaceInstructions?: boolean;
|
|
59
|
+
label?: string;
|
|
60
|
+
}): Promise<NavigateTreeResult>;
|
|
61
|
+
setModel(model: Model<any>): Promise<void>;
|
|
62
|
+
setThinkingLevel(level: ThinkingLevel): Promise<void>;
|
|
63
|
+
setActiveTools(toolNames: string[]): Promise<void>;
|
|
64
|
+
get steeringMode(): QueueMode;
|
|
65
|
+
set steeringMode(mode: QueueMode);
|
|
66
|
+
get followUpMode(): QueueMode;
|
|
67
|
+
set followUpMode(mode: QueueMode);
|
|
68
|
+
getResources(): AgentHarnessResources<TSkill, TPromptTemplate>;
|
|
69
|
+
setResources(resources: AgentHarnessResources<TSkill, TPromptTemplate>): Promise<void>;
|
|
70
|
+
setTools(tools: TTool[], activeToolNames?: string[]): Promise<void>;
|
|
71
|
+
abort(): Promise<AbortResult>;
|
|
72
|
+
waitForIdle(): Promise<void>;
|
|
73
|
+
subscribe(listener: (event: AgentHarnessEvent<TSkill, TPromptTemplate>, signal?: AbortSignal) => Promise<void> | void): () => void;
|
|
74
|
+
on<TType extends keyof AgentHarnessEventResultMap>(type: TType, handler: (event: Extract<AgentHarnessOwnEvent, {
|
|
75
|
+
type: TType;
|
|
76
|
+
}>) => Promise<AgentHarnessEventResultMap[TType]> | AgentHarnessEventResultMap[TType]): () => void;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=agent-harness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-harness.d.ts","sourceRoot":"","sources":["../../src/harness/agent-harness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,EAAe,MAAM,eAAe,CAAC;AACxF,OAAO,EAAE,KAAK,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAc,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAKtF,OAAO,KAAK,EACX,WAAW,EACX,iBAAiB,EACjB,0BAA0B,EAC1B,mBAAmB,EACnB,oBAAoB,EAEpB,qBAAqB,EAErB,YAAY,EACZ,kBAAkB,EAElB,cAAc,EAEd,KAAK,EACL,MAAM,YAAY,CAAC;AAQpB,qBAAa,YAAY,CACxB,MAAM,SAAS,KAAK,GAAG,KAAK,EAC5B,eAAe,SAAS,cAAc,GAAG,cAAc,EACvD,KAAK,SAAS,SAAS,GAAG,SAAS;IAEnC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,eAAe,CAAW;IAClC,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,SAAS,CAAiD;IAClE,OAAO,CAAC,YAAY,CAAsE;IAC1F,OAAO,CAAC,mBAAmB,CAAC,CAA6C;IACzE,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,SAAS,CAEb;IACJ,OAAO,CAAC,KAAK,CAAwF;IAErG,YAAY,OAAO,EAAE,mBAAmB,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,CAAC,EAgFvE;YAEa,OAAO;YAMP,OAAO;YAMP,QAAQ;YAeR,eAAe;YASf,eAAe;IA+B7B,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,iBAAiB;YAKX,yBAAyB;YAsBzB,gBAAgB;YAiChB,WAAW;IAwCnB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAU3F;IAEK,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,sBAAsB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAYpF;IAEK,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAYrF;IAED,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;KAAE,GAAG,IAAI,CAM/D;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;KAAE,GAAG,IAAI,CAMlE;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;KAAE,GAAG,IAAI,CAGlE;IAEK,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAMxD;IAEK,OAAO,CACZ,kBAAkB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CA8CjG;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,CAwG7B;IAEK,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAU/C;IAEK,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAU1D;IAEK,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvD;IAED,IAAI,YAAY,IAAI,SAAS,CAE5B;IAED,IAAI,YAAY,CAAC,IAAI,EAAE,SAAS,EAE/B;IAED,IAAI,YAAY,IAAI,SAAS,CAE5B;IAED,IAAI,YAAY,CAAC,IAAI,EAAE,SAAS,EAE/B;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,CAO3F;IAEK,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAWxE;IAEK,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC,CAWlC;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,CAGZ;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,CAQZ;CACD","sourcesContent":["import type { AssistantMessage, ImageContent, Model, UserMessage } from \"@elyracode/ai\";\nimport { Agent, type QueueMode } from \"../agent.js\";\nimport type { AgentEvent, AgentMessage, AgentTool, ThinkingLevel } from \"../types.js\";\nimport { collectEntriesForBranchSummary, generateBranchSummary } from \"./compaction/branch-summarization.js\";\nimport { compact, DEFAULT_COMPACTION_SETTINGS, prepareCompaction } from \"./compaction/compaction.js\";\nimport { formatPromptTemplateInvocation } from \"./prompt-templates.js\";\nimport { formatSkillInvocation } from \"./skills.js\";\nimport type {\n\tAbortResult,\n\tAgentHarnessEvent,\n\tAgentHarnessEventResultMap,\n\tAgentHarnessOptions,\n\tAgentHarnessOwnEvent,\n\tAgentHarnessPhase,\n\tAgentHarnessResources,\n\tAgentHarnessTurnState,\n\tExecutionEnv,\n\tNavigateTreeResult,\n\tPendingSessionWrite,\n\tPromptTemplate,\n\tSession,\n\tSkill,\n} from \"./types.js\";\n\nfunction createUserMessage(text: string, images?: ImageContent[]): UserMessage {\n\tconst content: Array<{ type: \"text\"; text: string } | ImageContent> = [{ type: \"text\", text }];\n\tif (images) content.push(...images);\n\treturn { role: \"user\", content, timestamp: Date.now() };\n}\n\nexport class AgentHarness<\n\tTSkill extends Skill = Skill,\n\tTPromptTemplate extends PromptTemplate = PromptTemplate,\n\tTTool extends AgentTool = AgentTool,\n> {\n\treadonly agent: Agent;\n\treadonly env: ExecutionEnv;\n\tprivate session: Session;\n\tprivate model: Model<any>;\n\tprivate thinkingLevel: ThinkingLevel;\n\tprivate activeToolNames: string[];\n\tprivate nextTurnQueue: AgentMessage[] = [];\n\tprivate phase: AgentHarnessPhase = \"idle\";\n\tprivate steerQueue: UserMessage[] = [];\n\tprivate followUpQueue: UserMessage[] = [];\n\tprivate pendingSessionWrites: PendingSessionWrite[] = [];\n\tprivate resources: AgentHarnessResources<TSkill, TPromptTemplate>;\n\tprivate systemPrompt: AgentHarnessOptions<TSkill, TPromptTemplate, TTool>[\"systemPrompt\"];\n\tprivate getApiKeyAndHeaders?: AgentHarnessOptions[\"getApiKeyAndHeaders\"];\n\tprivate tools = new Map<string, TTool>();\n\tprivate listeners = new Set<\n\t\t(event: AgentHarnessEvent<TSkill, TPromptTemplate>, signal?: AbortSignal) => Promise<void> | void\n\t>();\n\tprivate hooks = new Map<keyof AgentHarnessEventResultMap, Set<(event: any) => Promise<any> | any>>();\n\n\tconstructor(options: AgentHarnessOptions<TSkill, TPromptTemplate, TTool>) {\n\t\tthis.agent = new Agent({\n\t\t\tinitialState: {\n\t\t\t\tmodel: options.model,\n\t\t\t\tthinkingLevel: options.thinkingLevel,\n\t\t\t\ttools: options.tools ?? [],\n\t\t\t},\n\t\t\tsteeringMode: options.steeringMode,\n\t\t\tfollowUpMode: options.followUpMode,\n\t\t});\n\t\tthis.env = options.env;\n\t\tthis.session = options.session;\n\t\tthis.resources = options.resources ?? {};\n\t\tthis.systemPrompt = options.systemPrompt;\n\t\tthis.getApiKeyAndHeaders = options.getApiKeyAndHeaders;\n\t\tfor (const tool of options.tools ?? []) {\n\t\t\tthis.tools.set(tool.name, tool);\n\t\t}\n\t\tthis.model = options.model;\n\t\tthis.thinkingLevel = options.thinkingLevel ?? this.agent.state.thinkingLevel;\n\t\tthis.activeToolNames = options.activeToolNames ?? (options.tools ?? []).map((tool) => tool.name);\n\t\tthis.agent.state.model = this.model;\n\t\tthis.agent.state.thinkingLevel = this.thinkingLevel;\n\t\tthis.agent.getApiKey = async (provider) => {\n\t\t\tconst model = this.model;\n\t\t\tif (!this.getApiKeyAndHeaders || model.provider !== provider) return undefined;\n\t\t\treturn (await this.getApiKeyAndHeaders(model))?.apiKey;\n\t\t};\n\t\tthis.agent.transformContext = async (messages) => {\n\t\t\tconst result = await this.emitHook({ type: \"context\", messages: [...messages] });\n\t\t\treturn result?.messages ?? messages;\n\t\t};\n\t\tthis.agent.beforeToolCall = async ({ toolCall, args }) => {\n\t\t\tconst result = await this.emitHook({\n\t\t\t\ttype: \"tool_call\",\n\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\ttoolName: toolCall.name,\n\t\t\t\tinput: args as Record<string, unknown>,\n\t\t\t});\n\t\t\treturn result ? { block: result.block, reason: result.reason } : undefined;\n\t\t};\n\t\tthis.agent.afterToolCall = async ({ toolCall, args, result, isError }) => {\n\t\t\tconst patch = await this.emitHook({\n\t\t\t\ttype: \"tool_result\",\n\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\ttoolName: toolCall.name,\n\t\t\t\tinput: args as Record<string, unknown>,\n\t\t\t\tcontent: result.content,\n\t\t\t\tdetails: result.details,\n\t\t\t\tisError,\n\t\t\t});\n\t\t\treturn patch\n\t\t\t\t? { content: patch.content, details: patch.details, isError: patch.isError, terminate: patch.terminate }\n\t\t\t\t: undefined;\n\t\t};\n\t\tthis.agent.onPayload = async (payload) => {\n\t\t\tconst result = await this.emitHook({ type: \"before_provider_request\", payload });\n\t\t\treturn result?.payload ?? payload;\n\t\t};\n\t\tthis.agent.onResponse = async (response) => {\n\t\t\tconst headers = { ...(response.headers as Record<string, string>) };\n\t\t\tawait this.emitOwn({ type: \"after_provider_response\", status: response.status, headers }, this.agent.signal);\n\t\t};\n\t\tthis.agent.prepareNextTurn = async () => {\n\t\t\tawait this.flushPendingSessionWrites();\n\t\t\tconst turnState = await this.createTurnState();\n\t\t\tthis.applyTurnState(turnState);\n\t\t\treturn {\n\t\t\t\tcontext: {\n\t\t\t\t\tsystemPrompt: turnState.systemPrompt,\n\t\t\t\t\tmessages: turnState.messages.slice(),\n\t\t\t\t\ttools: turnState.activeTools.slice(),\n\t\t\t\t},\n\t\t\t\tmodel: turnState.model,\n\t\t\t\tthinkingLevel: turnState.thinkingLevel,\n\t\t\t};\n\t\t};\n\t\tthis.agent.subscribe(async (event, signal) => {\n\t\t\tawait this.handleAgentEvent(event, signal);\n\t\t});\n\t}\n\n\tprivate async emitOwn(event: AgentHarnessOwnEvent<TSkill, TPromptTemplate>, signal?: AbortSignal): Promise<void> {\n\t\tfor (const listener of this.listeners) {\n\t\t\tawait listener(event, signal);\n\t\t}\n\t}\n\n\tprivate async emitAny(event: AgentHarnessEvent<TSkill, TPromptTemplate>, signal?: AbortSignal): Promise<void> {\n\t\tfor (const listener of this.listeners) {\n\t\t\tawait listener(event, signal);\n\t\t}\n\t}\n\n\tprivate async emitHook<TType extends keyof AgentHarnessEventResultMap>(\n\t\tevent: Extract<AgentHarnessOwnEvent, { type: TType }>,\n\t): Promise<AgentHarnessEventResultMap[TType] | undefined> {\n\t\tconst handlers = this.hooks.get(event.type as TType);\n\t\tif (!handlers || handlers.size === 0) return undefined;\n\t\tlet lastResult: AgentHarnessEventResultMap[TType] | undefined;\n\t\tfor (const handler of handlers) {\n\t\t\tconst result = await handler(event);\n\t\t\tif (result !== undefined) {\n\t\t\t\tlastResult = result;\n\t\t\t}\n\t\t}\n\t\treturn lastResult;\n\t}\n\n\tprivate async emitQueueUpdate(): Promise<void> {\n\t\tawait this.emitOwn({\n\t\t\ttype: \"queue_update\",\n\t\t\tsteer: [...this.steerQueue],\n\t\t\tfollowUp: [...this.followUpQueue],\n\t\t\tnextTurn: [...this.nextTurnQueue],\n\t\t});\n\t}\n\n\tprivate async createTurnState(): Promise<AgentHarnessTurnState<TSkill, TPromptTemplate, TTool>> {\n\t\tconst context = await this.session.buildContext();\n\t\tconst resources = this.getResources();\n\t\tconst tools = [...this.tools.values()];\n\t\tconst activeTools = this.activeToolNames\n\t\t\t.map((name) => this.tools.get(name))\n\t\t\t.filter((tool): tool is TTool => tool !== undefined);\n\t\tlet systemPrompt = \"You are a helpful assistant.\";\n\t\tif (typeof this.systemPrompt === \"string\") {\n\t\t\tsystemPrompt = this.systemPrompt;\n\t\t} else if (this.systemPrompt) {\n\t\t\tsystemPrompt = await this.systemPrompt({\n\t\t\t\tenv: this.env,\n\t\t\t\tsession: this.session,\n\t\t\t\tmodel: this.model,\n\t\t\t\tthinkingLevel: this.thinkingLevel,\n\t\t\t\tactiveTools,\n\t\t\t\tresources,\n\t\t\t});\n\t\t}\n\t\treturn {\n\t\t\tmessages: context.messages,\n\t\t\tresources,\n\t\t\tsystemPrompt,\n\t\t\tmodel: this.model,\n\t\t\tthinkingLevel: this.thinkingLevel,\n\t\t\ttools,\n\t\t\tactiveTools,\n\t\t};\n\t}\n\n\tprivate applyTurnState(turnState: AgentHarnessTurnState<TSkill, TPromptTemplate, TTool>): void {\n\t\tthis.agent.state.messages = turnState.messages;\n\t\tthis.agent.state.systemPrompt = turnState.systemPrompt;\n\t\tthis.agent.state.model = turnState.model;\n\t\tthis.agent.state.thinkingLevel = turnState.thinkingLevel;\n\t\tthis.agent.state.tools = turnState.activeTools;\n\t}\n\n\tprivate validateToolNames(toolNames: string[]): void {\n\t\tconst missing = toolNames.filter((name) => !this.tools.has(name));\n\t\tif (missing.length > 0) throw new Error(`Unknown tool(s): ${missing.join(\", \")}`);\n\t}\n\n\tprivate async flushPendingSessionWrites(): Promise<void> {\n\t\tconst writes = this.pendingSessionWrites;\n\t\tthis.pendingSessionWrites = [];\n\t\tfor (const write of writes) {\n\t\t\tif (write.type === \"message\") {\n\t\t\t\tawait this.session.appendMessage(write.message);\n\t\t\t} else if (write.type === \"model_change\") {\n\t\t\t\tawait this.session.appendModelChange(write.provider, write.modelId);\n\t\t\t} else if (write.type === \"thinking_level_change\") {\n\t\t\t\tawait this.session.appendThinkingLevelChange(write.thinkingLevel);\n\t\t\t} else if (write.type === \"custom\") {\n\t\t\t\tawait this.session.appendCustomEntry(write.customType, write.data);\n\t\t\t} else if (write.type === \"custom_message\") {\n\t\t\t\tawait this.session.appendCustomMessageEntry(write.customType, write.content, write.display, write.details);\n\t\t\t} else if (write.type === \"label\") {\n\t\t\t\tawait this.session.appendLabel(write.targetId, write.label);\n\t\t\t} else if (write.type === \"session_info\") {\n\t\t\t\tawait this.session.appendSessionName(write.name ?? \"\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async handleAgentEvent(event: AgentEvent, signal?: AbortSignal): Promise<void> {\n\t\tawait this.emitAny(event, signal);\n\t\tif (event.type === \"message_start\" && event.message.role === \"user\") {\n\t\t\tconst steerIndex = this.steerQueue.indexOf(event.message);\n\t\t\tif (steerIndex !== -1) {\n\t\t\t\tthis.steerQueue.splice(steerIndex, 1);\n\t\t\t\tawait this.emitQueueUpdate();\n\t\t\t} else {\n\t\t\t\tconst followUpIndex = this.followUpQueue.indexOf(event.message);\n\t\t\t\tif (followUpIndex !== -1) {\n\t\t\t\t\tthis.followUpQueue.splice(followUpIndex, 1);\n\t\t\t\t\tawait this.emitQueueUpdate();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (event.type === \"message_end\") {\n\t\t\tawait this.session.appendMessage(event.message);\n\t\t}\n\t\tif (event.type === \"turn_end\") {\n\t\t\tconst hadPendingMutations = this.pendingSessionWrites.length > 0;\n\t\t\tawait this.flushPendingSessionWrites();\n\t\t\tawait this.emitOwn({\n\t\t\t\ttype: \"save_point\",\n\t\t\t\thadPendingMutations,\n\t\t\t});\n\t\t}\n\t\tif (event.type === \"agent_end\") {\n\t\t\tawait this.flushPendingSessionWrites();\n\t\t\tthis.phase = \"idle\";\n\t\t\tawait this.emitOwn({ type: \"settled\", nextTurnCount: this.nextTurnQueue.length }, signal);\n\t\t}\n\t}\n\n\tprivate async executeTurn(\n\t\tturnState: AgentHarnessTurnState<TSkill, TPromptTemplate, TTool>,\n\t\ttext: string,\n\t\toptions?: { images?: ImageContent[] },\n\t): Promise<AssistantMessage> {\n\t\tthis.applyTurnState(turnState);\n\t\tconst beforeLength = this.agent.state.messages.length;\n\t\tlet messages: AgentMessage[] = [createUserMessage(text, options?.images)];\n\t\tif (this.nextTurnQueue.length > 0) {\n\t\t\tmessages = [...this.nextTurnQueue, messages[0]!];\n\t\t\tthis.nextTurnQueue = [];\n\t\t\tawait this.emitQueueUpdate();\n\t\t}\n\t\tconst beforeResult = await this.emitHook({\n\t\t\ttype: \"before_agent_start\",\n\t\t\tprompt: text,\n\t\t\timages: options?.images,\n\t\t\tsystemPrompt: turnState.systemPrompt,\n\t\t\tresources: turnState.resources,\n\t\t});\n\t\tif (beforeResult?.messages) messages = [...beforeResult.messages, ...messages];\n\t\tif (beforeResult?.systemPrompt) this.agent.state.systemPrompt = beforeResult.systemPrompt;\n\t\ttry {\n\t\t\tawait this.agent.prompt(messages);\n\t\t} finally {\n\t\t\tawait this.flushPendingSessionWrites();\n\t\t}\n\t\tlet response: AssistantMessage | undefined;\n\t\tconst newMessages = this.agent.state.messages.slice(beforeLength);\n\t\tfor (let i = newMessages.length - 1; i >= 0; i--) {\n\t\t\tconst message = newMessages[i]!;\n\t\t\tif (message.role === \"assistant\") {\n\t\t\t\tresponse = message;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!response) throw new Error(\"AgentHarness prompt completed without an assistant message\");\n\t\treturn response;\n\t}\n\n\tasync prompt(text: string, options?: { images?: ImageContent[] }): Promise<AssistantMessage> {\n\t\tif (this.phase !== \"idle\") throw new Error(\"AgentHarness is busy\");\n\t\tthis.phase = \"turn\";\n\t\ttry {\n\t\t\tconst turnState = await this.createTurnState();\n\t\t\treturn await this.executeTurn(turnState, text, options);\n\t\t} catch (error) {\n\t\t\tthis.phase = \"idle\";\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync skill(name: string, additionalInstructions?: string): Promise<AssistantMessage> {\n\t\tif (this.phase !== \"idle\") throw new Error(\"AgentHarness is busy\");\n\t\tthis.phase = \"turn\";\n\t\ttry {\n\t\t\tconst turnState = await this.createTurnState();\n\t\t\tconst skill = (turnState.resources.skills ?? []).find((candidate) => candidate.name === name);\n\t\t\tif (!skill) throw new Error(`Unknown skill: ${name}`);\n\t\t\treturn await this.executeTurn(turnState, formatSkillInvocation(skill, additionalInstructions));\n\t\t} catch (error) {\n\t\t\tthis.phase = \"idle\";\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync promptFromTemplate(name: string, args: string[] = []): Promise<AssistantMessage> {\n\t\tif (this.phase !== \"idle\") throw new Error(\"AgentHarness is busy\");\n\t\tthis.phase = \"turn\";\n\t\ttry {\n\t\t\tconst turnState = await this.createTurnState();\n\t\t\tconst template = (turnState.resources.promptTemplates ?? []).find((candidate) => candidate.name === name);\n\t\t\tif (!template) throw new Error(`Unknown prompt template: ${name}`);\n\t\t\treturn await this.executeTurn(turnState, formatPromptTemplateInvocation(template, args));\n\t\t} catch (error) {\n\t\t\tthis.phase = \"idle\";\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tsteer(text: string, options?: { images?: ImageContent[] }): void {\n\t\tif (this.phase === \"idle\") throw new Error(\"Cannot steer while idle\");\n\t\tconst message = createUserMessage(text, options?.images);\n\t\tthis.steerQueue.push(message);\n\t\tthis.agent.steer(message);\n\t\tvoid this.emitQueueUpdate();\n\t}\n\n\tfollowUp(text: string, options?: { images?: ImageContent[] }): void {\n\t\tif (this.phase === \"idle\") throw new Error(\"Cannot follow up while idle\");\n\t\tconst message = createUserMessage(text, options?.images);\n\t\tthis.followUpQueue.push(message);\n\t\tthis.agent.followUp(message);\n\t\tvoid this.emitQueueUpdate();\n\t}\n\n\tnextTurn(text: string, options?: { images?: ImageContent[] }): void {\n\t\tthis.nextTurnQueue.push(createUserMessage(text, options?.images));\n\t\tvoid this.emitQueueUpdate();\n\t}\n\n\tasync appendMessage(message: AgentMessage): Promise<void> {\n\t\tif (this.phase === \"idle\") {\n\t\t\tawait this.session.appendMessage(message);\n\t\t} else {\n\t\t\tthis.pendingSessionWrites.push({ type: \"message\", message });\n\t\t}\n\t}\n\n\tasync compact(\n\t\tcustomInstructions?: string,\n\t): Promise<{ summary: string; firstKeptEntryId: string; tokensBefore: number; details?: unknown }> {\n\t\tif (this.phase !== \"idle\") throw new Error(\"compact() requires idle harness\");\n\t\tthis.phase = \"compaction\";\n\t\tconst model = this.model;\n\t\tif (!model) throw new Error(\"No model set for compaction\");\n\t\tconst auth = await this.getApiKeyAndHeaders?.(model);\n\t\tif (!auth) throw new Error(\"No auth available for compaction\");\n\t\tconst branchEntries = await this.session.getBranch();\n\t\tconst preparation = prepareCompaction(branchEntries, DEFAULT_COMPACTION_SETTINGS);\n\t\tif (!preparation) throw new Error(\"Nothing to compact\");\n\t\tconst hookResult = await this.emitHook({\n\t\t\ttype: \"session_before_compact\",\n\t\t\tpreparation,\n\t\t\tbranchEntries,\n\t\t\tcustomInstructions,\n\t\t\tsignal: new AbortController().signal,\n\t\t});\n\t\tif (hookResult?.cancel) {\n\t\t\tthis.phase = \"idle\";\n\t\t\tthrow new Error(\"Compaction cancelled\");\n\t\t}\n\t\tconst provided = hookResult?.compaction;\n\t\tconst result =\n\t\t\tprovided ??\n\t\t\t(await compact(\n\t\t\t\tpreparation,\n\t\t\t\tmodel,\n\t\t\t\tauth.apiKey,\n\t\t\t\tauth.headers,\n\t\t\t\tcustomInstructions,\n\t\t\t\tundefined,\n\t\t\t\tthis.thinkingLevel,\n\t\t\t));\n\t\tconst entryId = await this.session.appendCompaction(\n\t\t\tresult.summary,\n\t\t\tresult.firstKeptEntryId,\n\t\t\tresult.tokensBefore,\n\t\t\tresult.details,\n\t\t\tprovided !== undefined,\n\t\t);\n\t\tconst entry = await this.session.getEntry(entryId);\n\t\tif (entry?.type === \"compaction\") {\n\t\t\tawait this.emitOwn({ type: \"session_compact\", compactionEntry: entry, fromHook: provided !== undefined });\n\t\t}\n\t\tthis.phase = \"idle\";\n\t\treturn result;\n\t}\n\n\tasync navigateTree(\n\t\ttargetId: string,\n\t\toptions?: { summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string },\n\t): Promise<NavigateTreeResult> {\n\t\tif (this.phase !== \"idle\") throw new Error(\"navigateTree() requires idle harness\");\n\t\tthis.phase = \"branch_summary\";\n\t\tconst oldLeafId = await this.session.getLeafId();\n\t\tif (oldLeafId === targetId) {\n\t\t\tthis.phase = \"idle\";\n\t\t\treturn { cancelled: false };\n\t\t}\n\t\tconst targetEntry = await this.session.getEntry(targetId);\n\t\tif (!targetEntry) throw new Error(`Entry ${targetId} not found`);\n\t\tconst { entries, commonAncestorId } = await collectEntriesForBranchSummary(this.session, oldLeafId, targetId);\n\t\tconst preparation = {\n\t\t\ttargetId,\n\t\t\toldLeafId,\n\t\t\tcommonAncestorId,\n\t\t\tentriesToSummarize: entries,\n\t\t\tuserWantsSummary: options?.summarize ?? false,\n\t\t\tcustomInstructions: options?.customInstructions,\n\t\t\treplaceInstructions: options?.replaceInstructions,\n\t\t\tlabel: options?.label,\n\t\t};\n\t\tconst signal = new AbortController().signal;\n\t\tconst hookResult = await this.emitHook({\n\t\t\ttype: \"session_before_tree\",\n\t\t\tpreparation,\n\t\t\tsignal,\n\t\t});\n\t\tif (hookResult?.cancel) {\n\t\t\tthis.phase = \"idle\";\n\t\t\treturn { cancelled: true };\n\t\t}\n\t\tlet summaryEntry: any | undefined;\n\t\tlet summaryText: string | undefined = hookResult?.summary?.summary;\n\t\tlet summaryDetails: unknown = hookResult?.summary?.details;\n\t\tif (!summaryText && options?.summarize && entries.length > 0) {\n\t\t\tconst model = this.model;\n\t\t\tif (!model) throw new Error(\"No model set for branch summary\");\n\t\t\tconst auth = await this.getApiKeyAndHeaders?.(model);\n\t\t\tif (!auth) throw new Error(\"No auth available for branch summary\");\n\t\t\tconst branchSummary = await generateBranchSummary(entries, {\n\t\t\t\tmodel,\n\t\t\t\tapiKey: auth.apiKey,\n\t\t\t\theaders: auth.headers,\n\t\t\t\tsignal: new AbortController().signal,\n\t\t\t\tcustomInstructions: hookResult?.customInstructions ?? options?.customInstructions,\n\t\t\t\treplaceInstructions: hookResult?.replaceInstructions ?? options?.replaceInstructions,\n\t\t\t});\n\t\t\tif (branchSummary.aborted) {\n\t\t\t\tthis.phase = \"idle\";\n\t\t\t\treturn { cancelled: true };\n\t\t\t}\n\t\t\tif (branchSummary.error) throw new Error(branchSummary.error);\n\t\t\tsummaryText = branchSummary.summary;\n\t\t\tsummaryDetails = {\n\t\t\t\treadFiles: branchSummary.readFiles ?? [],\n\t\t\t\tmodifiedFiles: branchSummary.modifiedFiles ?? [],\n\t\t\t};\n\t\t}\n\t\tlet editorText: string | undefined;\n\t\tlet newLeafId: string | null;\n\t\tif (targetEntry.type === \"message\" && targetEntry.message.role === \"user\") {\n\t\t\tnewLeafId = targetEntry.parentId;\n\t\t\tconst content = targetEntry.message.content;\n\t\t\teditorText =\n\t\t\t\ttypeof content === \"string\"\n\t\t\t\t\t? content\n\t\t\t\t\t: content\n\t\t\t\t\t\t\t.filter((c): c is { readonly type: \"text\"; readonly text: string } => c.type === \"text\")\n\t\t\t\t\t\t\t.map((c) => c.text)\n\t\t\t\t\t\t\t.join(\"\");\n\t\t} else if (targetEntry.type === \"custom_message\") {\n\t\t\tnewLeafId = targetEntry.parentId;\n\t\t\teditorText =\n\t\t\t\ttypeof targetEntry.content === \"string\"\n\t\t\t\t\t? targetEntry.content\n\t\t\t\t\t: targetEntry.content\n\t\t\t\t\t\t\t.filter((c): c is { readonly type: \"text\"; readonly text: string } => c.type === \"text\")\n\t\t\t\t\t\t\t.map((c) => c.text)\n\t\t\t\t\t\t\t.join(\"\");\n\t\t} else {\n\t\t\tnewLeafId = targetId;\n\t\t}\n\t\tconst summaryId = await this.session.moveTo(\n\t\t\tnewLeafId,\n\t\t\tsummaryText\n\t\t\t\t? {\n\t\t\t\t\t\tsummary: summaryText,\n\t\t\t\t\t\tdetails: summaryDetails,\n\t\t\t\t\t\tfromHook: hookResult?.summary !== undefined,\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t);\n\t\tif (summaryId) {\n\t\t\tsummaryEntry = await this.session.getEntry(summaryId);\n\t\t}\n\t\tawait this.emitOwn({\n\t\t\ttype: \"session_tree\",\n\t\t\tnewLeafId: await this.session.getLeafId(),\n\t\t\toldLeafId,\n\t\t\tsummaryEntry,\n\t\t\tfromHook: hookResult?.summary !== undefined,\n\t\t});\n\t\tthis.phase = \"idle\";\n\t\treturn { cancelled: false, editorText, summaryEntry };\n\t}\n\n\tasync setModel(model: Model<any>): Promise<void> {\n\t\tconst previousModel = this.model;\n\t\tthis.model = model;\n\t\tif (this.phase === \"idle\") {\n\t\t\tthis.agent.state.model = model;\n\t\t\tawait this.session.appendModelChange(model.provider, model.id);\n\t\t} else {\n\t\t\tthis.pendingSessionWrites.push({ type: \"model_change\", provider: model.provider, modelId: model.id });\n\t\t}\n\t\tawait this.emitOwn({ type: \"model_select\", model, previousModel, source: \"set\" });\n\t}\n\n\tasync setThinkingLevel(level: ThinkingLevel): Promise<void> {\n\t\tconst previousLevel = this.thinkingLevel;\n\t\tthis.thinkingLevel = level;\n\t\tif (this.phase === \"idle\") {\n\t\t\tthis.agent.state.thinkingLevel = level;\n\t\t\tawait this.session.appendThinkingLevelChange(level);\n\t\t} else {\n\t\t\tthis.pendingSessionWrites.push({ type: \"thinking_level_change\", thinkingLevel: level });\n\t\t}\n\t\tawait this.emitOwn({ type: \"thinking_level_select\", level, previousLevel });\n\t}\n\n\tasync setActiveTools(toolNames: string[]): Promise<void> {\n\t\tthis.validateToolNames(toolNames);\n\t\tthis.activeToolNames = [...toolNames];\n\t\tif (this.phase === \"idle\") {\n\t\t\tthis.agent.state.tools = this.activeToolNames.map((name) => this.tools.get(name)!);\n\t\t}\n\t}\n\n\tget steeringMode(): QueueMode {\n\t\treturn this.agent.steeringMode;\n\t}\n\n\tset steeringMode(mode: QueueMode) {\n\t\tthis.agent.steeringMode = mode;\n\t}\n\n\tget followUpMode(): QueueMode {\n\t\treturn this.agent.followUpMode;\n\t}\n\n\tset followUpMode(mode: QueueMode) {\n\t\tthis.agent.followUpMode = mode;\n\t}\n\n\tgetResources(): AgentHarnessResources<TSkill, TPromptTemplate> {\n\t\treturn {\n\t\t\tskills: this.resources.skills?.slice(),\n\t\t\tpromptTemplates: this.resources.promptTemplates?.slice(),\n\t\t};\n\t}\n\n\tasync setResources(resources: AgentHarnessResources<TSkill, TPromptTemplate>): Promise<void> {\n\t\tconst previousResources = this.getResources();\n\t\tthis.resources = {\n\t\t\tskills: resources.skills?.slice(),\n\t\t\tpromptTemplates: resources.promptTemplates?.slice(),\n\t\t};\n\t\tawait this.emitOwn({ type: \"resources_update\", resources: this.getResources(), previousResources });\n\t}\n\n\tasync setTools(tools: TTool[], activeToolNames?: string[]): Promise<void> {\n\t\tthis.tools = new Map(tools.map((tool) => [tool.name, tool]));\n\t\tif (activeToolNames) {\n\t\t\tthis.validateToolNames(activeToolNames);\n\t\t\tthis.activeToolNames = [...activeToolNames];\n\t\t} else {\n\t\t\tthis.validateToolNames(this.activeToolNames);\n\t\t}\n\t\tif (this.phase === \"idle\") {\n\t\t\tthis.agent.state.tools = this.activeToolNames.map((name) => this.tools.get(name)!);\n\t\t}\n\t}\n\n\tasync abort(): Promise<AbortResult> {\n\t\tconst clearedSteer = [...this.steerQueue];\n\t\tconst clearedFollowUp = [...this.followUpQueue];\n\t\tthis.steerQueue = [];\n\t\tthis.followUpQueue = [];\n\t\tthis.agent.clearAllQueues();\n\t\tawait this.emitQueueUpdate();\n\t\tthis.agent.abort();\n\t\tawait this.agent.waitForIdle();\n\t\tawait this.emitOwn({ type: \"abort\", clearedSteer, clearedFollowUp });\n\t\treturn { clearedSteer, clearedFollowUp };\n\t}\n\n\tasync waitForIdle(): Promise<void> {\n\t\tawait this.agent.waitForIdle();\n\t}\n\n\tsubscribe(\n\t\tlistener: (event: AgentHarnessEvent<TSkill, TPromptTemplate>, signal?: AbortSignal) => Promise<void> | void,\n\t): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => this.listeners.delete(listener);\n\t}\n\n\ton<TType extends keyof AgentHarnessEventResultMap>(\n\t\ttype: TType,\n\t\thandler: (\n\t\t\tevent: Extract<AgentHarnessOwnEvent, { type: TType }>,\n\t\t) => Promise<AgentHarnessEventResultMap[TType]> | AgentHarnessEventResultMap[TType],\n\t): () => void {\n\t\tlet handlers = this.hooks.get(type);\n\t\tif (!handlers) {\n\t\t\thandlers = new Set();\n\t\t\tthis.hooks.set(type, handlers);\n\t\t}\n\t\thandlers.add(handler as any);\n\t\treturn () => handlers!.delete(handler as any);\n\t}\n}\n"]}
|