@earendil-works/pi-agent-core 0.83.0 → 0.84.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.
Files changed (146) hide show
  1. package/README.md +13 -7
  2. package/dist/agent-loop.d.ts.map +1 -1
  3. package/dist/agent-loop.js +5 -1
  4. package/dist/agent-loop.js.map +1 -1
  5. package/dist/agent.d.ts +3 -1
  6. package/dist/agent.d.ts.map +1 -1
  7. package/dist/agent.js +9 -0
  8. package/dist/agent.js.map +1 -1
  9. package/dist/harness/agent-harness.d.ts +452 -85
  10. package/dist/harness/agent-harness.d.ts.map +1 -1
  11. package/dist/harness/agent-harness.js +204 -917
  12. package/dist/harness/agent-harness.js.map +1 -1
  13. package/dist/harness/compaction/branch-summarization.d.ts +13 -6
  14. package/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  15. package/dist/harness/compaction/branch-summarization.js +11 -15
  16. package/dist/harness/compaction/branch-summarization.js.map +1 -1
  17. package/dist/harness/compaction/compaction.d.ts +14 -17
  18. package/dist/harness/compaction/compaction.d.ts.map +1 -1
  19. package/dist/harness/compaction/compaction.js +23 -36
  20. package/dist/harness/compaction/compaction.js.map +1 -1
  21. package/dist/harness/env/nodejs.d.ts +1 -0
  22. package/dist/harness/env/nodejs.d.ts.map +1 -1
  23. package/dist/harness/env/nodejs.js +23 -7
  24. package/dist/harness/env/nodejs.js.map +1 -1
  25. package/dist/harness/messages.d.ts +3 -3
  26. package/dist/harness/messages.d.ts.map +1 -1
  27. package/dist/harness/messages.js +3 -3
  28. package/dist/harness/messages.js.map +1 -1
  29. package/dist/harness/prompt-templates.d.ts.map +1 -1
  30. package/dist/harness/prompt-templates.js +4 -9
  31. package/dist/harness/prompt-templates.js.map +1 -1
  32. package/dist/harness/reducer.d.ts +100 -0
  33. package/dist/harness/reducer.d.ts.map +1 -0
  34. package/dist/harness/reducer.js +415 -0
  35. package/dist/harness/reducer.js.map +1 -0
  36. package/dist/harness/result.d.ts +40 -0
  37. package/dist/harness/result.d.ts.map +1 -0
  38. package/dist/harness/result.js +41 -0
  39. package/dist/harness/result.js.map +1 -0
  40. package/dist/harness/session/context.d.ts +22 -0
  41. package/dist/harness/session/context.d.ts.map +1 -0
  42. package/dist/harness/session/context.js +67 -0
  43. package/dist/harness/session/context.js.map +1 -0
  44. package/dist/harness/session/index.d.ts +7 -0
  45. package/dist/harness/session/index.d.ts.map +1 -0
  46. package/dist/harness/session/index.js +6 -0
  47. package/dist/harness/session/index.js.map +1 -0
  48. package/dist/harness/session/jsonl/codec.d.ts +8 -0
  49. package/dist/harness/session/jsonl/codec.d.ts.map +1 -0
  50. package/dist/harness/session/jsonl/codec.js +190 -0
  51. package/dist/harness/session/jsonl/codec.js.map +1 -0
  52. package/dist/harness/session/jsonl/errors.d.ts +5 -0
  53. package/dist/harness/session/jsonl/errors.d.ts.map +1 -0
  54. package/dist/harness/session/jsonl/errors.js +11 -0
  55. package/dist/harness/session/jsonl/errors.js.map +1 -0
  56. package/dist/harness/session/jsonl/repo.d.ts +23 -0
  57. package/dist/harness/session/jsonl/repo.d.ts.map +1 -0
  58. package/dist/harness/session/jsonl/repo.js +132 -0
  59. package/dist/harness/session/jsonl/repo.js.map +1 -0
  60. package/dist/harness/session/jsonl/storage.d.ts +43 -0
  61. package/dist/harness/session/jsonl/storage.d.ts.map +1 -0
  62. package/dist/harness/session/jsonl/storage.js +208 -0
  63. package/dist/harness/session/jsonl/storage.js.map +1 -0
  64. package/dist/harness/session/jsonl/types.d.ts +38 -0
  65. package/dist/harness/session/jsonl/types.d.ts.map +1 -0
  66. package/dist/harness/session/jsonl/types.js +2 -0
  67. package/dist/harness/session/jsonl/types.js.map +1 -0
  68. package/dist/harness/session/jsonl.d.ts +3 -0
  69. package/dist/harness/session/jsonl.d.ts.map +1 -0
  70. package/dist/harness/session/jsonl.js +2 -0
  71. package/dist/harness/session/jsonl.js.map +1 -0
  72. package/dist/harness/session/memory.d.ts +44 -0
  73. package/dist/harness/session/memory.d.ts.map +1 -0
  74. package/dist/harness/session/memory.js +141 -0
  75. package/dist/harness/session/memory.js.map +1 -0
  76. package/dist/harness/session/search.d.ts +19 -0
  77. package/dist/harness/session/search.d.ts.map +1 -0
  78. package/dist/harness/session/search.js +42 -0
  79. package/dist/harness/session/search.js.map +1 -0
  80. package/dist/harness/session/session.d.ts +43 -42
  81. package/dist/harness/session/session.d.ts.map +1 -1
  82. package/dist/harness/session/session.js +187 -228
  83. package/dist/harness/session/session.js.map +1 -1
  84. package/dist/harness/session/state.d.ts +65 -0
  85. package/dist/harness/session/state.d.ts.map +1 -0
  86. package/dist/harness/session/state.js +319 -0
  87. package/dist/harness/session/state.js.map +1 -0
  88. package/dist/harness/session/testing/conformance.d.ts +4 -0
  89. package/dist/harness/session/testing/conformance.d.ts.map +1 -0
  90. package/dist/harness/session/testing/conformance.js +743 -0
  91. package/dist/harness/session/testing/conformance.js.map +1 -0
  92. package/dist/harness/session/testing/index.d.ts +3 -0
  93. package/dist/harness/session/testing/index.d.ts.map +1 -0
  94. package/dist/harness/session/testing/index.js +2 -0
  95. package/dist/harness/session/testing/index.js.map +1 -0
  96. package/dist/harness/session/testing/types.d.ts +14 -0
  97. package/dist/harness/session/testing/types.d.ts.map +1 -0
  98. package/dist/harness/session/testing/types.js +2 -0
  99. package/dist/harness/session/testing/types.js.map +1 -0
  100. package/dist/harness/session/types.d.ts +333 -0
  101. package/dist/harness/session/types.d.ts.map +1 -0
  102. package/dist/harness/session/types.js +10 -0
  103. package/dist/harness/session/types.js.map +1 -0
  104. package/dist/harness/skills.d.ts.map +1 -1
  105. package/dist/harness/skills.js +21 -19
  106. package/dist/harness/skills.js.map +1 -1
  107. package/dist/harness/telemetry.d.ts +1221 -0
  108. package/dist/harness/telemetry.d.ts.map +1 -0
  109. package/dist/harness/telemetry.js +508 -0
  110. package/dist/harness/telemetry.js.map +1 -0
  111. package/dist/harness/types.d.ts +6 -459
  112. package/dist/harness/types.d.ts.map +1 -1
  113. package/dist/harness/types.js +0 -19
  114. package/dist/harness/types.js.map +1 -1
  115. package/dist/index.d.ts +10 -9
  116. package/dist/index.d.ts.map +1 -1
  117. package/dist/index.js +7 -8
  118. package/dist/index.js.map +1 -1
  119. package/dist/proxy.d.ts +1 -1
  120. package/dist/proxy.d.ts.map +1 -1
  121. package/dist/proxy.js +1 -0
  122. package/dist/proxy.js.map +1 -1
  123. package/dist/types.d.ts +6 -0
  124. package/dist/types.d.ts.map +1 -1
  125. package/dist/types.js.map +1 -1
  126. package/package.json +9 -2
  127. package/dist/harness/session/jsonl-repo.d.ts +0 -26
  128. package/dist/harness/session/jsonl-repo.d.ts.map +0 -1
  129. package/dist/harness/session/jsonl-repo.js +0 -103
  130. package/dist/harness/session/jsonl-repo.js.map +0 -1
  131. package/dist/harness/session/jsonl-storage.d.ts +0 -42
  132. package/dist/harness/session/jsonl-storage.d.ts.map +0 -1
  133. package/dist/harness/session/jsonl-storage.js +0 -293
  134. package/dist/harness/session/jsonl-storage.js.map +0 -1
  135. package/dist/harness/session/memory-repo.d.ts +0 -18
  136. package/dist/harness/session/memory-repo.d.ts.map +0 -1
  137. package/dist/harness/session/memory-repo.js +0 -42
  138. package/dist/harness/session/memory-repo.js.map +0 -1
  139. package/dist/harness/session/memory-storage.d.ts +0 -33
  140. package/dist/harness/session/memory-storage.d.ts.map +0 -1
  141. package/dist/harness/session/memory-storage.js +0 -168
  142. package/dist/harness/session/memory-storage.js.map +0 -1
  143. package/dist/harness/session/repo-utils.d.ts +0 -11
  144. package/dist/harness/session/repo-utils.d.ts.map +0 -1
  145. package/dist/harness/session/repo-utils.js +0 -39
  146. package/dist/harness/session/repo-utils.js.map +0 -1
