@gea-ai/agent-sdk 0.1.260920-alpha.1 → 0.1.260920-alpha.2
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 +10 -0
- package/dist/agent-core.wasm +0 -0
- package/dist/agent-session-execution.js +38 -2
- package/dist/agent-session-inbox.d.ts +2 -0
- package/dist/agent-session-inbox.js +95 -3
- package/dist/agent-session-stream.js +19 -4
- package/dist/agent-worker.js +198 -18
- package/dist/experimental/agent-core-messages.d.ts +1 -1
- package/dist/experimental/agent-core-messages.js +2 -2
- package/dist/experimental/agent-core-tools.js +3 -2
- package/dist/experimental/agent-core-ui.js +3 -2
- package/dist/experimental/agent-core-worker-tools.js +7 -3
- package/dist/experimental/agent-core.d.ts +3 -3
- package/dist/experimental/agent-core.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -19,6 +19,16 @@ provider configuration, or environment values.
|
|
|
19
19
|
`toModelOutput({ toolCallId, input, output })`, following AI SDK's separation
|
|
20
20
|
between the result used by the application and the result shown to the model.
|
|
21
21
|
Both server and client tools retain output types in `InferAgentUITools`.
|
|
22
|
+
Both the default Agent Core engine and `aiSdk()` support client Tools without
|
|
23
|
+
`execute`. A client Tool waits for an `output-available` or `output-error` part
|
|
24
|
+
on the original assistant message and Tool call ID. Submit all pending client
|
|
25
|
+
results/approval decisions together through the existing continuation flow.
|
|
26
|
+
Core pauses server handlers in the same batch until those interactions complete,
|
|
27
|
+
following its existing whole-batch approval behavior.
|
|
28
|
+
Tool results resume the same Run while its interaction remains pending.
|
|
29
|
+
Waiting for client input releases execution: a new user message skips the old
|
|
30
|
+
interaction and starts a new Run in the same Session, without an explicit cancel.
|
|
31
|
+
Skipped calls become errors in the transcript/model context; late results are rejected.
|
|
22
32
|
|
|
23
33
|
`outputSchema` is a declaration/type hint. It never parses, coerces or validates
|
|
24
34
|
returned data, including client-supplied results. It is serialized in the Agent
|
package/dist/agent-core.wasm
CHANGED
|
Binary file
|
|
@@ -3,7 +3,7 @@ import { agentModelCallsSchema, } from "@gea-ai/contract/agent-usage";
|
|
|
3
3
|
import { AGENT_SESSION_COMPUTER_LEASE_MS, agentSessionComputerSchema, agentSessionComputerReferenceSchema, AGENT_SESSION_EXECUTION_LEASE_MS, AGENT_SESSION_EXECUTION_PROTOCOL_VERSION, MAX_AGENT_SESSION_RESPONSE_BYTES, MAX_AGENT_SESSION_EXECUTION_ATTEMPTS, MAX_AGENT_SESSION_EXECUTION_BODY_BYTES, MAX_AGENT_SESSION_PAGE_SIZE, agentSessionAttemptIdentitySchema, agentSessionExecutionRenewSchema, agentSessionExecutionCompleteSchema, agentSessionExecutionPauseSchema, agentSessionExecutionControlSchema, agentSessionExecutionMutationSchema, agentSessionExecutionStartSchema, } from "@gea-ai/contract/agent-session";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { activeComputerOperation } from "./agent-session-computer.js";
|
|
6
|
-
import { isAgentSessionInboxBusy, scheduleAgentSessionInbox, getAgentSessionRunState, handleAgentSessionInboxRequest, hasAgentSessionInbox, } from "./agent-session-inbox.js";
|
|
6
|
+
import { isAgentSessionInboxBusy, scheduleAgentSessionInbox, getAgentSessionRunState, handleAgentSessionInboxRequest, hasAgentSessionInbox, skipAgentSessionInputWait, } from "./agent-session-inbox.js";
|
|
7
7
|
// Managed execution owns its own durable state; PostgreSQL copies the live stream.
|
|
8
8
|
const prefix = "execution-v2:";
|
|
9
9
|
const key = (name) => `${prefix}${name}`;
|
|
@@ -11,6 +11,8 @@ const sequenceKey = (name, sequence) => key(`${name}:${sequence.toString().padSt
|
|
|
11
11
|
const runEventRangeSchema = z.strictObject({
|
|
12
12
|
start: z.number().int().nonnegative(),
|
|
13
13
|
end: z.number().int().nonnegative().nullable(),
|
|
14
|
+
messageId: z.string().optional(),
|
|
15
|
+
messageStart: z.number().int().nonnegative().optional(),
|
|
14
16
|
});
|
|
15
17
|
class SessionProtocolError extends Error {
|
|
16
18
|
reason;
|
|
@@ -100,6 +102,21 @@ async function writeValues(tx, input) {
|
|
|
100
102
|
await tx.put(key("message-sequence"), messageSequence);
|
|
101
103
|
let eventSequence = (await tx.get(key("event-sequence"))) ?? 0;
|
|
102
104
|
for (const event of input.events) {
|
|
105
|
+
if (event.type === "start" &&
|
|
106
|
+
typeof event.messageId === "string" &&
|
|
107
|
+
input.runId) {
|
|
108
|
+
const rangeKey = key(`run-events:${encodeURIComponent(input.runId)}`);
|
|
109
|
+
const stored = await tx.get(rangeKey);
|
|
110
|
+
if (stored !== undefined) {
|
|
111
|
+
const range = runEventRangeSchema.parse(stored);
|
|
112
|
+
if (range.messageId !== event.messageId)
|
|
113
|
+
await tx.put(rangeKey, {
|
|
114
|
+
...range,
|
|
115
|
+
messageId: event.messageId,
|
|
116
|
+
messageStart: eventSequence,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
103
120
|
const entry = { event, sequence: ++eventSequence };
|
|
104
121
|
await putSessionPayload(tx, sequenceKey("event", entry.sequence), entry);
|
|
105
122
|
}
|
|
@@ -449,6 +466,14 @@ export async function handleAgentSessionExecutionRequest(request, storage) {
|
|
|
449
466
|
return { duplicate: false, outcome };
|
|
450
467
|
}));
|
|
451
468
|
}
|
|
469
|
+
if (request.method === "POST" && url.pathname === "/v2/turns/skip-input") {
|
|
470
|
+
const input = z
|
|
471
|
+
.strictObject({ runId: z.uuid() })
|
|
472
|
+
.parse(await readBody(request));
|
|
473
|
+
return json(await storage.transaction(async (tx) => ({
|
|
474
|
+
requested: await skipAgentSessionInputWait(tx, input.runId),
|
|
475
|
+
})));
|
|
476
|
+
}
|
|
452
477
|
if (request.method === "POST" && url.pathname === "/v2/turns/cancel") {
|
|
453
478
|
const input = z
|
|
454
479
|
.object({ runId: agentSessionAttemptIdentitySchema.shape.runId })
|
|
@@ -497,6 +522,14 @@ export async function handleAgentSessionExecutionRequest(request, storage) {
|
|
|
497
522
|
return { duplicate: false, revision, turn };
|
|
498
523
|
}));
|
|
499
524
|
}
|
|
525
|
+
const messageMatch = /^\/v2\/messages\/([^/]+)$/u.exec(url.pathname);
|
|
526
|
+
if (request.method === "GET" && messageMatch) {
|
|
527
|
+
const id = decodeURIComponent(messageMatch[1]);
|
|
528
|
+
const sequence = await storage.get(key(`message-id:${encodeURIComponent(id)}`));
|
|
529
|
+
if (sequence === undefined)
|
|
530
|
+
throw new SessionProtocolError("message_not_found", 404);
|
|
531
|
+
return json(await storage.transaction((tx) => getSessionPayload(tx, sequenceKey("message", sequence))));
|
|
532
|
+
}
|
|
500
533
|
if (request.method === "GET" && url.pathname === "/v2/model-context")
|
|
501
534
|
return json({
|
|
502
535
|
context: (await storage.transaction((tx) => getSessionPayload(tx, key("model-context")))) ?? null,
|
|
@@ -520,7 +553,10 @@ export async function handleAgentSessionExecutionRequest(request, storage) {
|
|
|
520
553
|
const end = range.end ?? (await tx.get(key("event-sequence"))) ?? 0;
|
|
521
554
|
if (after > end || (after !== 0 && after < range.start))
|
|
522
555
|
throw new SessionProtocolError("invalid_cursor", 400);
|
|
523
|
-
const start = Math.max(after,
|
|
556
|
+
const start = Math.max(after, !url.searchParams.has("after") &&
|
|
557
|
+
url.searchParams.get("latestMessage") === "true"
|
|
558
|
+
? (range.messageStart ?? range.start)
|
|
559
|
+
: range.start);
|
|
524
560
|
const events = await entries(tx, "event", start, Math.min(limit, end - start));
|
|
525
561
|
const nextCursor = events.at(-1)?.sequence ?? start;
|
|
526
562
|
const receipt = await tx.get(key(`outcome:${encodeURIComponent(runId)}`));
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type AgentChildRun } from "@gea-ai/contract/agent-worker-tools";
|
|
2
2
|
import type { AgentSessionStorage, AgentSessionTransactionStorage } from "./agent-session";
|
|
3
|
+
/** Atomically supersede only an idle input wait, never a running invocation. */
|
|
4
|
+
export declare function skipAgentSessionInputWait(tx: AgentSessionTransactionStorage, runId: string): Promise<boolean>;
|
|
3
5
|
export declare function hasAgentSessionInbox(tx: AgentSessionTransactionStorage): Promise<boolean>;
|
|
4
6
|
/** Read the logical Run independently of the currently leased invocation. */
|
|
5
7
|
export declare function getAgentSessionRunState(tx: AgentSessionTransactionStorage, runId: string): Promise<{
|
|
@@ -7,6 +7,7 @@ import { agentChildRunSchema, } from "@gea-ai/contract/agent-worker-tools";
|
|
|
7
7
|
import { combineTraceContexts, readTraceContext } from "./trace-context.js";
|
|
8
8
|
import { traceContextSchema } from "@gea-ai/contract/traces";
|
|
9
9
|
import { activeComputerOperation } from "./agent-session-computer.js";
|
|
10
|
+
import { getSessionPayload, putSessionPayload } from "./agent-session-payload.js";
|
|
10
11
|
const stateKey = "inbox:v1";
|
|
11
12
|
const waitSchema = agentRunWaitInputSchema.omit({ timeoutMs: true }).extend({
|
|
12
13
|
turnId: z.uuid(),
|
|
@@ -39,6 +40,82 @@ const stateSchema = z.strictObject({
|
|
|
39
40
|
terminalQueue: z.array(terminalSchema).max(8).default([]),
|
|
40
41
|
});
|
|
41
42
|
const executionInputSchema = z.strictObject({ executionId: z.uuid() });
|
|
43
|
+
async function skipInputWait(tx, state, runs) {
|
|
44
|
+
const pending = state.inputWait;
|
|
45
|
+
if (!pending || !state.transport)
|
|
46
|
+
return false;
|
|
47
|
+
// Both journals retain the same assistant ID. Seal visible pending parts as
|
|
48
|
+
// well as the Run so a late client result cannot resurrect the interaction.
|
|
49
|
+
for (const prefix of ["", "execution-v2:"]) {
|
|
50
|
+
const sequence = await tx.get(`${prefix}message-id:${encodeURIComponent(pending.messageId)}`);
|
|
51
|
+
if (sequence === undefined)
|
|
52
|
+
continue;
|
|
53
|
+
const key = `${prefix}message:${String(sequence).padStart(16, "0")}`;
|
|
54
|
+
const stored = await getSessionPayload(tx, key);
|
|
55
|
+
const envelope = prefix
|
|
56
|
+
? z
|
|
57
|
+
.object({ message: agentApplicationAssistantMessageSchema })
|
|
58
|
+
.passthrough()
|
|
59
|
+
.parse(stored)
|
|
60
|
+
: null;
|
|
61
|
+
const message = envelope?.message ?? agentApplicationAssistantMessageSchema.parse(stored);
|
|
62
|
+
const skipped = {
|
|
63
|
+
...message,
|
|
64
|
+
parts: message.parts.map((part) => (part.type === "dynamic-tool" || part.type.startsWith("tool-")) &&
|
|
65
|
+
[
|
|
66
|
+
"input-streaming",
|
|
67
|
+
"input-available",
|
|
68
|
+
"approval-requested",
|
|
69
|
+
"approval-responded",
|
|
70
|
+
].includes(String(part.state))
|
|
71
|
+
? {
|
|
72
|
+
...part,
|
|
73
|
+
state: "output-error",
|
|
74
|
+
errorText: "Tool interaction was skipped by a new user message; no result was provided.",
|
|
75
|
+
}
|
|
76
|
+
: part),
|
|
77
|
+
};
|
|
78
|
+
await putSessionPayload(tx, key, envelope ? { ...envelope, message: skipped } : skipped);
|
|
79
|
+
}
|
|
80
|
+
const terminal = {
|
|
81
|
+
execution: {
|
|
82
|
+
id: pending.turnId,
|
|
83
|
+
turnId: pending.turnId,
|
|
84
|
+
messages: [],
|
|
85
|
+
waitResult: null,
|
|
86
|
+
},
|
|
87
|
+
outcome: {
|
|
88
|
+
status: "interrupted",
|
|
89
|
+
text: "Pending tool interaction skipped by a new user message.",
|
|
90
|
+
},
|
|
91
|
+
transport: state.transport,
|
|
92
|
+
};
|
|
93
|
+
state.inputWait = null;
|
|
94
|
+
if (runs.some((run) => !run.outcome)) {
|
|
95
|
+
state.stopped = true;
|
|
96
|
+
for (const run of runs)
|
|
97
|
+
if (!run.outcome)
|
|
98
|
+
run.cancelRequested = true;
|
|
99
|
+
await tx.put("child-runs", { runs });
|
|
100
|
+
state.draining = terminal;
|
|
101
|
+
}
|
|
102
|
+
else if (state.terminal)
|
|
103
|
+
state.terminalQueue.push(terminal);
|
|
104
|
+
else
|
|
105
|
+
state.terminal = terminal;
|
|
106
|
+
await save(tx, state, runs);
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
/** Atomically supersede only an idle input wait, never a running invocation. */
|
|
110
|
+
export async function skipAgentSessionInputWait(tx, runId) {
|
|
111
|
+
const state = await readState(tx);
|
|
112
|
+
if (!state ||
|
|
113
|
+
state.execution ||
|
|
114
|
+
state.inputWait?.turnId !== runId ||
|
|
115
|
+
state.terminalQueue.length >= 8)
|
|
116
|
+
return false;
|
|
117
|
+
return skipInputWait(tx, state, await readChildRuns(tx));
|
|
118
|
+
}
|
|
42
119
|
// A turn admits a bounded batch. Messages beyond it retain their original order.
|
|
43
120
|
function takeMessages(state, steeringOnly) {
|
|
44
121
|
const messages = [];
|
|
@@ -219,7 +296,9 @@ async function save(tx, state, runs) {
|
|
|
219
296
|
});
|
|
220
297
|
const ready = state.wait
|
|
221
298
|
? waitResult(state, runs) !== null
|
|
222
|
-
:
|
|
299
|
+
: state.inputWait
|
|
300
|
+
? state.messages.some((message) => message.sender.type === "user")
|
|
301
|
+
: state.messages.length > 0;
|
|
223
302
|
const cancelling = runs.some((run) => !run.outcome && run.cancelRequested);
|
|
224
303
|
state.pendingStarts = state.pendingStarts.filter((id) => runs.some((run) => run.id === id && !run.outcome && !run.cancelRequested));
|
|
225
304
|
const storedTurn = state.execution
|
|
@@ -352,14 +431,20 @@ export async function handleAgentSessionInboxRequest(request, storage) {
|
|
|
352
431
|
state.terminalQueue.length >= 8 ||
|
|
353
432
|
(state.wait && input.message?.mode !== "steering") ||
|
|
354
433
|
(state.inputWait &&
|
|
355
|
-
input.continuation
|
|
434
|
+
input.continuation &&
|
|
435
|
+
input.continuation.id !== state.inputWait.messageId))
|
|
356
436
|
return Response.json({ error: "session_busy" }, { status: 409 });
|
|
357
|
-
state.transport = input.transport;
|
|
358
437
|
const previous = input.message
|
|
359
438
|
? await tx.get(`inbox:message:${input.message.id}`)
|
|
360
439
|
: undefined;
|
|
361
440
|
if (previous !== undefined)
|
|
362
441
|
return Response.json({ error: "message_already_accepted" }, { status: 409 });
|
|
442
|
+
if (input.message && state.inputWait) {
|
|
443
|
+
await skipInputWait(tx, state, runs);
|
|
444
|
+
if (state.draining)
|
|
445
|
+
return Response.json({ error: "session_busy" }, { status: 409 });
|
|
446
|
+
}
|
|
447
|
+
state.transport = input.transport;
|
|
363
448
|
let resumedWait = state.resumeWait;
|
|
364
449
|
if (state.wait && input.message) {
|
|
365
450
|
state.messages.push(input.message);
|
|
@@ -458,6 +543,12 @@ export async function handleAgentSessionInboxRequest(request, storage) {
|
|
|
458
543
|
await save(tx, state, runs);
|
|
459
544
|
return Response.json({ execution: null });
|
|
460
545
|
}
|
|
546
|
+
if (state.inputWait &&
|
|
547
|
+
state.messages.some((message) => message.sender.type === "user") &&
|
|
548
|
+
!state.execution &&
|
|
549
|
+
!state.draining &&
|
|
550
|
+
state.terminalQueue.length < 8)
|
|
551
|
+
await skipInputWait(tx, state, runs);
|
|
461
552
|
if (state.execution ||
|
|
462
553
|
state.terminal ||
|
|
463
554
|
state.draining ||
|
|
@@ -468,6 +559,7 @@ export async function handleAgentSessionInboxRequest(request, storage) {
|
|
|
468
559
|
return Response.json({ execution: null });
|
|
469
560
|
const messages = takeMessages(state, state.wait !== null);
|
|
470
561
|
const joining = state.wait?.toolCallId === null;
|
|
562
|
+
state.stopped = false;
|
|
471
563
|
state.execution = {
|
|
472
564
|
id: crypto.randomUUID(),
|
|
473
565
|
turnId: state.wait?.turnId ?? crypto.randomUUID(),
|
|
@@ -4,9 +4,10 @@ import { UI_MESSAGE_STREAM_HEADERS } from "ai";
|
|
|
4
4
|
export async function streamManagedAgentSessionRun(request, session) {
|
|
5
5
|
const url = new URL(request.url);
|
|
6
6
|
url.pathname = "/v2/run-events";
|
|
7
|
-
//
|
|
7
|
+
// Replay the active response. User steering starts a new response within the same Run.
|
|
8
8
|
url.searchParams.delete("after");
|
|
9
9
|
url.searchParams.delete("limit");
|
|
10
|
+
url.searchParams.set("latestMessage", "true");
|
|
10
11
|
const abort = new AbortController();
|
|
11
12
|
let cancelled = false;
|
|
12
13
|
const onDisconnect = () => abort.abort(request.signal.reason);
|
|
@@ -34,14 +35,28 @@ export async function streamManagedAgentSessionRun(request, session) {
|
|
|
34
35
|
return new Response(null, { status: 204 });
|
|
35
36
|
}
|
|
36
37
|
const encoder = new TextEncoder();
|
|
38
|
+
let messageId;
|
|
37
39
|
return new Response(new ReadableStream({
|
|
38
40
|
async pull(controller) {
|
|
39
41
|
try {
|
|
40
42
|
while (!abort.signal.aborted) {
|
|
41
43
|
if (page.events.length) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
.
|
|
44
|
+
let text = "";
|
|
45
|
+
for (const { event } of page.events) {
|
|
46
|
+
if (event.type === "start" &&
|
|
47
|
+
typeof event.messageId === "string") {
|
|
48
|
+
if (messageId && messageId !== event.messageId) {
|
|
49
|
+
// The old subscriber must never feed a second response into useChat's reducer.
|
|
50
|
+
controller.enqueue(encoder.encode(text + "data: [DONE]\n\n"));
|
|
51
|
+
controller.close();
|
|
52
|
+
dispose();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
messageId = event.messageId;
|
|
56
|
+
}
|
|
57
|
+
text += `data: ${JSON.stringify(event)}\n\n`;
|
|
58
|
+
}
|
|
59
|
+
controller.enqueue(encoder.encode(text));
|
|
45
60
|
page = { ...page, events: [] };
|
|
46
61
|
return;
|
|
47
62
|
}
|
package/dist/agent-worker.js
CHANGED
|
@@ -29,7 +29,7 @@ import { toAgentHttpFile, } from "@gea-ai/contract/agent-http-api";
|
|
|
29
29
|
import { handleHostedAgentHttp } from "./agent-http.js";
|
|
30
30
|
import { createWorkerAgentTool, createWorkerRunCancelTool } from "./agent-call.js";
|
|
31
31
|
import { AgentSessionRunner, resumeSessionWait } from "./agent-session-runner.js";
|
|
32
|
-
import { agentRunWaitInputSchema, agentSessionInboxExecutionSchema, sessionExecutionMessage, } from "@gea-ai/contract/agent-session-inbox";
|
|
32
|
+
import { agentRunWaitInputSchema, toAgentRunWaitOutput, agentSessionInboxExecutionSchema, sessionExecutionMessage, } from "@gea-ai/contract/agent-session-inbox";
|
|
33
33
|
import { agentWorkerInvocationIdentitySchema } from "@gea-ai/contract/agent-worker-tools";
|
|
34
34
|
import { MAX_AGENT_ARTIFACT_IMAGES, MAX_AGENT_ARTIFACT_IMAGE_BYTES, studioArtifactInputFileSchema, studioArtifactCreateUploadSchema, studioArtifactListSchema, } from "@gea-ai/contract/studio-artifacts";
|
|
35
35
|
import { parsePatch } from "./vendor/codex-patch/parser.js";
|
|
@@ -42,7 +42,7 @@ import { AGENT_APPLICATION_PREFIX, buildAgentApplicationPath, agentApplicationAs
|
|
|
42
42
|
import { AGENT_APPLICATION_CHAT_ID_HEADER, AGENT_APPLICATION_MESSAGE_ID_HEADER, AGENT_APPLICATION_RUN_ID_HEADER, agentApplicationKeySchema, agentApplicationRunRequestSchema, } from "@gea-ai/contract";
|
|
43
43
|
import { AGENT_CHANNEL_EXECUTION_TIMEOUT_MS, agentChannelInvocationContextSchema, agentChannelAddressSchema, agentChannelHttpMessageRequestSchema, agentChannelOpaqueIdSchema, agentChannelProjectTerminalCommandSchema, agentChannelRunTerminalCallbackSchema, agentChannelStartRunCommandSchema, } from "@gea-ai/contract/agent-channels";
|
|
44
44
|
import { agentSessionClaimChannelRunResultSchema, agentSessionCompleteChannelRunResultSchema, agentSessionGetModelContextResultSchema, agentSessionAttemptIdentitySchema, agentSessionExecutionStartResultSchema, agentSessionExecutionMutationResultSchema, agentSessionPutModelContextResultSchema, } from "@gea-ai/contract/agent-session";
|
|
45
|
-
import { InvalidResponseDataError, convertToModelMessages, isToolUIPart, createUIMessageStreamResponse, createUIMessageStream, asSchema, jsonSchema, stepCountIs, streamText, tool, } from "ai";
|
|
45
|
+
import { InvalidResponseDataError, convertToModelMessages, isToolUIPart, validateUIMessages, createUIMessageStreamResponse, createUIMessageStream, asSchema, jsonSchema, stepCountIs, streamText, tool, } from "ai";
|
|
46
46
|
import { agentWorkerConnectionDeleteOutputSchema, agentWorkerConnectionGetOutputSchema, agentWorkerConnectionSetOutputSchema, agentWorkerToolInitializationSchema, MAX_AGENT_WORKER_TOOLS, } from "@gea-ai/contract/agent-worker-tools";
|
|
47
47
|
import { agentToolIdentitySchema, } from "@gea-ai/contract/agent-packages";
|
|
48
48
|
import { z } from "zod";
|
|
@@ -475,7 +475,8 @@ async function runPreparedAgent(runtime, agentKey, request, environment, identif
|
|
|
475
475
|
const headers = new Headers(response.headers);
|
|
476
476
|
headers.set(AGENT_APPLICATION_CHAT_ID_HEADER, chatId);
|
|
477
477
|
headers.set(AGENT_APPLICATION_RUN_ID_HEADER, runId);
|
|
478
|
-
headers.set(AGENT_APPLICATION_MESSAGE_ID_HEADER,
|
|
478
|
+
headers.set(AGENT_APPLICATION_MESSAGE_ID_HEADER, response.headers.get(AGENT_APPLICATION_MESSAGE_ID_HEADER) ??
|
|
479
|
+
responseMessageId);
|
|
479
480
|
return new Response(response.body, {
|
|
480
481
|
headers,
|
|
481
482
|
status: response.status,
|
|
@@ -3404,6 +3405,14 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
3404
3405
|
path: sessionExecution ? "/v2/model-context" : "/v1/model-context",
|
|
3405
3406
|
schema: agentSessionGetModelContextResultSchema,
|
|
3406
3407
|
});
|
|
3408
|
+
if (submittedUser &&
|
|
3409
|
+
storedContext.context &&
|
|
3410
|
+
storedContext.context.runId !== payload.runId) {
|
|
3411
|
+
// A new user Run supersedes the previous idle tool interaction. Close its
|
|
3412
|
+
// missing results before appending user input; never execute the skipped batch.
|
|
3413
|
+
storedContext.context.messages = closeInterruptedToolCalls(storedContext.context.messages.map(decodeAgentModelProxyValue), "Tool interaction was skipped by a new user message; no result was provided.").map(encodeAgentModelProxyValue);
|
|
3414
|
+
delete storedContext.context.metadata.agentCore;
|
|
3415
|
+
}
|
|
3407
3416
|
// Reuse durable conversions when UI history is replayed, so file conversion
|
|
3408
3417
|
// does not upload another Artifact on every turn or approval continuation.
|
|
3409
3418
|
const retainedToolCalls = new Set();
|
|
@@ -3420,6 +3429,66 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
3420
3429
|
modelOutputs.set(part.toolCallId, part.output);
|
|
3421
3430
|
}
|
|
3422
3431
|
}
|
|
3432
|
+
const suspendedMessageId = storedContext.context?.runId === payload.runId
|
|
3433
|
+
? storedContext.context.metadata.suspendedMessageId
|
|
3434
|
+
: undefined;
|
|
3435
|
+
const resumesResponse = Boolean(suspendedMessageId &&
|
|
3436
|
+
input.inboxExecution &&
|
|
3437
|
+
!input.inboxExecution.messages.some((message) => message.sender.type === "user"));
|
|
3438
|
+
let responseBaseline;
|
|
3439
|
+
let interruptedResponse;
|
|
3440
|
+
let interruptedWait;
|
|
3441
|
+
if (suspendedMessageId && input.inboxExecution) {
|
|
3442
|
+
const saved = await requestSessionJson({
|
|
3443
|
+
chatId: payload.chatId,
|
|
3444
|
+
method: "GET",
|
|
3445
|
+
namespace: input.sessionNamespace,
|
|
3446
|
+
path: `${sessionExecution ? "/v2" : "/v1"}/messages/${encodeURIComponent(suspendedMessageId)}`,
|
|
3447
|
+
schema: z.object({ message: z.unknown() }),
|
|
3448
|
+
});
|
|
3449
|
+
const [message] = await validateUIMessages({
|
|
3450
|
+
messages: [saved.message],
|
|
3451
|
+
});
|
|
3452
|
+
if (!message || message.role !== "assistant")
|
|
3453
|
+
throw new Error("Suspended response is not an assistant message.");
|
|
3454
|
+
// Invocation completion is not message completion. Do not retain its waiting metadata.
|
|
3455
|
+
if (message.metadata) {
|
|
3456
|
+
delete message.metadata.sessionStatus;
|
|
3457
|
+
delete message.metadata.finishedAt;
|
|
3458
|
+
delete message.metadata.finishReason;
|
|
3459
|
+
}
|
|
3460
|
+
const result = input.inboxExecution.waitResult;
|
|
3461
|
+
if (result) {
|
|
3462
|
+
const part = message.parts.find((part) => isToolUIPart(part) && part.toolCallId === result.toolCallId);
|
|
3463
|
+
if (!part || !isToolUIPart(part))
|
|
3464
|
+
throw new Error("Suspended response is missing its wait tool.");
|
|
3465
|
+
if (resumesResponse) {
|
|
3466
|
+
Object.assign(part, {
|
|
3467
|
+
state: "output-available",
|
|
3468
|
+
output: toAgentRunWaitOutput(result),
|
|
3469
|
+
});
|
|
3470
|
+
}
|
|
3471
|
+
else {
|
|
3472
|
+
const errorText = "Wait interrupted by a new user message.";
|
|
3473
|
+
Object.assign(part, { state: "output-error", errorText });
|
|
3474
|
+
interruptedWait = {
|
|
3475
|
+
type: "tool-output-error",
|
|
3476
|
+
toolCallId: result.toolCallId,
|
|
3477
|
+
errorText,
|
|
3478
|
+
};
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
if (resumesResponse)
|
|
3482
|
+
responseBaseline = message;
|
|
3483
|
+
else {
|
|
3484
|
+
message.metadata = {
|
|
3485
|
+
...message.metadata,
|
|
3486
|
+
finishedAt: new Date(),
|
|
3487
|
+
finishReason: "other",
|
|
3488
|
+
};
|
|
3489
|
+
interruptedResponse = message;
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3423
3492
|
const modelMessages = replaceInputFiles(await convertToModelMessages(payload.originalMessages.map((message) => storedContext.context && message.role === "assistant"
|
|
3424
3493
|
? {
|
|
3425
3494
|
...message,
|
|
@@ -3492,6 +3561,12 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
3492
3561
|
})
|
|
3493
3562
|
: [...context.messages, ...currentTurn];
|
|
3494
3563
|
}
|
|
3564
|
+
if (responseBaseline) {
|
|
3565
|
+
payload.responseMessageId = responseBaseline.id;
|
|
3566
|
+
// Model context was restored independently above; this baseline is only for UI assembly.
|
|
3567
|
+
payload.originalMessages = [responseBaseline];
|
|
3568
|
+
}
|
|
3569
|
+
delete context.metadata.suspendedMessageId;
|
|
3495
3570
|
if (submittedUser && startsNewTurn)
|
|
3496
3571
|
context.metadata.turnImages = inputFiles
|
|
3497
3572
|
.filter((file) => file.mediaType.startsWith("image/"))
|
|
@@ -3910,16 +3985,18 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
3910
3985
|
})),
|
|
3911
3986
|
];
|
|
3912
3987
|
if (inboxRunner?.suspendedToolCallId) {
|
|
3913
|
-
responseMessage.parts = responseMessage.parts.map((part) =>
|
|
3914
|
-
part
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
state: "input-available"
|
|
3919
|
-
input: "input" in part ? part.input : {},
|
|
3988
|
+
responseMessage.parts = responseMessage.parts.map((part) => {
|
|
3989
|
+
if (isToolUIPart(part) &&
|
|
3990
|
+
part.toolCallId === inboxRunner.suspendedToolCallId &&
|
|
3991
|
+
part.state === "output-available") {
|
|
3992
|
+
const { output: _output, approval: _approval, ...pending } = part;
|
|
3993
|
+
return { ...pending, state: "input-available" };
|
|
3920
3994
|
}
|
|
3921
|
-
|
|
3995
|
+
return part;
|
|
3996
|
+
});
|
|
3922
3997
|
}
|
|
3998
|
+
if (inboxRunner?.suspended)
|
|
3999
|
+
context.metadata.suspendedMessageId = responseMessage.id;
|
|
3923
4000
|
responseMessage.metadata = {
|
|
3924
4001
|
...responseMessage.metadata,
|
|
3925
4002
|
...(await contextFinished),
|
|
@@ -4009,13 +4086,16 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
4009
4086
|
const pending = context.metadata.agentCore;
|
|
4010
4087
|
let lastCoreFinishReason = pending ? "tool-calls" : "stop";
|
|
4011
4088
|
if (pending && currentTurn.some((message) => message.role === "user"))
|
|
4012
|
-
throw new Error("Resolve pending
|
|
4089
|
+
throw new Error("Resolve pending tool interactions before starting another turn.");
|
|
4013
4090
|
const messageId = pending?.messageId ?? payload.responseMessageId;
|
|
4014
|
-
const
|
|
4091
|
+
const pendingMessage = pending
|
|
4015
4092
|
? z
|
|
4016
4093
|
.object({ parts: z.array(z.unknown()) })
|
|
4017
4094
|
.parse(payload.originalMessages.find((message) => message.id === pending.messageId))
|
|
4018
|
-
|
|
4095
|
+
: undefined;
|
|
4096
|
+
const responses = pendingMessage
|
|
4097
|
+
? pendingMessage.parts
|
|
4098
|
+
.flatMap((part) => {
|
|
4019
4099
|
const parsed = z
|
|
4020
4100
|
.object({
|
|
4021
4101
|
state: z.literal("approval-responded"),
|
|
@@ -4029,6 +4109,49 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
4029
4109
|
// Keep unknown IDs so Rust still rejects foreign/duplicate responses.
|
|
4030
4110
|
.filter((response) => !pending.pendingStep.approvals.some((approval) => approval.id === response.id && approval.response != null))
|
|
4031
4111
|
: [];
|
|
4112
|
+
// Model conversion already applies the Tool's toModelOutput (including
|
|
4113
|
+
// managed file adoption); retain the raw client output for the UI stream.
|
|
4114
|
+
const modelResults = new Map(fromModelMessages((pending?.pendingStep.client_calls?.length
|
|
4115
|
+
? modelMessages
|
|
4116
|
+
: []).flatMap((message) => message.role === "tool"
|
|
4117
|
+
? [
|
|
4118
|
+
{
|
|
4119
|
+
...message,
|
|
4120
|
+
content: message.content.filter((part) => part.type === "tool-result"),
|
|
4121
|
+
},
|
|
4122
|
+
]
|
|
4123
|
+
: [])).flatMap((message) => message.content.flatMap((part) => part.type === "tool_result" ? [[part.call_id, part]] : [])));
|
|
4124
|
+
const clientResults = (pendingMessage?.parts ?? []).flatMap((part) => {
|
|
4125
|
+
const result = z
|
|
4126
|
+
.discriminatedUnion("state", [
|
|
4127
|
+
z.object({
|
|
4128
|
+
state: z.literal("output-available"),
|
|
4129
|
+
toolCallId: z.string(),
|
|
4130
|
+
output: z.json(),
|
|
4131
|
+
}),
|
|
4132
|
+
z.object({
|
|
4133
|
+
state: z.literal("output-error"),
|
|
4134
|
+
toolCallId: z.string(),
|
|
4135
|
+
errorText: z.string(),
|
|
4136
|
+
}),
|
|
4137
|
+
])
|
|
4138
|
+
.safeParse(part);
|
|
4139
|
+
if (!result.success ||
|
|
4140
|
+
!pending?.pendingStep.client_calls?.includes(result.data.toolCallId))
|
|
4141
|
+
return [];
|
|
4142
|
+
const value = result.data;
|
|
4143
|
+
const modelResult = modelResults.get(value.toolCallId);
|
|
4144
|
+
if (!modelResult)
|
|
4145
|
+
throw new Error(`Missing client Tool model output: ${value.toolCallId}`);
|
|
4146
|
+
return [
|
|
4147
|
+
{
|
|
4148
|
+
call_id: value.toolCallId,
|
|
4149
|
+
output: value.state === "output-error" ? value.errorText : value.output,
|
|
4150
|
+
is_error: value.state === "output-error",
|
|
4151
|
+
model_output: modelResult.model_output,
|
|
4152
|
+
},
|
|
4153
|
+
];
|
|
4154
|
+
});
|
|
4032
4155
|
const coreTools = await createCoreWorkerTools({
|
|
4033
4156
|
tools,
|
|
4034
4157
|
approval: toolApproval,
|
|
@@ -4087,7 +4210,9 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
4087
4210
|
}
|
|
4088
4211
|
: undefined,
|
|
4089
4212
|
pending_step: pending?.pendingStep,
|
|
4090
|
-
}), pending
|
|
4213
|
+
}), pending
|
|
4214
|
+
? { type: "tool_response", responses, results: clientResults }
|
|
4215
|
+
: { type: "start" }, {
|
|
4091
4216
|
...coreTools,
|
|
4092
4217
|
onError: engine.onError,
|
|
4093
4218
|
fetch: (request, init) => coreConnection.fetch(request, init),
|
|
@@ -4191,7 +4316,8 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
4191
4316
|
? "stop"
|
|
4192
4317
|
: outcome.reason === "stopped"
|
|
4193
4318
|
? lastCoreFinishReason
|
|
4194
|
-
: outcome.reason === "awaiting_approval"
|
|
4319
|
+
: outcome.reason === "awaiting_approval" ||
|
|
4320
|
+
outcome.reason === "awaiting_tool_results"
|
|
4195
4321
|
? "tool-calls"
|
|
4196
4322
|
: "length",
|
|
4197
4323
|
});
|
|
@@ -4432,6 +4558,46 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
4432
4558
|
}
|
|
4433
4559
|
const durableStream = stream.pipeThrough(new TransformStream({
|
|
4434
4560
|
async transform(chunk, controller) {
|
|
4561
|
+
if (chunk.type === "start" && interruptedResponse) {
|
|
4562
|
+
const events = [
|
|
4563
|
+
...(interruptedWait ? [interruptedWait] : []),
|
|
4564
|
+
{ type: "finish", finishReason: "other" },
|
|
4565
|
+
];
|
|
4566
|
+
if (sessionExecution)
|
|
4567
|
+
await mutateSession({
|
|
4568
|
+
messages: [{ ...interruptedResponse }],
|
|
4569
|
+
events,
|
|
4570
|
+
});
|
|
4571
|
+
else {
|
|
4572
|
+
await appendSessionValue({
|
|
4573
|
+
body: { message: interruptedResponse, runId: payload.runId },
|
|
4574
|
+
chatId: payload.chatId,
|
|
4575
|
+
namespace: input.sessionNamespace,
|
|
4576
|
+
path: "/v1/messages",
|
|
4577
|
+
});
|
|
4578
|
+
for (const event of events)
|
|
4579
|
+
await appendStreamEvent(event);
|
|
4580
|
+
}
|
|
4581
|
+
}
|
|
4582
|
+
if (chunk.type === "start" && responseBaseline) {
|
|
4583
|
+
// Each internal invocation still has its own start/finish for accounting.
|
|
4584
|
+
// The public journal represents one response across those invocations.
|
|
4585
|
+
controller.enqueue(chunk);
|
|
4586
|
+
const result = input.inboxExecution?.waitResult;
|
|
4587
|
+
if (result) {
|
|
4588
|
+
const output = {
|
|
4589
|
+
type: "tool-output-available",
|
|
4590
|
+
toolCallId: result.toolCallId,
|
|
4591
|
+
output: toAgentRunWaitOutput(result),
|
|
4592
|
+
};
|
|
4593
|
+
if (sessionExecution)
|
|
4594
|
+
await mutateSession({ events: [output] });
|
|
4595
|
+
else
|
|
4596
|
+
await appendStreamEvent(output);
|
|
4597
|
+
controller.enqueue(output);
|
|
4598
|
+
}
|
|
4599
|
+
return;
|
|
4600
|
+
}
|
|
4435
4601
|
if (chunk.type === "tool-output-available" &&
|
|
4436
4602
|
chunk.toolCallId === inboxRunner?.suspendedToolCallId)
|
|
4437
4603
|
return;
|
|
@@ -4458,6 +4624,10 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
4458
4624
|
finishReason: metadata.finishReason,
|
|
4459
4625
|
messageMetadata: metadata,
|
|
4460
4626
|
};
|
|
4627
|
+
if (metadata.sessionStatus === "waiting") {
|
|
4628
|
+
controller.enqueue(chunk);
|
|
4629
|
+
return;
|
|
4630
|
+
}
|
|
4461
4631
|
}
|
|
4462
4632
|
if (sessionExecution) {
|
|
4463
4633
|
await mutateSession({ events: [chunk] });
|
|
@@ -4486,7 +4656,17 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
4486
4656
|
reader.releaseLock();
|
|
4487
4657
|
}
|
|
4488
4658
|
})());
|
|
4489
|
-
return createUIMessageStreamResponse({
|
|
4659
|
+
return createUIMessageStreamResponse({
|
|
4660
|
+
stream: response,
|
|
4661
|
+
headers: {
|
|
4662
|
+
[AGENT_APPLICATION_MESSAGE_ID_HEADER]: payload.responseMessageId,
|
|
4663
|
+
},
|
|
4664
|
+
});
|
|
4490
4665
|
}
|
|
4491
|
-
return createUIMessageStreamResponse({
|
|
4666
|
+
return createUIMessageStreamResponse({
|
|
4667
|
+
stream: durableStream,
|
|
4668
|
+
headers: {
|
|
4669
|
+
[AGENT_APPLICATION_MESSAGE_ID_HEADER]: payload.responseMessageId,
|
|
4670
|
+
},
|
|
4671
|
+
});
|
|
4492
4672
|
}
|
|
@@ -19,7 +19,7 @@ export declare function toFileData(data: AgentCoreFileData): {
|
|
|
19
19
|
export declare function toCoreModelOutput(output: ToolResultOutput): AgentCoreModelOutput;
|
|
20
20
|
export declare function fromModelMessages(messages: ModelMessage[]): AgentCoreMessage[];
|
|
21
21
|
/** Close only the interrupted trailing batch, after host operations have settled. */
|
|
22
|
-
export declare function closeInterruptedToolCalls(messages: ModelMessage[]): ModelMessage[];
|
|
22
|
+
export declare function closeInterruptedToolCalls(messages: ModelMessage[], reason?: string): ModelMessage[];
|
|
23
23
|
export declare function toToolModelOutput(part: Extract<AgentCoreMessage["content"][number], {
|
|
24
24
|
type: "tool_result";
|
|
25
25
|
}>): LanguageModelV4ToolResultOutput;
|
|
@@ -137,7 +137,7 @@ export function fromModelMessages(messages) {
|
|
|
137
137
|
}));
|
|
138
138
|
}
|
|
139
139
|
/** Close only the interrupted trailing batch, after host operations have settled. */
|
|
140
|
-
export function closeInterruptedToolCalls(messages) {
|
|
140
|
+
export function closeInterruptedToolCalls(messages, reason = "Agent execution was interrupted before a tool result was recorded. The operation may have taken effect; its outcome is unknown.") {
|
|
141
141
|
let index = messages.length - 1;
|
|
142
142
|
while (index >= 0 && messages[index]?.role === "tool")
|
|
143
143
|
index--;
|
|
@@ -165,7 +165,7 @@ export function closeInterruptedToolCalls(messages) {
|
|
|
165
165
|
toolName,
|
|
166
166
|
output: {
|
|
167
167
|
type: "error-text",
|
|
168
|
-
value:
|
|
168
|
+
value: reason,
|
|
169
169
|
},
|
|
170
170
|
})),
|
|
171
171
|
},
|
|
@@ -7,7 +7,7 @@ export function createAgentCoreTools(options) {
|
|
|
7
7
|
return {
|
|
8
8
|
async decideTool(call, signal) {
|
|
9
9
|
const action = options.actions[call.name];
|
|
10
|
-
if (!action
|
|
10
|
+
if (!action)
|
|
11
11
|
return { type: "denied", reason: `Tool is unavailable: ${call.name}` };
|
|
12
12
|
const parsed = await action.inputSchema.safeParseAsync(call.input);
|
|
13
13
|
if (!parsed.success)
|
|
@@ -35,8 +35,9 @@ export function createAgentCoreTools(options) {
|
|
|
35
35
|
return {
|
|
36
36
|
type: "approval_required",
|
|
37
37
|
approval_id: options.approvalId?.(call) ?? crypto.randomUUID(),
|
|
38
|
+
...(!action.handler ? { client: true } : {}),
|
|
38
39
|
};
|
|
39
|
-
return { type: "approved" };
|
|
40
|
+
return { type: action.handler ? "approved" : "client" };
|
|
40
41
|
},
|
|
41
42
|
async tool(call, signal) {
|
|
42
43
|
const action = options.actions[call.name];
|
|
@@ -158,7 +158,7 @@ export async function* projectAgentCoreEvents(turn, options) {
|
|
|
158
158
|
break;
|
|
159
159
|
case "tool_ready":
|
|
160
160
|
calls.set(event.call.id, event.call);
|
|
161
|
-
if (resumed)
|
|
161
|
+
if (resumed && !event.client)
|
|
162
162
|
break;
|
|
163
163
|
part = {
|
|
164
164
|
type: "tool-call",
|
|
@@ -267,7 +267,8 @@ export async function* projectAgentCoreEvents(turn, options) {
|
|
|
267
267
|
: outcome.reason === "model_limit"
|
|
268
268
|
? "length"
|
|
269
269
|
: outcome.reason === "step_limit" ||
|
|
270
|
-
outcome.reason === "awaiting_approval"
|
|
270
|
+
outcome.reason === "awaiting_approval" ||
|
|
271
|
+
outcome.reason === "awaiting_tool_results"
|
|
271
272
|
? "tool-calls"
|
|
272
273
|
: "error",
|
|
273
274
|
messageMetadata,
|
|
@@ -37,7 +37,7 @@ export async function createCoreWorkerTools(options) {
|
|
|
37
37
|
async decideTool(call, signal) {
|
|
38
38
|
signal.throwIfAborted();
|
|
39
39
|
const tool = options.tools[call.name];
|
|
40
|
-
if (!tool
|
|
40
|
+
if (!tool)
|
|
41
41
|
return { type: "denied", reason: `Tool is unavailable: ${call.name}` };
|
|
42
42
|
const parsed = await safeValidateTypes({
|
|
43
43
|
value: call.input,
|
|
@@ -69,8 +69,12 @@ export async function createCoreWorkerTools(options) {
|
|
|
69
69
|
: "Tool execution denied",
|
|
70
70
|
};
|
|
71
71
|
if (type === "user-approval" || guardrailType === "user-approval")
|
|
72
|
-
return {
|
|
73
|
-
|
|
72
|
+
return {
|
|
73
|
+
type: "approval_required",
|
|
74
|
+
approval_id: crypto.randomUUID(),
|
|
75
|
+
...(!tool.execute ? { client: true } : {}),
|
|
76
|
+
};
|
|
77
|
+
return { type: tool.execute ? "approved" : "client" };
|
|
74
78
|
},
|
|
75
79
|
async tool(call, signal) {
|
|
76
80
|
const tool = options.tools[call.name];
|
|
@@ -26,7 +26,7 @@ export interface AgentCoreHost {
|
|
|
26
26
|
prepareStep?(step: AgentCorePrepareStep, signal: AbortSignal): Promise<AgentCoreMessage[] | null | void>;
|
|
27
27
|
finishStep?(step: AgentCoreFinishedStep, signal: AbortSignal): Promise<AgentCoreMessage[] | null | void>;
|
|
28
28
|
/** Core awaits this even after cancellation. Drain retained work and persist
|
|
29
|
-
* final context here;
|
|
29
|
+
* final context here; approval/client-result waits are pauses, not completed turns. */
|
|
30
30
|
finishRun?(outcome: AgentCoreOutcome, signal: AbortSignal): Promise<void>;
|
|
31
31
|
model?(request: AgentCoreModelRequest, signal: AbortSignal): AsyncIterable<AgentCoreModelPart>;
|
|
32
32
|
tool(call: AgentCoreToolCall, signal: AbortSignal): Promise<AgentCoreToolResult>;
|
|
@@ -37,13 +37,13 @@ export interface AgentCoreHost {
|
|
|
37
37
|
export declare function createAgentCore(module: WebAssembly.Module, config: AgentCoreConfig): {
|
|
38
38
|
run(message: AgentCoreInput, host: AgentCoreHost, emit: (event: AgentCoreEvent) => Promise<void>, signal: AbortSignal): Promise<{
|
|
39
39
|
output?: z.util.JSONType | undefined;
|
|
40
|
-
reason: "awaiting_approval" | "cancelled" | "completed" | "failed" | "model_limit" | "step_limit" | "stopped";
|
|
40
|
+
reason: "awaiting_approval" | "awaiting_tool_results" | "cancelled" | "completed" | "failed" | "model_limit" | "step_limit" | "stopped";
|
|
41
41
|
error: string | null;
|
|
42
42
|
details?: AgentCoreErrorDetails | undefined;
|
|
43
43
|
}>;
|
|
44
44
|
runOutcome(message: AgentCoreInput, host: AgentCoreHost, emit: (event: AgentCoreEvent) => Promise<void>, signal: AbortSignal): Promise<{
|
|
45
45
|
output?: z.util.JSONType | undefined;
|
|
46
|
-
reason: "awaiting_approval" | "cancelled" | "completed" | "failed" | "model_limit" | "step_limit" | "stopped";
|
|
46
|
+
reason: "awaiting_approval" | "awaiting_tool_results" | "cancelled" | "completed" | "failed" | "model_limit" | "step_limit" | "stopped";
|
|
47
47
|
error: string | null;
|
|
48
48
|
details?: AgentCoreErrorDetails | undefined;
|
|
49
49
|
}>;
|
|
@@ -351,7 +351,7 @@ export function createAgentCore(module, config) {
|
|
|
351
351
|
})),
|
|
352
352
|
},
|
|
353
353
|
}).exports);
|
|
354
|
-
if (exports.agent_abi_version() !==
|
|
354
|
+
if (exports.agent_abi_version() !== 14)
|
|
355
355
|
throw new Error("Unsupported Agent Core ABI.");
|
|
356
356
|
const run = jspi.promising(exports.agent_run);
|
|
357
357
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gea-ai/agent-sdk",
|
|
3
|
-
"version": "0.1.260920-alpha.
|
|
3
|
+
"version": "0.1.260920-alpha.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"homepage": "https://musegea.com/developers",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"@ai-sdk/otel": "1.0.9",
|
|
105
105
|
"@ai-sdk/provider": "4.0.1",
|
|
106
106
|
"@ai-sdk/provider-utils": "5.0.2",
|
|
107
|
-
"@gea-ai/contract": "0.1.260920-alpha.
|
|
107
|
+
"@gea-ai/contract": "0.1.260920-alpha.2",
|
|
108
108
|
"@opentelemetry/api": "1.9.1",
|
|
109
109
|
"@opentelemetry/context-async-hooks": "2.10.0",
|
|
110
110
|
"@opentelemetry/core": "2.10.0",
|