@tangle-network/agent-runtime 0.4.2 → 0.5.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 +71 -4
- package/dist/index.d.ts +209 -1
- package/dist/index.js +450 -0
- package/dist/index.js.map +1 -1
- package/docs/domain-agent-runtime-integration-issues.md +165 -0
- package/docs/product-runtime-kernel.md +58 -0
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -6,6 +6,24 @@ import {
|
|
|
6
6
|
scoreKnowledgeReadiness,
|
|
7
7
|
userQuestionsForKnowledgeGaps
|
|
8
8
|
} from "@tangle-network/agent-eval";
|
|
9
|
+
var InMemoryRuntimeSessionStore = class {
|
|
10
|
+
sessions = /* @__PURE__ */ new Map();
|
|
11
|
+
events = /* @__PURE__ */ new Map();
|
|
12
|
+
get(sessionId) {
|
|
13
|
+
return this.sessions.get(sessionId);
|
|
14
|
+
}
|
|
15
|
+
put(session) {
|
|
16
|
+
this.sessions.set(session.id, session);
|
|
17
|
+
}
|
|
18
|
+
appendEvent(sessionId, event) {
|
|
19
|
+
const existing = this.events.get(sessionId) ?? [];
|
|
20
|
+
existing.push(event);
|
|
21
|
+
this.events.set(sessionId, existing);
|
|
22
|
+
}
|
|
23
|
+
listEvents(sessionId) {
|
|
24
|
+
return [...this.events.get(sessionId) ?? []];
|
|
25
|
+
}
|
|
26
|
+
};
|
|
9
27
|
async function runAgentTask(options) {
|
|
10
28
|
const task = options.task;
|
|
11
29
|
await emit(options.onEvent, { type: "task_start", task });
|
|
@@ -95,6 +113,95 @@ function summarizeAgentTaskRun(result) {
|
|
|
95
113
|
costUsd: result.control.spentCostUsd
|
|
96
114
|
};
|
|
97
115
|
}
|
|
116
|
+
async function* runAgentTaskStream(options) {
|
|
117
|
+
const task = options.task;
|
|
118
|
+
const input = { task, ...options.input ?? {} };
|
|
119
|
+
const started = streamEvent({ type: "task_start", task });
|
|
120
|
+
yield started;
|
|
121
|
+
const readinessStart = streamEvent({ type: "readiness_start", task });
|
|
122
|
+
yield readinessStart;
|
|
123
|
+
let knowledge = await buildReadiness(task, options.knowledge);
|
|
124
|
+
const questions = userQuestionsForKnowledgeGaps(knowledge.blockingMissingRequirements);
|
|
125
|
+
const acquisitionPlans = acquisitionPlansForKnowledgeGaps([
|
|
126
|
+
...knowledge.blockingMissingRequirements,
|
|
127
|
+
...knowledge.nonBlockingGaps
|
|
128
|
+
]);
|
|
129
|
+
const preflight = await runKnowledgePreflightStream(task, questions, acquisitionPlans, options.knowledge);
|
|
130
|
+
for (const event of preflight.events) yield event;
|
|
131
|
+
if (options.knowledge?.refreshReadiness && (Object.keys(preflight.userAnswers).length > 0 || preflight.acquiredEvidenceIds.length > 0)) {
|
|
132
|
+
yield streamEvent({ type: "readiness_start", task });
|
|
133
|
+
knowledge = await options.knowledge.refreshReadiness({
|
|
134
|
+
task,
|
|
135
|
+
previous: knowledge,
|
|
136
|
+
userAnswers: preflight.userAnswers,
|
|
137
|
+
acquiredEvidenceIds: preflight.acquiredEvidenceIds
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const decision = decideKnowledgeReadiness(knowledge, { minimumScore: options.minimumReadinessScore });
|
|
141
|
+
yield streamEvent({ type: "readiness_end", task, knowledge, decision });
|
|
142
|
+
if (!decision.passed && decision.status === "blocked") {
|
|
143
|
+
const reason = `knowledge readiness blocked: ${decision.reason}`;
|
|
144
|
+
yield streamEvent({ type: "task_end", task, status: "blocked", reason });
|
|
145
|
+
yield streamEvent({ type: "final", task, status: "blocked", reason });
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const store = options.sessionStore;
|
|
149
|
+
const existing = options.sessionId ? await store?.get(options.sessionId) : void 0;
|
|
150
|
+
const shouldResume = Boolean(options.resume && existing);
|
|
151
|
+
let session = shouldResume && existing ? await resumeBackendSession(options.backend, existing, input, { task, knowledge, signal: options.signal }) : await startBackendSession(options.backend, input, { task, knowledge, signal: options.signal }, options.sessionId);
|
|
152
|
+
await store?.put(session);
|
|
153
|
+
const sessionEvent = streamEvent({
|
|
154
|
+
type: shouldResume ? "session_resumed" : "session_created",
|
|
155
|
+
task,
|
|
156
|
+
session
|
|
157
|
+
});
|
|
158
|
+
await store?.appendEvent?.(session.id, sessionEvent);
|
|
159
|
+
yield sessionEvent;
|
|
160
|
+
const backendStart = streamEvent({ type: "backend_start", task, session, backend: options.backend.kind });
|
|
161
|
+
await store?.appendEvent?.(session.id, backendStart);
|
|
162
|
+
yield backendStart;
|
|
163
|
+
let finalText = "";
|
|
164
|
+
try {
|
|
165
|
+
for await (const rawEvent of options.backend.stream(input, { task, knowledge, session, signal: options.signal })) {
|
|
166
|
+
const event = normalizeBackendStreamEvent(rawEvent, task, session);
|
|
167
|
+
if (event.type === "text_delta") finalText += event.text;
|
|
168
|
+
await store?.appendEvent?.(session.id, event);
|
|
169
|
+
yield event;
|
|
170
|
+
}
|
|
171
|
+
const completedStatus = "completed";
|
|
172
|
+
session = touchSession({ ...session, status: completedStatus });
|
|
173
|
+
await store?.put(session);
|
|
174
|
+
const backendEnd = streamEvent({ type: "backend_end", task, session, backend: options.backend.kind });
|
|
175
|
+
await store?.appendEvent?.(session.id, backendEnd);
|
|
176
|
+
yield backendEnd;
|
|
177
|
+
const reason = "backend completed";
|
|
178
|
+
const taskEnd = streamEvent({ type: "task_end", task, status: completedStatus, reason });
|
|
179
|
+
await store?.appendEvent?.(session.id, taskEnd);
|
|
180
|
+
yield taskEnd;
|
|
181
|
+
const final = streamEvent({ type: "final", task, session, status: completedStatus, reason, text: finalText || void 0 });
|
|
182
|
+
await store?.appendEvent?.(session.id, final);
|
|
183
|
+
yield final;
|
|
184
|
+
} catch (err) {
|
|
185
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
186
|
+
session = touchSession({ ...session, status: options.signal?.aborted ? "aborted" : "failed" });
|
|
187
|
+
await store?.put(session);
|
|
188
|
+
const backendError = streamEvent({
|
|
189
|
+
type: "backend_error",
|
|
190
|
+
task,
|
|
191
|
+
session,
|
|
192
|
+
backend: options.backend.kind,
|
|
193
|
+
message,
|
|
194
|
+
recoverable: !options.signal?.aborted
|
|
195
|
+
});
|
|
196
|
+
await store?.appendEvent?.(session.id, backendError);
|
|
197
|
+
yield backendError;
|
|
198
|
+
const status = options.signal?.aborted ? "aborted" : "failed";
|
|
199
|
+
const taskEnd = streamEvent({ type: "task_end", task, status, reason: message });
|
|
200
|
+
await store?.appendEvent?.(session.id, taskEnd);
|
|
201
|
+
yield taskEnd;
|
|
202
|
+
yield streamEvent({ type: "final", task, session, status, reason: message, text: finalText || void 0 });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
98
205
|
function decideKnowledgeReadiness(report, options = {}) {
|
|
99
206
|
const minimumScore = options.minimumScore ?? 0.7;
|
|
100
207
|
const blockingGapIds = report.blockingMissingRequirements.map((requirement) => requirement.id);
|
|
@@ -189,6 +296,98 @@ function sanitizeAgentRuntimeEvent(event, options = {}) {
|
|
|
189
296
|
}
|
|
190
297
|
return { ...base, status: event.status, reason: event.reason };
|
|
191
298
|
}
|
|
299
|
+
function sanitizeRuntimeStreamEvent(event, options = {}) {
|
|
300
|
+
const withTask = "task" in event && event.task ? { task: sanitizeTask(event.task, options) } : {};
|
|
301
|
+
const withSession = "session" in event && event.session ? { session: sanitizeRuntimeSession(event.session, options) } : {};
|
|
302
|
+
if (event.type === "readiness_end") {
|
|
303
|
+
return {
|
|
304
|
+
type: event.type,
|
|
305
|
+
...withTask,
|
|
306
|
+
timestamp: event.timestamp,
|
|
307
|
+
decision: event.decision,
|
|
308
|
+
knowledge: sanitizeKnowledgeReadinessReport(event.knowledge, options)
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
if (event.type === "questions_start") {
|
|
312
|
+
return { type: event.type, ...withTask, timestamp: event.timestamp, questions: event.questions.map((question) => sanitizeQuestion(question, options)) };
|
|
313
|
+
}
|
|
314
|
+
if (event.type === "questions_end") {
|
|
315
|
+
return {
|
|
316
|
+
type: event.type,
|
|
317
|
+
...withTask,
|
|
318
|
+
timestamp: event.timestamp,
|
|
319
|
+
questions: event.questions.map((question) => sanitizeQuestion(question, options)),
|
|
320
|
+
userAnswers: options.includeUserAnswers ? event.userAnswers : redactRecord(event.userAnswers)
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
if (event.type === "acquisition_start") {
|
|
324
|
+
return { type: event.type, ...withTask, timestamp: event.timestamp, acquisitionPlans: event.acquisitionPlans.map(sanitizeAcquisitionPlan) };
|
|
325
|
+
}
|
|
326
|
+
if (event.type === "acquisition_end") {
|
|
327
|
+
return {
|
|
328
|
+
type: event.type,
|
|
329
|
+
...withTask,
|
|
330
|
+
timestamp: event.timestamp,
|
|
331
|
+
acquisitionPlans: event.acquisitionPlans.map(sanitizeAcquisitionPlan),
|
|
332
|
+
acquiredEvidenceCount: event.acquiredEvidenceIds.length,
|
|
333
|
+
acquiredEvidenceIds: options.includeEvidenceIds ? event.acquiredEvidenceIds : void 0
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
if (event.type === "tool_call") {
|
|
337
|
+
return {
|
|
338
|
+
type: event.type,
|
|
339
|
+
...withTask,
|
|
340
|
+
...withSession,
|
|
341
|
+
timestamp: event.timestamp,
|
|
342
|
+
toolName: event.toolName,
|
|
343
|
+
toolCallId: event.toolCallId,
|
|
344
|
+
args: options.includeControlPayloads ? event.args : void 0
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
if (event.type === "tool_result") {
|
|
348
|
+
return {
|
|
349
|
+
type: event.type,
|
|
350
|
+
...withTask,
|
|
351
|
+
...withSession,
|
|
352
|
+
timestamp: event.timestamp,
|
|
353
|
+
toolName: event.toolName,
|
|
354
|
+
toolCallId: event.toolCallId,
|
|
355
|
+
result: options.includeControlPayloads ? event.result : void 0
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
if (event.type === "artifact") {
|
|
359
|
+
return {
|
|
360
|
+
type: event.type,
|
|
361
|
+
...withTask,
|
|
362
|
+
...withSession,
|
|
363
|
+
timestamp: event.timestamp,
|
|
364
|
+
artifactId: event.artifactId,
|
|
365
|
+
name: event.name,
|
|
366
|
+
mimeType: event.mimeType,
|
|
367
|
+
uri: options.includeEvidenceIds ? event.uri : void 0,
|
|
368
|
+
metadata: options.includeMetadata ? event.metadata : void 0
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
if (event.type === "final") {
|
|
372
|
+
return {
|
|
373
|
+
type: event.type,
|
|
374
|
+
...withTask,
|
|
375
|
+
...withSession,
|
|
376
|
+
timestamp: event.timestamp,
|
|
377
|
+
status: event.status,
|
|
378
|
+
reason: event.reason,
|
|
379
|
+
text: options.includeControlPayloads ? event.text : void 0,
|
|
380
|
+
metadata: options.includeMetadata ? event.metadata : void 0
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
type: event.type,
|
|
385
|
+
...withTask,
|
|
386
|
+
...withSession,
|
|
387
|
+
timestamp: "timestamp" in event ? event.timestamp : void 0,
|
|
388
|
+
...pickPublicStreamFields(event)
|
|
389
|
+
};
|
|
390
|
+
}
|
|
192
391
|
function createRuntimeEventCollector(options = {}) {
|
|
193
392
|
const events = [];
|
|
194
393
|
return {
|
|
@@ -220,6 +419,93 @@ function readinessServerSentEvent(report, options = {}) {
|
|
|
220
419
|
readiness: sanitizeKnowledgeReadinessReport(report, telemetryOptions)
|
|
221
420
|
}, { event, id, retry });
|
|
222
421
|
}
|
|
422
|
+
function runtimeStreamServerSentEvent(event, options = {}) {
|
|
423
|
+
const { event: sseEvent, id, retry, ...telemetryOptions } = options;
|
|
424
|
+
return encodeServerSentEvent(sanitizeRuntimeStreamEvent(event, telemetryOptions), { event: sseEvent, id, retry });
|
|
425
|
+
}
|
|
426
|
+
function createIterableBackend(options) {
|
|
427
|
+
return options;
|
|
428
|
+
}
|
|
429
|
+
function createSandboxPromptBackend(options) {
|
|
430
|
+
return {
|
|
431
|
+
kind: options.kind ?? "sandbox",
|
|
432
|
+
async start(input, context) {
|
|
433
|
+
const box = await options.getBox(input, context);
|
|
434
|
+
return newRuntimeSession(options.kind ?? "sandbox", options.getSessionId?.(box, input) ?? context.requestedSessionId, {
|
|
435
|
+
resumable: true
|
|
436
|
+
});
|
|
437
|
+
},
|
|
438
|
+
resume(session) {
|
|
439
|
+
return touchSession({ ...session, status: "active" });
|
|
440
|
+
},
|
|
441
|
+
async *stream(input, context) {
|
|
442
|
+
const box = await options.getBox(input, context);
|
|
443
|
+
const message = input.message ?? input.messages?.at(-1)?.content ?? context.task.intent;
|
|
444
|
+
for await (const event of options.streamPrompt(box, message, context)) {
|
|
445
|
+
const mapped = options.mapEvent?.(event, context) ?? mapCommonBackendEvent(event, context);
|
|
446
|
+
if (mapped) yield mapped;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
function createCliBridgeBackend(options) {
|
|
452
|
+
const fetcher = options.fetchImpl ?? fetch;
|
|
453
|
+
return {
|
|
454
|
+
kind: options.kind ?? "cli-bridge",
|
|
455
|
+
start(_input, context) {
|
|
456
|
+
return newRuntimeSession(options.kind ?? "cli-bridge", context.requestedSessionId, { resumable: true });
|
|
457
|
+
},
|
|
458
|
+
resume(session) {
|
|
459
|
+
return touchSession({ ...session, status: "active" });
|
|
460
|
+
},
|
|
461
|
+
async *stream(input, context) {
|
|
462
|
+
const response = await fetcher(options.url, {
|
|
463
|
+
method: "POST",
|
|
464
|
+
headers: {
|
|
465
|
+
"Content-Type": "application/json",
|
|
466
|
+
...options.bearer ? { Authorization: `Bearer ${options.bearer}` } : {}
|
|
467
|
+
},
|
|
468
|
+
body: JSON.stringify({
|
|
469
|
+
sessionId: context.session.id,
|
|
470
|
+
resumeToken: context.session.resumeToken,
|
|
471
|
+
task: input.task,
|
|
472
|
+
message: input.message,
|
|
473
|
+
messages: input.messages,
|
|
474
|
+
inputs: input.inputs
|
|
475
|
+
}),
|
|
476
|
+
signal: context.signal
|
|
477
|
+
});
|
|
478
|
+
if (!response.ok) throw new Error(`cli bridge returned ${response.status}`);
|
|
479
|
+
yield* streamResponseEvents(response, context);
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
function createOpenAICompatibleBackend(options) {
|
|
484
|
+
const fetcher = options.fetchImpl ?? fetch;
|
|
485
|
+
return {
|
|
486
|
+
kind: options.kind ?? "tcloud",
|
|
487
|
+
start(_input, context) {
|
|
488
|
+
return newRuntimeSession(options.kind ?? "tcloud", context.requestedSessionId);
|
|
489
|
+
},
|
|
490
|
+
async *stream(input, context) {
|
|
491
|
+
const response = await fetcher(`${options.baseUrl.replace(/\/$/, "")}/chat/completions`, {
|
|
492
|
+
method: "POST",
|
|
493
|
+
headers: {
|
|
494
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
495
|
+
"Content-Type": "application/json"
|
|
496
|
+
},
|
|
497
|
+
body: JSON.stringify({
|
|
498
|
+
model: options.model,
|
|
499
|
+
stream: true,
|
|
500
|
+
messages: input.messages ?? [{ role: "user", content: input.message ?? context.task.intent }]
|
|
501
|
+
}),
|
|
502
|
+
signal: context.signal
|
|
503
|
+
});
|
|
504
|
+
if (!response.ok) throw new Error(`chat backend returned ${response.status}`);
|
|
505
|
+
yield* streamResponseEvents(response, context);
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
}
|
|
223
509
|
async function runKnowledgePreflight(task, questions, acquisitionPlans, provider, onEvent) {
|
|
224
510
|
let userAnswers = {};
|
|
225
511
|
let acquiredEvidenceIds = [];
|
|
@@ -235,6 +521,22 @@ async function runKnowledgePreflight(task, questions, acquisitionPlans, provider
|
|
|
235
521
|
}
|
|
236
522
|
return { userAnswers, acquiredEvidenceIds };
|
|
237
523
|
}
|
|
524
|
+
async function runKnowledgePreflightStream(task, questions, acquisitionPlans, provider) {
|
|
525
|
+
const events = [];
|
|
526
|
+
let userAnswers = {};
|
|
527
|
+
let acquiredEvidenceIds = [];
|
|
528
|
+
if (questions.length > 0 && provider?.answerQuestions) {
|
|
529
|
+
events.push(streamEvent({ type: "questions_start", task, questions }));
|
|
530
|
+
userAnswers = await provider.answerQuestions(questions, task);
|
|
531
|
+
events.push(streamEvent({ type: "questions_end", task, questions, userAnswers }));
|
|
532
|
+
}
|
|
533
|
+
if (acquisitionPlans.length > 0 && provider?.executeAcquisitionPlans) {
|
|
534
|
+
events.push(streamEvent({ type: "acquisition_start", task, acquisitionPlans }));
|
|
535
|
+
acquiredEvidenceIds = await provider.executeAcquisitionPlans(acquisitionPlans, task);
|
|
536
|
+
events.push(streamEvent({ type: "acquisition_end", task, acquisitionPlans, acquiredEvidenceIds }));
|
|
537
|
+
}
|
|
538
|
+
return { userAnswers, acquiredEvidenceIds, events };
|
|
539
|
+
}
|
|
238
540
|
function sanitizeTask(task, options) {
|
|
239
541
|
return {
|
|
240
542
|
id: task.id,
|
|
@@ -247,6 +549,17 @@ function sanitizeTask(task, options) {
|
|
|
247
549
|
metadata: options.includeMetadata ? task.metadata : task.metadata ? "[redacted]" : void 0
|
|
248
550
|
};
|
|
249
551
|
}
|
|
552
|
+
function sanitizeRuntimeSession(session, options) {
|
|
553
|
+
return {
|
|
554
|
+
id: session.id,
|
|
555
|
+
backend: session.backend,
|
|
556
|
+
status: session.status,
|
|
557
|
+
hasResumeToken: Boolean(session.resumeToken),
|
|
558
|
+
createdAt: session.createdAt,
|
|
559
|
+
updatedAt: session.updatedAt,
|
|
560
|
+
metadata: options.includeMetadata ? session.metadata : session.metadata ? "[redacted]" : void 0
|
|
561
|
+
};
|
|
562
|
+
}
|
|
250
563
|
function sanitizeKnowledgeRequirement(requirement, options) {
|
|
251
564
|
const includeDescription = options.includeRequirementDescriptions && requirement.sensitivity !== "secret";
|
|
252
565
|
return {
|
|
@@ -337,6 +650,135 @@ function redactRecord(record) {
|
|
|
337
650
|
function stripNewlines(value) {
|
|
338
651
|
return value.replace(/[\r\n]/g, " ");
|
|
339
652
|
}
|
|
653
|
+
function timestamp() {
|
|
654
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
655
|
+
}
|
|
656
|
+
function streamEvent(event) {
|
|
657
|
+
return { ...event, timestamp: timestamp() };
|
|
658
|
+
}
|
|
659
|
+
function newRuntimeSession(backend, requestedId, metadata) {
|
|
660
|
+
const now = timestamp();
|
|
661
|
+
return {
|
|
662
|
+
id: requestedId || crypto.randomUUID(),
|
|
663
|
+
backend,
|
|
664
|
+
status: "active",
|
|
665
|
+
createdAt: now,
|
|
666
|
+
updatedAt: now,
|
|
667
|
+
metadata
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
function touchSession(session) {
|
|
671
|
+
return { ...session, updatedAt: timestamp() };
|
|
672
|
+
}
|
|
673
|
+
async function startBackendSession(backend, input, context, requestedSessionId) {
|
|
674
|
+
if (backend.start) return backend.start(input, { ...context, requestedSessionId });
|
|
675
|
+
return newRuntimeSession(backend.kind, requestedSessionId);
|
|
676
|
+
}
|
|
677
|
+
async function resumeBackendSession(backend, session, input, context) {
|
|
678
|
+
if (session.backend !== backend.kind) {
|
|
679
|
+
throw new Error(`Cannot resume ${session.backend} session with ${backend.kind} backend`);
|
|
680
|
+
}
|
|
681
|
+
if (backend.resume) return backend.resume(session, input, context);
|
|
682
|
+
return touchSession({ ...session, status: "active" });
|
|
683
|
+
}
|
|
684
|
+
function normalizeBackendStreamEvent(event, task, session) {
|
|
685
|
+
if ("task" in event && event.task && "session" in event && event.session && "timestamp" in event && event.timestamp) return event;
|
|
686
|
+
return {
|
|
687
|
+
...event,
|
|
688
|
+
task: "task" in event && event.task ? event.task : task,
|
|
689
|
+
session: "session" in event && event.session ? event.session : session,
|
|
690
|
+
timestamp: "timestamp" in event && event.timestamp ? event.timestamp : timestamp()
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function pickPublicStreamFields(event) {
|
|
694
|
+
if (event.type === "session_created" || event.type === "session_resumed") return {};
|
|
695
|
+
if (event.type === "backend_start" || event.type === "backend_end") return { backend: event.backend };
|
|
696
|
+
if (event.type === "backend_error") return { backend: event.backend, message: event.message, recoverable: event.recoverable };
|
|
697
|
+
if (event.type === "task_end") return { status: event.status, reason: event.reason };
|
|
698
|
+
if (event.type === "text_delta" || event.type === "reasoning_delta") return { text: event.text };
|
|
699
|
+
return {};
|
|
700
|
+
}
|
|
701
|
+
function mapCommonBackendEvent(event, context) {
|
|
702
|
+
if (!event || typeof event !== "object") return void 0;
|
|
703
|
+
const record = event;
|
|
704
|
+
const type = String(record.type ?? "");
|
|
705
|
+
const data = record.data && typeof record.data === "object" ? record.data : record;
|
|
706
|
+
if (type === "message.part.updated" || type === "text_delta" || type === "delta") {
|
|
707
|
+
const text = stringValue(data.text) ?? stringValue(data.delta) ?? stringValue(record.text);
|
|
708
|
+
return text ? { type: "text_delta", task: context.task, session: context.session, text, timestamp: timestamp() } : void 0;
|
|
709
|
+
}
|
|
710
|
+
if (type === "reasoning_delta") {
|
|
711
|
+
const text = stringValue(data.text) ?? stringValue(record.text);
|
|
712
|
+
return text ? { type: "reasoning_delta", task: context.task, session: context.session, text, timestamp: timestamp() } : void 0;
|
|
713
|
+
}
|
|
714
|
+
if (type === "tool_call") {
|
|
715
|
+
return {
|
|
716
|
+
type: "tool_call",
|
|
717
|
+
task: context.task,
|
|
718
|
+
session: context.session,
|
|
719
|
+
toolName: stringValue(data.name) ?? stringValue(record.toolName) ?? "tool",
|
|
720
|
+
toolCallId: stringValue(data.id) ?? stringValue(record.toolCallId),
|
|
721
|
+
args: data.args ?? data.input ?? record.args,
|
|
722
|
+
timestamp: timestamp()
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
if (type === "tool_result") {
|
|
726
|
+
return {
|
|
727
|
+
type: "tool_result",
|
|
728
|
+
task: context.task,
|
|
729
|
+
session: context.session,
|
|
730
|
+
toolName: stringValue(data.name) ?? stringValue(record.toolName) ?? "tool",
|
|
731
|
+
toolCallId: stringValue(data.id) ?? stringValue(record.toolCallId),
|
|
732
|
+
result: data.result ?? data.output ?? record.result,
|
|
733
|
+
timestamp: timestamp()
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
if (type === "result" || type === "final") {
|
|
737
|
+
const text = stringValue(data.finalText) ?? stringValue(data.text) ?? stringValue(record.text);
|
|
738
|
+
return text ? { type: "text_delta", task: context.task, session: context.session, text, timestamp: timestamp() } : void 0;
|
|
739
|
+
}
|
|
740
|
+
return void 0;
|
|
741
|
+
}
|
|
742
|
+
async function* streamResponseEvents(response, context) {
|
|
743
|
+
const body = response.body;
|
|
744
|
+
if (!body) return;
|
|
745
|
+
const reader = body.getReader();
|
|
746
|
+
const decoder = new TextDecoder();
|
|
747
|
+
let buffer = "";
|
|
748
|
+
for (; ; ) {
|
|
749
|
+
const { done, value } = await reader.read();
|
|
750
|
+
if (done) break;
|
|
751
|
+
buffer += decoder.decode(value, { stream: true });
|
|
752
|
+
const chunks = buffer.split(/\n\n/);
|
|
753
|
+
buffer = chunks.pop() ?? "";
|
|
754
|
+
for (const chunk of chunks) {
|
|
755
|
+
const event = parseStreamChunk(chunk, context);
|
|
756
|
+
if (event) yield event;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
if (buffer.trim()) {
|
|
760
|
+
const event = parseStreamChunk(buffer, context);
|
|
761
|
+
if (event) yield event;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
function parseStreamChunk(chunk, context) {
|
|
765
|
+
const data = chunk.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
|
|
766
|
+
if (!data || data === "[DONE]") return void 0;
|
|
767
|
+
try {
|
|
768
|
+
const parsed = JSON.parse(data);
|
|
769
|
+
const choice = Array.isArray(parsed.choices) ? parsed.choices[0] : void 0;
|
|
770
|
+
const delta = choice?.delta;
|
|
771
|
+
const message = choice?.message;
|
|
772
|
+
const text = stringValue(delta?.content) ?? stringValue(message?.content) ?? stringValue(parsed.text);
|
|
773
|
+
if (text) return { type: "text_delta", task: context.task, session: context.session, text, timestamp: timestamp() };
|
|
774
|
+
return mapCommonBackendEvent(parsed, context);
|
|
775
|
+
} catch {
|
|
776
|
+
return { type: "text_delta", task: context.task, session: context.session, text: data, timestamp: timestamp() };
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
function stringValue(value) {
|
|
780
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
781
|
+
}
|
|
340
782
|
function buildReadiness(task, provider) {
|
|
341
783
|
if (provider?.buildReadiness) return provider.buildReadiness(task);
|
|
342
784
|
return scoreKnowledgeReadiness({
|
|
@@ -373,13 +815,21 @@ function toAgentContext(task, knowledge, ctx) {
|
|
|
373
815
|
};
|
|
374
816
|
}
|
|
375
817
|
export {
|
|
818
|
+
InMemoryRuntimeSessionStore,
|
|
819
|
+
createCliBridgeBackend,
|
|
820
|
+
createIterableBackend,
|
|
821
|
+
createOpenAICompatibleBackend,
|
|
376
822
|
createRuntimeEventCollector,
|
|
823
|
+
createSandboxPromptBackend,
|
|
377
824
|
decideKnowledgeReadiness,
|
|
378
825
|
encodeServerSentEvent,
|
|
379
826
|
readinessServerSentEvent,
|
|
380
827
|
runAgentTask,
|
|
828
|
+
runAgentTaskStream,
|
|
829
|
+
runtimeStreamServerSentEvent,
|
|
381
830
|
sanitizeAgentRuntimeEvent,
|
|
382
831
|
sanitizeKnowledgeReadinessReport,
|
|
832
|
+
sanitizeRuntimeStreamEvent,
|
|
383
833
|
summarizeAgentTaskRun
|
|
384
834
|
};
|
|
385
835
|
//# sourceMappingURL=index.js.map
|