@@ -1,965 +1,252 @@
1
- import { contentText, } from "@earendil-works/pi-ai";
2
- import { runAgentLoop } from "../agent-loop.js";
3
- import { collectEntriesForBranchSummary, generateBranchSummary } from "./compaction/branch-summarization.js";
4
- import { compact, DEFAULT_COMPACTION_SETTINGS, prepareCompaction } from "./compaction/compaction.js";
5
- import { convertToLlm } from "./messages.js";
6
- import { formatPromptTemplateInvocation } from "./prompt-templates.js";
7
- import { formatSkillInvocation } from "./skills.js";
8
- import { AgentHarnessError, BranchSummaryError, CompactionError, SessionError, toError } from "./types.js";
9
- function createUserMessage(text, images) {
10
- const content = [{ type: "text", text }];
11
- if (images)
12
- content.push(...images);
13
- return { role: "user", content, timestamp: Date.now() };
1
+ import { TaggedError } from "./result.js";
2
+ export class LaneBusy extends TaggedError("LaneBusy") {
14
3
  }
15
- function createFailureMessage(model, error, aborted) {
16
- return {
17
- role: "assistant",
18
- content: [{ type: "text", text: "" }],
19
- api: model.api,
20
- provider: model.provider,
21
- model: model.id,
22
- stopReason: aborted ? "aborted" : "error",
23
- errorMessage: error instanceof Error ? error.message : String(error),
24
- timestamp: Date.now(),
25
- usage: {
26
- input: 0,
27
- output: 0,
28
- cacheRead: 0,
29
- cacheWrite: 0,
30
- totalTokens: 0,
31
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
32
- },
33
- };
4
+ export class MissingIdentities extends TaggedError("MissingIdentities") {
34
5
  }
35
- function cloneStreamOptions(streamOptions) {
36
- return {
37
- ...streamOptions,
38
- headers: streamOptions?.headers ? { ...streamOptions.headers } : undefined,
39
- metadata: streamOptions?.metadata ? { ...streamOptions.metadata } : undefined,
40
- };
6
+ export class NoActiveRun extends TaggedError("NoActiveRun") {
41
7
  }
42
- function findDuplicateNames(names) {
43
- const seen = new Set();
44
- const duplicates = new Set();
45
- for (const name of names) {
46
- if (seen.has(name))
47
- duplicates.add(name);
48
- seen.add(name);
49
- }
50
- return [...duplicates];
8
+ export class NoActiveOperation extends TaggedError("NoActiveOperation") {
51
9
  }
52
- function applyStreamOptionsPatch(base, patch) {
53
- const result = cloneStreamOptions(base);
54
- if (!patch)
55
- return result;
56
- if (Object.hasOwn(patch, "transport"))
57
- result.transport = patch.transport;
58
- if (Object.hasOwn(patch, "timeoutMs"))
59
- result.timeoutMs = patch.timeoutMs;
60
- if (Object.hasOwn(patch, "maxRetries"))
61
- result.maxRetries = patch.maxRetries;
62
- if (Object.hasOwn(patch, "maxRetryDelayMs"))
63
- result.maxRetryDelayMs = patch.maxRetryDelayMs;
64
- if (Object.hasOwn(patch, "cacheRetention"))
65
- result.cacheRetention = patch.cacheRetention;
66
- if (Object.hasOwn(patch, "headers")) {
67
- if (patch.headers === undefined) {
68
- result.headers = undefined;
69
- }
70
- else {
71
- const headers = { ...(result.headers ?? {}) };
72
- for (const [key, value] of Object.entries(patch.headers)) {
73
- if (value === undefined)
74
- delete headers[key];
75
- else
76
- headers[key] = value;
77
- }
78
- result.headers = Object.keys(headers).length > 0 ? headers : undefined;
79
- }
80
- }
81
- if (Object.hasOwn(patch, "metadata")) {
82
- if (patch.metadata === undefined) {
83
- result.metadata = undefined;
84
- }
85
- else {
86
- const metadata = { ...(result.metadata ?? {}) };
87
- for (const [key, value] of Object.entries(patch.metadata)) {
88
- if (value === undefined)
89
- delete metadata[key];
90
- else
91
- metadata[key] = value;
92
- }
93
- result.metadata = Object.keys(metadata).length > 0 ? metadata : undefined;
94
- }
95
- }
96
- return result;
10
+ export class NothingToResume extends TaggedError("NothingToResume") {
97
11
  }
98
- const SUBSCRIBER_EVENT_TYPE = "*";
99
- function normalizeHarnessError(error, fallbackCode) {
100
- if (error instanceof AgentHarnessError)
101
- return error;
102
- const cause = toError(error);
103
- if (cause instanceof SessionError)
104
- return new AgentHarnessError("session", cause.message, cause);
105
- if (cause instanceof CompactionError)
106
- return new AgentHarnessError("compaction", cause.message, cause);
107
- if (cause instanceof BranchSummaryError)
108
- return new AgentHarnessError("branch_summary", cause.message, cause);
109
- return new AgentHarnessError(fallbackCode, cause.message, cause);
12
+ export class InvalidMessage extends TaggedError("InvalidMessage") {
110
13
  }
111
- function normalizeHookError(error) {
112
- return normalizeHarnessError(error, "hook");
14
+ export class UnknownSkill extends TaggedError("UnknownSkill") {
15
+ }
16
+ export class UnknownTemplate extends TaggedError("UnknownTemplate") {
17
+ }
18
+ export class UnknownTarget extends TaggedError("UnknownTarget") {
19
+ }
20
+ export class UnknownQueueItem extends TaggedError("UnknownQueueItem") {
21
+ }
22
+ export class LaneExists extends TaggedError("LaneExists") {
23
+ }
24
+ export class InvalidLane extends TaggedError("InvalidLane") {
25
+ }
26
+ export class NothingToCompact extends TaggedError("NothingToCompact") {
27
+ }
28
+ export class Closed extends TaggedError("Closed") {
29
+ }
30
+ export class HarnessFault extends Error {
31
+ cause;
32
+ constructor(message, cause) {
33
+ super(message);
34
+ this.name = "HarnessFault";
35
+ this.cause = cause;
36
+ }
37
+ }
38
+ export class HarnessClosed extends Error {
39
+ constructor() {
40
+ super("AgentHarness was closed while the operation was active");
41
+ this.name = "HarnessClosed";
42
+ }
43
+ }
44
+ export class HarnessNotImplemented extends Error {
45
+ operation;
46
+ constructor(operation) {
47
+ super(`AgentHarness.${operation} is not implemented yet`);
48
+ this.name = "HarnessNotImplemented";
49
+ this.operation = operation;
50
+ }
51
+ }
52
+ class UnavailableRegistry {
53
+ operation;
54
+ isClosed;
55
+ constructor(operation, isClosed) {
56
+ this.operation = operation;
57
+ this.isClosed = isClosed;
58
+ }
59
+ on(_name, _handler, _options) {
60
+ throw this.isClosed() ? new HarnessClosed() : new HarnessNotImplemented(this.operation);
61
+ }
113
62
  }
114
63
  export class AgentHarness {
64
+ name = "main";
115
65
  session;
116
- models;
117
- phase = "idle";
118
- runAbortController;
119
- runPromise;
120
- pendingSessionWrites = [];
66
+ hooks;
67
+ events;
68
+ durableSession;
121
69
  model;
122
70
  thinkingLevel;
123
- systemPrompt;
124
- toolContext;
125
- streamOptions;
126
- retry;
127
- resources;
128
- tools = new Map();
129
71
  activeToolNames;
130
- steerQueue = [];
131
- steeringQueueMode;
132
- followUpQueue = [];
133
- followUpQueueMode;
134
- nextTurnQueue = [];
135
- handlers = new Map();
72
+ tools;
73
+ resources;
74
+ streamOptions;
75
+ retryPolicy;
76
+ compactionSettings;
77
+ steeringMode;
78
+ followUpMode;
79
+ closed = false;
136
80
  constructor(options) {
81
+ this.durableSession = options.session;
137
82
  this.session = options.session;
138
- this.models = options.models;
139
- this.resources = options.resources ?? {};
140
- this.streamOptions = cloneStreamOptions(options.streamOptions);
141
- this.retry = options.retry;
142
- this.systemPrompt = options.systemPrompt;
143
- this.toolContext = options.toolContext;
144
- this.validateUniqueNames((options.tools ?? []).map((tool) => tool.name), "Duplicate tool name(s)");
145
- for (const tool of options.tools ?? []) {
146
- this.tools.set(tool.name, tool);
147
- }
83
+ this.hooks = new UnavailableRegistry("hooks.on", () => this.closed);
84
+ this.events = new UnavailableRegistry("events.on", () => this.closed);
148
85
  this.model = options.model;
149
86
  this.thinkingLevel = options.thinkingLevel ?? "off";
150
- this.activeToolNames = options.activeToolNames
151
- ? [...options.activeToolNames]
152
- : (options.tools ?? []).map((tool) => tool.name);
153
- this.validateUniqueNames(this.activeToolNames, "Duplicate active tool name(s)");
154
- this.validateToolNames(this.activeToolNames);
155
- this.steeringQueueMode = options.steeringMode ?? "one-at-a-time";
156
- this.followUpQueueMode = options.followUpMode ?? "one-at-a-time";
157
- }
158
- getHandlers(type) {
159
- return this.handlers.get(type);
160
- }
161
- async emitOwn(event, signal) {
162
- for (const listener of this.getHandlers(SUBSCRIBER_EVENT_TYPE) ?? []) {
163
- try {
164
- await listener(event, signal);
165
- }
166
- catch (error) {
167
- throw normalizeHookError(error);
168
- }
169
- }
170
- }
171
- async emitAny(event, signal) {
172
- for (const listener of this.getHandlers(SUBSCRIBER_EVENT_TYPE) ?? []) {
173
- try {
174
- await listener(event, signal);
175
- }
176
- catch (error) {
177
- throw normalizeHookError(error);
178
- }
179
- }
180
- }
181
- async emitHook(event) {
182
- const handlers = this.getHandlers(event.type);
183
- if (!handlers || handlers.size === 0)
184
- return undefined;
185
- let lastResult;
186
- for (const handler of handlers) {
187
- try {
188
- const result = await handler(event);
189
- if (result !== undefined) {
190
- lastResult = result;
191
- }
192
- }
193
- catch (error) {
194
- throw normalizeHookError(error);
195
- }
196
- }
197
- return lastResult;
198
- }
199
- retryCallbacks(operation) {
200
- return {
201
- onRetryScheduled: (attempt, maxAttempts, delayMs, errorMessage) => this.emitOwn({ type: "retry_scheduled", operation, attempt, maxAttempts, delayMs, errorMessage }),
202
- onRetryAttemptStart: () => this.emitOwn({ type: "retry_attempt_start", operation }),
203
- onRetryFinished: () => this.emitOwn({ type: "retry_finished", operation }),
87
+ this.activeToolNames = [...(options.activeToolNames ?? options.tools?.map((tool) => tool.name) ?? [])];
88
+ this.tools = [...(options.tools ?? [])];
89
+ this.resources = {
90
+ skills: options.resources?.skills ? [...options.resources.skills] : undefined,
91
+ promptTemplates: options.resources?.promptTemplates ? [...options.resources.promptTemplates] : undefined,
204
92
  };
205
- }
206
- async emitBeforeProviderRequest(model, sessionId, streamOptions) {
207
- const handlers = this.getHandlers("before_provider_request");
208
- let current = cloneStreamOptions(streamOptions);
209
- if (!handlers || handlers.size === 0)
210
- return current;
211
- for (const handler of handlers) {
212
- try {
213
- const result = await handler({
214
- type: "before_provider_request",
215
- model,
216
- sessionId,
217
- streamOptions: cloneStreamOptions(current),
218
- });
219
- if (result?.streamOptions) {
220
- current = applyStreamOptionsPatch(current, result.streamOptions);
221
- }
222
- }
223
- catch (error) {
224
- throw normalizeHookError(error);
225
- }
226
- }
227
- return current;
228
- }
229
- async emitBeforeProviderPayload(model, payload) {
230
- const handlers = this.getHandlers("before_provider_payload");
231
- let current = payload;
232
- if (!handlers || handlers.size === 0)
233
- return current;
234
- for (const handler of handlers) {
235
- try {
236
- const result = await handler({ type: "before_provider_payload", model, payload: current });
237
- if (result !== undefined) {
238
- current = result.payload;
239
- }
240
- }
241
- catch (error) {
242
- throw normalizeHookError(error);
243
- }
244
- }
245
- return current;
246
- }
247
- async emitQueueUpdate() {
248
- await this.emitOwn({
249
- type: "queue_update",
250
- steer: [...this.steerQueue],
251
- followUp: [...this.followUpQueue],
252
- nextTurn: [...this.nextTurnQueue],
253
- });
254
- }
255
- startRunPromise() {
256
- let finish = () => { };
257
- this.runPromise = new Promise((resolve) => {
258
- finish = resolve;
259
- });
260
- return () => {
261
- this.runPromise = undefined;
262
- finish();
93
+ this.streamOptions = { ...(options.streamOptions ?? {}) };
94
+ this.retryPolicy = options.retry ?? { enabled: false, maxRetries: 0, baseDelayMs: 1000 };
95
+ this.compactionSettings = options.compaction ?? {
96
+ enabled: true,
97
+ reserveTokens: 16384,
98
+ keepRecentTokens: 20000,
263
99
  };
100
+ this.steeringMode = options.steeringMode ?? "one-at-a-time";
101
+ this.followUpMode = options.followUpMode ?? "one-at-a-time";
264
102
  }
265
- async resolveToolContext() {
266
- if (typeof this.toolContext === "function") {
267
- return await this.toolContext();
268
- }
269
- return this.toolContext;
103
+ static async create(options) {
104
+ const [record] = await options.session.findRecords({ limit: 1 });
105
+ if (record !== undefined)
106
+ throw new HarnessNotImplemented("create.restore");
107
+ return { harness: new AgentHarness(options), suspended: [] };
270
108
  }
271
- bindToolContext(tool, context) {
272
- return {
273
- ...tool,
274
- execute: (toolCallId, params, signal, onUpdate) => tool.execute(toolCallId, params, signal, onUpdate, context),
275
- };
109
+ unavailable(operation) {
110
+ return Promise.reject(this.closed ? new HarnessClosed() : new HarnessNotImplemented(operation));
276
111
  }
277
- async createTurnState() {
278
- const context = await this.session.buildContext();
279
- const resources = this.getResources();
280
- const sessionMetadata = await this.session.getMetadata();
281
- const toolContext = await this.resolveToolContext();
282
- const tools = [...this.tools.values()];
283
- const activeTools = this.activeToolNames
284
- .map((name) => this.tools.get(name))
285
- .filter((tool) => tool !== undefined);
286
- let systemPrompt = "You are a helpful assistant.";
287
- if (typeof this.systemPrompt === "string") {
288
- systemPrompt = this.systemPrompt;
289
- }
290
- else if (this.systemPrompt) {
291
- systemPrompt = await this.systemPrompt({
292
- session: this.session,
293
- model: this.model,
294
- thinkingLevel: this.thinkingLevel,
295
- activeTools,
296
- resources,
297
- });
298
- }
299
- return {
300
- messages: context.messages,
301
- resources,
302
- toolContext,
303
- streamOptions: cloneStreamOptions(this.streamOptions),
304
- sessionId: sessionMetadata.id,
305
- systemPrompt,
306
- model: this.model,
307
- thinkingLevel: this.thinkingLevel,
308
- tools,
309
- activeTools,
310
- };
112
+ async getLeafId() {
113
+ return this.durableSession.getLeafId();
311
114
  }
312
- createContext(turnState, systemPrompt) {
313
- return {
314
- systemPrompt: systemPrompt ?? turnState.systemPrompt,
315
- messages: turnState.messages.slice(),
316
- tools: turnState.activeTools.map((tool) => this.bindToolContext(tool, turnState.toolContext)),
317
- };
115
+ async prompt(_input, _images) {
116
+ return this.unavailable("prompt");
318
117
  }
319
- createStreamFn(getTurnState) {
320
- return async (model, context, streamOptions) => {
321
- const turnState = getTurnState();
322
- const snapshotOptions = { ...turnState.streamOptions };
323
- const requestOptions = await this.emitBeforeProviderRequest(model, turnState.sessionId, snapshotOptions);
324
- return this.models.streamSimple(model, context, {
325
- cacheRetention: requestOptions.cacheRetention,
326
- headers: requestOptions.headers,
327
- maxRetries: requestOptions.maxRetries,
328
- maxRetryDelayMs: requestOptions.maxRetryDelayMs,
329
- metadata: requestOptions.metadata,
330
- onPayload: async (payload) => await this.emitBeforeProviderPayload(model, payload),
331
- onResponse: async (response) => {
332
- const headers = { ...response.headers };
333
- await this.emitOwn({ type: "after_provider_response", status: response.status, headers }, streamOptions?.signal);
334
- },
335
- reasoning: streamOptions?.reasoning,
336
- signal: streamOptions?.signal,
337
- sessionId: turnState.sessionId,
338
- timeoutMs: requestOptions.timeoutMs,
339
- transport: requestOptions.transport,
340
- });
341
- };
118
+ async skill(_name, _additionalInstructions) {
119
+ return this.unavailable("skill");
342
120
  }
343
- async drainQueuedMessages(queue, mode) {
344
- const messages = mode === "all" ? queue.splice(0) : queue.splice(0, 1);
345
- if (messages.length === 0)
346
- return messages;
347
- try {
348
- await this.emitQueueUpdate();
349
- return messages;
350
- }
351
- catch (error) {
352
- queue.unshift(...messages);
353
- throw normalizeHookError(error);
354
- }
355
- }
356
- createLoopConfig(getTurnState, setTurnState) {
357
- const turnState = getTurnState();
358
- return {
359
- model: turnState.model,
360
- reasoning: turnState.thinkingLevel === "off" ? undefined : turnState.thinkingLevel,
361
- convertToLlm,
362
- transformContext: async (messages) => {
363
- const result = await this.emitHook({ type: "context", messages: [...messages] });
364
- return result?.messages ?? messages;
365
- },
366
- beforeToolCall: async ({ toolCall, args }) => {
367
- const result = await this.emitHook({
368
- type: "tool_call",
369
- toolCallId: toolCall.id,
370
- toolName: toolCall.name,
371
- input: args,
372
- });
373
- return result ? { block: result.block, reason: result.reason } : undefined;
374
- },
375
- afterToolCall: async ({ toolCall, args, result, isError }) => {
376
- const patch = await this.emitHook({
377
- type: "tool_result",
378
- toolCallId: toolCall.id,
379
- toolName: toolCall.name,
380
- input: args,
381
- content: result.content,
382
- details: result.details,
383
- isError,
384
- usage: result.usage,
385
- });
386
- return patch
387
- ? {
388
- content: patch.content,
389
- details: patch.details,
390
- isError: patch.isError,
391
- usage: patch.usage,
392
- terminate: patch.terminate,
393
- }
394
- : undefined;
395
- },
396
- prepareNextTurn: async () => {
397
- await this.flushPendingSessionWrites();
398
- const nextTurnState = await this.createTurnState();
399
- setTurnState(nextTurnState);
400
- return {
401
- context: this.createContext(nextTurnState),
402
- model: nextTurnState.model,
403
- thinkingLevel: nextTurnState.thinkingLevel,
404
- };
405
- },
406
- getSteeringMessages: async () => this.drainQueuedMessages(this.steerQueue, this.steeringQueueMode),
407
- getFollowUpMessages: async () => this.drainQueuedMessages(this.followUpQueue, this.followUpQueueMode),
408
- };
121
+ async promptFromTemplate(_name, _args) {
122
+ return this.unavailable("promptFromTemplate");
409
123
  }
410
- validateUniqueNames(names, message) {
411
- const duplicates = findDuplicateNames(names);
412
- if (duplicates.length > 0)
413
- throw new AgentHarnessError("invalid_argument", `${message}: ${duplicates.join(", ")}`);
414
- }
415
- validateToolNames(toolNames, tools = this.tools) {
416
- this.validateUniqueNames(toolNames, "Duplicate active tool name(s)");
417
- const missing = toolNames.filter((name) => !tools.has(name));
418
- if (missing.length > 0)
419
- throw new AgentHarnessError("invalid_argument", `Unknown tool(s): ${missing.join(", ")}`);
420
- }
421
- async flushPendingSessionWrites() {
422
- while (this.pendingSessionWrites.length > 0) {
423
- const write = this.pendingSessionWrites[0];
424
- if (write.type === "message") {
425
- await this.session.appendMessage(write.message);
426
- }
427
- else if (write.type === "model_change") {
428
- await this.session.appendModelChange(write.provider, write.modelId);
429
- }
430
- else if (write.type === "thinking_level_change") {
431
- await this.session.appendThinkingLevelChange(write.thinkingLevel);
432
- }
433
- else if (write.type === "active_tools_change") {
434
- await this.session.appendActiveToolsChange(write.activeToolNames);
435
- }
436
- else if (write.type === "custom") {
437
- await this.session.appendCustomEntry(write.customType, write.data);
438
- }
439
- else if (write.type === "custom_message") {
440
- await this.session.appendCustomMessageEntry(write.customType, write.content, write.display, write.details);
441
- }
442
- else if (write.type === "label") {
443
- await this.session.appendLabel(write.targetId, write.label);
444
- }
445
- else if (write.type === "session_info") {
446
- await this.session.appendSessionName(write.name ?? "");
447
- }
448
- else if (write.type === "leaf") {
449
- await this.session.getStorage().setLeafId(write.targetId);
450
- }
451
- this.pendingSessionWrites.shift();
452
- }
453
- }
454
- async handleAgentEvent(event, signal) {
455
- if (event.type === "message_end") {
456
- await this.session.appendMessage(event.message);
457
- await this.emitAny(event, signal);
458
- return;
459
- }
460
- if (event.type === "turn_end") {
461
- let eventError;
462
- try {
463
- await this.emitAny(event, signal);
464
- }
465
- catch (error) {
466
- eventError = error;
467
- }
468
- const hadPendingMutations = this.pendingSessionWrites.length > 0;
469
- await this.flushPendingSessionWrites();
470
- if (eventError)
471
- throw eventError;
472
- await this.emitOwn({ type: "save_point", hadPendingMutations });
473
- return;
474
- }
475
- if (event.type === "agent_end") {
476
- await this.flushPendingSessionWrites();
477
- this.phase = "idle";
478
- await this.emitAny(event, signal);
479
- await this.emitOwn({ type: "settled", nextTurnCount: this.nextTurnQueue.length }, signal);
480
- return;
481
- }
482
- await this.emitAny(event, signal);
483
- }
484
- async emitRunFailure(model, error, aborted, signal) {
485
- const failureMessage = createFailureMessage(model, error, aborted);
486
- await this.handleAgentEvent({ type: "message_start", message: failureMessage }, signal);
487
- await this.handleAgentEvent({ type: "message_end", message: failureMessage }, signal);
488
- await this.handleAgentEvent({ type: "turn_end", message: failureMessage, toolResults: [] }, signal);
489
- await this.handleAgentEvent({ type: "agent_end", messages: [failureMessage] }, signal);
490
- return [failureMessage];
491
- }
492
- async executeTurn(turnState, text, options) {
493
- let activeTurnState = turnState;
494
- let messages = [createUserMessage(text, options?.images)];
495
- if (this.nextTurnQueue.length > 0) {
496
- const queuedMessages = this.nextTurnQueue.splice(0);
497
- try {
498
- await this.emitQueueUpdate();
499
- }
500
- catch (error) {
501
- this.nextTurnQueue.unshift(...queuedMessages);
502
- throw normalizeHookError(error);
503
- }
504
- messages = [...queuedMessages, messages[0]];
505
- }
506
- const beforeResult = await this.emitHook({
507
- type: "before_agent_start",
508
- prompt: text,
509
- images: options?.images,
510
- systemPrompt: turnState.systemPrompt,
511
- resources: turnState.resources,
512
- });
513
- if (beforeResult?.messages)
514
- messages = [...messages, ...beforeResult.messages];
515
- const abortController = new AbortController();
516
- const getTurnState = () => activeTurnState;
517
- const setTurnState = (nextTurnState) => {
518
- activeTurnState = nextTurnState;
519
- };
520
- this.runAbortController = abortController;
521
- const runResultPromise = (async () => {
522
- try {
523
- return await runAgentLoop(messages, this.createContext(turnState, beforeResult?.systemPrompt), this.createLoopConfig(getTurnState, setTurnState), (event) => this.handleAgentEvent(event, abortController.signal), abortController.signal, this.createStreamFn(getTurnState));
524
- }
525
- catch (error) {
526
- try {
527
- return await this.emitRunFailure(activeTurnState.model, error, abortController.signal.aborted, abortController.signal);
528
- }
529
- catch (failureError) {
530
- const cause = new AggregateError([toError(error), toError(failureError)], "Agent run failed and failure reporting failed");
531
- throw new AgentHarnessError("unknown", cause.message, cause);
532
- }
533
- }
534
- })();
535
- try {
536
- const newMessages = await runResultPromise;
537
- for (let i = newMessages.length - 1; i >= 0; i--) {
538
- const message = newMessages[i];
539
- if (message.role === "assistant") {
540
- return message;
541
- }
542
- }
543
- throw new AgentHarnessError("invalid_state", "AgentHarness prompt completed without an assistant message");
544
- }
545
- finally {
546
- try {
547
- await this.flushPendingSessionWrites();
548
- }
549
- finally {
550
- this.runAbortController = undefined;
551
- }
552
- }
553
- }
554
- async prompt(text, options) {
555
- if (this.phase !== "idle")
556
- throw new AgentHarnessError("busy", "AgentHarness is busy");
557
- this.phase = "turn";
558
- const finishRunPromise = this.startRunPromise();
559
- try {
560
- const turnState = await this.createTurnState();
561
- return await this.executeTurn(turnState, text, options);
562
- }
563
- catch (error) {
564
- this.phase = "idle";
565
- throw normalizeHarnessError(error, "unknown");
566
- }
567
- finally {
568
- finishRunPromise();
569
- }
570
- }
571
- async skill(name, additionalInstructions) {
572
- if (this.phase !== "idle")
573
- throw new AgentHarnessError("busy", "AgentHarness is busy");
574
- this.phase = "turn";
575
- const finishRunPromise = this.startRunPromise();
576
- try {
577
- const turnState = await this.createTurnState();
578
- const skill = (turnState.resources.skills ?? []).find((candidate) => candidate.name === name);
579
- if (!skill)
580
- throw new AgentHarnessError("invalid_argument", `Unknown skill: ${name}`);
581
- return await this.executeTurn(turnState, formatSkillInvocation(skill, additionalInstructions));
582
- }
583
- catch (error) {
584
- this.phase = "idle";
585
- throw normalizeHarnessError(error, "unknown");
586
- }
587
- finally {
588
- finishRunPromise();
589
- }
590
- }
591
- async promptFromTemplate(name, args = []) {
592
- if (this.phase !== "idle")
593
- throw new AgentHarnessError("busy", "AgentHarness is busy");
594
- this.phase = "turn";
595
- const finishRunPromise = this.startRunPromise();
596
- try {
597
- const turnState = await this.createTurnState();
598
- const template = (turnState.resources.promptTemplates ?? []).find((candidate) => candidate.name === name);
599
- if (!template)
600
- throw new AgentHarnessError("invalid_argument", `Unknown prompt template: ${name}`);
601
- return await this.executeTurn(turnState, formatPromptTemplateInvocation(template, args));
602
- }
603
- catch (error) {
604
- this.phase = "idle";
605
- throw normalizeHarnessError(error, "unknown");
606
- }
607
- finally {
608
- finishRunPromise();
609
- }
610
- }
611
- async steer(text, options) {
612
- if (this.phase === "idle")
613
- throw new AgentHarnessError("invalid_state", "Cannot steer while idle");
614
- this.steerQueue.push(createUserMessage(text, options?.images));
615
- await this.emitQueueUpdate();
616
- }
617
- async followUp(text, options) {
618
- if (this.phase === "idle")
619
- throw new AgentHarnessError("invalid_state", "Cannot follow up while idle");
620
- this.followUpQueue.push(createUserMessage(text, options?.images));
621
- await this.emitQueueUpdate();
622
- }
623
- async nextTurn(text, options) {
624
- this.nextTurnQueue.push(createUserMessage(text, options?.images));
625
- await this.emitQueueUpdate();
626
- }
627
- async appendMessage(message) {
628
- try {
629
- if (this.phase === "idle") {
630
- await this.session.appendMessage(message);
631
- }
632
- else {
633
- this.pendingSessionWrites.push({ type: "message", message });
634
- }
635
- }
636
- catch (error) {
637
- throw normalizeHarnessError(error, "session");
638
- }
639
- }
640
- async compact(customInstructions) {
641
- if (this.phase !== "idle")
642
- throw new AgentHarnessError("busy", "compact() requires idle harness");
643
- this.phase = "compaction";
644
- try {
645
- const model = this.model;
646
- if (!model)
647
- throw new AgentHarnessError("invalid_state", "No model set for compaction");
648
- const branchEntries = await this.session.getBranch();
649
- const preparationResult = prepareCompaction(branchEntries, DEFAULT_COMPACTION_SETTINGS);
650
- if (!preparationResult.ok)
651
- throw preparationResult.error;
652
- const preparation = preparationResult.value;
653
- if (!preparation)
654
- throw new AgentHarnessError("compaction", "Nothing to compact");
655
- const hookResult = await this.emitHook({
656
- type: "session_before_compact",
657
- preparation,
658
- branchEntries,
659
- customInstructions,
660
- signal: new AbortController().signal,
661
- });
662
- if (hookResult?.cancel)
663
- throw new AgentHarnessError("compaction", "Compaction cancelled");
664
- const provided = hookResult?.compaction;
665
- const compactResult = provided
666
- ? { ok: true, value: provided }
667
- : await compact(preparation, this.models, model, customInstructions, undefined, this.thinkingLevel, this.retry, this.retryCallbacks("compaction"));
668
- if (!compactResult.ok)
669
- throw compactResult.error;
670
- const result = compactResult.value;
671
- const entryId = await this.session.appendCompaction(result.summary, result.firstKeptEntryId, result.tokensBefore, result.details, provided !== undefined, result.usage, result.retainedTail);
672
- const entry = await this.session.getEntry(entryId);
673
- if (entry?.type === "compaction") {
674
- await this.emitOwn({ type: "session_compact", compactionEntry: entry, fromHook: provided !== undefined });
675
- }
676
- return result;
677
- }
678
- catch (error) {
679
- throw normalizeHarnessError(error, "compaction");
680
- }
681
- finally {
682
- this.phase = "idle";
683
- }
684
- }
685
- async navigateTree(targetId, options) {
686
- if (this.phase !== "idle")
687
- throw new AgentHarnessError("busy", "navigateTree() requires idle harness");
688
- this.phase = "branch_summary";
689
- try {
690
- const oldLeafId = await this.session.getLeafId();
691
- if (oldLeafId === targetId)
692
- return { cancelled: false };
693
- const targetEntry = await this.session.getEntry(targetId);
694
- if (!targetEntry)
695
- throw new AgentHarnessError("invalid_argument", `Entry ${targetId} not found`);
696
- const { entries, commonAncestorId } = await collectEntriesForBranchSummary(this.session, oldLeafId, targetId);
697
- const preparation = {
698
- targetId,
699
- oldLeafId,
700
- commonAncestorId,
701
- entriesToSummarize: entries,
702
- userWantsSummary: options?.summarize ?? false,
703
- customInstructions: options?.customInstructions,
704
- replaceInstructions: options?.replaceInstructions,
705
- label: options?.label,
706
- };
707
- const signal = new AbortController().signal;
708
- const hookResult = await this.emitHook({ type: "session_before_tree", preparation, signal });
709
- if (hookResult?.cancel)
710
- return { cancelled: true };
711
- let summaryEntry;
712
- let summaryText = hookResult?.summary?.summary;
713
- let summaryDetails = hookResult?.summary?.details;
714
- let summaryUsage = hookResult?.summary?.usage;
715
- if (!summaryText && options?.summarize && entries.length > 0) {
716
- const model = this.model;
717
- if (!model)
718
- throw new AgentHarnessError("invalid_state", "No model set for branch summary");
719
- const branchSummary = await generateBranchSummary(entries, {
720
- models: this.models,
721
- model,
722
- signal: new AbortController().signal,
723
- customInstructions: hookResult?.customInstructions ?? options?.customInstructions,
724
- replaceInstructions: hookResult?.replaceInstructions ?? options?.replaceInstructions,
725
- retry: this.retry,
726
- callbacks: this.retryCallbacks("branch_summary"),
727
- });
728
- if (!branchSummary.ok) {
729
- if (branchSummary.error.code === "aborted")
730
- return { cancelled: true };
731
- throw new AgentHarnessError("branch_summary", branchSummary.error.message, branchSummary.error);
732
- }
733
- summaryText = branchSummary.value.summary;
734
- summaryUsage = branchSummary.value.usage;
735
- summaryDetails = {
736
- readFiles: branchSummary.value.readFiles,
737
- modifiedFiles: branchSummary.value.modifiedFiles,
738
- };
739
- }
740
- let editorText;
741
- let newLeafId;
742
- if (targetEntry.type === "message" && targetEntry.message.role === "user") {
743
- newLeafId = targetEntry.parentId;
744
- editorText = contentText(targetEntry.message.content, "");
745
- }
746
- else if (targetEntry.type === "custom_message") {
747
- newLeafId = targetEntry.parentId;
748
- editorText = contentText(targetEntry.content, "");
749
- }
750
- else {
751
- newLeafId = targetId;
752
- }
753
- const summaryId = await this.session.moveTo(newLeafId, summaryText
754
- ? {
755
- summary: summaryText,
756
- details: summaryDetails,
757
- usage: summaryUsage,
758
- fromHook: hookResult?.summary !== undefined,
759
- }
760
- : undefined);
761
- if (summaryId) {
762
- const entry = await this.session.getEntry(summaryId);
763
- if (entry?.type === "branch_summary")
764
- summaryEntry = entry;
765
- }
766
- await this.emitOwn({
767
- type: "session_tree",
768
- newLeafId: await this.session.getLeafId(),
769
- oldLeafId,
770
- summaryEntry,
771
- fromHook: hookResult?.summary !== undefined,
772
- });
773
- return { cancelled: false, editorText, summaryEntry };
774
- }
775
- catch (error) {
776
- throw normalizeHarnessError(error, "branch_summary");
777
- }
778
- finally {
779
- this.phase = "idle";
780
- }
781
- }
782
- getModel() {
124
+ async compact(_options) {
125
+ return this.unavailable("compact");
126
+ }
127
+ async navigateTree(_targetId, _options) {
128
+ return this.unavailable("navigateTree");
129
+ }
130
+ async resume() {
131
+ return this.unavailable("resume");
132
+ }
133
+ async abort() {
134
+ return this.unavailable("abort");
135
+ }
136
+ async steer(_input, _images) {
137
+ return this.unavailable("steer");
138
+ }
139
+ async followUp(_input, _images) {
140
+ return this.unavailable("followUp");
141
+ }
142
+ async nextRun(_input, _images) {
143
+ return this.unavailable("nextRun");
144
+ }
145
+ async cancelQueued(_entryId) {
146
+ return this.unavailable("cancelQueued");
147
+ }
148
+ async recordUsage(_usage, _options) {
149
+ return this.unavailable("recordUsage");
150
+ }
151
+ async waitForIdle() {
152
+ return this.unavailable("waitForIdle");
153
+ }
154
+ async runWhenIdle(_callback) {
155
+ return this.unavailable("runWhenIdle");
156
+ }
157
+ async peekAction() {
158
+ return this.unavailable("peekAction");
159
+ }
160
+ async executeAction() {
161
+ return this.unavailable("executeAction");
162
+ }
163
+ async runToCompletion() {
164
+ return this.unavailable("runToCompletion");
165
+ }
166
+ async getModel() {
783
167
  return this.model;
784
168
  }
785
169
  async setModel(model) {
786
- try {
787
- const previousModel = this.model;
788
- if (this.phase === "idle") {
789
- await this.session.appendModelChange(model.provider, model.id);
790
- }
791
- else {
792
- this.pendingSessionWrites.push({ type: "model_change", provider: model.provider, modelId: model.id });
793
- }
794
- this.model = model;
795
- await this.emitOwn({ type: "model_update", model, previousModel, source: "set" });
796
- }
797
- catch (error) {
798
- throw normalizeHarnessError(error, "session");
799
- }
800
- }
801
- getThinkingLevel() {
170
+ this.model = model;
171
+ }
172
+ async getThinkingLevel() {
802
173
  return this.thinkingLevel;
803
174
  }
804
175
  async setThinkingLevel(level) {
805
- try {
806
- const previousLevel = this.thinkingLevel;
807
- if (this.phase === "idle") {
808
- await this.session.appendThinkingLevelChange(level);
809
- }
810
- else {
811
- this.pendingSessionWrites.push({ type: "thinking_level_change", thinkingLevel: level });
812
- }
813
- this.thinkingLevel = level;
814
- await this.emitOwn({ type: "thinking_level_update", level, previousLevel });
815
- }
816
- catch (error) {
817
- throw normalizeHarnessError(error, "session");
818
- }
819
- }
820
- getTools() {
821
- return [...this.tools.values()];
822
- }
823
- async setTools(tools, activeToolNames) {
824
- try {
825
- this.validateUniqueNames(tools.map((tool) => tool.name), "Duplicate tool name(s)");
826
- const nextTools = new Map(tools.map((tool) => [tool.name, tool]));
827
- const nextActiveToolNames = activeToolNames ? [...activeToolNames] : this.activeToolNames;
828
- this.validateToolNames(nextActiveToolNames, nextTools);
829
- const previousToolNames = [...this.tools.keys()];
830
- const previousActiveToolNames = [...this.activeToolNames];
831
- if (this.phase === "idle") {
832
- await this.session.appendActiveToolsChange(nextActiveToolNames);
833
- }
834
- else {
835
- this.pendingSessionWrites.push({ type: "active_tools_change", activeToolNames: [...nextActiveToolNames] });
836
- }
837
- this.tools = nextTools;
838
- this.activeToolNames = [...nextActiveToolNames];
839
- await this.emitOwn({
840
- type: "tools_update",
841
- toolNames: [...this.tools.keys()],
842
- previousToolNames,
843
- activeToolNames: [...this.activeToolNames],
844
- previousActiveToolNames,
845
- source: "set",
846
- });
847
- }
848
- catch (error) {
849
- throw normalizeHarnessError(error, "invalid_argument");
850
- }
851
- }
852
- getActiveTools() {
853
- return this.activeToolNames.map((name) => this.tools.get(name));
854
- }
855
- async setActiveTools(toolNames) {
856
- try {
857
- this.validateToolNames(toolNames);
858
- const previousToolNames = [...this.tools.keys()];
859
- const previousActiveToolNames = [...this.activeToolNames];
860
- if (this.phase === "idle") {
861
- await this.session.appendActiveToolsChange(toolNames);
862
- }
863
- else {
864
- this.pendingSessionWrites.push({ type: "active_tools_change", activeToolNames: [...toolNames] });
865
- }
866
- this.activeToolNames = [...toolNames];
867
- await this.emitOwn({
868
- type: "tools_update",
869
- toolNames: [...this.tools.keys()],
870
- previousToolNames,
871
- activeToolNames: [...this.activeToolNames],
872
- previousActiveToolNames,
873
- source: "set",
874
- });
875
- }
876
- catch (error) {
877
- throw normalizeHarnessError(error, "invalid_argument");
878
- }
879
- }
880
- getSteeringMode() {
881
- return this.steeringQueueMode;
176
+ this.thinkingLevel = level;
882
177
  }
883
- async setSteeringMode(mode) {
884
- this.steeringQueueMode = mode;
178
+ async getActiveTools() {
179
+ return [...this.activeToolNames];
885
180
  }
886
- getFollowUpMode() {
887
- return this.followUpQueueMode;
181
+ async setActiveTools(names) {
182
+ this.activeToolNames = [...names];
888
183
  }
889
- async setFollowUpMode(mode) {
890
- this.followUpQueueMode = mode;
184
+ async watch() {
185
+ return this.unavailable("watch");
891
186
  }
892
- getResources() {
187
+ async lane(_name) {
188
+ return this.unavailable("lane");
189
+ }
190
+ async createLane(_name, _at) {
191
+ return this.unavailable("createLane");
192
+ }
193
+ async lanes() {
194
+ return this.unavailable("lanes");
195
+ }
196
+ async getTools() {
197
+ return [...this.tools];
198
+ }
199
+ async setTools(tools, activeNames) {
200
+ this.tools = [...tools];
201
+ this.activeToolNames = [...(activeNames ?? tools.map((tool) => tool.name))];
202
+ }
203
+ async getResources() {
893
204
  return {
894
- skills: this.resources.skills?.slice(),
895
- promptTemplates: this.resources.promptTemplates?.slice(),
205
+ skills: this.resources.skills ? [...this.resources.skills] : undefined,
206
+ promptTemplates: this.resources.promptTemplates ? [...this.resources.promptTemplates] : undefined,
896
207
  };
897
208
  }
898
209
  async setResources(resources) {
899
- const previousResources = this.getResources();
900
210
  this.resources = {
901
- skills: resources.skills?.slice(),
902
- promptTemplates: resources.promptTemplates?.slice(),
211
+ skills: resources.skills ? [...resources.skills] : undefined,
212
+ promptTemplates: resources.promptTemplates ? [...resources.promptTemplates] : undefined,
903
213
  };
904
- await this.emitOwn({ type: "resources_update", resources: this.getResources(), previousResources });
905
214
  }
906
- getStreamOptions() {
907
- return cloneStreamOptions(this.streamOptions);
215
+ async getStreamOptions() {
216
+ return { ...this.streamOptions };
908
217
  }
909
- async setStreamOptions(streamOptions) {
910
- this.streamOptions = cloneStreamOptions(streamOptions);
218
+ async setStreamOptions(options) {
219
+ this.streamOptions = { ...options };
911
220
  }
912
- async abort() {
913
- const clearedSteer = [...this.steerQueue];
914
- const clearedFollowUp = [...this.followUpQueue];
915
- this.steerQueue = [];
916
- this.followUpQueue = [];
917
- this.runAbortController?.abort();
918
- const errors = [];
919
- try {
920
- await this.emitQueueUpdate();
921
- }
922
- catch (error) {
923
- errors.push(toError(error));
924
- }
925
- try {
926
- await this.waitForIdle();
927
- }
928
- catch (error) {
929
- errors.push(toError(error));
930
- }
931
- try {
932
- await this.emitOwn({ type: "abort", clearedSteer, clearedFollowUp });
933
- }
934
- catch (error) {
935
- errors.push(toError(error));
936
- }
937
- if (errors.length > 0) {
938
- const cause = errors.length === 1 ? errors[0] : new AggregateError(errors, "Abort completed with errors");
939
- throw normalizeHarnessError(cause, "hook");
940
- }
941
- return { clearedSteer, clearedFollowUp };
221
+ async getRetryPolicy() {
222
+ return { ...this.retryPolicy };
942
223
  }
943
- async waitForIdle() {
944
- await this.runPromise;
945
- }
946
- subscribe(listener) {
947
- let handlers = this.handlers.get(SUBSCRIBER_EVENT_TYPE);
948
- if (!handlers) {
949
- handlers = new Set();
950
- this.handlers.set(SUBSCRIBER_EVENT_TYPE, handlers);
951
- }
952
- handlers.add(listener);
953
- return () => handlers.delete(listener);
954
- }
955
- on(type, handler) {
956
- let handlers = this.handlers.get(type);
957
- if (!handlers) {
958
- handlers = new Set();
959
- this.handlers.set(type, handlers);
960
- }
961
- handlers.add(handler);
962
- return () => handlers.delete(handler);
224
+ async setRetryPolicy(policy) {
225
+ this.retryPolicy = { ...policy };
226
+ }
227
+ async getCompactionSettings() {
228
+ return { ...this.compactionSettings };
229
+ }
230
+ async setCompactionSettings(settings) {
231
+ this.compactionSettings = { ...settings };
232
+ }
233
+ async getSteeringMode() {
234
+ return this.steeringMode;
235
+ }
236
+ async setSteeringMode(mode) {
237
+ this.steeringMode = mode;
238
+ }
239
+ async getFollowUpMode() {
240
+ return this.followUpMode;
241
+ }
242
+ async setFollowUpMode(mode) {
243
+ this.followUpMode = mode;
244
+ }
245
+ async watchSession() {
246
+ return this.unavailable("watchSession");
247
+ }
248
+ async close() {
249
+ this.closed = true;
963
250
  }
964
251
  }
965
252
  //# sourceMappingURL=agent-harness.js.map