@minpeter/pss-runtime 0.0.11 → 0.1.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -5
- package/dist/agent-namespace.js +17 -0
- package/dist/agent-namespace.js.map +1 -0
- package/dist/agent-validation.js +35 -0
- package/dist/agent-validation.js.map +1 -0
- package/dist/agent.d.ts +11 -2
- package/dist/agent.js +79 -14
- package/dist/agent.js.map +1 -1
- package/dist/child-session-cleanups.js +61 -0
- package/dist/child-session-cleanups.js.map +1 -0
- package/dist/session/events.d.ts +21 -1
- package/dist/session/history.d.ts +1 -0
- package/dist/session/input-normalization.js +66 -0
- package/dist/session/input-normalization.js.map +1 -0
- package/dist/session/runtime-input.d.ts +1 -0
- package/dist/session/runtime-input.js +69 -0
- package/dist/session/runtime-input.js.map +1 -0
- package/dist/session/session-errors.js +23 -0
- package/dist/session/session-errors.js.map +1 -0
- package/dist/session/session-kill.js +23 -0
- package/dist/session/session-kill.js.map +1 -0
- package/dist/session/session-runtime-drain.js +22 -0
- package/dist/session/session-runtime-drain.js.map +1 -0
- package/dist/session/session-state.d.ts +1 -0
- package/dist/session/session-state.js +102 -0
- package/dist/session/session-state.js.map +1 -0
- package/dist/session/session-turn-error.js +35 -0
- package/dist/session/session-turn-error.js.map +1 -0
- package/dist/session/session.js +95 -240
- package/dist/session/session.js.map +1 -1
- package/dist/session/store/file.d.ts +1 -0
- package/dist/session/store/file.js +14 -0
- package/dist/session/store/file.js.map +1 -1
- package/dist/session/store/memory.d.ts +1 -0
- package/dist/session/store/memory.js +5 -0
- package/dist/session/store/memory.js.map +1 -1
- package/dist/session/store/types.d.ts +1 -0
- package/dist/subagent-job-cancel.js +28 -0
- package/dist/subagent-job-cancel.js.map +1 -0
- package/dist/subagent-job-output.js +63 -0
- package/dist/subagent-job-output.js.map +1 -0
- package/dist/subagent-jobs.js +151 -0
- package/dist/subagent-jobs.js.map +1 -0
- package/dist/subagent-prompt-schema.js +114 -0
- package/dist/subagent-prompt-schema.js.map +1 -0
- package/dist/subagent-run.js +111 -0
- package/dist/subagent-run.js.map +1 -0
- package/dist/subagents.js +92 -0
- package/dist/subagents.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ Minimal, platform-agnostic agent runtime with keyed sessions, synchronized
|
|
|
13
13
|
import { Agent } from "@minpeter/pss-runtime";
|
|
14
14
|
import { createYourLanguageModel } from "...";
|
|
15
15
|
|
|
16
|
-
const agent =
|
|
16
|
+
const agent = new Agent({
|
|
17
17
|
instructions: "Answer briefly.",
|
|
18
18
|
model: createYourLanguageModel(),
|
|
19
19
|
});
|
|
@@ -80,6 +80,63 @@ The public transcript protocol is `AgentEvent`: live runs emit runtime-defined
|
|
|
80
80
|
events through `run.events()`. Provider/model message history is internal
|
|
81
81
|
continuation state, not a public history API.
|
|
82
82
|
|
|
83
|
+
## Subagents
|
|
84
|
+
|
|
85
|
+
Compose specialist agents by constructing them first and passing them as an
|
|
86
|
+
array. Top-level agents may omit metadata, but agents used as subagents need a
|
|
87
|
+
stable `name` and `description` so the runtime can expose clear model-facing
|
|
88
|
+
delegate tools.
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
const researcher = new Agent({
|
|
92
|
+
name: "researcher",
|
|
93
|
+
description: "Researches facts and returns concise evidence.",
|
|
94
|
+
model,
|
|
95
|
+
instructions: "Research facts and return concise evidence.",
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const coordinator = new Agent({
|
|
99
|
+
model,
|
|
100
|
+
instructions: "Coordinate work and delegate when useful.",
|
|
101
|
+
subagents: [researcher],
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
For each subagent, the parent model receives a generated
|
|
106
|
+
`delegate_to_<name>` tool. The tool accepts `prompt`, optional `description`,
|
|
107
|
+
optional `sessionKey` suffix, and `run_in_background`. A provided `sessionKey`
|
|
108
|
+
is always scoped under the parent session and subagent name; the model cannot
|
|
109
|
+
select an arbitrary child session key. Omitting `run_in_background` defaults to
|
|
110
|
+
blocking behavior and returns compact child text, not the full child event
|
|
111
|
+
stream.
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
delegate_to_researcher({
|
|
115
|
+
prompt: "Find the current release notes and summarize the evidence.",
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
When the model sets `run_in_background: true`, the parent run can finish while
|
|
120
|
+
the child keeps working. The launch result includes a `bg_...` `task_id`. A
|
|
121
|
+
compact runtime reminder is queued for the parent when the child finishes, and
|
|
122
|
+
the model can retrieve the result with `background_output`.
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
delegate_to_researcher({
|
|
126
|
+
prompt: "Compare the API designs.",
|
|
127
|
+
run_in_background: true,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
background_output({ task_id: "bg_...", block: true });
|
|
131
|
+
background_cancel({ task_id: "bg_..." });
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The parent model context stays compact by default: completion reminders include
|
|
135
|
+
the task id, subagent name, description, and retrieval instruction. Full child
|
|
136
|
+
traces are not injected into the parent transcript by default. Background jobs
|
|
137
|
+
run in task-scoped child sessions, and retrieved completed jobs are forgotten
|
|
138
|
+
after `background_output` returns.
|
|
139
|
+
|
|
83
140
|
## Send and Steer
|
|
84
141
|
|
|
85
142
|
Use `session.send(input)` for a new user turn. If a run is already active, the
|
|
@@ -135,28 +192,33 @@ Custom stores own version generation. `load(key)` returns the opaque `state` wit
|
|
|
135
192
|
the store-minted `version`; `commit(key, { state }, { expectedVersion })` receives
|
|
136
193
|
state only and should reject stale versions by returning `{ ok: false, reason:
|
|
137
194
|
"conflict" }`. On success, the store persists `{ state, version }` and returns the
|
|
138
|
-
new version to the runtime.
|
|
195
|
+
new version to the runtime. `delete(key)` removes the persisted session for that
|
|
196
|
+
key.
|
|
139
197
|
|
|
140
198
|
```ts
|
|
141
199
|
import type { SessionStore } from "@minpeter/pss-runtime";
|
|
142
200
|
import { MemorySessionStore } from "@minpeter/pss-runtime/session-store/memory";
|
|
143
201
|
|
|
144
|
-
const agent =
|
|
202
|
+
const agent = new Agent({
|
|
145
203
|
model,
|
|
146
204
|
sessions: {
|
|
205
|
+
namespace: "support-agent",
|
|
147
206
|
store: new MemorySessionStore(), // default when omitted
|
|
148
207
|
},
|
|
149
208
|
});
|
|
150
209
|
```
|
|
151
210
|
|
|
152
|
-
For durable sessions, use the exported file POC
|
|
211
|
+
For durable sessions, use the exported file POC. Set a stable `namespace` when
|
|
212
|
+
subagents also use durable stores, so reconstructed agents map the same parent
|
|
213
|
+
session and child `sessionKey` suffixes back to the same child transcripts:
|
|
153
214
|
|
|
154
215
|
```ts
|
|
155
216
|
import { FileSessionStore } from "@minpeter/pss-runtime/session-store/file";
|
|
156
217
|
|
|
157
|
-
const agent =
|
|
218
|
+
const agent = new Agent({
|
|
158
219
|
model,
|
|
159
220
|
sessions: {
|
|
221
|
+
namespace: "support-agent",
|
|
160
222
|
store: new FileSessionStore(".pss/sessions"),
|
|
161
223
|
},
|
|
162
224
|
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/agent-namespace.ts
|
|
2
|
+
function randomAgentNamespace() {
|
|
3
|
+
return agentNamespace(crypto.randomUUID());
|
|
4
|
+
}
|
|
5
|
+
function agentNamespace(namespace) {
|
|
6
|
+
return `agent:${namespacePart(namespace)}`;
|
|
7
|
+
}
|
|
8
|
+
function namespacePart(value) {
|
|
9
|
+
return encodeURIComponent(value);
|
|
10
|
+
}
|
|
11
|
+
function parentSessionNamespace({ generation, sessionKey, sessionNamespace }) {
|
|
12
|
+
return `${sessionNamespace}:session:${namespacePart(sessionKey)}:generation:${generation}`;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { agentNamespace, parentSessionNamespace, randomAgentNamespace };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=agent-namespace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-namespace.js","names":[],"sources":["../src/agent-namespace.ts"],"sourcesContent":["export function randomAgentNamespace(): string {\n return agentNamespace(crypto.randomUUID());\n}\n\nexport function agentNamespace(namespace: string): string {\n return `agent:${namespacePart(namespace)}`;\n}\n\nexport function namespacePart(value: string): string {\n return encodeURIComponent(value);\n}\n\nexport function parentSessionNamespace({\n generation,\n sessionKey,\n sessionNamespace,\n}: {\n readonly generation: number;\n readonly sessionKey: string;\n readonly sessionNamespace: string;\n}): string {\n return `${sessionNamespace}:session:${namespacePart(\n sessionKey\n )}:generation:${generation}`;\n}\n"],"mappings":";AAAA,SAAgB,uBAA+B;CAC7C,OAAO,eAAe,OAAO,WAAW,CAAC;AAC3C;AAEA,SAAgB,eAAe,WAA2B;CACxD,OAAO,SAAS,cAAc,SAAS;AACzC;AAEA,SAAgB,cAAc,OAAuB;CACnD,OAAO,mBAAmB,KAAK;AACjC;AAEA,SAAgB,uBAAuB,EACrC,YACA,YACA,oBAKS;CACT,OAAO,GAAG,iBAAiB,WAAW,cACpC,UACF,EAAE,cAAc;AAClB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/agent-validation.ts
|
|
2
|
+
const subagentNamePattern = /^[a-z][a-z0-9_-]{0,51}$/;
|
|
3
|
+
function assertSubagents(options, agentClass, hasCustomLlm) {
|
|
4
|
+
if (!("subagents" in options) || options.subagents === void 0) return;
|
|
5
|
+
if (hasCustomLlm) throw new TypeError("Agent: subagents require options.model.");
|
|
6
|
+
if (!Array.isArray(options.subagents)) throw new TypeError("Agent: subagents must be an array.");
|
|
7
|
+
assertSubagentTools(options.subagents, agentClass, options.tools ?? {});
|
|
8
|
+
}
|
|
9
|
+
function assertSubagentTools(subagents, agentClass, tools) {
|
|
10
|
+
const toolNames = new Set(Object.keys(tools));
|
|
11
|
+
const generatedToolNames = /* @__PURE__ */ new Set();
|
|
12
|
+
for (const [index, subagent] of subagents.entries()) {
|
|
13
|
+
const toolName = `delegate_to_${assertSubagentMetadata(subagent, index, agentClass).replaceAll("-", "_")}`;
|
|
14
|
+
if (toolNames.has(toolName)) throw new TypeError(`Agent: subagent tool ${toolName} collides with an existing tool.`);
|
|
15
|
+
if (generatedToolNames.has(toolName)) throw new TypeError(`Agent: duplicate subagent tool name ${toolName}.`);
|
|
16
|
+
generatedToolNames.add(toolName);
|
|
17
|
+
}
|
|
18
|
+
for (const reservedToolName of ["background_output", "background_cancel"]) if (toolNames.has(reservedToolName)) throw new TypeError(`Agent: ${reservedToolName} collides with a reserved subagent tool.`);
|
|
19
|
+
}
|
|
20
|
+
function assertSubagentMetadata(subagent, index, agentClass) {
|
|
21
|
+
if (!(subagent instanceof agentClass)) throw new TypeError(`Agent: subagents[${index}] must be an Agent.`);
|
|
22
|
+
if (!isValidSubagentName(subagent.name)) throw new TypeError(`Agent: subagents[${index}].name is required or too long.`);
|
|
23
|
+
if (!isNonEmptyText(subagent.description)) throw new TypeError(`Agent: subagents[${index}].description is required.`);
|
|
24
|
+
return subagent.name;
|
|
25
|
+
}
|
|
26
|
+
function isNonEmptyText(value) {
|
|
27
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
28
|
+
}
|
|
29
|
+
function isValidSubagentName(value) {
|
|
30
|
+
return typeof value === "string" && subagentNamePattern.test(value);
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { assertSubagents };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=agent-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-validation.js","names":[],"sources":["../src/agent-validation.ts"],"sourcesContent":["import type { ToolSet } from \"ai\";\nimport type { Agent, AgentOptions } from \"./agent\";\n\nconst subagentNamePattern = /^[a-z][a-z0-9_-]{0,51}$/;\n\nexport function assertSubagents(\n options: AgentOptions,\n agentClass: new (options: AgentOptions) => Agent,\n hasCustomLlm: boolean\n): void {\n if (!(\"subagents\" in options) || options.subagents === undefined) {\n return;\n }\n\n if (hasCustomLlm) {\n throw new TypeError(\"Agent: subagents require options.model.\");\n }\n\n if (!Array.isArray(options.subagents)) {\n throw new TypeError(\"Agent: subagents must be an array.\");\n }\n\n assertSubagentTools(options.subagents, agentClass, options.tools ?? {});\n}\n\nfunction assertSubagentTools(\n subagents: readonly Agent[],\n agentClass: new (options: AgentOptions) => Agent,\n tools: ToolSet\n): void {\n const toolNames = new Set(Object.keys(tools));\n const generatedToolNames = new Set<string>();\n for (const [index, subagent] of subagents.entries()) {\n const name = assertSubagentMetadata(subagent, index, agentClass);\n const toolName = `delegate_to_${name.replaceAll(\"-\", \"_\")}`;\n if (toolNames.has(toolName)) {\n throw new TypeError(\n `Agent: subagent tool ${toolName} collides with an existing tool.`\n );\n }\n\n if (generatedToolNames.has(toolName)) {\n throw new TypeError(`Agent: duplicate subagent tool name ${toolName}.`);\n }\n\n generatedToolNames.add(toolName);\n }\n\n for (const reservedToolName of [\"background_output\", \"background_cancel\"]) {\n if (toolNames.has(reservedToolName)) {\n throw new TypeError(\n `Agent: ${reservedToolName} collides with a reserved subagent tool.`\n );\n }\n }\n}\n\nfunction assertSubagentMetadata(\n subagent: Agent,\n index: number,\n agentClass: new (options: AgentOptions) => Agent\n): string {\n if (!(subagent instanceof agentClass)) {\n throw new TypeError(`Agent: subagents[${index}] must be an Agent.`);\n }\n\n if (!isValidSubagentName(subagent.name)) {\n throw new TypeError(\n `Agent: subagents[${index}].name is required or too long.`\n );\n }\n\n if (!isNonEmptyText(subagent.description)) {\n throw new TypeError(`Agent: subagents[${index}].description is required.`);\n }\n\n return subagent.name;\n}\n\nfunction isNonEmptyText(value: string | undefined): value is string {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n\nfunction isValidSubagentName(value: string | undefined): value is string {\n return typeof value === \"string\" && subagentNamePattern.test(value);\n}\n"],"mappings":";AAGA,MAAM,sBAAsB;AAE5B,SAAgB,gBACd,SACA,YACA,cACM;CACN,IAAI,EAAE,eAAe,YAAY,QAAQ,cAAc,KAAA,GACrD;CAGF,IAAI,cACF,MAAM,IAAI,UAAU,yCAAyC;CAG/D,IAAI,CAAC,MAAM,QAAQ,QAAQ,SAAS,GAClC,MAAM,IAAI,UAAU,oCAAoC;CAG1D,oBAAoB,QAAQ,WAAW,YAAY,QAAQ,SAAS,CAAC,CAAC;AACxE;AAEA,SAAS,oBACP,WACA,YACA,OACM;CACN,MAAM,YAAY,IAAI,IAAI,OAAO,KAAK,KAAK,CAAC;CAC5C,MAAM,qCAAqB,IAAI,IAAY;CAC3C,KAAK,MAAM,CAAC,OAAO,aAAa,UAAU,QAAQ,GAAG;EAEnD,MAAM,WAAW,eADJ,uBAAuB,UAAU,OAAO,UAClB,EAAE,WAAW,KAAK,GAAG;EACxD,IAAI,UAAU,IAAI,QAAQ,GACxB,MAAM,IAAI,UACR,wBAAwB,SAAS,iCACnC;EAGF,IAAI,mBAAmB,IAAI,QAAQ,GACjC,MAAM,IAAI,UAAU,uCAAuC,SAAS,EAAE;EAGxE,mBAAmB,IAAI,QAAQ;CACjC;CAEA,KAAK,MAAM,oBAAoB,CAAC,qBAAqB,mBAAmB,GACtE,IAAI,UAAU,IAAI,gBAAgB,GAChC,MAAM,IAAI,UACR,UAAU,iBAAiB,yCAC7B;AAGN;AAEA,SAAS,uBACP,UACA,OACA,YACQ;CACR,IAAI,EAAE,oBAAoB,aACxB,MAAM,IAAI,UAAU,oBAAoB,MAAM,oBAAoB;CAGpE,IAAI,CAAC,oBAAoB,SAAS,IAAI,GACpC,MAAM,IAAI,UACR,oBAAoB,MAAM,gCAC5B;CAGF,IAAI,CAAC,eAAe,SAAS,WAAW,GACtC,MAAM,IAAI,UAAU,oBAAoB,MAAM,2BAA2B;CAG3E,OAAO,SAAS;AAClB;AAEA,SAAS,eAAe,OAA4C;CAClE,OAAO,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS;AAC5D;AAEA,SAAS,oBAAoB,OAA4C;CACvE,OAAO,OAAO,UAAU,YAAY,oBAAoB,KAAK,KAAK;AACpE"}
|
package/dist/agent.d.ts
CHANGED
|
@@ -7,27 +7,35 @@ import { LanguageModel, ToolSet } from "ai";
|
|
|
7
7
|
|
|
8
8
|
//#region src/agent.d.ts
|
|
9
9
|
interface AgentLanguageModelOptions {
|
|
10
|
+
description?: string;
|
|
10
11
|
hooks?: AgentHooks;
|
|
11
12
|
instructions?: string;
|
|
12
13
|
llm?: never;
|
|
13
14
|
model: LanguageModel;
|
|
15
|
+
name?: string;
|
|
14
16
|
sessions?: AgentSessionOptions;
|
|
17
|
+
subagents?: readonly Agent[];
|
|
15
18
|
toolChoice?: AgentToolChoice;
|
|
16
19
|
tools?: ToolSet;
|
|
17
20
|
}
|
|
18
21
|
interface AgentLlmOptions {
|
|
22
|
+
description?: string;
|
|
19
23
|
hooks?: AgentHooks;
|
|
20
24
|
instructions?: never;
|
|
21
25
|
llm: Llm;
|
|
22
26
|
model?: never;
|
|
27
|
+
name?: string;
|
|
23
28
|
sessions?: AgentSessionOptions;
|
|
29
|
+
subagents?: never;
|
|
24
30
|
toolChoice?: never;
|
|
25
31
|
tools?: never;
|
|
26
32
|
}
|
|
27
33
|
interface AgentSessionOptions {
|
|
34
|
+
namespace?: string;
|
|
28
35
|
store?: SessionStore;
|
|
29
36
|
}
|
|
30
37
|
interface SessionHandle {
|
|
38
|
+
delete(): Promise<void>;
|
|
31
39
|
interrupt(): void;
|
|
32
40
|
kill(): void;
|
|
33
41
|
send(input: AgentInput): Promise<AgentRun>;
|
|
@@ -36,8 +44,9 @@ interface SessionHandle {
|
|
|
36
44
|
type AgentOptions = AgentLanguageModelOptions | AgentLlmOptions;
|
|
37
45
|
declare class Agent {
|
|
38
46
|
#private;
|
|
39
|
-
|
|
40
|
-
|
|
47
|
+
readonly description?: string;
|
|
48
|
+
readonly name?: string;
|
|
49
|
+
constructor(options: AgentOptions);
|
|
41
50
|
send(input: AgentInput): Promise<AgentRun>;
|
|
42
51
|
session(key: string): SessionHandle;
|
|
43
52
|
}
|
package/dist/agent.js
CHANGED
|
@@ -1,25 +1,42 @@
|
|
|
1
|
+
import { agentNamespace, parentSessionNamespace, randomAgentNamespace } from "./agent-namespace.js";
|
|
2
|
+
import { assertSubagents } from "./agent-validation.js";
|
|
3
|
+
import { ChildSessionCleanups } from "./child-session-cleanups.js";
|
|
1
4
|
import { createLlm } from "./llm.js";
|
|
2
5
|
import { AgentSession } from "./session/session.js";
|
|
3
6
|
import { MemorySessionStore } from "./session/store/memory.js";
|
|
7
|
+
import { createSubagentTools } from "./subagents.js";
|
|
4
8
|
//#region src/agent.ts
|
|
5
9
|
var Agent = class Agent {
|
|
10
|
+
#baseTools;
|
|
6
11
|
#hooks;
|
|
7
12
|
#llm;
|
|
13
|
+
#modelOptions;
|
|
14
|
+
#childSessionCleanups = new ChildSessionCleanups();
|
|
15
|
+
#sessionGenerations = /* @__PURE__ */ new Map();
|
|
8
16
|
#sessions = /* @__PURE__ */ new Map();
|
|
17
|
+
#sessionNamespace;
|
|
9
18
|
#store;
|
|
19
|
+
#subagents;
|
|
20
|
+
description;
|
|
21
|
+
name;
|
|
10
22
|
constructor(options) {
|
|
11
23
|
assertAgentOptions(options);
|
|
24
|
+
this.description = options.description;
|
|
25
|
+
this.name = options.name;
|
|
26
|
+
this.#sessionNamespace = stableAgentNamespace(options);
|
|
12
27
|
this.#store = options.sessions?.store ?? new MemorySessionStore();
|
|
13
28
|
this.#hooks = options.hooks;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
29
|
+
assertSubagents(options, Agent, hasCustomLlm(options));
|
|
30
|
+
this.#subagents = hasCustomLlm(options) ? [] : options.subagents ?? [];
|
|
31
|
+
if (hasCustomLlm(options)) this.#llm = options.llm;
|
|
32
|
+
else {
|
|
33
|
+
this.#baseTools = options.tools;
|
|
34
|
+
this.#modelOptions = {
|
|
35
|
+
instructions: options.instructions,
|
|
36
|
+
model: options.model,
|
|
37
|
+
toolChoice: options.toolChoice
|
|
38
|
+
};
|
|
39
|
+
}
|
|
23
40
|
}
|
|
24
41
|
send(input) {
|
|
25
42
|
return this.session("default").send(input);
|
|
@@ -27,14 +44,32 @@ var Agent = class Agent {
|
|
|
27
44
|
session(key) {
|
|
28
45
|
const existing = this.#sessions.get(key);
|
|
29
46
|
if (existing) return existing;
|
|
30
|
-
|
|
47
|
+
let session;
|
|
48
|
+
const getSession = () => {
|
|
49
|
+
if (!session) throw new Error("Agent session is not initialized.");
|
|
50
|
+
return session;
|
|
51
|
+
};
|
|
52
|
+
const parentAgentNamespace = parentSessionNamespace({
|
|
53
|
+
generation: this.#sessionGenerations.get(key) ?? 0,
|
|
54
|
+
sessionKey: key,
|
|
55
|
+
sessionNamespace: this.#sessionNamespace
|
|
56
|
+
});
|
|
57
|
+
session = new AgentSession(this.#llm ?? createLlm(this.#createLlmOptionsForSession(key, parentAgentNamespace, (input, placement) => getSession().enqueueRuntimeInput(input, placement), (event) => getSession().emitObserverEvent(event))), {
|
|
31
58
|
key,
|
|
32
59
|
store: this.#store
|
|
33
60
|
}, this.#hooks);
|
|
34
61
|
const handle = {
|
|
62
|
+
delete: async () => {
|
|
63
|
+
await session.delete();
|
|
64
|
+
this.#sessions.delete(key);
|
|
65
|
+
this.#sessionGenerations.set(key, (this.#sessionGenerations.get(key) ?? 0) + 1);
|
|
66
|
+
await this.#deleteChildSessions(key);
|
|
67
|
+
},
|
|
35
68
|
interrupt: () => session.interrupt(),
|
|
36
69
|
kill: () => {
|
|
37
70
|
session.kill();
|
|
71
|
+
this.#sessionGenerations.set(key, (this.#sessionGenerations.get(key) ?? 0) + 1);
|
|
72
|
+
this.#deleteChildSessions(key).catch(() => void 0);
|
|
38
73
|
this.#sessions.delete(key);
|
|
39
74
|
},
|
|
40
75
|
send: (input) => session.send(input),
|
|
@@ -43,14 +78,44 @@ var Agent = class Agent {
|
|
|
43
78
|
this.#sessions.set(key, handle);
|
|
44
79
|
return handle;
|
|
45
80
|
}
|
|
81
|
+
#createLlmOptionsForSession(key, parentAgentNamespace, enqueueRuntimeInput, emitObserverEvent) {
|
|
82
|
+
const modelOptions = this.#modelOptions;
|
|
83
|
+
if (!modelOptions) throw new Error("Agent: missing model options.");
|
|
84
|
+
const tools = this.#subagents.length === 0 ? this.#baseTools : {
|
|
85
|
+
...this.#baseTools,
|
|
86
|
+
...createSubagentTools({
|
|
87
|
+
parentAgentNamespace,
|
|
88
|
+
parentSession: {
|
|
89
|
+
emitObserverEvent,
|
|
90
|
+
enqueueRuntimeInput
|
|
91
|
+
},
|
|
92
|
+
parentSessionKey: key,
|
|
93
|
+
registerChildSession: (sessionKey, cleanup) => this.#childSessionCleanups.register(sessionKey, cleanup),
|
|
94
|
+
subagents: this.#subagents
|
|
95
|
+
})
|
|
96
|
+
};
|
|
97
|
+
return {
|
|
98
|
+
instructions: modelOptions.instructions,
|
|
99
|
+
model: modelOptions.model,
|
|
100
|
+
toolChoice: modelOptions.toolChoice,
|
|
101
|
+
tools
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
async #deleteChildSessions(parentSessionKey) {
|
|
105
|
+
await this.#childSessionCleanups.delete(parentSessionKey);
|
|
106
|
+
}
|
|
46
107
|
};
|
|
108
|
+
function stableAgentNamespace(options) {
|
|
109
|
+
const namespace = options.sessions?.namespace ?? options.name;
|
|
110
|
+
return namespace ? agentNamespace(namespace) : randomAgentNamespace();
|
|
111
|
+
}
|
|
47
112
|
function assertAgentOptions(options) {
|
|
48
113
|
if (options === null || typeof options !== "object") throw new TypeError("Agent options are required. Provide either { model } or { llm }.");
|
|
49
114
|
const hasLlm = hasCustomLlm(options);
|
|
50
|
-
const hasModel = "model" in options && options.model
|
|
51
|
-
if (hasLlm && hasModel) throw new TypeError("Agent
|
|
52
|
-
if ("llm" in options && options.llm !== void 0 && !hasLlm) throw new TypeError("Agent
|
|
53
|
-
if (!(hasLlm || hasModel)) throw new TypeError("Agent
|
|
115
|
+
const hasModel = "model" in options && options.model != null;
|
|
116
|
+
if (hasLlm && hasModel) throw new TypeError("Agent: provide either options.llm or options.model.");
|
|
117
|
+
if ("llm" in options && options.llm !== void 0 && !hasLlm) throw new TypeError("Agent: invalid options.llm.");
|
|
118
|
+
if (!(hasLlm || hasModel)) throw new TypeError("Agent: missing options.model.");
|
|
54
119
|
}
|
|
55
120
|
function hasCustomLlm(options) {
|
|
56
121
|
return "llm" in options && typeof options.llm === "function";
|
package/dist/agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","names":["#hooks","#llm","#sessions","#store"],"sources":["../src/agent.ts"],"sourcesContent":["import type { LanguageModel, ToolSet } from \"ai\";\nimport type { AgentHooks } from \"./hooks\";\nimport { type AgentToolChoice, createLlm, type Llm } from \"./llm\";\nimport type { AgentRun } from \"./session/run\";\nimport { type AgentInput, AgentSession } from \"./session/session\";\nimport { MemorySessionStore } from \"./session/store/memory\";\nimport type { SessionStore } from \"./session/store/types\";\n\ninterface AgentLanguageModelOptions {\n hooks?: AgentHooks;\n instructions?: string;\n llm?: never;\n model: LanguageModel;\n sessions?: AgentSessionOptions;\n toolChoice?: AgentToolChoice;\n tools?: ToolSet;\n}\n\ninterface AgentLlmOptions {\n hooks?: AgentHooks;\n instructions?: never;\n llm: Llm;\n model?: never;\n sessions?: AgentSessionOptions;\n toolChoice?: never;\n tools?: never;\n}\n\nexport interface AgentSessionOptions {\n store?: SessionStore;\n}\n\nexport interface SessionHandle {\n interrupt(): void;\n kill(): void;\n send(input: AgentInput): Promise<AgentRun>;\n steer(input: AgentInput): Promise<AgentRun>;\n}\n\nexport type AgentOptions = AgentLanguageModelOptions | AgentLlmOptions;\n\nexport class Agent {\n readonly #hooks?: AgentHooks;\n readonly #llm: Llm;\n readonly #sessions = new Map<string, SessionHandle>();\n readonly #store: SessionStore;\n\n private constructor(options: AgentOptions) {\n assertAgentOptions(options);\n\n this.#store = options.sessions?.store ?? new MemorySessionStore();\n this.#hooks = options.hooks;\n this.#llm = hasCustomLlm(options)\n ? options.llm\n : createLlm({\n instructions: options.instructions,\n model: options.model,\n toolChoice: options.toolChoice,\n tools: options.tools,\n });\n }\n\n static create(options: AgentOptions): Promise<Agent> {\n return Promise.resolve().then(() => new Agent(options));\n }\n\n send(input: AgentInput): Promise<AgentRun> {\n return this.session(\"default\").send(input);\n }\n\n session(key: string): SessionHandle {\n const existing = this.#sessions.get(key);\n if (existing) {\n return existing;\n }\n\n const session = new AgentSession(\n this.#llm,\n { key, store: this.#store },\n this.#hooks\n );\n const handle: SessionHandle = {\n interrupt: () => session.interrupt(),\n kill: () => {\n session.kill();\n this.#sessions.delete(key);\n },\n send: (input) => session.send(input),\n steer: (input) => session.steer(input),\n };\n this.#sessions.set(key, handle);\n return handle;\n }\n}\n\nfunction assertAgentOptions(options: unknown): asserts options is AgentOptions {\n if (options === null || typeof options !== \"object\") {\n throw new TypeError(\n \"Agent options are required. Provide either { model } or { llm }.\"\n );\n }\n\n const hasLlm = hasCustomLlm(options);\n const hasModel =\n \"model\" in options && options.model !== undefined && options.model !== null;\n\n if (hasLlm && hasModel) {\n throw new TypeError(\n \"Agent.create: provide either options.llm or options.model, not both.\"\n );\n }\n\n if (\"llm\" in options && options.llm !== undefined && !hasLlm) {\n throw new TypeError(\"Agent.create: invalid options.llm.\");\n }\n\n if (!(hasLlm || hasModel)) {\n throw new TypeError(\"Agent.create: missing options.model.\");\n }\n}\n\nfunction hasCustomLlm(options: object): options is AgentLlmOptions {\n return \"llm\" in options && typeof options.llm === \"function\";\n}\n"],"mappings":";;;;AAyCA,IAAa,QAAb,MAAa,MAAM;CACjB;CACA;CACA,4BAAqB,IAAI,IAA2B;CACpD;CAEA,YAAoB,SAAuB;EACzC,mBAAmB,OAAO;EAE1B,KAAKG,SAAS,QAAQ,UAAU,SAAS,IAAI,mBAAmB;EAChE,KAAKH,SAAS,QAAQ;EACtB,KAAKC,OAAO,aAAa,OAAO,IAC5B,QAAQ,MACR,UAAU;GACR,cAAc,QAAQ;GACtB,OAAO,QAAQ;GACf,YAAY,QAAQ;GACpB,OAAO,QAAQ;EACjB,CAAC;CACP;CAEA,OAAO,OAAO,SAAuC;EACnD,OAAO,QAAQ,QAAQ,EAAE,WAAW,IAAI,MAAM,OAAO,CAAC;CACxD;CAEA,KAAK,OAAsC;EACzC,OAAO,KAAK,QAAQ,SAAS,EAAE,KAAK,KAAK;CAC3C;CAEA,QAAQ,KAA4B;EAClC,MAAM,WAAW,KAAKC,UAAU,IAAI,GAAG;EACvC,IAAI,UACF,OAAO;EAGT,MAAM,UAAU,IAAI,aAClB,KAAKD,MACL;GAAE;GAAK,OAAO,KAAKE;EAAO,GAC1B,KAAKH,MACP;EACA,MAAM,SAAwB;GAC5B,iBAAiB,QAAQ,UAAU;GACnC,YAAY;IACV,QAAQ,KAAK;IACb,KAAKE,UAAU,OAAO,GAAG;GAC3B;GACA,OAAO,UAAU,QAAQ,KAAK,KAAK;GACnC,QAAQ,UAAU,QAAQ,MAAM,KAAK;EACvC;EACA,KAAKA,UAAU,IAAI,KAAK,MAAM;EAC9B,OAAO;CACT;AACF;AAEA,SAAS,mBAAmB,SAAmD;CAC7E,IAAI,YAAY,QAAQ,OAAO,YAAY,UACzC,MAAM,IAAI,UACR,kEACF;CAGF,MAAM,SAAS,aAAa,OAAO;CACnC,MAAM,WACJ,WAAW,WAAW,QAAQ,UAAU,KAAA,KAAa,QAAQ,UAAU;CAEzE,IAAI,UAAU,UACZ,MAAM,IAAI,UACR,sEACF;CAGF,IAAI,SAAS,WAAW,QAAQ,QAAQ,KAAA,KAAa,CAAC,QACpD,MAAM,IAAI,UAAU,oCAAoC;CAG1D,IAAI,EAAE,UAAU,WACd,MAAM,IAAI,UAAU,sCAAsC;AAE9D;AAEA,SAAS,aAAa,SAA6C;CACjE,OAAO,SAAS,WAAW,OAAO,QAAQ,QAAQ;AACpD"}
|
|
1
|
+
{"version":3,"file":"agent.js","names":["#baseTools","#hooks","#llm","#modelOptions","#childSessionCleanups","#sessionGenerations","#sessions","#sessionNamespace","#store","#subagents","#createLlmOptionsForSession","#deleteChildSessions"],"sources":["../src/agent.ts"],"sourcesContent":["import type { LanguageModel, ToolSet } from \"ai\";\nimport {\n agentNamespace,\n parentSessionNamespace,\n randomAgentNamespace,\n} from \"./agent-namespace\";\nimport { assertSubagents } from \"./agent-validation\";\nimport { ChildSessionCleanups } from \"./child-session-cleanups\";\nimport type { AgentHooks } from \"./hooks\";\nimport { type AgentToolChoice, createLlm, type Llm } from \"./llm\";\nimport type { UserInput } from \"./session/events\";\nimport type { AgentRun } from \"./session/run\";\nimport { type AgentInput, AgentSession } from \"./session/session\";\nimport { MemorySessionStore } from \"./session/store/memory\";\nimport type { SessionStore } from \"./session/store/types\";\nimport { createSubagentTools } from \"./subagents\";\n\ninterface AgentLanguageModelOptions {\n description?: string;\n hooks?: AgentHooks;\n instructions?: string;\n llm?: never;\n model: LanguageModel;\n name?: string;\n sessions?: AgentSessionOptions;\n subagents?: readonly Agent[];\n toolChoice?: AgentToolChoice;\n tools?: ToolSet;\n}\n\ninterface AgentLlmOptions {\n description?: string;\n hooks?: AgentHooks;\n instructions?: never;\n llm: Llm;\n model?: never;\n name?: string;\n sessions?: AgentSessionOptions;\n subagents?: never;\n toolChoice?: never;\n tools?: never;\n}\n\nexport interface AgentSessionOptions {\n namespace?: string;\n store?: SessionStore;\n}\n\nexport interface SessionHandle {\n delete(): Promise<void>;\n interrupt(): void;\n kill(): void;\n send(input: AgentInput): Promise<AgentRun>;\n steer(input: AgentInput): Promise<AgentRun>;\n}\n\nexport type AgentOptions = AgentLanguageModelOptions | AgentLlmOptions;\ntype AgentModelOptions = Pick<\n AgentLanguageModelOptions,\n \"instructions\" | \"model\" | \"toolChoice\"\n>;\n\nexport class Agent {\n readonly #baseTools?: ToolSet;\n readonly #hooks?: AgentHooks;\n readonly #llm?: Llm;\n readonly #modelOptions?: AgentModelOptions;\n readonly #childSessionCleanups = new ChildSessionCleanups();\n readonly #sessionGenerations = new Map<string, number>();\n readonly #sessions = new Map<string, SessionHandle>();\n readonly #sessionNamespace: string;\n readonly #store: SessionStore;\n readonly #subagents: readonly Agent[];\n readonly description?: string;\n readonly name?: string;\n\n constructor(options: AgentOptions) {\n assertAgentOptions(options);\n\n this.description = options.description;\n this.name = options.name;\n this.#sessionNamespace = stableAgentNamespace(options);\n this.#store = options.sessions?.store ?? new MemorySessionStore();\n this.#hooks = options.hooks;\n assertSubagents(options, Agent, hasCustomLlm(options));\n this.#subagents = hasCustomLlm(options) ? [] : (options.subagents ?? []);\n if (hasCustomLlm(options)) {\n this.#llm = options.llm;\n } else {\n this.#baseTools = options.tools;\n this.#modelOptions = {\n instructions: options.instructions,\n model: options.model,\n toolChoice: options.toolChoice,\n };\n }\n }\n\n send(input: AgentInput): Promise<AgentRun> {\n return this.session(\"default\").send(input);\n }\n\n session(key: string): SessionHandle {\n const existing = this.#sessions.get(key);\n if (existing) {\n return existing;\n }\n\n let session: AgentSession | undefined;\n const getSession = () => {\n if (!session) {\n throw new Error(\"Agent session is not initialized.\");\n }\n return session;\n };\n const parentAgentNamespace = parentSessionNamespace({\n generation: this.#sessionGenerations.get(key) ?? 0,\n sessionKey: key,\n sessionNamespace: this.#sessionNamespace,\n });\n const llm =\n this.#llm ??\n createLlm(\n this.#createLlmOptionsForSession(\n key,\n parentAgentNamespace,\n (input: UserInput, placement?: \"turn-start\") =>\n getSession().enqueueRuntimeInput(input, placement),\n (event) => getSession().emitObserverEvent(event)\n )\n );\n session = new AgentSession(llm, { key, store: this.#store }, this.#hooks);\n const handle: SessionHandle = {\n delete: async () => {\n await session.delete();\n this.#sessions.delete(key);\n this.#sessionGenerations.set(\n key,\n (this.#sessionGenerations.get(key) ?? 0) + 1\n );\n await this.#deleteChildSessions(key);\n },\n interrupt: () => session.interrupt(),\n kill: () => {\n session.kill();\n this.#sessionGenerations.set(\n key,\n (this.#sessionGenerations.get(key) ?? 0) + 1\n );\n this.#deleteChildSessions(key).catch(() => undefined);\n this.#sessions.delete(key);\n },\n send: (input) => session.send(input),\n steer: (input) => session.steer(input),\n };\n this.#sessions.set(key, handle);\n return handle;\n }\n\n #createLlmOptionsForSession(\n key: string,\n parentAgentNamespace: string,\n enqueueRuntimeInput: AgentSession[\"enqueueRuntimeInput\"],\n emitObserverEvent: AgentSession[\"emitObserverEvent\"]\n ): Parameters<typeof createLlm>[0] {\n const modelOptions = this.#modelOptions;\n if (!modelOptions) {\n throw new Error(\"Agent: missing model options.\");\n }\n const tools =\n this.#subagents.length === 0\n ? this.#baseTools\n : {\n ...this.#baseTools,\n ...createSubagentTools({\n parentAgentNamespace,\n parentSession: { emitObserverEvent, enqueueRuntimeInput },\n parentSessionKey: key,\n registerChildSession: (sessionKey, cleanup) =>\n this.#childSessionCleanups.register(sessionKey, cleanup),\n subagents: this.#subagents,\n }),\n };\n\n return {\n instructions: modelOptions.instructions,\n model: modelOptions.model,\n toolChoice: modelOptions.toolChoice,\n tools,\n };\n }\n\n async #deleteChildSessions(parentSessionKey: string): Promise<void> {\n await this.#childSessionCleanups.delete(parentSessionKey);\n }\n}\n\nfunction stableAgentNamespace(options: AgentOptions): string {\n const namespace = options.sessions?.namespace ?? options.name;\n return namespace ? agentNamespace(namespace) : randomAgentNamespace();\n}\n\nfunction assertAgentOptions(options: unknown): asserts options is AgentOptions {\n if (options === null || typeof options !== \"object\") {\n throw new TypeError(\n \"Agent options are required. Provide either { model } or { llm }.\"\n );\n }\n\n const hasLlm = hasCustomLlm(options);\n const hasModel = \"model\" in options && options.model != null;\n\n if (hasLlm && hasModel) {\n throw new TypeError(\"Agent: provide either options.llm or options.model.\");\n }\n\n if (\"llm\" in options && options.llm !== undefined && !hasLlm) {\n throw new TypeError(\"Agent: invalid options.llm.\");\n }\n\n if (!(hasLlm || hasModel)) {\n throw new TypeError(\"Agent: missing options.model.\");\n }\n}\n\nfunction hasCustomLlm(options: object): options is AgentLlmOptions {\n return \"llm\" in options && typeof options.llm === \"function\";\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
//#region src/child-session-cleanups.ts
|
|
2
|
+
var ChildSessionCleanups = class {
|
|
3
|
+
#byParentSession = /* @__PURE__ */ new Map();
|
|
4
|
+
async delete(parentSessionKey) {
|
|
5
|
+
const cleanups = this.#byParentSession.get(parentSessionKey);
|
|
6
|
+
if (!cleanups) return;
|
|
7
|
+
this.#byParentSession.delete(parentSessionKey);
|
|
8
|
+
const results = await Promise.all([...cleanups].map(runCleanup));
|
|
9
|
+
const failedCleanups = [];
|
|
10
|
+
let firstError;
|
|
11
|
+
for (const result of results) {
|
|
12
|
+
if (result.ok) continue;
|
|
13
|
+
firstError ??= result.error;
|
|
14
|
+
failedCleanups.push(result.cleanup);
|
|
15
|
+
}
|
|
16
|
+
if (failedCleanups.length === 0) return;
|
|
17
|
+
this.#restore(parentSessionKey, failedCleanups);
|
|
18
|
+
throw firstError instanceof Error ? firstError : new Error(String(firstError));
|
|
19
|
+
}
|
|
20
|
+
register(parentSessionKey, cleanup) {
|
|
21
|
+
const existing = this.#byParentSession.get(parentSessionKey);
|
|
22
|
+
if (existing) {
|
|
23
|
+
existing.add(cleanup);
|
|
24
|
+
return () => this.#unregister(parentSessionKey, existing, cleanup);
|
|
25
|
+
}
|
|
26
|
+
const cleanups = new Set([cleanup]);
|
|
27
|
+
this.#byParentSession.set(parentSessionKey, cleanups);
|
|
28
|
+
return () => this.#unregister(parentSessionKey, cleanups, cleanup);
|
|
29
|
+
}
|
|
30
|
+
#unregister(parentSessionKey, cleanups, cleanup) {
|
|
31
|
+
cleanups.delete(cleanup);
|
|
32
|
+
if (cleanups.size === 0 && this.#byParentSession.get(parentSessionKey) === cleanups) this.#byParentSession.delete(parentSessionKey);
|
|
33
|
+
}
|
|
34
|
+
#restore(parentSessionKey, failedCleanups) {
|
|
35
|
+
const current = this.#byParentSession.get(parentSessionKey);
|
|
36
|
+
if (current) {
|
|
37
|
+
for (const cleanup of failedCleanups) current.add(cleanup);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
this.#byParentSession.set(parentSessionKey, new Set(failedCleanups));
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
async function runCleanup(cleanup) {
|
|
44
|
+
try {
|
|
45
|
+
await cleanup();
|
|
46
|
+
return {
|
|
47
|
+
cleanup,
|
|
48
|
+
ok: true
|
|
49
|
+
};
|
|
50
|
+
} catch (error) {
|
|
51
|
+
return {
|
|
52
|
+
cleanup,
|
|
53
|
+
error,
|
|
54
|
+
ok: false
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { ChildSessionCleanups };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=child-session-cleanups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"child-session-cleanups.js","names":["#byParentSession","#restore","#unregister"],"sources":["../src/child-session-cleanups.ts"],"sourcesContent":["type ChildSessionCleanup = () => Promise<void>;\n\ntype CleanupResult =\n | { readonly cleanup: ChildSessionCleanup; readonly ok: true }\n | {\n readonly cleanup: ChildSessionCleanup;\n readonly error: unknown;\n readonly ok: false;\n };\n\nexport class ChildSessionCleanups {\n readonly #byParentSession = new Map<string, Set<ChildSessionCleanup>>();\n\n async delete(parentSessionKey: string): Promise<void> {\n const cleanups = this.#byParentSession.get(parentSessionKey);\n if (!cleanups) {\n return;\n }\n\n this.#byParentSession.delete(parentSessionKey);\n const results = await Promise.all([...cleanups].map(runCleanup));\n const failedCleanups: ChildSessionCleanup[] = [];\n let firstError: unknown;\n for (const result of results) {\n if (result.ok) {\n continue;\n }\n\n firstError ??= result.error;\n failedCleanups.push(result.cleanup);\n }\n\n if (failedCleanups.length === 0) {\n return;\n }\n\n this.#restore(parentSessionKey, failedCleanups);\n throw firstError instanceof Error\n ? firstError\n : new Error(String(firstError));\n }\n\n register(parentSessionKey: string, cleanup: ChildSessionCleanup): () => void {\n const existing = this.#byParentSession.get(parentSessionKey);\n if (existing) {\n existing.add(cleanup);\n return () => this.#unregister(parentSessionKey, existing, cleanup);\n }\n\n const cleanups = new Set([cleanup]);\n this.#byParentSession.set(parentSessionKey, cleanups);\n return () => this.#unregister(parentSessionKey, cleanups, cleanup);\n }\n\n #unregister(\n parentSessionKey: string,\n cleanups: Set<ChildSessionCleanup>,\n cleanup: ChildSessionCleanup\n ): void {\n cleanups.delete(cleanup);\n if (\n cleanups.size === 0 &&\n this.#byParentSession.get(parentSessionKey) === cleanups\n ) {\n this.#byParentSession.delete(parentSessionKey);\n }\n }\n\n #restore(\n parentSessionKey: string,\n failedCleanups: readonly ChildSessionCleanup[]\n ): void {\n const current = this.#byParentSession.get(parentSessionKey);\n if (current) {\n for (const cleanup of failedCleanups) {\n current.add(cleanup);\n }\n return;\n }\n\n this.#byParentSession.set(parentSessionKey, new Set(failedCleanups));\n }\n}\n\nasync function runCleanup(\n cleanup: ChildSessionCleanup\n): Promise<CleanupResult> {\n try {\n await cleanup();\n return { cleanup, ok: true };\n } catch (error) {\n return { cleanup, error, ok: false };\n }\n}\n"],"mappings":";AAUA,IAAa,uBAAb,MAAkC;CAChC,mCAA4B,IAAI,IAAsC;CAEtE,MAAM,OAAO,kBAAyC;EACpD,MAAM,WAAW,KAAKA,iBAAiB,IAAI,gBAAgB;EAC3D,IAAI,CAAC,UACH;EAGF,KAAKA,iBAAiB,OAAO,gBAAgB;EAC7C,MAAM,UAAU,MAAM,QAAQ,IAAI,CAAC,GAAG,QAAQ,EAAE,IAAI,UAAU,CAAC;EAC/D,MAAM,iBAAwC,CAAC;EAC/C,IAAI;EACJ,KAAK,MAAM,UAAU,SAAS;GAC5B,IAAI,OAAO,IACT;GAGF,eAAe,OAAO;GACtB,eAAe,KAAK,OAAO,OAAO;EACpC;EAEA,IAAI,eAAe,WAAW,GAC5B;EAGF,KAAKC,SAAS,kBAAkB,cAAc;EAC9C,MAAM,sBAAsB,QACxB,aACA,IAAI,MAAM,OAAO,UAAU,CAAC;CAClC;CAEA,SAAS,kBAA0B,SAA0C;EAC3E,MAAM,WAAW,KAAKD,iBAAiB,IAAI,gBAAgB;EAC3D,IAAI,UAAU;GACZ,SAAS,IAAI,OAAO;GACpB,aAAa,KAAKE,YAAY,kBAAkB,UAAU,OAAO;EACnE;EAEA,MAAM,WAAW,IAAI,IAAI,CAAC,OAAO,CAAC;EAClC,KAAKF,iBAAiB,IAAI,kBAAkB,QAAQ;EACpD,aAAa,KAAKE,YAAY,kBAAkB,UAAU,OAAO;CACnE;CAEA,YACE,kBACA,UACA,SACM;EACN,SAAS,OAAO,OAAO;EACvB,IACE,SAAS,SAAS,KAClB,KAAKF,iBAAiB,IAAI,gBAAgB,MAAM,UAEhD,KAAKA,iBAAiB,OAAO,gBAAgB;CAEjD;CAEA,SACE,kBACA,gBACM;EACN,MAAM,UAAU,KAAKA,iBAAiB,IAAI,gBAAgB;EAC1D,IAAI,SAAS;GACX,KAAK,MAAM,WAAW,gBACpB,QAAQ,IAAI,OAAO;GAErB;EACF;EAEA,KAAKA,iBAAiB,IAAI,kBAAkB,IAAI,IAAI,cAAc,CAAC;CACrE;AACF;AAEA,eAAe,WACb,SACwB;CACxB,IAAI;EACF,MAAM,QAAQ;EACd,OAAO;GAAE;GAAS,IAAI;EAAK;CAC7B,SAAS,OAAO;EACd,OAAO;GAAE;GAAS;GAAO,IAAI;EAAM;CACrC;AACF"}
|
package/dist/session/events.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ interface ToolResult {
|
|
|
30
30
|
toolName: string;
|
|
31
31
|
type: "tool-result";
|
|
32
32
|
}
|
|
33
|
+
type SubagentJobStatus = "aborted" | "cancelled" | "completed" | "error" | "pending" | "running";
|
|
33
34
|
type AgentEvent = /** User input was accepted into the session queue. */UserText /** User multipart input was accepted into the session queue. */ | UserMessage /** Runtime/API-originated input inserted into the current turn, not human input. */ | RuntimeInput /** A queued user input started running as a turn. */ | {
|
|
34
35
|
type: "turn-start";
|
|
35
36
|
} /** The active turn was interrupted before normal completion. */ | {
|
|
@@ -41,7 +42,26 @@ type AgentEvent = /** User input was accepted into the session queue. */UserText
|
|
|
41
42
|
type: "turn-end";
|
|
42
43
|
} /** One model/tool-loop iteration started within the active turn. */ | {
|
|
43
44
|
type: "step-start";
|
|
44
|
-
} /** The model produced reasoning content. */ | AssistantReasoning /** The model produced visible assistant text. */ | AssistantText /** The model requested a tool call. */ | ToolCall /** A tool call returned a result. */ | ToolResult
|
|
45
|
+
} /** The model produced reasoning content. */ | AssistantReasoning /** The model produced visible assistant text. */ | AssistantText /** The model requested a tool call. */ | ToolCall /** A tool call returned a result. */ | ToolResult | {
|
|
46
|
+
description?: string;
|
|
47
|
+
run_in_background: boolean;
|
|
48
|
+
subagent: string;
|
|
49
|
+
task_id?: string;
|
|
50
|
+
type: "subagent-job-start";
|
|
51
|
+
} | {
|
|
52
|
+
eventType?: AgentEvent["type"];
|
|
53
|
+
status: SubagentJobStatus;
|
|
54
|
+
subagent: string;
|
|
55
|
+
task_id: string;
|
|
56
|
+
type: "subagent-job-update";
|
|
57
|
+
} | {
|
|
58
|
+
error?: string;
|
|
59
|
+
eventCount: number;
|
|
60
|
+
status: Exclude<SubagentJobStatus, "pending" | "running">;
|
|
61
|
+
subagent: string;
|
|
62
|
+
task_id?: string;
|
|
63
|
+
type: "subagent-job-end";
|
|
64
|
+
} /** One model/tool-loop iteration finished within the active turn. */ | {
|
|
45
65
|
type: "step-end";
|
|
46
66
|
};
|
|
47
67
|
type AgentEventListener = (event: AgentEvent) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { ModelMessage } from "ai";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
//#region src/session/input-normalization.ts
|
|
2
|
+
function normalizeAgentInput(input) {
|
|
3
|
+
if (typeof input === "string") return {
|
|
4
|
+
type: "user-text",
|
|
5
|
+
text: input
|
|
6
|
+
};
|
|
7
|
+
if (isStringArrayInput(input)) return {
|
|
8
|
+
type: "user-text",
|
|
9
|
+
text: structuredClone(input)
|
|
10
|
+
};
|
|
11
|
+
if (isArrayInput(input)) {
|
|
12
|
+
assertUserMessageContent(input);
|
|
13
|
+
return {
|
|
14
|
+
type: "user-message",
|
|
15
|
+
content: structuredClone(input)
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (isUserMessage(input)) {
|
|
19
|
+
assertUserMessageContent(input.content);
|
|
20
|
+
return structuredClone(input);
|
|
21
|
+
}
|
|
22
|
+
if (isUserText(input)) return structuredClone(input);
|
|
23
|
+
throw new TypeError("Agent input must be text, text parts, content parts, user-text, or user-message.");
|
|
24
|
+
}
|
|
25
|
+
function isStringArrayInput(input) {
|
|
26
|
+
return Array.isArray(input) && hasDenseItems(input, isString);
|
|
27
|
+
}
|
|
28
|
+
function isArrayInput(input) {
|
|
29
|
+
return Array.isArray(input);
|
|
30
|
+
}
|
|
31
|
+
function isUserMessage(input) {
|
|
32
|
+
return input !== null && typeof input === "object" && !isArrayInput(input) && input.type === "user-message" && "content" in input && Array.isArray(input.content);
|
|
33
|
+
}
|
|
34
|
+
function isUserText(input) {
|
|
35
|
+
return input !== null && typeof input === "object" && !isArrayInput(input) && input.type === "user-text" && (typeof input.text === "string" || isStringArrayInput(input.text));
|
|
36
|
+
}
|
|
37
|
+
function assertUserMessageContent(input) {
|
|
38
|
+
for (const part of input) if (!isUserMessageContentPart(part)) throw new TypeError("Agent input content parts must be { type: \"text\", text }, { type: \"image\", image }, or { type: \"file\", data, mediaType }.");
|
|
39
|
+
}
|
|
40
|
+
function isUserMessageContentPart(part) {
|
|
41
|
+
if (part === null || typeof part !== "object" || !("type" in part)) return false;
|
|
42
|
+
if (part.type === "text") return "text" in part && typeof part.text === "string";
|
|
43
|
+
if (part.type === "image") return "image" in part && typeof part.image === "string" && (!("mediaType" in part) || typeof part.mediaType === "string");
|
|
44
|
+
if (part.type === "file") return "data" in part && isUserMessageFileData(part.data) && "mediaType" in part && typeof part.mediaType === "string" && (!("filename" in part) || typeof part.filename === "string");
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
function isUserMessageFileData(data) {
|
|
48
|
+
if (typeof data === "string") return true;
|
|
49
|
+
if (data === null || typeof data !== "object" || !("type" in data)) return false;
|
|
50
|
+
if (data.type === "data") return "data" in data && typeof data.data === "string";
|
|
51
|
+
if (data.type === "reference") return "reference" in data && data.reference !== null && typeof data.reference === "object" && Object.values(data.reference).every((value) => typeof value === "string");
|
|
52
|
+
if (data.type === "text") return "text" in data && typeof data.text === "string";
|
|
53
|
+
if (data.type === "url") return "url" in data && typeof data.url === "string";
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
function hasDenseItems(input, predicate) {
|
|
57
|
+
for (let index = 0; index < input.length; index += 1) if (!(index in input && predicate(input[index]))) return false;
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
function isString(value) {
|
|
61
|
+
return typeof value === "string";
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { normalizeAgentInput };
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=input-normalization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-normalization.js","names":[],"sources":["../../src/session/input-normalization.ts"],"sourcesContent":["import type {\n AgentInput,\n UserInput,\n UserMessage,\n UserMessageContentPart,\n UserText,\n} from \"./input\";\n\nexport function normalizeAgentInput(input: AgentInput): UserInput {\n if (typeof input === \"string\") {\n return {\n type: \"user-text\",\n text: input,\n };\n }\n\n if (isStringArrayInput(input)) {\n return {\n type: \"user-text\",\n text: structuredClone(input),\n };\n }\n\n if (isArrayInput(input)) {\n assertUserMessageContent(input);\n return {\n type: \"user-message\",\n content: structuredClone(input),\n };\n }\n\n if (isUserMessage(input)) {\n assertUserMessageContent(input.content);\n return structuredClone(input);\n }\n\n if (isUserText(input)) {\n return structuredClone(input);\n }\n\n throw new TypeError(\n \"Agent input must be text, text parts, content parts, user-text, or user-message.\"\n );\n}\n\nfunction isStringArrayInput(input: unknown): input is readonly string[] {\n return Array.isArray(input) && hasDenseItems(input, isString);\n}\n\nfunction isArrayInput(\n input: AgentInput\n): input is readonly string[] | readonly UserMessageContentPart[] {\n return Array.isArray(input);\n}\n\nfunction isUserMessage(input: AgentInput): input is UserMessage {\n return (\n input !== null &&\n typeof input === \"object\" &&\n !isArrayInput(input) &&\n input.type === \"user-message\" &&\n \"content\" in input &&\n Array.isArray(input.content)\n );\n}\n\nfunction isUserText(input: AgentInput): input is UserText {\n return (\n input !== null &&\n typeof input === \"object\" &&\n !isArrayInput(input) &&\n input.type === \"user-text\" &&\n (typeof input.text === \"string\" || isStringArrayInput(input.text))\n );\n}\n\nfunction assertUserMessageContent(\n input: readonly unknown[]\n): asserts input is readonly UserMessageContentPart[] {\n for (const part of input) {\n if (!isUserMessageContentPart(part)) {\n throw new TypeError(\n 'Agent input content parts must be { type: \"text\", text }, { type: \"image\", image }, or { type: \"file\", data, mediaType }.'\n );\n }\n }\n}\n\nfunction isUserMessageContentPart(\n part: unknown\n): part is UserMessageContentPart {\n if (part === null || typeof part !== \"object\" || !(\"type\" in part)) {\n return false;\n }\n\n if (part.type === \"text\") {\n return \"text\" in part && typeof part.text === \"string\";\n }\n\n if (part.type === \"image\") {\n return (\n \"image\" in part &&\n typeof part.image === \"string\" &&\n (!(\"mediaType\" in part) || typeof part.mediaType === \"string\")\n );\n }\n\n if (part.type === \"file\") {\n return (\n \"data\" in part &&\n isUserMessageFileData(part.data) &&\n \"mediaType\" in part &&\n typeof part.mediaType === \"string\" &&\n (!(\"filename\" in part) || typeof part.filename === \"string\")\n );\n }\n\n return false;\n}\n\nfunction isUserMessageFileData(data: unknown): boolean {\n if (typeof data === \"string\") {\n return true;\n }\n\n if (data === null || typeof data !== \"object\" || !(\"type\" in data)) {\n return false;\n }\n\n if (data.type === \"data\") {\n return \"data\" in data && typeof data.data === \"string\";\n }\n\n if (data.type === \"reference\") {\n return (\n \"reference\" in data &&\n data.reference !== null &&\n typeof data.reference === \"object\" &&\n Object.values(data.reference).every((value) => typeof value === \"string\")\n );\n }\n\n if (data.type === \"text\") {\n return \"text\" in data && typeof data.text === \"string\";\n }\n\n if (data.type === \"url\") {\n return \"url\" in data && typeof data.url === \"string\";\n }\n\n return false;\n}\n\nfunction hasDenseItems<T>(\n input: readonly unknown[],\n predicate: (value: unknown) => value is T\n): input is readonly T[] {\n for (let index = 0; index < input.length; index += 1) {\n if (!(index in input && predicate(input[index]))) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === \"string\";\n}\n"],"mappings":";AAQA,SAAgB,oBAAoB,OAA8B;CAChE,IAAI,OAAO,UAAU,UACnB,OAAO;EACL,MAAM;EACN,MAAM;CACR;CAGF,IAAI,mBAAmB,KAAK,GAC1B,OAAO;EACL,MAAM;EACN,MAAM,gBAAgB,KAAK;CAC7B;CAGF,IAAI,aAAa,KAAK,GAAG;EACvB,yBAAyB,KAAK;EAC9B,OAAO;GACL,MAAM;GACN,SAAS,gBAAgB,KAAK;EAChC;CACF;CAEA,IAAI,cAAc,KAAK,GAAG;EACxB,yBAAyB,MAAM,OAAO;EACtC,OAAO,gBAAgB,KAAK;CAC9B;CAEA,IAAI,WAAW,KAAK,GAClB,OAAO,gBAAgB,KAAK;CAG9B,MAAM,IAAI,UACR,kFACF;AACF;AAEA,SAAS,mBAAmB,OAA4C;CACtE,OAAO,MAAM,QAAQ,KAAK,KAAK,cAAc,OAAO,QAAQ;AAC9D;AAEA,SAAS,aACP,OACgE;CAChE,OAAO,MAAM,QAAQ,KAAK;AAC5B;AAEA,SAAS,cAAc,OAAyC;CAC9D,OACE,UAAU,QACV,OAAO,UAAU,YACjB,CAAC,aAAa,KAAK,KACnB,MAAM,SAAS,kBACf,aAAa,SACb,MAAM,QAAQ,MAAM,OAAO;AAE/B;AAEA,SAAS,WAAW,OAAsC;CACxD,OACE,UAAU,QACV,OAAO,UAAU,YACjB,CAAC,aAAa,KAAK,KACnB,MAAM,SAAS,gBACd,OAAO,MAAM,SAAS,YAAY,mBAAmB,MAAM,IAAI;AAEpE;AAEA,SAAS,yBACP,OACoD;CACpD,KAAK,MAAM,QAAQ,OACjB,IAAI,CAAC,yBAAyB,IAAI,GAChC,MAAM,IAAI,UACR,iIACF;AAGN;AAEA,SAAS,yBACP,MACgC;CAChC,IAAI,SAAS,QAAQ,OAAO,SAAS,YAAY,EAAE,UAAU,OAC3D,OAAO;CAGT,IAAI,KAAK,SAAS,QAChB,OAAO,UAAU,QAAQ,OAAO,KAAK,SAAS;CAGhD,IAAI,KAAK,SAAS,SAChB,OACE,WAAW,QACX,OAAO,KAAK,UAAU,aACrB,EAAE,eAAe,SAAS,OAAO,KAAK,cAAc;CAIzD,IAAI,KAAK,SAAS,QAChB,OACE,UAAU,QACV,sBAAsB,KAAK,IAAI,KAC/B,eAAe,QACf,OAAO,KAAK,cAAc,aACzB,EAAE,cAAc,SAAS,OAAO,KAAK,aAAa;CAIvD,OAAO;AACT;AAEA,SAAS,sBAAsB,MAAwB;CACrD,IAAI,OAAO,SAAS,UAClB,OAAO;CAGT,IAAI,SAAS,QAAQ,OAAO,SAAS,YAAY,EAAE,UAAU,OAC3D,OAAO;CAGT,IAAI,KAAK,SAAS,QAChB,OAAO,UAAU,QAAQ,OAAO,KAAK,SAAS;CAGhD,IAAI,KAAK,SAAS,aAChB,OACE,eAAe,QACf,KAAK,cAAc,QACnB,OAAO,KAAK,cAAc,YAC1B,OAAO,OAAO,KAAK,SAAS,EAAE,OAAO,UAAU,OAAO,UAAU,QAAQ;CAI5E,IAAI,KAAK,SAAS,QAChB,OAAO,UAAU,QAAQ,OAAO,KAAK,SAAS;CAGhD,IAAI,KAAK,SAAS,OAChB,OAAO,SAAS,QAAQ,OAAO,KAAK,QAAQ;CAG9C,OAAO;AACT;AAEA,SAAS,cACP,OACA,WACuB;CACvB,KAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GACjD,IAAI,EAAE,SAAS,SAAS,UAAU,MAAM,MAAM,IAC5C,OAAO;CAIX,OAAO;AACT;AAEA,SAAS,SAAS,OAAiC;CACjD,OAAO,OAAO,UAAU;AAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|