@dxos/agent-runtime 0.11.1 → 0.12.0-next-73daef452f1464b62efdbca75fb0067c1066f264
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/lib/chunk-AgentService.mjs +165 -102
- package/dist/lib/chunk-AgentService.mjs.map +1 -1
- package/dist/lib/index.mjs +2 -2
- package/dist/lib/testing.mjs +33 -26
- package/dist/lib/testing.mjs.map +1 -1
- package/dist/types/src/agent-service/AgentService.d.ts +8 -1
- package/dist/types/src/agent-service/AgentService.d.ts.map +1 -1
- package/dist/types/src/agent-service/agent-process.d.ts +281 -314
- package/dist/types/src/agent-service/agent-process.d.ts.map +1 -1
- package/dist/types/src/agent-service/delegation-strategy.d.ts +1 -1
- package/dist/types/src/agent-service/delegation-strategy.d.ts.map +1 -1
- package/dist/types/src/agent-service/index.d.ts +1 -0
- package/dist/types/src/agent-service/index.d.ts.map +1 -1
- package/dist/types/src/agent-service/redelivery.test.d.ts +2 -0
- package/dist/types/src/agent-service/redelivery.test.d.ts.map +1 -0
- package/dist/types/src/agent-service/turn-producer.d.ts +52 -0
- package/dist/types/src/agent-service/turn-producer.d.ts.map +1 -0
- package/dist/types/src/testing/ResearchService.d.ts +1 -1
- package/dist/types/src/testing/ResearchService.d.ts.map +1 -1
- package/dist/types/src/testing/assistant-test-layer.d.ts +13 -6
- package/dist/types/src/testing/assistant-test-layer.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +0 -1
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-agent.d.ts +4 -3
- package/dist/types/src/testing/test-agent.d.ts.map +1 -1
- package/dist/types/src/testing/trace-pretty-print.d.ts +1 -1
- package/dist/types/src/testing/trace-pretty-print.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +18 -21
- package/src/agent-service/AgentService.test.ts +121 -42
- package/src/agent-service/AgentService.ts +15 -5
- package/src/agent-service/agent-process.test.ts +2 -2
- package/src/agent-service/agent-process.ts +121 -74
- package/src/agent-service/delegation-scripted.test.ts +4 -3
- package/src/agent-service/delegation-strategy.ts +1 -1
- package/src/agent-service/index.ts +1 -0
- package/src/agent-service/redelivery.test.ts +90 -0
- package/src/agent-service/turn-producer.ts +69 -0
- package/src/assistant-session-tests/format.test.ts +5 -2
- package/src/assistant-session-tests/request.test.ts +7 -7
- package/src/assistant-session-tests/scripted-loop.test.ts +5 -5
- package/src/assistant-session-tests/session.test.ts +2 -2
- package/src/assistant-session-tests/xml-response.test.ts +2 -2
- package/src/functions.test.ts +66 -6
- package/src/testing/ResearchService.ts +4 -6
- package/src/testing/assistant-test-layer.ts +22 -23
- package/src/testing/index.ts +0 -2
- package/src/testing/test-agent.ts +4 -3
- package/src/testing/trace-pretty-print.ts +2 -1
- package/src/agent-service/AgentService.conversations.json +0 -1
- package/src/assistant-session-tests/request.conversations.json +0 -1
- package/src/assistant-session-tests/xml-response.conversations.json +0 -1
- package/src/functions.conversations.json +0 -1
|
@@ -3,22 +3,29 @@ import * as Effect from "effect/Effect";
|
|
|
3
3
|
import * as Layer from "effect/Layer";
|
|
4
4
|
import * as Option from "effect/Option";
|
|
5
5
|
import { AgentRequestBegin, AgentRequestEnd, AiContext, AiSession, HarnessControl, SkillHooks, getOperationFromTool, makeToolExecutionService, makeToolResolverFromOperations } from "@dxos/assistant";
|
|
6
|
-
import { Credential, Instructions, Operation, Process, Skill, Trace } from "@dxos/compute";
|
|
7
6
|
import { ProcessManager } from "@dxos/compute-runtime";
|
|
8
|
-
import { AgentService
|
|
7
|
+
import { AgentService, getSession } from "@dxos/compute/AgentService";
|
|
8
|
+
import * as Process from "@dxos/compute/Process";
|
|
9
|
+
import * as Skill from "@dxos/compute/Skill";
|
|
9
10
|
import { Annotation, Database, Feed, Obj, Ref, Registry } from "@dxos/echo";
|
|
10
11
|
import { EffectEx } from "@dxos/effect";
|
|
11
12
|
import { DXN, EID } from "@dxos/keys";
|
|
12
13
|
import { log } from "@dxos/log";
|
|
13
|
-
import * as
|
|
14
|
-
import * as Toolkit from "@effect/ai/Toolkit";
|
|
14
|
+
import * as Clock from "effect/Clock";
|
|
15
15
|
import * as DateTime from "effect/DateTime";
|
|
16
16
|
import * as Duration from "effect/Duration";
|
|
17
17
|
import * as Exit from "effect/Exit";
|
|
18
18
|
import * as Match from "effect/Match";
|
|
19
19
|
import * as Schema from "effect/Schema";
|
|
20
|
+
import * as Struct from "effect/Struct";
|
|
21
|
+
import * as Tool from "effect/unstable/ai/Tool";
|
|
22
|
+
import * as Toolkit from "effect/unstable/ai/Toolkit";
|
|
20
23
|
import { AiService, OpaqueToolkit } from "@dxos/ai";
|
|
24
|
+
import * as Credential from "@dxos/compute/Credential";
|
|
25
|
+
import * as Instructions from "@dxos/compute/Instructions";
|
|
26
|
+
import * as Operation from "@dxos/compute/Operation";
|
|
21
27
|
import * as StorageService from "@dxos/compute/StorageService";
|
|
28
|
+
import * as Trace from "@dxos/compute/Trace";
|
|
22
29
|
import { ContentBlock } from "@dxos/types";
|
|
23
30
|
import { trim } from "@dxos/util";
|
|
24
31
|
//#region \0rolldown/runtime.js
|
|
@@ -33,6 +40,20 @@ var __exportAll = (all, no_symbols) => {
|
|
|
33
40
|
return target;
|
|
34
41
|
};
|
|
35
42
|
//#endregion
|
|
43
|
+
//#region src/agent-service/turn-producer.ts
|
|
44
|
+
/**
|
|
45
|
+
* The default producer: `AiSession.Session`, which resolves the model, binds skills and context
|
|
46
|
+
* objects as tools, and appends each message to the feed via its `onOutput` hook.
|
|
47
|
+
*/
|
|
48
|
+
var makeAiSessionTurnProducer = ({ feed, runtime, instructions }) => EffectEx.acquireReleaseResource(() => new AiSession.Session({
|
|
49
|
+
feed,
|
|
50
|
+
runtime,
|
|
51
|
+
instructions
|
|
52
|
+
})).pipe(Effect.map((session) => ({
|
|
53
|
+
runTurn: (params) => session.createRequest(params),
|
|
54
|
+
getSkills: () => session.context.getSkills()
|
|
55
|
+
})));
|
|
56
|
+
//#endregion
|
|
36
57
|
//#region src/agent-service/agent-process.ts
|
|
37
58
|
var __dxlog_file$1 = "/__w/dxos/dxos/packages/core/compute/agent-runtime/src/agent-service/agent-process.ts";
|
|
38
59
|
var AGENT_PROCESS_KEY = "org.dxos.testing.process.agent";
|
|
@@ -42,7 +63,7 @@ var AGENT_PROCESS_KEY = "org.dxos.testing.process.agent";
|
|
|
42
63
|
*/
|
|
43
64
|
var AgentProcess = (options) => Process.make({
|
|
44
65
|
key: AGENT_PROCESS_KEY,
|
|
45
|
-
input: Schema.Union(Schema.String, Schema.Array(ContentBlock.Any)),
|
|
66
|
+
input: Schema.Union([Schema.String, Schema.Array(ContentBlock.Any)]),
|
|
46
67
|
output: Schema.Void,
|
|
47
68
|
services: [
|
|
48
69
|
Database.Service,
|
|
@@ -61,38 +82,38 @@ var AgentProcess = (options) => Process.make({
|
|
|
61
82
|
const feed = yield* Database.resolve(feedDxn, Feed.Feed).pipe(Effect.orDie);
|
|
62
83
|
const instructionsDxn = Annotation.getDictionary(ctx.params.annotations, Process.InstructionsAnnotation).pipe(Option.getOrUndefined);
|
|
63
84
|
const instructions = instructionsDxn ? yield* Database.resolve(instructionsDxn, Instructions.Instructions).pipe(Effect.orElseSucceed(() => void 0)) : void 0;
|
|
64
|
-
const runtime = yield* Effect.
|
|
65
|
-
const session = yield*
|
|
85
|
+
const runtime = yield* Effect.context();
|
|
86
|
+
const session = yield* (options.makeTurnProducer ?? makeAiSessionTurnProducer)({
|
|
66
87
|
feed,
|
|
67
88
|
runtime,
|
|
68
89
|
instructions: instructions ? [instructions] : []
|
|
69
|
-
})
|
|
90
|
+
});
|
|
70
91
|
let inputQueue = [...yield* AgentEventsCell.get];
|
|
71
92
|
const storageService = yield* StorageService.StorageService;
|
|
72
93
|
const toolCallManager = new ToolCallManager(storageService);
|
|
73
94
|
yield* toolCallManager.load();
|
|
74
|
-
const clock = yield*
|
|
95
|
+
const clock = yield* Clock.Clock;
|
|
75
96
|
const alarmManager = new AlarmManager({
|
|
76
97
|
storageService,
|
|
77
98
|
setAlarm: (timeout) => ctx.setAlarm(timeout),
|
|
78
|
-
now: () => clock.
|
|
99
|
+
now: () => clock.currentTimeMillisUnsafe()
|
|
79
100
|
});
|
|
80
101
|
yield* alarmManager.load();
|
|
81
102
|
yield* toolCallManager.reconcileWithInputQueue(inputQueue);
|
|
82
|
-
const strategy = Option.
|
|
103
|
+
const strategy = Option.fromNullishOr(options.delegationStrategy);
|
|
83
104
|
let delegations = [...yield* DelegationsCell.get];
|
|
84
105
|
const requestModelLayer = AiService.model(options.model ? DXN.getName(options.model) : "com.anthropic.model.claude-opus-4-8.default", { provider: options.provider });
|
|
85
106
|
const operationInvoker = yield* ProcessManager.ProcessOperationInvoker.Service;
|
|
86
107
|
const runEndRequestHooks = Effect.gen(function* () {
|
|
87
108
|
yield* SkillHooks.runHooks({
|
|
88
|
-
skills: session.
|
|
109
|
+
skills: session.getSkills(),
|
|
89
110
|
phase: "end-request",
|
|
90
111
|
invoke: (operation, input) => Effect.gen(function* () {
|
|
91
112
|
const exit = yield* (yield* operationInvoker.invokeFiber(operation, input, {
|
|
92
113
|
environment: { conversation: Obj.getURI(feed) },
|
|
93
114
|
traceMeta: { conversation: Ref.make(feed) }
|
|
94
115
|
})).await;
|
|
95
|
-
if (Exit.isFailure(exit)) yield* Effect.failCause(exit.cause);
|
|
116
|
+
if (Exit.isFailure(exit)) return yield* Effect.failCause(exit.cause);
|
|
96
117
|
}).pipe(Effect.asVoid, Effect.orDie)
|
|
97
118
|
});
|
|
98
119
|
});
|
|
@@ -113,7 +134,7 @@ var AgentProcess = (options) => Process.make({
|
|
|
113
134
|
log("agent work enqueued by end-request hook, continuing", void 0, {
|
|
114
135
|
"~LogMeta": "~LogMeta",
|
|
115
136
|
F: __dxlog_file$1,
|
|
116
|
-
L:
|
|
137
|
+
L: 205,
|
|
117
138
|
S: this
|
|
118
139
|
});
|
|
119
140
|
alarmManager.reconcile(true);
|
|
@@ -122,13 +143,13 @@ var AgentProcess = (options) => Process.make({
|
|
|
122
143
|
log("agent work complete, succeeding", void 0, {
|
|
123
144
|
"~LogMeta": "~LogMeta",
|
|
124
145
|
F: __dxlog_file$1,
|
|
125
|
-
L:
|
|
146
|
+
L: 210,
|
|
126
147
|
S: this
|
|
127
148
|
});
|
|
128
149
|
ctx.succeed();
|
|
129
150
|
});
|
|
130
151
|
return {
|
|
131
|
-
rpcHandlers: yield* HarnessControl.
|
|
152
|
+
rpcHandlers: yield* HarnessControl.toHandlers({
|
|
132
153
|
setAlarm: Effect.fn(function* ({ at, message }) {
|
|
133
154
|
yield* alarmManager.setWakeAt(DateTime.toEpochMillis(at), message);
|
|
134
155
|
alarmManager.reconcile(inputQueue.length > 0);
|
|
@@ -146,7 +167,7 @@ var AgentProcess = (options) => Process.make({
|
|
|
146
167
|
log("agent onInput received", { backlog: inputQueue.length }, {
|
|
147
168
|
"~LogMeta": "~LogMeta",
|
|
148
169
|
F: __dxlog_file$1,
|
|
149
|
-
L:
|
|
170
|
+
L: 229,
|
|
150
171
|
S: this
|
|
151
172
|
});
|
|
152
173
|
const content = typeof prompt === "string" ? [ContentBlock.Text.make({ text: prompt })] : [...prompt];
|
|
@@ -157,21 +178,21 @@ var AgentProcess = (options) => Process.make({
|
|
|
157
178
|
log("agent onInput persisting queue", { depth: inputQueue.length }, {
|
|
158
179
|
"~LogMeta": "~LogMeta",
|
|
159
180
|
F: __dxlog_file$1,
|
|
160
|
-
L:
|
|
181
|
+
L: 232,
|
|
161
182
|
S: this
|
|
162
183
|
});
|
|
163
184
|
yield* AgentEventsCell.set(inputQueue);
|
|
164
185
|
log("agent onInput persisted", { depth: inputQueue.length }, {
|
|
165
186
|
"~LogMeta": "~LogMeta",
|
|
166
187
|
F: __dxlog_file$1,
|
|
167
|
-
L:
|
|
188
|
+
L: 234,
|
|
168
189
|
S: this
|
|
169
190
|
});
|
|
170
191
|
alarmManager.reconcile(true);
|
|
171
192
|
log("agent onInput alarm scheduled", void 0, {
|
|
172
193
|
"~LogMeta": "~LogMeta",
|
|
173
194
|
F: __dxlog_file$1,
|
|
174
|
-
L:
|
|
195
|
+
L: 236,
|
|
175
196
|
S: this
|
|
176
197
|
});
|
|
177
198
|
}),
|
|
@@ -179,7 +200,7 @@ var AgentProcess = (options) => Process.make({
|
|
|
179
200
|
log("agent onAlarm fired", { pending: inputQueue.length }, {
|
|
180
201
|
"~LogMeta": "~LogMeta",
|
|
181
202
|
F: __dxlog_file$1,
|
|
182
|
-
L:
|
|
203
|
+
L: 240,
|
|
183
204
|
S: this
|
|
184
205
|
});
|
|
185
206
|
const fired = yield* alarmManager.takeFiredAlarm();
|
|
@@ -187,7 +208,7 @@ var AgentProcess = (options) => Process.make({
|
|
|
187
208
|
log("agent onAlarm self-wake", { firedAt: fired.firedAt }, {
|
|
188
209
|
"~LogMeta": "~LogMeta",
|
|
189
210
|
F: __dxlog_file$1,
|
|
190
|
-
L:
|
|
211
|
+
L: 245,
|
|
191
212
|
S: this
|
|
192
213
|
});
|
|
193
214
|
inputQueue.push({
|
|
@@ -197,26 +218,18 @@ var AgentProcess = (options) => Process.make({
|
|
|
197
218
|
});
|
|
198
219
|
yield* AgentEventsCell.set(inputQueue);
|
|
199
220
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
F: __dxlog_file$1,
|
|
207
|
-
L: 243,
|
|
208
|
-
S: this
|
|
209
|
-
});
|
|
210
|
-
continue;
|
|
211
|
-
}
|
|
212
|
-
break;
|
|
213
|
-
}
|
|
221
|
+
for (const pid of dropReportedToolResults(inputQueue, (pid) => toolCallManager.isReported(pid))) log.info("skip tool result that was reported synchronously", { pid }, {
|
|
222
|
+
"~LogMeta": "~LogMeta",
|
|
223
|
+
F: __dxlog_file$1,
|
|
224
|
+
L: 251,
|
|
225
|
+
S: this
|
|
226
|
+
});
|
|
214
227
|
const item = inputQueue.shift();
|
|
215
228
|
if (!item) {
|
|
216
229
|
log("agent onAlarm empty queue", {}, {
|
|
217
230
|
"~LogMeta": "~LogMeta",
|
|
218
231
|
F: __dxlog_file$1,
|
|
219
|
-
L:
|
|
232
|
+
L: 256,
|
|
220
233
|
S: this
|
|
221
234
|
});
|
|
222
235
|
alarmManager.reconcile(false);
|
|
@@ -227,44 +240,35 @@ var AgentProcess = (options) => Process.make({
|
|
|
227
240
|
log("agent onAlarm handling", { tag: item._tag }, {
|
|
228
241
|
"~LogMeta": "~LogMeta",
|
|
229
242
|
F: __dxlog_file$1,
|
|
230
|
-
L:
|
|
243
|
+
L: 263,
|
|
231
244
|
S: this
|
|
232
245
|
});
|
|
233
|
-
const prompt =
|
|
234
|
-
text: toolErrorResponse(item.pid, item.result),
|
|
235
|
-
disposition: "synthetic"
|
|
236
|
-
})] : [ContentBlock.Text.make({
|
|
237
|
-
text: toolResultResponse(item.pid, item.result),
|
|
238
|
-
disposition: "synthetic"
|
|
239
|
-
})]), Match.tag("alarm", (item) => [ContentBlock.Text.make({
|
|
240
|
-
text: wakeUpPrompt(item.firedAt, item.message),
|
|
241
|
-
disposition: "synthetic"
|
|
242
|
-
})]), Match.exhaustive);
|
|
246
|
+
const prompt = agentEventToPrompt(item);
|
|
243
247
|
log("begin request", { prompt }, {
|
|
244
248
|
"~LogMeta": "~LogMeta",
|
|
245
249
|
F: __dxlog_file$1,
|
|
246
|
-
L:
|
|
250
|
+
L: 267,
|
|
247
251
|
S: this
|
|
248
252
|
});
|
|
249
253
|
log("trace agent request begin", void 0, {
|
|
250
254
|
"~LogMeta": "~LogMeta",
|
|
251
255
|
F: __dxlog_file$1,
|
|
252
|
-
L:
|
|
256
|
+
L: 268,
|
|
253
257
|
S: this
|
|
254
258
|
});
|
|
255
259
|
yield* Trace.write(AgentRequestBegin, {});
|
|
256
|
-
yield* session.
|
|
260
|
+
yield* session.runTurn({
|
|
257
261
|
prompt,
|
|
258
262
|
system: options.systemPrompt,
|
|
259
263
|
mcpServers: options.getMcpServers?.()
|
|
260
264
|
}).pipe(Effect.onExit((exit) => Trace.write(AgentRequestEnd, {
|
|
261
|
-
status: Exit.isSuccess(exit) ? "success" : Exit.
|
|
265
|
+
status: Exit.isSuccess(exit) ? "success" : Exit.hasInterrupts(exit) ? "interrupted" : "error",
|
|
262
266
|
error: Exit.isFailure(exit) ? Cause.pretty(exit.cause) : void 0
|
|
263
267
|
})));
|
|
264
268
|
log("end request", void 0, {
|
|
265
269
|
"~LogMeta": "~LogMeta",
|
|
266
270
|
F: __dxlog_file$1,
|
|
267
|
-
L:
|
|
271
|
+
L: 288,
|
|
268
272
|
S: this
|
|
269
273
|
});
|
|
270
274
|
yield* AgentEventsCell.set(inputQueue);
|
|
@@ -283,7 +287,7 @@ var AgentProcess = (options) => Process.make({
|
|
|
283
287
|
}, {
|
|
284
288
|
"~LogMeta": "~LogMeta",
|
|
285
289
|
F: __dxlog_file$1,
|
|
286
|
-
L:
|
|
290
|
+
L: 299,
|
|
287
291
|
S: this
|
|
288
292
|
});
|
|
289
293
|
}
|
|
@@ -300,7 +304,7 @@ var AgentProcess = (options) => Process.make({
|
|
|
300
304
|
log("childEvent", { event }, {
|
|
301
305
|
"~LogMeta": "~LogMeta",
|
|
302
306
|
F: __dxlog_file$1,
|
|
303
|
-
L:
|
|
307
|
+
L: 325,
|
|
304
308
|
S: this
|
|
305
309
|
});
|
|
306
310
|
if (event._tag === "exited") {
|
|
@@ -309,7 +313,28 @@ var AgentProcess = (options) => Process.make({
|
|
|
309
313
|
delegations = delegations.filter((other) => other.pid !== event.pid);
|
|
310
314
|
yield* DelegationsCell.set(delegations);
|
|
311
315
|
const exit = yield* (yield* (yield* ProcessManager.ProcessOperationInvoker.Service).attachFiber(event.pid).pipe(Effect.orDie)).await;
|
|
312
|
-
if (Option.isSome(strategy))
|
|
316
|
+
if (Option.isSome(strategy)) {
|
|
317
|
+
yield* strategy.value.onComplete(feed, delegation.id, exit);
|
|
318
|
+
const activeIds = new Set(delegations.map((delegation) => delegation.id));
|
|
319
|
+
const pending = yield* strategy.value.reconcile(feed, activeIds);
|
|
320
|
+
for (const next of pending) {
|
|
321
|
+
const pid = yield* next.spawn;
|
|
322
|
+
delegations.push({
|
|
323
|
+
pid,
|
|
324
|
+
id: next.id
|
|
325
|
+
});
|
|
326
|
+
log("delegated work", {
|
|
327
|
+
pid,
|
|
328
|
+
id: next.id
|
|
329
|
+
}, {
|
|
330
|
+
"~LogMeta": "~LogMeta",
|
|
331
|
+
F: __dxlog_file$1,
|
|
332
|
+
L: 347,
|
|
333
|
+
S: this
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
if (pending.length > 0) yield* DelegationsCell.set(delegations);
|
|
337
|
+
}
|
|
313
338
|
log("delegated work completed", {
|
|
314
339
|
pid: event.pid,
|
|
315
340
|
id: delegation.id,
|
|
@@ -317,7 +342,7 @@ var AgentProcess = (options) => Process.make({
|
|
|
317
342
|
}, {
|
|
318
343
|
"~LogMeta": "~LogMeta",
|
|
319
344
|
F: __dxlog_file$1,
|
|
320
|
-
L:
|
|
345
|
+
L: 353,
|
|
321
346
|
S: this
|
|
322
347
|
});
|
|
323
348
|
yield* maybeComplete;
|
|
@@ -328,7 +353,7 @@ var AgentProcess = (options) => Process.make({
|
|
|
328
353
|
log.verbose("childEvent skipped (process gone, result already handled)", { pid: event.pid }, {
|
|
329
354
|
"~LogMeta": "~LogMeta",
|
|
330
355
|
F: __dxlog_file$1,
|
|
331
|
-
L:
|
|
356
|
+
L: 366,
|
|
332
357
|
S: this
|
|
333
358
|
});
|
|
334
359
|
return;
|
|
@@ -356,7 +381,7 @@ var AgentProcess = (options) => Process.make({
|
|
|
356
381
|
}, {
|
|
357
382
|
"~LogMeta": "~LogMeta",
|
|
358
383
|
F: __dxlog_file$1,
|
|
359
|
-
L:
|
|
384
|
+
L: 391,
|
|
360
385
|
S: this
|
|
361
386
|
});
|
|
362
387
|
yield* AgentEventsCell.set(inputQueue);
|
|
@@ -364,28 +389,32 @@ var AgentProcess = (options) => Process.make({
|
|
|
364
389
|
log("agent onChildEvent alarm scheduled", { depth: inputQueue.length }, {
|
|
365
390
|
"~LogMeta": "~LogMeta",
|
|
366
391
|
F: __dxlog_file$1,
|
|
367
|
-
L:
|
|
392
|
+
L: 394,
|
|
368
393
|
S: this
|
|
369
394
|
});
|
|
370
395
|
} else log.verbose("childEvent ignored non-tool call and not a delegation", { pid: event.pid }, {
|
|
371
396
|
"~LogMeta": "~LogMeta",
|
|
372
397
|
F: __dxlog_file$1,
|
|
373
|
-
L:
|
|
398
|
+
L: 396,
|
|
374
399
|
S: this
|
|
375
400
|
});
|
|
376
401
|
}
|
|
377
402
|
})
|
|
378
403
|
};
|
|
379
404
|
}));
|
|
380
|
-
var AgentEvent = Schema.Union(
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
405
|
+
var AgentEvent = Schema.Union([
|
|
406
|
+
Schema.TaggedStruct("prompt", { content: Schema.Array(ContentBlock.Any) }),
|
|
407
|
+
Schema.TaggedStruct("tool_result", {
|
|
408
|
+
pid: Process.ID,
|
|
409
|
+
result: Schema.Unknown,
|
|
410
|
+
isError: Schema.Boolean
|
|
411
|
+
}),
|
|
412
|
+
Schema.TaggedStruct("alarm", {
|
|
413
|
+
firedAt: Schema.Number,
|
|
414
|
+
message: Schema.NullOr(Schema.String)
|
|
415
|
+
})
|
|
416
|
+
]);
|
|
417
|
+
var AgentEventsCell = StorageService.cell(Schema.fromJsonString(Schema.Array(AgentEvent).pipe(Schema.mutable)), "inputQueue").pipe(StorageService.withDefault(() => []));
|
|
389
418
|
/**
|
|
390
419
|
* Tracks delegated sub-agent child processes (pid -> correlation id) so that, after a hibernation,
|
|
391
420
|
* a delegated child's exit can be matched back to the work it was fulfilling.
|
|
@@ -393,13 +422,13 @@ var AgentEventsCell = StorageService.cell(Schema.parseJson(Schema.Array(AgentEve
|
|
|
393
422
|
var Delegation = Schema.Struct({
|
|
394
423
|
pid: Process.ID,
|
|
395
424
|
id: Schema.String
|
|
396
|
-
}).
|
|
397
|
-
var DelegationsCell = StorageService.cell(Schema.
|
|
425
|
+
}).mapFields(Struct.map(Schema.mutableKey));
|
|
426
|
+
var DelegationsCell = StorageService.cell(Schema.fromJsonString(Schema.Array(Delegation).pipe(Schema.mutable)), "delegations").pipe(StorageService.withDefault(() => []));
|
|
398
427
|
var ToolCallState = Schema.Struct({ activeCalls: Schema.Array(Schema.Struct({
|
|
399
428
|
pid: Process.ID,
|
|
400
429
|
reported: Schema.Boolean
|
|
401
|
-
}).
|
|
402
|
-
var ToolCallStateCell = StorageService.cell(Schema.
|
|
430
|
+
}).mapFields(Struct.map(Schema.mutableKey))).pipe(Schema.mutable) });
|
|
431
|
+
var ToolCallStateCell = StorageService.cell(Schema.fromJsonString(ToolCallState.mapFields(Struct.map(Schema.mutableKey))), "toolCallState").pipe(StorageService.withDefault(() => ({ activeCalls: [] })));
|
|
403
432
|
var ToolCallManager = class {
|
|
404
433
|
#storageService;
|
|
405
434
|
#state = { activeCalls: [] };
|
|
@@ -407,12 +436,12 @@ var ToolCallManager = class {
|
|
|
407
436
|
this.#storageService = storageService;
|
|
408
437
|
}
|
|
409
438
|
load() {
|
|
410
|
-
return Effect.gen(this, function* () {
|
|
439
|
+
return Effect.gen({ self: this }, function* () {
|
|
411
440
|
this.#state = yield* ToolCallStateCell.get;
|
|
412
441
|
}).pipe(Effect.provideService(StorageService.StorageService, this.#storageService));
|
|
413
442
|
}
|
|
414
443
|
beginCall(pid) {
|
|
415
|
-
return Effect.gen(this, function* () {
|
|
444
|
+
return Effect.gen({ self: this }, function* () {
|
|
416
445
|
this.#state.activeCalls.push({
|
|
417
446
|
pid,
|
|
418
447
|
reported: false
|
|
@@ -421,7 +450,7 @@ var ToolCallManager = class {
|
|
|
421
450
|
}).pipe(Effect.provideService(StorageService.StorageService, this.#storageService));
|
|
422
451
|
}
|
|
423
452
|
markAsReported(pid) {
|
|
424
|
-
return Effect.gen(this, function* () {
|
|
453
|
+
return Effect.gen({ self: this }, function* () {
|
|
425
454
|
const call = this.#state.activeCalls.find((call) => call.pid === pid);
|
|
426
455
|
if (!call) return;
|
|
427
456
|
call.reported = true;
|
|
@@ -443,7 +472,7 @@ var ToolCallManager = class {
|
|
|
443
472
|
* After reload the in-flight createRequest is gone, so those results must be redelivered via onAlarm.
|
|
444
473
|
*/
|
|
445
474
|
reconcileWithInputQueue(queue) {
|
|
446
|
-
return Effect.gen(this, function* () {
|
|
475
|
+
return Effect.gen({ self: this }, function* () {
|
|
447
476
|
let changed = false;
|
|
448
477
|
for (const item of queue) {
|
|
449
478
|
if (item._tag !== "tool_result") continue;
|
|
@@ -454,7 +483,7 @@ var ToolCallManager = class {
|
|
|
454
483
|
log("reconcile queued tool result", { pid: item.pid }, {
|
|
455
484
|
"~LogMeta": "~LogMeta",
|
|
456
485
|
F: __dxlog_file$1,
|
|
457
|
-
L:
|
|
486
|
+
L: 535,
|
|
458
487
|
S: this
|
|
459
488
|
});
|
|
460
489
|
}
|
|
@@ -466,10 +495,43 @@ var ToolCallManager = class {
|
|
|
466
495
|
/** True while the agent still has queued work, a self-wake, subprocesses, or undelivered tool results. */
|
|
467
496
|
var isAgentWorkPending = ({ inputQueue, alarmManager, delegations, toolCallManager }) => inputQueue.length > 0 || alarmManager.wakeAt != null || delegations.length > 0 || toolCallManager.hasPendingToolResults();
|
|
468
497
|
/**
|
|
498
|
+
* Discards tool results at the head of the queue whose values already reached the agent.
|
|
499
|
+
*
|
|
500
|
+
* A tool that returned inside its turn is reported synchronously AND left queued; after a reload the
|
|
501
|
+
* queue is replayed, so without this the model would be handed a result it has already seen. Only the
|
|
502
|
+
* head is examined: a result further back belongs to a turn that has not run yet.
|
|
503
|
+
*
|
|
504
|
+
* Mutates `queue` and returns the pids dropped, so the caller owns the logging.
|
|
505
|
+
*/
|
|
506
|
+
var dropReportedToolResults = (queue, isReported) => {
|
|
507
|
+
const dropped = [];
|
|
508
|
+
while (queue.length > 0) {
|
|
509
|
+
const head = queue[0];
|
|
510
|
+
if (head._tag !== "tool_result" || !isReported(head.pid)) break;
|
|
511
|
+
queue.shift();
|
|
512
|
+
dropped.push(head.pid);
|
|
513
|
+
}
|
|
514
|
+
return dropped;
|
|
515
|
+
};
|
|
516
|
+
/**
|
|
517
|
+
* Renders a queued event as the next turn's prompt.
|
|
518
|
+
*
|
|
519
|
+
* A tool result recovered across a reload is redelivered as a synthetic `<result pid=N>` TEXT block
|
|
520
|
+
* rather than a tool-result part, because the request it belonged to is gone and its tool-call id
|
|
521
|
+
* cannot be answered. `disposition: 'synthetic'` keeps it out of the user-visible transcript.
|
|
522
|
+
*/
|
|
523
|
+
var agentEventToPrompt = (event) => Match.value(event).pipe(Match.tag("prompt", (event) => [...event.content]), Match.tag("tool_result", (event) => [ContentBlock.Text.make({
|
|
524
|
+
text: event.isError ? toolErrorResponse(event.pid, event.result) : toolResultResponse(event.pid, event.result),
|
|
525
|
+
disposition: "synthetic"
|
|
526
|
+
})]), Match.tag("alarm", (event) => [ContentBlock.Text.make({
|
|
527
|
+
text: wakeUpPrompt(event.firedAt, event.message),
|
|
528
|
+
disposition: "synthetic"
|
|
529
|
+
})]), Match.exhaustive);
|
|
530
|
+
/**
|
|
469
531
|
* Persisted next agent-scheduled self-wake: the UNIX timestamp (ms) and an optional reminder
|
|
470
532
|
* message delivered when it fires, or `null` when no self-wake is set.
|
|
471
533
|
*/
|
|
472
|
-
var AgentAlarmCell = StorageService.cell(Schema.
|
|
534
|
+
var AgentAlarmCell = StorageService.cell(Schema.fromJsonString(Schema.NullOr(Schema.Struct({
|
|
473
535
|
wakeAt: Schema.Number,
|
|
474
536
|
message: Schema.NullOr(Schema.String)
|
|
475
537
|
}))), "agentAlarm").pipe(StorageService.withDefault(() => null));
|
|
@@ -512,7 +574,7 @@ var AlarmManager = class {
|
|
|
512
574
|
}
|
|
513
575
|
/** Restores the persisted alarm state. */
|
|
514
576
|
load() {
|
|
515
|
-
return Effect.gen(this, function* () {
|
|
577
|
+
return Effect.gen({ self: this }, function* () {
|
|
516
578
|
const persisted = yield* AgentAlarmCell.get;
|
|
517
579
|
this.#wakeAt = persisted?.wakeAt ?? null;
|
|
518
580
|
this.#message = persisted?.message ?? null;
|
|
@@ -520,7 +582,7 @@ var AlarmManager = class {
|
|
|
520
582
|
}
|
|
521
583
|
/** Records a new self-wake target (with an optional reminder message) and persists it. */
|
|
522
584
|
setWakeAt(wakeAt, message = null) {
|
|
523
|
-
return Effect.gen(this, function* () {
|
|
585
|
+
return Effect.gen({ self: this }, function* () {
|
|
524
586
|
this.#wakeAt = wakeAt;
|
|
525
587
|
this.#message = message;
|
|
526
588
|
yield* AgentAlarmCell.set({
|
|
@@ -534,7 +596,7 @@ var AlarmManager = class {
|
|
|
534
596
|
* reminder message it carried (or `null` if no alarm was due).
|
|
535
597
|
*/
|
|
536
598
|
takeFiredAlarm() {
|
|
537
|
-
return Effect.gen(this, function* () {
|
|
599
|
+
return Effect.gen({ self: this }, function* () {
|
|
538
600
|
if (this.#wakeAt == null || this.#now() < this.#wakeAt) return null;
|
|
539
601
|
const firedAt = this.#wakeAt;
|
|
540
602
|
const message = this.#message;
|
|
@@ -571,7 +633,7 @@ var wakeUpPrompt = (firedAt, message) => message != null ? trim`
|
|
|
571
633
|
Your scheduled alarm fired (it was set for ${new Date(firedAt).toISOString()}).
|
|
572
634
|
Continue with whatever you intended to do when you scheduled this wake-up.
|
|
573
635
|
`;
|
|
574
|
-
var ToolExecutionService = ({ enableBackgrounding, backgroundThreshold = Duration.seconds(1), toolCallManager, feed }) => Layer.
|
|
636
|
+
var ToolExecutionService = ({ enableBackgrounding, backgroundThreshold = Duration.seconds(1), toolCallManager, feed }) => Layer.unwrap(Effect.gen(function* () {
|
|
575
637
|
const operationInvoker = yield* ProcessManager.ProcessOperationInvoker.Service;
|
|
576
638
|
return makeToolExecutionService({ invoke: (tool, input) => Effect.gen(function* () {
|
|
577
639
|
const operationDef = getOperationFromTool(tool).pipe(Option.getOrThrow);
|
|
@@ -581,7 +643,7 @@ var ToolExecutionService = ({ enableBackgrounding, backgroundThreshold = Duratio
|
|
|
581
643
|
}, {
|
|
582
644
|
"~LogMeta": "~LogMeta",
|
|
583
645
|
F: __dxlog_file$1,
|
|
584
|
-
L:
|
|
646
|
+
L: 770,
|
|
585
647
|
S: this
|
|
586
648
|
});
|
|
587
649
|
const fiber = yield* operationInvoker.invokeFiber(operationDef, input, {
|
|
@@ -596,15 +658,15 @@ var ToolExecutionService = ({ enableBackgrounding, backgroundThreshold = Duratio
|
|
|
596
658
|
}, {
|
|
597
659
|
"~LogMeta": "~LogMeta",
|
|
598
660
|
F: __dxlog_file$1,
|
|
599
|
-
L:
|
|
661
|
+
L: 780,
|
|
600
662
|
S: this
|
|
601
663
|
});
|
|
602
664
|
const awaitWithReport = fiber.await.pipe(Effect.tap(() => toolCallManager.markAsReported(fiber.pid)));
|
|
603
|
-
const result = enableBackgrounding ? yield* awaitWithReport.pipe(Effect.timeout(backgroundThreshold), Effect.catchTag("
|
|
665
|
+
const result = enableBackgrounding ? yield* awaitWithReport.pipe(Effect.timeout(backgroundThreshold), Effect.catchTag("TimeoutError", () => Effect.succeed(Exit.succeed(toolIsRunningInBackgroundResponse(fiber.pid))))) : yield* awaitWithReport;
|
|
604
666
|
log("result", { result }, {
|
|
605
667
|
"~LogMeta": "~LogMeta",
|
|
606
668
|
F: __dxlog_file$1,
|
|
607
|
-
L:
|
|
669
|
+
L: 791,
|
|
608
670
|
S: this
|
|
609
671
|
});
|
|
610
672
|
return yield* result;
|
|
@@ -618,17 +680,17 @@ var AsynchronousExectionToolkit = class extends Toolkit.make(Tool.make("poll-too
|
|
|
618
680
|
Set an appropriate timeout to avoid waiting forever.
|
|
619
681
|
You will also be notified about the job completion separatelly, so you do not always need to inspect the job if you dont need the result right now.
|
|
620
682
|
`,
|
|
621
|
-
parameters: {
|
|
622
|
-
ids: Schema.Array(Schema.String).
|
|
623
|
-
wait: Schema.optional(Schema.Boolean).
|
|
683
|
+
parameters: Schema.Struct({
|
|
684
|
+
ids: Schema.Array(Schema.String).annotate({ description: "The IDs of the jobs to inspect." }),
|
|
685
|
+
wait: Schema.optional(Schema.Boolean).annotate({
|
|
624
686
|
description: "Whether to wait for the tool call to complete before returning.",
|
|
625
687
|
default: false
|
|
626
688
|
}),
|
|
627
|
-
timeout: Schema.optional(Schema.Number).
|
|
689
|
+
timeout: Schema.optional(Schema.Number).annotate({
|
|
628
690
|
description: "Maximum time to wait for the job to complete. If the job does not complete within the timeout, the current state is returned.",
|
|
629
691
|
default: 1e4
|
|
630
692
|
})
|
|
631
|
-
}
|
|
693
|
+
})
|
|
632
694
|
})) {};
|
|
633
695
|
var AsynchronousExectionToolkitLayer = AsynchronousExectionToolkit.toLayer(Effect.gen(function* () {
|
|
634
696
|
const invoker = yield* ProcessManager.ProcessOperationInvoker.Service;
|
|
@@ -636,7 +698,7 @@ var AsynchronousExectionToolkitLayer = AsynchronousExectionToolkit.toLayer(Effec
|
|
|
636
698
|
return yield* Effect.forEach(ids, (pid) => invoker.attachFiber(Process.ID.make(pid)).pipe(Effect.flatMap((_) => _.await), Effect.timeout(Duration.millis(timeout)), Effect.flatMap(Exit.match({
|
|
637
699
|
onSuccess: (value) => Effect.succeed(toolResultResponse(pid, value)),
|
|
638
700
|
onFailure: (cause) => Effect.succeed(toolErrorResponse(pid, Cause.pretty(cause)))
|
|
639
|
-
})), Effect.catchTag("ProcessNotFoundError", () => Effect.succeed(`Process not found: ${pid}`)), Effect.catchTag("
|
|
701
|
+
})), Effect.catchTag("ProcessNotFoundError", () => Effect.succeed(`Process not found: ${pid}`)), Effect.catchTag("TimeoutError", () => Effect.succeed(`Process still running: ${pid}`))));
|
|
640
702
|
}) };
|
|
641
703
|
}));
|
|
642
704
|
/**
|
|
@@ -656,7 +718,7 @@ var isTerminalProcess = (state) => state === Process.State.SUCCEEDED || state ==
|
|
|
656
718
|
var createSession = Effect.fn("createSession")(function* (opts) {
|
|
657
719
|
const skills = yield* Effect.forEach(opts?.skills ?? [], (skill) => Skill.upsert(Skill.getKey(skill)).pipe(Effect.map(Ref.make)));
|
|
658
720
|
const feed = yield* Database.add(Feed.make());
|
|
659
|
-
const runtime = yield* Effect.
|
|
721
|
+
const runtime = yield* Effect.context();
|
|
660
722
|
const binder = yield* EffectEx.acquireReleaseResource(() => new AiContext.Binder({
|
|
661
723
|
feed,
|
|
662
724
|
runtime
|
|
@@ -670,11 +732,12 @@ var createSession = Effect.fn("createSession")(function* (opts) {
|
|
|
670
732
|
provider: opts?.provider
|
|
671
733
|
});
|
|
672
734
|
}, Effect.scoped);
|
|
673
|
-
var layer = (opts) => Layer.effect(AgentService
|
|
735
|
+
var layer = (opts) => Layer.effect(AgentService, Effect.gen(function* () {
|
|
674
736
|
const processManager = yield* ProcessManager.Service;
|
|
675
737
|
const sessionCache = /* @__PURE__ */ new Map();
|
|
676
738
|
const makeExecutable = (model, provider) => AgentProcess({
|
|
677
739
|
systemPrompt: opts?.systemPrompt,
|
|
740
|
+
makeTurnProducer: opts?.makeTurnProducer,
|
|
678
741
|
model: model ?? opts?.model,
|
|
679
742
|
provider: provider ?? opts?.provider,
|
|
680
743
|
getMcpServers: opts?.getMcpServers,
|
|
@@ -743,16 +806,16 @@ var layer = (opts) => Layer.effect(AgentService$1, Effect.gen(function* () {
|
|
|
743
806
|
log("agent hydrate", { count: agents.length }, {
|
|
744
807
|
"~LogMeta": "~LogMeta",
|
|
745
808
|
F: __dxlog_file,
|
|
746
|
-
L:
|
|
809
|
+
L: 150,
|
|
747
810
|
S: this
|
|
748
811
|
});
|
|
749
|
-
for (const agent of agents) yield* agent.hydrate(executable).pipe(Effect.
|
|
812
|
+
for (const agent of agents) yield* agent.hydrate(executable).pipe(Effect.catchCause((cause) => Effect.sync(() => log.warn("agent hydrate skipped", {
|
|
750
813
|
pid: agent.pid,
|
|
751
814
|
cause: Cause.pretty(cause)
|
|
752
815
|
}, {
|
|
753
816
|
"~LogMeta": "~LogMeta",
|
|
754
817
|
F: __dxlog_file,
|
|
755
|
-
L:
|
|
818
|
+
L: 156,
|
|
756
819
|
S: this
|
|
757
820
|
}))));
|
|
758
821
|
})
|
|
@@ -761,14 +824,14 @@ var layer = (opts) => Layer.effect(AgentService$1, Effect.gen(function* () {
|
|
|
761
824
|
var makeSession = (process, feed, releaseSession) => ({
|
|
762
825
|
feed,
|
|
763
826
|
getContext: () => Effect.gen(function* () {
|
|
764
|
-
const runtime = yield* Effect.
|
|
827
|
+
const runtime = yield* Effect.context();
|
|
765
828
|
return (yield* EffectEx.acquireReleaseResource(() => new AiContext.Binder({
|
|
766
829
|
feed,
|
|
767
830
|
runtime
|
|
768
831
|
}))).getObjects().map((object) => Ref.make(object));
|
|
769
832
|
}).pipe(Effect.scoped),
|
|
770
833
|
addContext: (context) => Effect.gen(function* () {
|
|
771
|
-
const runtime = yield* Effect.
|
|
834
|
+
const runtime = yield* Effect.context();
|
|
772
835
|
const binder = yield* EffectEx.acquireReleaseResource(() => new AiContext.Binder({
|
|
773
836
|
feed,
|
|
774
837
|
runtime
|
|
@@ -784,6 +847,6 @@ var makeSession = (process, feed, releaseSession) => ({
|
|
|
784
847
|
subscribeEphemeral: () => process.subscribeEphemeral()
|
|
785
848
|
});
|
|
786
849
|
//#endregion
|
|
787
|
-
export { __exportAll as i, layer as n, AGENT_PROCESS_KEY as r, AgentService_exports as t };
|
|
850
|
+
export { __exportAll as a, makeAiSessionTurnProducer as i, layer as n, AGENT_PROCESS_KEY as r, AgentService_exports as t };
|
|
788
851
|
|
|
789
852
|
//# sourceMappingURL=chunk-AgentService.mjs.map
|