@gea-ai/agent-sdk 0.1.260924-alpha.0 → 0.1.260925-alpha.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/THIRD_PARTY_NOTICES.md +21 -0
- package/dist/agent-channel-author-runtime.d.ts +13 -13
- package/dist/agent-channel-receiver.d.ts +2 -2
- package/dist/agent-channel-receiver.js +5 -1
- package/dist/agent-remote-run.d.ts +3 -1
- package/dist/agent-remote-run.js +25 -7
- package/dist/agent-run-host.js +8 -1
- package/dist/agent-session-child-store.d.ts +44 -0
- package/dist/agent-session-children.js +15 -0
- package/dist/agent-session-inbox.js +98 -18
- package/dist/agent-session-runner.d.ts +3 -2
- package/dist/agent-worker.d.ts +3 -11
- package/dist/agent-worker.js +27 -154
- package/dist/index.d.ts +23 -43
- package/dist/index.js +35 -139
- package/dist/mcp-tool-output.d.ts +4 -0
- package/dist/mcp-tool-output.js +26 -0
- package/dist/script-tools.d.ts +8 -0
- package/dist/script-tools.js +143 -0
- package/dist/session-authority.d.ts +14 -2
- package/dist/session-authority.js +9 -5
- package/dist/typescript.d.ts +8 -0
- package/dist/typescript.js +3 -0
- package/dist/worker-bundle-plugin.d.ts +8 -0
- package/dist/worker-bundle-plugin.js +94 -0
- package/dist/worker.d.ts +14 -0
- package/dist/worker.js +53 -0
- package/package.json +21 -3
- package/script-runtime/javascript.mjs +8 -0
- package/script-runtime/javascript.worker.json +7 -0
- package/script-runtime/python.mjs +50 -0
- package/script-runtime/result.mjs +60 -0
- package/script-runtime/typescript.mjs +15 -0
- package/script-runtime/typescript.worker.json +7 -0
- package/scripts/prepare-python.d.mts +9 -0
- package/scripts/prepare-python.mjs +192 -0
- package/dist/agent-http.d.ts +0 -13
- package/dist/agent-http.js +0 -30
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -65,3 +65,24 @@ inventory ship in [third-party/agent-core](./third-party/agent-core/NOTICE).
|
|
|
65
65
|
This includes Serde/serde_json, httpdate, jsonschema and its validation/regex/hash
|
|
66
66
|
dependencies, plus build dependencies. The inventory records upstream repository
|
|
67
67
|
license provenance where a crate distribution omitted its license file. The Agent CLI embeds this asset into the immutable Worker bundle.
|
|
68
|
+
|
|
69
|
+
## Optional developer-prepared Python environment
|
|
70
|
+
|
|
71
|
+
The Python preparation utility uses the developer-installed Pyodide (MPL-2.0),
|
|
72
|
+
CPython and the developer-selected packages from that distribution's
|
|
73
|
+
checksum-pinned package index. Its version is recorded in the generated lock.
|
|
74
|
+
These bytes are not included in the SDK tarball or Worker Runtime image.
|
|
75
|
+
When selected, NumPy, pandas and their dependency wheels remain
|
|
76
|
+
intact, including their metadata and license files, in the developer's private
|
|
77
|
+
bundle. Pyodide's glue is adapted by local environment-selection prefixes in
|
|
78
|
+
`scripts/prepare-python.mjs`; the runner is `script-runtime/python.mjs`.
|
|
79
|
+
|
|
80
|
+
Distribution/source references:
|
|
81
|
+
|
|
82
|
+
- https://github.com/pyodide/pyodide
|
|
83
|
+
- https://pyodide.org/en/stable/usage/downloading-and-deploying.html
|
|
84
|
+
- https://github.com/numpy/numpy
|
|
85
|
+
- https://github.com/pandas-dev/pandas
|
|
86
|
+
|
|
87
|
+
Optional TypeScript transpilation uses Sucrase 3.35.1 (MIT), bundled into the private
|
|
88
|
+
JavaScript/TypeScript child Worker by esbuild.
|
|
@@ -19,6 +19,19 @@ export declare function executeChannelBehavior(input: {
|
|
|
19
19
|
environment: AgentChannelFetchEnvironment;
|
|
20
20
|
signal: AbortSignal;
|
|
21
21
|
}): Promise<{
|
|
22
|
+
sequence: number;
|
|
23
|
+
duplicate: boolean;
|
|
24
|
+
} | {
|
|
25
|
+
state: AgentChannelJson;
|
|
26
|
+
intents: {
|
|
27
|
+
key: string;
|
|
28
|
+
payload: AgentChannelJson;
|
|
29
|
+
eventId: string;
|
|
30
|
+
operationId: string;
|
|
31
|
+
}[];
|
|
32
|
+
cursor: number;
|
|
33
|
+
idempotencyWindowMs?: number | undefined;
|
|
34
|
+
} | {
|
|
22
35
|
status: "sent";
|
|
23
36
|
receipt?: AgentChannelJson | undefined;
|
|
24
37
|
} | {
|
|
@@ -43,19 +56,6 @@ export declare function executeChannelBehavior(input: {
|
|
|
43
56
|
message: string;
|
|
44
57
|
retryable: boolean;
|
|
45
58
|
};
|
|
46
|
-
} | {
|
|
47
|
-
sequence: number;
|
|
48
|
-
duplicate: boolean;
|
|
49
|
-
} | {
|
|
50
|
-
state: AgentChannelJson;
|
|
51
|
-
intents: {
|
|
52
|
-
key: string;
|
|
53
|
-
payload: AgentChannelJson;
|
|
54
|
-
eventId: string;
|
|
55
|
-
operationId: string;
|
|
56
|
-
}[];
|
|
57
|
-
cursor: number;
|
|
58
|
-
idempotencyWindowMs?: number | undefined;
|
|
59
59
|
} | {
|
|
60
60
|
events: {
|
|
61
61
|
id: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type DefinedAgent } from "./index";
|
|
2
2
|
import type { AgentChannelAddressStorage } from "./agent-channel-worker";
|
|
3
3
|
import type { AgentChannelFetchEnvironment } from "./agent-worker";
|
|
4
4
|
export type AgentChannelReceiverEnvironment = AgentChannelFetchEnvironment & {
|
|
@@ -27,7 +27,7 @@ export declare class AgentChannelReceiver {
|
|
|
27
27
|
private definition?;
|
|
28
28
|
private starting;
|
|
29
29
|
constructor(storage: AgentChannelAddressStorage, environment: AgentChannelReceiverEnvironment, agents: Record<string, {
|
|
30
|
-
definition:
|
|
30
|
+
definition: DefinedAgent;
|
|
31
31
|
}>);
|
|
32
32
|
private load;
|
|
33
33
|
private persist;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { TaggedError } from "better-result";
|
|
3
3
|
import { agentChannelReceiverControlSchema, agentChannelReceiverInitializationSchema, agentChannelReceiverStateSchema, agentChannelReceiverErrorSchema, } from "@gea-ai/contract/agent-channel-receivers";
|
|
4
|
+
import { resolveAgentDefinition } from "./index.js";
|
|
4
5
|
import { createChannelInputContext } from "./agent-channel-author-runtime.js";
|
|
5
6
|
const recordSchema = z
|
|
6
7
|
.object({
|
|
@@ -138,7 +139,10 @@ export class AgentChannelReceiver {
|
|
|
138
139
|
async context(record, controller) {
|
|
139
140
|
controller.signal.throwIfAborted();
|
|
140
141
|
const initialized = agentChannelReceiverInitializationSchema.parse(await (await this.host(record.control, "initialize", {}, controller.signal)).json());
|
|
141
|
-
const
|
|
142
|
+
const agent = this.agents[record.control.agentKey]?.definition;
|
|
143
|
+
const definition = agent &&
|
|
144
|
+
resolveAgentDefinition(agent).channels.find((entry) => entry.provider === "custom" &&
|
|
145
|
+
entry.key === record.control.channelKey);
|
|
142
146
|
if (!definition?.receiver)
|
|
143
147
|
throw new Error("Channel receiver definition is unavailable.");
|
|
144
148
|
this.definition = definition;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Result } from "better-result";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { agentApplicationAssistantMessageSchema } from "@gea-ai/contract/agent-applications";
|
|
2
4
|
import type { AgentCallMessage, AgentChildRun, AgentChildRunDestination, AgentChildRunOutcome } from "@gea-ai/contract/agent-worker-tools";
|
|
3
5
|
import type { StudioArtifactInputFile } from "@gea-ai/contract/studio-artifacts";
|
|
4
6
|
/** Internal transport shared by hosted and local Run dispatch; not a public API client. */
|
|
@@ -26,5 +28,5 @@ export declare function submitRemoteRun(fetch: RemoteRunFetch, input: {
|
|
|
26
28
|
sessionId: string;
|
|
27
29
|
}, RemoteRunAdmissionError>>;
|
|
28
30
|
export declare function cancelRemoteRun(fetch: RemoteRunFetch, run: AgentChildRun): Promise<void>;
|
|
29
|
-
export declare function observeRemoteRun(fetch: RemoteRunFetch, run: AgentChildRun, signal: AbortSignal): Promise<AgentChildRunOutcome>;
|
|
31
|
+
export declare function observeRemoteRun(fetch: RemoteRunFetch, run: AgentChildRun, signal: AbortSignal, onInputRequired?: (message: z.infer<typeof agentApplicationAssistantMessageSchema>) => Promise<void>): Promise<AgentChildRunOutcome>;
|
|
30
32
|
export {};
|
package/dist/agent-remote-run.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Result, TaggedError } from "better-result";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { agentApplicationAssistantMessageSchema, agentInputRequestKey, } from "@gea-ai/contract/agent-applications";
|
|
3
4
|
import { agentHttpRunSchema, agentHttpMessageResourceSchema, } from "@gea-ai/contract/agent-http-api";
|
|
4
5
|
const sessionSchema = z.object({ id: z.uuid() });
|
|
5
6
|
const messagesSchema = z.object({
|
|
@@ -56,28 +57,45 @@ export async function cancelRemoteRun(fetch, run) {
|
|
|
56
57
|
const response = await fetch(`/runs/${run.id}/cancel`, { method: "POST" });
|
|
57
58
|
await responseJson(response);
|
|
58
59
|
}
|
|
59
|
-
export async function observeRemoteRun(fetch, run, signal) {
|
|
60
|
+
export async function observeRemoteRun(fetch, run, signal, onInputRequired) {
|
|
61
|
+
let reportedInput;
|
|
60
62
|
while (true) {
|
|
61
63
|
signal.throwIfAborted();
|
|
62
64
|
const record = agentHttpRunSchema.parse(await responseJson(await fetch(`/runs/${run.id}`, { signal })));
|
|
63
65
|
if (record.id !== run.id || record.session_id !== run.sessionId)
|
|
64
66
|
throw new Error("Remote Run identity mismatch.");
|
|
65
|
-
|
|
67
|
+
const terminal = ["finished", "error", "aborted", "interrupted"].includes(record.status);
|
|
68
|
+
const inputMessageId = record.status === "waiting" ? record.input_message_id : null;
|
|
69
|
+
if (terminal || (onInputRequired && inputMessageId)) {
|
|
66
70
|
const text = [];
|
|
67
71
|
let cursor = null;
|
|
68
72
|
do {
|
|
69
73
|
const page = messagesSchema.parse(await responseJson(await fetch(`/sessions/${run.sessionId}/messages?limit=100${cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""}`, { signal })));
|
|
70
74
|
for (const message of page.items)
|
|
71
|
-
if (message.run_id === run.id && message.role === "assistant")
|
|
75
|
+
if (message.run_id === run.id && message.role === "assistant") {
|
|
76
|
+
if (!terminal && message.id === inputMessageId && onInputRequired) {
|
|
77
|
+
const input = agentApplicationAssistantMessageSchema.parse({
|
|
78
|
+
id: message.id,
|
|
79
|
+
role: message.role,
|
|
80
|
+
parts: message.parts,
|
|
81
|
+
});
|
|
82
|
+
const key = agentInputRequestKey(input);
|
|
83
|
+
if (key !== reportedInput) {
|
|
84
|
+
await onInputRequired(input);
|
|
85
|
+
reportedInput = key;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
72
88
|
for (const part of message.parts)
|
|
73
89
|
if (part.type === "text" && typeof part.text === "string")
|
|
74
90
|
text.push(part.text);
|
|
91
|
+
}
|
|
75
92
|
cursor = page.next_cursor;
|
|
76
93
|
} while (cursor);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
94
|
+
if (terminal)
|
|
95
|
+
return {
|
|
96
|
+
status: record.status,
|
|
97
|
+
text: text.join("\n").slice(0, 200_000),
|
|
98
|
+
};
|
|
81
99
|
}
|
|
82
100
|
if (!["queued", "running", "waiting"].includes(record.status))
|
|
83
101
|
throw new Error("Unknown remote Run status.");
|
package/dist/agent-run-host.js
CHANGED
|
@@ -226,7 +226,14 @@ export class AgentRunHost {
|
|
|
226
226
|
const fetch = (path, init) => this.host.remoteFetch(destination, path, init);
|
|
227
227
|
if (run.cancelRequested)
|
|
228
228
|
await cancelRemoteRun(fetch, run);
|
|
229
|
-
const outcome = await observeRemoteRun(fetch, run, cancellation.signal)
|
|
229
|
+
const outcome = await observeRemoteRun(fetch, run, cancellation.signal, async (message) => {
|
|
230
|
+
const stored = await this.host.session("input", {
|
|
231
|
+
runId: run.id,
|
|
232
|
+
message,
|
|
233
|
+
});
|
|
234
|
+
if (!stored.ok)
|
|
235
|
+
throw new Error(`Remote input notification rejected (${stored.status}).`);
|
|
236
|
+
});
|
|
230
237
|
const stored = await this.host.session("complete", {
|
|
231
238
|
runId: run.id,
|
|
232
239
|
...outcome,
|
|
@@ -72,6 +72,17 @@ export declare function getChildRun(tx: AgentSessionTransactionStorage, runId: s
|
|
|
72
72
|
status: "aborted" | "error" | "finished" | "interrupted";
|
|
73
73
|
text: string;
|
|
74
74
|
} | null;
|
|
75
|
+
inputRequest?: {
|
|
76
|
+
id: string;
|
|
77
|
+
role: "assistant";
|
|
78
|
+
parts: {
|
|
79
|
+
[x: string]: unknown;
|
|
80
|
+
type: string;
|
|
81
|
+
}[];
|
|
82
|
+
metadata?: unknown;
|
|
83
|
+
} | undefined;
|
|
84
|
+
observedInputRequest?: string | undefined;
|
|
85
|
+
explicitWaitOnly?: boolean | undefined;
|
|
75
86
|
} | undefined>;
|
|
76
87
|
export declare function getChildSession(tx: AgentSessionTransactionStorage, sessionId: string): Promise<{
|
|
77
88
|
agentKey: string;
|
|
@@ -149,6 +160,17 @@ export declare function readChildRuns(tx: AgentSessionTransactionStorage, refere
|
|
|
149
160
|
status: "aborted" | "error" | "finished" | "interrupted";
|
|
150
161
|
text: string;
|
|
151
162
|
} | null;
|
|
163
|
+
inputRequest?: {
|
|
164
|
+
id: string;
|
|
165
|
+
role: "assistant";
|
|
166
|
+
parts: {
|
|
167
|
+
[x: string]: unknown;
|
|
168
|
+
type: string;
|
|
169
|
+
}[];
|
|
170
|
+
metadata?: unknown;
|
|
171
|
+
} | undefined;
|
|
172
|
+
observedInputRequest?: string | undefined;
|
|
173
|
+
explicitWaitOnly?: boolean | undefined;
|
|
152
174
|
}[]>;
|
|
153
175
|
export declare function listChildRuns(tx: AgentSessionTransactionStorage, after: number, limit: number): Promise<{
|
|
154
176
|
runs: {
|
|
@@ -204,6 +226,17 @@ export declare function listChildRuns(tx: AgentSessionTransactionStorage, after:
|
|
|
204
226
|
status: "aborted" | "error" | "finished" | "interrupted";
|
|
205
227
|
text: string;
|
|
206
228
|
} | null;
|
|
229
|
+
inputRequest?: {
|
|
230
|
+
id: string;
|
|
231
|
+
role: "assistant";
|
|
232
|
+
parts: {
|
|
233
|
+
[x: string]: unknown;
|
|
234
|
+
type: string;
|
|
235
|
+
}[];
|
|
236
|
+
metadata?: unknown;
|
|
237
|
+
} | undefined;
|
|
238
|
+
observedInputRequest?: string | undefined;
|
|
239
|
+
explicitWaitOnly?: boolean | undefined;
|
|
207
240
|
}[];
|
|
208
241
|
nextCursor: null;
|
|
209
242
|
subagentConcurrencyVersion?: undefined;
|
|
@@ -262,6 +295,17 @@ export declare function listChildRuns(tx: AgentSessionTransactionStorage, after:
|
|
|
262
295
|
status: "aborted" | "error" | "finished" | "interrupted";
|
|
263
296
|
text: string;
|
|
264
297
|
} | null;
|
|
298
|
+
inputRequest?: {
|
|
299
|
+
id: string;
|
|
300
|
+
role: "assistant";
|
|
301
|
+
parts: {
|
|
302
|
+
[x: string]: unknown;
|
|
303
|
+
type: string;
|
|
304
|
+
}[];
|
|
305
|
+
metadata?: unknown;
|
|
306
|
+
} | undefined;
|
|
307
|
+
observedInputRequest?: string | undefined;
|
|
308
|
+
explicitWaitOnly?: boolean | undefined;
|
|
265
309
|
}[];
|
|
266
310
|
nextCursor: number | null;
|
|
267
311
|
}>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { agentApplicationAssistantMessageSchema } from "@gea-ai/contract/agent-applications";
|
|
2
3
|
import { readTraceContext } from "./trace-context.js";
|
|
3
4
|
import { traceContextSchema } from "@gea-ai/contract/traces";
|
|
4
5
|
import { DEFAULT_MAX_CONCURRENT_SUBAGENTS, maxConcurrentSubagentsSchema, } from "@gea-ai/contract/agent-packages";
|
|
@@ -69,6 +70,20 @@ export async function handleAgentSessionChildren(request, storage) {
|
|
|
69
70
|
await acceptAgentSessionChildRun(tx, runId);
|
|
70
71
|
return Response.json({ accepted: true });
|
|
71
72
|
}
|
|
73
|
+
case "input": {
|
|
74
|
+
const { runId, message } = runIdSchema
|
|
75
|
+
.extend({ message: agentApplicationAssistantMessageSchema })
|
|
76
|
+
.parse(value);
|
|
77
|
+
const run = await getChildRun(tx, runId);
|
|
78
|
+
if (!run)
|
|
79
|
+
return Response.json({ error: "unknown_run" }, { status: 404 });
|
|
80
|
+
if (!run.outcome) {
|
|
81
|
+
run.inputRequest = message;
|
|
82
|
+
await putChildRun(tx, run);
|
|
83
|
+
await scheduleAgentSessionChildRunChanges(tx);
|
|
84
|
+
}
|
|
85
|
+
return Response.json({ run });
|
|
86
|
+
}
|
|
72
87
|
case "start":
|
|
73
88
|
case "reserve": {
|
|
74
89
|
const input = startSchema.parse(value);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getChildRun, putChildRun, readChildRuns, readChildRunIndex, } from "./agent-session-child-store.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { agentSessionExecutionTurnSchema } from "@gea-ai/contract/agent-session";
|
|
4
|
-
import { agentApplicationAssistantMessageSchema } from "@gea-ai/contract/agent-applications";
|
|
4
|
+
import { agentApplicationAssistantMessageSchema, agentInputRequestKey, } from "@gea-ai/contract/agent-applications";
|
|
5
5
|
import { canonicalAgentChannelJson } from "@gea-ai/contract/agent-channels";
|
|
6
6
|
import { agentSessionIdentitySchema, agentSessionBootstrapSchema, agentSessionTransportSchema, agentSessionDispatchSchema, agentSessionInboxFinishSchema, agentSessionInboxExecutionSchema, agentSessionSendSchema, agentRunWaitInputSchema, agentRunWaitResultSchema, toAgentRunWaitOutput, } from "@gea-ai/contract/agent-session-inbox";
|
|
7
7
|
import { combineTraceContexts, readTraceContext } from "./trace-context.js";
|
|
@@ -40,6 +40,14 @@ const stateSchema = z.strictObject({
|
|
|
40
40
|
terminal: terminalSchema.nullable().default(null),
|
|
41
41
|
draining: terminalSchema.nullable().default(null),
|
|
42
42
|
terminalQueue: z.array(terminalSchema).max(8).default([]),
|
|
43
|
+
inputNotification: z
|
|
44
|
+
.strictObject({
|
|
45
|
+
execution: agentSessionInboxExecutionSchema,
|
|
46
|
+
transport: agentSessionTransportSchema,
|
|
47
|
+
message: agentApplicationAssistantMessageSchema,
|
|
48
|
+
})
|
|
49
|
+
.nullable()
|
|
50
|
+
.default(null),
|
|
43
51
|
});
|
|
44
52
|
/** Only private definitions/self copies share the owning Agent's business context. */
|
|
45
53
|
export async function inheritedAgentSessionMetadata(tx, destination) {
|
|
@@ -101,6 +109,7 @@ async function skipInputWait(tx, state, runs) {
|
|
|
101
109
|
transport: state.transport,
|
|
102
110
|
};
|
|
103
111
|
state.inputWait = null;
|
|
112
|
+
state.inputNotification = null;
|
|
104
113
|
if (runs.some((run) => !run.outcome)) {
|
|
105
114
|
state.stopped = true;
|
|
106
115
|
for (const run of runs)
|
|
@@ -280,17 +289,33 @@ function waitResult(state, runs, cancelled = false) {
|
|
|
280
289
|
? "steering"
|
|
281
290
|
: !pendingRunIds.length
|
|
282
291
|
? "completed"
|
|
283
|
-
:
|
|
284
|
-
|
|
285
|
-
|
|
292
|
+
: selected.some((run) => !run.outcome &&
|
|
293
|
+
run.inputRequest &&
|
|
294
|
+
agentInputRequestKey(run.inputRequest) !==
|
|
295
|
+
run.observedInputRequest)
|
|
296
|
+
? "input_required"
|
|
297
|
+
: state.wait.deadline !== null && state.wait.deadline <= Date.now()
|
|
298
|
+
? "timeout"
|
|
299
|
+
: null;
|
|
286
300
|
return reason
|
|
287
301
|
? {
|
|
288
302
|
toolCallId: state.wait.toolCallId ?? "join",
|
|
289
303
|
reason,
|
|
290
304
|
runs: selected
|
|
291
|
-
.filter((run) => run.outcome !== null
|
|
305
|
+
.filter((run) => run.outcome !== null ||
|
|
306
|
+
(reason === "input_required" && run.inputRequest))
|
|
292
307
|
.map((run) => {
|
|
293
308
|
const limit = Math.floor(170_000 / Math.max(1, selected.length) / 6);
|
|
309
|
+
if (!run.outcome)
|
|
310
|
+
return {
|
|
311
|
+
runId: run.id,
|
|
312
|
+
sessionId: run.sessionId,
|
|
313
|
+
status: "waiting",
|
|
314
|
+
text: "This Run needs external tool input. Reply through its Session API, then explicitly call runWait again to await its completion.",
|
|
315
|
+
input: z
|
|
316
|
+
.json()
|
|
317
|
+
.parse(JSON.parse(JSON.stringify(run.inputRequest))),
|
|
318
|
+
};
|
|
294
319
|
return {
|
|
295
320
|
runId: run.id,
|
|
296
321
|
sessionId: run.sessionId,
|
|
@@ -305,6 +330,20 @@ function waitResult(state, runs, cancelled = false) {
|
|
|
305
330
|
}
|
|
306
331
|
: null;
|
|
307
332
|
}
|
|
333
|
+
/** Returning input transfers further waiting to the caller, including the other selected Runs. */
|
|
334
|
+
async function consumeInputRequest(tx, state, runs, result) {
|
|
335
|
+
if (result?.reason !== "input_required" || !state.wait)
|
|
336
|
+
return;
|
|
337
|
+
for (const run of runs)
|
|
338
|
+
if (state.wait.runIds.includes(run.id)) {
|
|
339
|
+
run.explicitWaitOnly = true;
|
|
340
|
+
if (run.inputRequest)
|
|
341
|
+
run.observedInputRequest = agentInputRequestKey(run.inputRequest);
|
|
342
|
+
if (run.destination.type === "remote")
|
|
343
|
+
state.pendingStarts = state.pendingStarts.filter((id) => id !== run.id);
|
|
344
|
+
await putChildRun(tx, run);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
308
347
|
/** State and the single wake deadline always commit in the same storage transaction. */
|
|
309
348
|
async function save(tx, state, runs) {
|
|
310
349
|
// Completion bursts spill to individual records; only a bounded batch joins the inbox.
|
|
@@ -320,7 +359,8 @@ async function save(tx, state, runs) {
|
|
|
320
359
|
await tx.delete(key);
|
|
321
360
|
}
|
|
322
361
|
}
|
|
323
|
-
if (state.draining &&
|
|
362
|
+
if (state.draining &&
|
|
363
|
+
!runs.some((run) => !run.outcome && (!run.explicitWaitOnly || state.stopped))) {
|
|
324
364
|
if (state.terminal)
|
|
325
365
|
state.terminalQueue.push(state.draining);
|
|
326
366
|
else
|
|
@@ -349,7 +389,10 @@ async function save(tx, state, runs) {
|
|
|
349
389
|
const leaseDeadline = turn?.runId === state.execution?.turnId && turn?.status === "running"
|
|
350
390
|
? Date.parse(turn.leaseExpiresAt)
|
|
351
391
|
: null;
|
|
352
|
-
const scheduled = cancelling ||
|
|
392
|
+
const scheduled = cancelling ||
|
|
393
|
+
state.pendingStarts.length ||
|
|
394
|
+
state.terminal ||
|
|
395
|
+
state.inputNotification
|
|
353
396
|
? Date.now()
|
|
354
397
|
: state.execution
|
|
355
398
|
? state.started || !state.transport
|
|
@@ -384,7 +427,7 @@ export async function notifyAgentSessionChildRun(tx, run) {
|
|
|
384
427
|
await save(tx, state, runs);
|
|
385
428
|
return;
|
|
386
429
|
}
|
|
387
|
-
if (!state.wait?.runIds.includes(run.id)) {
|
|
430
|
+
if (!state.wait?.runIds.includes(run.id) && !run.explicitWaitOnly) {
|
|
388
431
|
const id = `run:${run.id}`;
|
|
389
432
|
if (!(await tx.get(`inbox:message:${id}`))) {
|
|
390
433
|
const message = agentSessionSendSchema.parse({
|
|
@@ -425,11 +468,18 @@ async function finishInbox(tx, state, runs, input) {
|
|
|
425
468
|
return Response.json({ error: "execution_not_expired" }, { status: 409 });
|
|
426
469
|
}
|
|
427
470
|
}
|
|
428
|
-
if (inputWait && !outcome && !state.stopped)
|
|
471
|
+
if (inputWait && !outcome && !state.stopped) {
|
|
429
472
|
state.inputWait = {
|
|
430
473
|
turnId: state.execution.turnId,
|
|
431
474
|
messageId: inputWait.messageId,
|
|
432
475
|
};
|
|
476
|
+
if (inputWait.message && state.transport)
|
|
477
|
+
state.inputNotification = {
|
|
478
|
+
execution: { ...state.execution, messages: [], waitResult: null },
|
|
479
|
+
transport: state.transport,
|
|
480
|
+
message: inputWait.message,
|
|
481
|
+
};
|
|
482
|
+
}
|
|
433
483
|
// A transport disconnect does not revoke already accepted child runs.
|
|
434
484
|
if (outcome?.status === "cancelled" &&
|
|
435
485
|
!state.stopped &&
|
|
@@ -464,7 +514,7 @@ async function finishInbox(tx, state, runs, input) {
|
|
|
464
514
|
},
|
|
465
515
|
transport: state.transport,
|
|
466
516
|
};
|
|
467
|
-
if (runs.some((run) => !run.outcome))
|
|
517
|
+
if (runs.some((run) => !run.outcome && (!run.explicitWaitOnly || state.stopped)))
|
|
468
518
|
state.draining = terminal;
|
|
469
519
|
else if (state.terminal)
|
|
470
520
|
state.terminalQueue.push(terminal);
|
|
@@ -530,6 +580,7 @@ export async function handleAgentSessionInboxRequest(request, storage) {
|
|
|
530
580
|
execution: null,
|
|
531
581
|
wait: null,
|
|
532
582
|
inputWait: null,
|
|
583
|
+
inputNotification: null,
|
|
533
584
|
alarmAt: null,
|
|
534
585
|
transport: null,
|
|
535
586
|
started: false,
|
|
@@ -628,6 +679,7 @@ export async function handleAgentSessionInboxRequest(request, storage) {
|
|
|
628
679
|
};
|
|
629
680
|
state.wait = null;
|
|
630
681
|
state.inputWait = null;
|
|
682
|
+
state.inputNotification = null;
|
|
631
683
|
state.resumeWait = null;
|
|
632
684
|
if (!state.draining)
|
|
633
685
|
state.stopped = false;
|
|
@@ -654,6 +706,14 @@ export async function handleAgentSessionInboxRequest(request, storage) {
|
|
|
654
706
|
const input = agentSessionDispatchSchema.parse(body);
|
|
655
707
|
if (input.cancelRunIds || input.startRunIds)
|
|
656
708
|
return Response.json({ accepted: true });
|
|
709
|
+
if (input.inputRequired) {
|
|
710
|
+
if (input.execution.id === state.inputNotification?.execution.id &&
|
|
711
|
+
input.inputRequired.id === state.inputNotification.message.id) {
|
|
712
|
+
state.inputNotification = null;
|
|
713
|
+
await save(tx, state, runs);
|
|
714
|
+
}
|
|
715
|
+
return Response.json({ accepted: true });
|
|
716
|
+
}
|
|
657
717
|
if (input.outcome &&
|
|
658
718
|
input.execution.id === state.terminal?.execution.id) {
|
|
659
719
|
state.terminal = state.terminalQueue.shift() ?? null;
|
|
@@ -717,6 +777,7 @@ export async function handleAgentSessionInboxRequest(request, storage) {
|
|
|
717
777
|
return Response.json({ execution: null });
|
|
718
778
|
const messages = takeMessages(state, state.wait !== null);
|
|
719
779
|
const joining = state.wait?.toolCallId === null;
|
|
780
|
+
await consumeInputRequest(tx, state, runs, result);
|
|
720
781
|
state.stopped = false;
|
|
721
782
|
state.execution = {
|
|
722
783
|
id: crypto.randomUUID(),
|
|
@@ -768,6 +829,7 @@ export async function handleAgentSessionInboxRequest(request, storage) {
|
|
|
768
829
|
state.wait?.turnId ??
|
|
769
830
|
state.execution?.turnId;
|
|
770
831
|
state.inputWait = null;
|
|
832
|
+
state.inputNotification = null;
|
|
771
833
|
state.wait = null;
|
|
772
834
|
if (state.execution && !state.started) {
|
|
773
835
|
state.resumeWait ??= state.execution.waitResult;
|
|
@@ -816,7 +878,7 @@ export async function handleAgentSessionInboxRequest(request, storage) {
|
|
|
816
878
|
return Response.json({ error: "execution_cancelled" }, { status: 409 });
|
|
817
879
|
if (path.endsWith("/join")) {
|
|
818
880
|
const runIds = runs
|
|
819
|
-
.filter((run) => !run.outcome ||
|
|
881
|
+
.filter((run) => (!run.outcome && !run.explicitWaitOnly) ||
|
|
820
882
|
state.messages.some((entry) => entry.id === `run:${run.id}`))
|
|
821
883
|
.map((run) => run.id)
|
|
822
884
|
.slice(0, 128);
|
|
@@ -859,11 +921,19 @@ export async function handleAgentSessionInboxRequest(request, storage) {
|
|
|
859
921
|
: Date.now() + input.timeoutMs,
|
|
860
922
|
traceContext: readTraceContext(request.headers),
|
|
861
923
|
};
|
|
924
|
+
// A remote observation may have stopped after returning input to the caller.
|
|
925
|
+
for (const run of runs)
|
|
926
|
+
if (input.runIds.includes(run.id) &&
|
|
927
|
+
run.destination.type === "remote" &&
|
|
928
|
+
!run.outcome &&
|
|
929
|
+
!state.pendingStarts.includes(run.id))
|
|
930
|
+
state.pendingStarts.push(run.id);
|
|
862
931
|
for (const id of input.runIds)
|
|
863
932
|
await tx.delete(`inbox:child-result:${id}`);
|
|
864
933
|
// A completed result already queued as a notification is consumed by this wait.
|
|
865
934
|
state.messages = state.messages.filter((entry) => !input.runIds.some((id) => entry.id === `run:${id}`));
|
|
866
935
|
const result = waitResult(state, runs);
|
|
936
|
+
await consumeInputRequest(tx, state, runs, result);
|
|
867
937
|
if (result)
|
|
868
938
|
state.wait = null;
|
|
869
939
|
await save(tx, state, runs);
|
|
@@ -932,9 +1002,14 @@ export async function handleAgentSessionAlarm(storage, environment) {
|
|
|
932
1002
|
.filter((run) => !run.outcome && run.cancelRequested)
|
|
933
1003
|
.map((run) => run.id);
|
|
934
1004
|
const childCommands = cancelling.length > 0 || state.pendingStarts.length > 0;
|
|
935
|
-
if (state.started &&
|
|
1005
|
+
if (state.started &&
|
|
1006
|
+
!childCommands &&
|
|
1007
|
+
!state.terminal &&
|
|
1008
|
+
!state.inputNotification)
|
|
936
1009
|
return;
|
|
937
|
-
let execution = state.terminal?.execution ??
|
|
1010
|
+
let execution = state.terminal?.execution ??
|
|
1011
|
+
state.inputNotification?.execution ??
|
|
1012
|
+
state.execution;
|
|
938
1013
|
if (childCommands && !execution)
|
|
939
1014
|
execution = {
|
|
940
1015
|
id: crypto.randomUUID(),
|
|
@@ -959,9 +1034,10 @@ export async function handleAgentSessionAlarm(storage, environment) {
|
|
|
959
1034
|
const current = await readState(tx);
|
|
960
1035
|
if (!current ||
|
|
961
1036
|
(!childCommands &&
|
|
962
|
-
((current.terminal?.execution.id ??
|
|
963
|
-
|
|
964
|
-
|
|
1037
|
+
((current.terminal?.execution.id ??
|
|
1038
|
+
current.inputNotification?.execution.id ??
|
|
1039
|
+
current.execution?.id) !== executionId ||
|
|
1040
|
+
(current.started && !current.terminal && !current.inputNotification))))
|
|
965
1041
|
return false;
|
|
966
1042
|
current.alarmAt = Date.now() + 30_000;
|
|
967
1043
|
await tx.setAlarm(current.alarmAt);
|
|
@@ -972,7 +1048,9 @@ export async function handleAgentSessionAlarm(storage, environment) {
|
|
|
972
1048
|
return;
|
|
973
1049
|
const transport = !childCommands && state.terminal
|
|
974
1050
|
? state.terminal.transport
|
|
975
|
-
: state.
|
|
1051
|
+
: !childCommands && state.inputNotification
|
|
1052
|
+
? state.inputNotification.transport
|
|
1053
|
+
: state.transport;
|
|
976
1054
|
const target = environment[transport.namespace];
|
|
977
1055
|
const response = await target.get(target.idFromName(transport.name)).fetch(new Request("https://agent-session.internal/v1/inbox/dispatch", {
|
|
978
1056
|
method: "POST",
|
|
@@ -987,7 +1065,9 @@ export async function handleAgentSessionAlarm(storage, environment) {
|
|
|
987
1065
|
? { startRunIds: state.pendingStarts }
|
|
988
1066
|
: state.terminal
|
|
989
1067
|
? { outcome: state.terminal.outcome }
|
|
990
|
-
:
|
|
1068
|
+
: state.inputNotification
|
|
1069
|
+
? { inputRequired: state.inputNotification.message }
|
|
1070
|
+
: {}),
|
|
991
1071
|
}),
|
|
992
1072
|
}));
|
|
993
1073
|
if (!response.ok)
|
|
@@ -14,12 +14,13 @@ export declare class AgentSessionRunner {
|
|
|
14
14
|
join(): Promise<void>;
|
|
15
15
|
private request;
|
|
16
16
|
wait(input: z.infer<typeof agentRunWaitInputSchema>, toolCallId: string): Promise<{
|
|
17
|
-
reason: "cancelled" | "completed" | "steering" | "timeout";
|
|
17
|
+
reason: "cancelled" | "completed" | "input_required" | "steering" | "timeout";
|
|
18
18
|
runs: {
|
|
19
|
-
status: "aborted" | "error" | "finished" | "interrupted";
|
|
20
19
|
text: string;
|
|
20
|
+
status: "aborted" | "error" | "finished" | "interrupted" | "waiting";
|
|
21
21
|
runId: string;
|
|
22
22
|
sessionId: string;
|
|
23
|
+
input?: z.util.JSONType | undefined;
|
|
23
24
|
textTruncated?: boolean | undefined;
|
|
24
25
|
}[];
|
|
25
26
|
pendingRunIds: string[];
|
package/dist/agent-worker.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ import { type AgentExecutionEnvironment, type AgentPackageSnapshot, type AgentRu
|
|
|
17
17
|
import { z } from "zod";
|
|
18
18
|
export { AgentChannelReceiver } from "./agent-channel-receiver";
|
|
19
19
|
import { type AgentChannelJournalAppend } from "@gea-ai/contract/agent-channel-runtime";
|
|
20
|
-
import { type AgentDurableObjectNamespace, type AgentToolApprovalDecision, type AgentToolIdentity, type AgentToolRuntimeSdk, type
|
|
20
|
+
import { type AgentDurableObjectNamespace, type AgentToolApprovalDecision, type AgentToolIdentity, type AgentToolRuntimeSdk, type DefinedAgent } from "./index";
|
|
21
21
|
import { type AgentChannelAddressEnvironment } from "./agent-channel-worker";
|
|
22
22
|
export { handleAgentChannelAddressAlarm, handleAgentChannelAddressRequest, type AgentChannelAddressEnvironment, type AgentChannelAddressStorage, type AgentChannelAddressTransactionStorage, } from "./agent-channel-worker";
|
|
23
23
|
export type AgentHostBinding = Partial<WorkerAI> & {
|
|
@@ -76,7 +76,6 @@ export type AgentWorkerComputerOptions = {
|
|
|
76
76
|
signal?: AbortSignal;
|
|
77
77
|
};
|
|
78
78
|
export type AgentFetchEnvironment = Record<string, unknown> & {
|
|
79
|
-
PROJECT?: import("@gea-ai/contract").WorkerProjectBinding;
|
|
80
79
|
AGENT_SESSIONS: AgentSessionNamespace;
|
|
81
80
|
AGENT_TASK_SESSIONS?: AgentSessionNamespace;
|
|
82
81
|
AGENTS?: AgentHostBinding;
|
|
@@ -96,8 +95,8 @@ export type AgentChannelFetchEnvironment = AgentFetchEnvironment & AgentChannelA
|
|
|
96
95
|
CHANNEL_SESSIONS: AgentSessionNamespace;
|
|
97
96
|
CHANNEL_RECEIVERS?: AgentChannelAddressNamespace;
|
|
98
97
|
};
|
|
99
|
-
type AgentApplicationDefinition = {
|
|
100
|
-
definition:
|
|
98
|
+
export type AgentApplicationDefinition = {
|
|
99
|
+
definition: DefinedAgent;
|
|
101
100
|
instructions?: string;
|
|
102
101
|
skillMount?: AgentWorkerSkillMount;
|
|
103
102
|
subagents?: Record<string, AgentApplicationDefinition>;
|
|
@@ -107,13 +106,6 @@ type AgentStartupTiming = {
|
|
|
107
106
|
phases: Record<string, number>;
|
|
108
107
|
};
|
|
109
108
|
export declare function composeFetch<TEnvironment, TContext>(...handlers: ReadonlyArray<ComposableFetch<TEnvironment, TContext>>): (request: Request, environment: TEnvironment, context: TContext) => Promise<Response>;
|
|
110
|
-
export declare function createAgentFetch<TEnvironment extends AgentFetchEnvironment = AgentFetchEnvironment, TContext = unknown>(definition: DefinedAgentPackage): ComposableFetch<TEnvironment, TContext>;
|
|
111
|
-
/**
|
|
112
|
-
* Creates the public SDK-first Agent application protocol. A root agent.ts is
|
|
113
|
-
* addressed by /gea/agents/run; top-level agents/<key>/agent.ts entrypoints are
|
|
114
|
-
* addressed by /gea/agents/<key>/run. All main Agents share the Worker
|
|
115
|
-
* deployment lifecycle while keeping separate AgentSession namespaces.
|
|
116
|
-
*/
|
|
117
109
|
export declare function createAgentApplicationFetch<TEnvironment extends AgentFetchEnvironment = AgentFetchEnvironment, TContext = unknown>(input: {
|
|
118
110
|
agents: Record<string, AgentApplicationDefinition>;
|
|
119
111
|
defaultAgentKey: string;
|