@minpeter/pss-runtime 0.0.11 → 0.1.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +191 -20
- package/dist/agent-loop.d.ts +1 -0
- package/dist/agent-loop.js +14 -8
- package/dist/agent-loop.js.map +1 -1
- package/dist/agent.d.ts +8 -10
- package/dist/agent.js +34 -13
- package/dist/agent.js.map +1 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.js +6 -1
- package/dist/llm.js +7 -1
- package/dist/llm.js.map +1 -1
- package/dist/plugins/compaction.d.ts +15 -0
- package/dist/plugins/compaction.js +98 -0
- package/dist/plugins/compaction.js.map +1 -0
- package/dist/plugins/index.d.ts +5 -0
- package/dist/plugins/index.js +5 -0
- package/dist/plugins/memory.d.ts +11 -0
- package/dist/plugins/memory.js +146 -0
- package/dist/plugins/memory.js.map +1 -0
- package/dist/plugins/runner.d.ts +1 -0
- package/dist/plugins/runner.js +83 -0
- package/dist/plugins/runner.js.map +1 -0
- package/dist/plugins/scope.d.ts +1 -0
- package/dist/plugins/scope.js +13 -0
- package/dist/plugins/scope.js.map +1 -0
- package/dist/plugins/sessions.d.ts +12 -0
- package/dist/plugins/sessions.js +34 -0
- package/dist/plugins/sessions.js.map +1 -0
- package/dist/plugins/tool-hook-handlers.js +77 -0
- package/dist/plugins/tool-hook-handlers.js.map +1 -0
- package/dist/plugins/tool-hook-results.js +64 -0
- package/dist/plugins/tool-hook-results.js.map +1 -0
- package/dist/plugins/tool-hooks.js +111 -0
- package/dist/plugins/tool-hooks.js.map +1 -0
- package/dist/plugins/types.d.ts +105 -0
- package/dist/plugins/types.js +20 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/session/events.d.ts +19 -2
- package/dist/session/input.d.ts +4 -0
- package/dist/session/lifecycle.d.ts +12 -0
- package/dist/session/lifecycle.js +126 -0
- package/dist/session/lifecycle.js.map +1 -0
- package/dist/session/mapping.js +2 -1
- package/dist/session/mapping.js.map +1 -1
- package/dist/session/overlay-anchor.js +151 -0
- package/dist/session/overlay-anchor.js.map +1 -0
- package/dist/session/overlay.js +141 -0
- package/dist/session/overlay.js.map +1 -0
- package/dist/session/run.js +0 -1
- package/dist/session/run.js.map +1 -1
- package/dist/session/runtime-input.d.ts +1 -0
- package/dist/session/runtime-input.js +89 -0
- package/dist/session/runtime-input.js.map +1 -0
- package/dist/session/session.js +166 -129
- package/dist/session/session.js.map +1 -1
- package/dist/session/snapshot.d.ts +1 -0
- package/dist/session/snapshot.js +31 -5
- package/dist/session/snapshot.js.map +1 -1
- package/package.json +6 -1
- package/dist/hooks.d.ts +0 -32
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-hook-results.js","names":[],"sources":["../../src/plugins/tool-hook-results.ts"],"sourcesContent":["import type {\n AgentPluginToolCallResult,\n AgentPluginToolResultResult,\n AgentPluginToolResultStatus,\n} from \"./types\";\n\nexport interface ToolResultState {\n readonly error?: string;\n readonly output?: unknown;\n readonly status: AgentPluginToolResultStatus;\n}\n\nexport interface ToolResultHandlerOutput {\n readonly replaced: boolean;\n readonly state: ToolResultState;\n}\n\nexport function cloneToolHookValue<T>(value: T): T {\n return structuredClone(value);\n}\n\nexport function cloneToolResultState(state: ToolResultState): ToolResultState {\n return {\n error: state.error,\n output: cloneToolHookValue(state.output),\n status: state.status,\n };\n}\n\nexport function normalizeToolCallResult(\n result: unknown\n): Exclude<AgentPluginToolCallResult, void> | undefined {\n if (result === undefined) {\n return;\n }\n if (!isRecord(result) || typeof result.action !== \"string\") {\n throw new TypeError(\"tool.call handlers must return a valid action.\");\n }\n\n if (result.action === \"allow\") {\n return { action: \"allow\" };\n }\n if (result.action === \"modify\") {\n return { action: \"modify\", input: result.input };\n }\n if (\n (result.action === \"error\" || result.action === \"reject-and-continue\") &&\n typeof result.message === \"string\"\n ) {\n return { action: result.action, message: result.message };\n }\n if (result.action === \"synthesize\" && isSyntheticResult(result.result)) {\n return { action: \"synthesize\", result: result.result };\n }\n\n throw new TypeError(\"tool.call handlers must return a valid action.\");\n}\n\nexport function normalizeToolResultResult(\n result: unknown\n): Exclude<AgentPluginToolResultResult, void> | undefined {\n if (result === undefined) {\n return;\n }\n if (!(isRecord(result) && isToolResultStatus(result.status))) {\n throw new TypeError(\"tool.result handlers must return a valid status.\");\n }\n\n return {\n error: typeof result.error === \"string\" ? result.error : undefined,\n output: result.output,\n status: result.status,\n };\n}\n\nexport function toolResultOutput(state: ToolResultState): unknown {\n if (state.status === \"done\" || state.output !== undefined) {\n return state.output;\n }\n\n return { error: state.error, status: state.status };\n}\n\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport class AgentPluginToolPolicyError extends Error {\n readonly name = \"AgentPluginToolPolicyError\";\n}\n\nfunction isSyntheticResult(value: unknown): value is {\n readonly output: unknown;\n} {\n return isRecord(value) && \"output\" in value;\n}\n\nfunction isToolResultStatus(\n value: unknown\n): value is AgentPluginToolResultStatus {\n return value === \"done\" || value === \"error\" || value === \"cancelled\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\";\n}\n"],"mappings":";AAiBA,SAAgB,mBAAsB,OAAa;CACjD,OAAO,gBAAgB,KAAK;AAC9B;AAEA,SAAgB,qBAAqB,OAAyC;CAC5E,OAAO;EACL,OAAO,MAAM;EACb,QAAQ,mBAAmB,MAAM,MAAM;EACvC,QAAQ,MAAM;CAChB;AACF;AAEA,SAAgB,wBACd,QACsD;CACtD,IAAI,WAAW,KAAA,GACb;CAEF,IAAI,CAAC,SAAS,MAAM,KAAK,OAAO,OAAO,WAAW,UAChD,MAAM,IAAI,UAAU,gDAAgD;CAGtE,IAAI,OAAO,WAAW,SACpB,OAAO,EAAE,QAAQ,QAAQ;CAE3B,IAAI,OAAO,WAAW,UACpB,OAAO;EAAE,QAAQ;EAAU,OAAO,OAAO;CAAM;CAEjD,KACG,OAAO,WAAW,WAAW,OAAO,WAAW,0BAChD,OAAO,OAAO,YAAY,UAE1B,OAAO;EAAE,QAAQ,OAAO;EAAQ,SAAS,OAAO;CAAQ;CAE1D,IAAI,OAAO,WAAW,gBAAgB,kBAAkB,OAAO,MAAM,GACnE,OAAO;EAAE,QAAQ;EAAc,QAAQ,OAAO;CAAO;CAGvD,MAAM,IAAI,UAAU,gDAAgD;AACtE;AAEA,SAAgB,0BACd,QACwD;CACxD,IAAI,WAAW,KAAA,GACb;CAEF,IAAI,EAAE,SAAS,MAAM,KAAK,mBAAmB,OAAO,MAAM,IACxD,MAAM,IAAI,UAAU,kDAAkD;CAGxE,OAAO;EACL,OAAO,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,KAAA;EACzD,QAAQ,OAAO;EACf,QAAQ,OAAO;CACjB;AACF;AAEA,SAAgB,iBAAiB,OAAiC;CAChE,IAAI,MAAM,WAAW,UAAU,MAAM,WAAW,KAAA,GAC9C,OAAO,MAAM;CAGf,OAAO;EAAE,OAAO,MAAM;EAAO,QAAQ,MAAM;CAAO;AACpD;AAEA,SAAgB,aAAa,OAAwB;CACnD,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;AAEA,IAAa,6BAAb,cAAgD,MAAM;CACpD,OAAgB;AAClB;AAEA,SAAS,kBAAkB,OAEzB;CACA,OAAO,SAAS,KAAK,KAAK,YAAY;AACxC;AAEA,SAAS,mBACP,OACsC;CACtC,OAAO,UAAU,UAAU,UAAU,WAAW,UAAU;AAC5D;AAEA,SAAS,SAAS,OAAkD;CAClE,OAAO,UAAU,QAAQ,OAAO,UAAU;AAC5C"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { getActiveAgentPluginScope, runWithAgentPluginScope } from "./scope.js";
|
|
2
|
+
import { AgentPluginToolPolicyError, errorMessage, toolResultOutput } from "./tool-hook-results.js";
|
|
3
|
+
import { runToolCallHandlers, runToolResultHandlers } from "./tool-hook-handlers.js";
|
|
4
|
+
//#region src/plugins/tool-hooks.ts
|
|
5
|
+
const toolHookQueues = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
function wrapToolsWithPluginHooks({ history, signal, tools }) {
|
|
7
|
+
const scope = getActiveAgentPluginScope();
|
|
8
|
+
if (!(tools && scope && hasToolHookHandlers(scope))) return tools;
|
|
9
|
+
const wrapped = {};
|
|
10
|
+
for (const toolName of Object.keys(tools)) {
|
|
11
|
+
const currentTool = tools[toolName];
|
|
12
|
+
const execute = currentTool?.execute;
|
|
13
|
+
if (!currentTool || typeof execute !== "function") {
|
|
14
|
+
if (currentTool) wrapped[toolName] = currentTool;
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
wrapped[toolName] = {
|
|
18
|
+
...currentTool,
|
|
19
|
+
execute: (input, options) => executeWithToolHooks({
|
|
20
|
+
execute,
|
|
21
|
+
history,
|
|
22
|
+
input,
|
|
23
|
+
options,
|
|
24
|
+
scope,
|
|
25
|
+
signal,
|
|
26
|
+
tool: toolName
|
|
27
|
+
})
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return wrapped;
|
|
31
|
+
}
|
|
32
|
+
function executeWithToolHooks(options) {
|
|
33
|
+
return runExclusiveToolHooks(options.scope, () => runWithAgentPluginScope(options.scope, () => executeWithScopedToolHooks(options)));
|
|
34
|
+
}
|
|
35
|
+
async function executeWithScopedToolHooks({ execute, history, input, options, scope, signal, tool }) {
|
|
36
|
+
const callDecision = await runToolCallHandlers({
|
|
37
|
+
history,
|
|
38
|
+
input,
|
|
39
|
+
options,
|
|
40
|
+
scope,
|
|
41
|
+
signal,
|
|
42
|
+
tool
|
|
43
|
+
});
|
|
44
|
+
if (callDecision.kind === "error") throw new AgentPluginToolPolicyError(callDecision.message);
|
|
45
|
+
if (callDecision.kind === "synthetic") return toolResultOutput((await runToolResultHandlers({
|
|
46
|
+
history,
|
|
47
|
+
input: callDecision.input,
|
|
48
|
+
initialState: {
|
|
49
|
+
output: callDecision.output,
|
|
50
|
+
status: "done"
|
|
51
|
+
},
|
|
52
|
+
options,
|
|
53
|
+
scope,
|
|
54
|
+
signal,
|
|
55
|
+
tool
|
|
56
|
+
})).state);
|
|
57
|
+
const startedAt = Date.now();
|
|
58
|
+
try {
|
|
59
|
+
const output = await execute(callDecision.input, options);
|
|
60
|
+
return toolResultOutput((await runToolResultHandlers({
|
|
61
|
+
elapsedMs: Date.now() - startedAt,
|
|
62
|
+
history,
|
|
63
|
+
input: callDecision.input,
|
|
64
|
+
initialState: {
|
|
65
|
+
output,
|
|
66
|
+
status: "done"
|
|
67
|
+
},
|
|
68
|
+
options,
|
|
69
|
+
scope,
|
|
70
|
+
signal,
|
|
71
|
+
tool
|
|
72
|
+
})).state);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
const result = await runToolResultHandlers({
|
|
75
|
+
elapsedMs: Date.now() - startedAt,
|
|
76
|
+
history,
|
|
77
|
+
input: callDecision.input,
|
|
78
|
+
initialState: {
|
|
79
|
+
error: errorMessage(error),
|
|
80
|
+
status: "error"
|
|
81
|
+
},
|
|
82
|
+
options,
|
|
83
|
+
scope,
|
|
84
|
+
signal,
|
|
85
|
+
tool
|
|
86
|
+
});
|
|
87
|
+
if (!result.replaced) throw error;
|
|
88
|
+
return toolResultOutput(result.state);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function runExclusiveToolHooks(scope, callback) {
|
|
92
|
+
const previous = toolHookQueues.get(scope) ?? Promise.resolve();
|
|
93
|
+
let release = () => void 0;
|
|
94
|
+
const current = new Promise((resolve) => {
|
|
95
|
+
release = resolve;
|
|
96
|
+
});
|
|
97
|
+
toolHookQueues.set(scope, previous.then(() => current));
|
|
98
|
+
await previous;
|
|
99
|
+
try {
|
|
100
|
+
return await callback();
|
|
101
|
+
} finally {
|
|
102
|
+
release();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function hasToolHookHandlers(scope) {
|
|
106
|
+
return (scope.eventHandlers?.get("tool.call")?.length ?? 0) > 0 || (scope.eventHandlers?.get("tool.result")?.length ?? 0) > 0;
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { wrapToolsWithPluginHooks };
|
|
110
|
+
|
|
111
|
+
//# sourceMappingURL=tool-hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-hooks.js","names":[],"sources":["../../src/plugins/tool-hooks.ts"],"sourcesContent":["import type { ModelMessage, ToolExecutionOptions, ToolSet } from \"ai\";\nimport type { AgentPluginScope } from \"./scope\";\nimport { getActiveAgentPluginScope, runWithAgentPluginScope } from \"./scope\";\nimport {\n runToolCallHandlers,\n runToolResultHandlers,\n} from \"./tool-hook-handlers\";\nimport {\n AgentPluginToolPolicyError,\n errorMessage,\n toolResultOutput,\n} from \"./tool-hook-results\";\n\ninterface ToolHookWrapOptions {\n readonly history: readonly ModelMessage[];\n readonly signal: AbortSignal;\n readonly tools?: ToolSet;\n}\n\ninterface ExecuteWithToolHooksOptions {\n readonly execute: (\n input: unknown,\n options: ToolExecutionOptions<unknown>\n ) => unknown;\n readonly history: readonly ModelMessage[];\n readonly input: unknown;\n readonly options: ToolExecutionOptions<unknown>;\n readonly scope: AgentPluginScope;\n readonly signal: AbortSignal;\n readonly tool: string;\n}\n\nconst toolHookQueues = new WeakMap<AgentPluginScope, Promise<void>>();\n\nexport function wrapToolsWithPluginHooks({\n history,\n signal,\n tools,\n}: ToolHookWrapOptions): ToolSet | undefined {\n const scope = getActiveAgentPluginScope();\n if (!(tools && scope && hasToolHookHandlers(scope))) {\n return tools;\n }\n\n const wrapped: ToolSet = {};\n for (const toolName of Object.keys(tools)) {\n const currentTool = tools[toolName];\n const execute = currentTool?.execute;\n if (!currentTool || typeof execute !== \"function\") {\n if (currentTool) {\n wrapped[toolName] = currentTool;\n }\n continue;\n }\n\n wrapped[toolName] = {\n ...currentTool,\n execute: (input: unknown, options: ToolExecutionOptions<unknown>) =>\n executeWithToolHooks({\n execute,\n history,\n input,\n options,\n scope,\n signal,\n tool: toolName,\n }),\n };\n }\n\n return wrapped;\n}\n\nfunction executeWithToolHooks(\n options: ExecuteWithToolHooksOptions\n): Promise<unknown> {\n return runExclusiveToolHooks(options.scope, () =>\n runWithAgentPluginScope(options.scope, () =>\n executeWithScopedToolHooks(options)\n )\n );\n}\n\nasync function executeWithScopedToolHooks({\n execute,\n history,\n input,\n options,\n scope,\n signal,\n tool,\n}: ExecuteWithToolHooksOptions): Promise<unknown> {\n const callDecision = await runToolCallHandlers({\n history,\n input,\n options,\n scope,\n signal,\n tool,\n });\n\n if (callDecision.kind === \"error\") {\n throw new AgentPluginToolPolicyError(callDecision.message);\n }\n\n if (callDecision.kind === \"synthetic\") {\n const result = await runToolResultHandlers({\n history,\n input: callDecision.input,\n initialState: { output: callDecision.output, status: \"done\" },\n options,\n scope,\n signal,\n tool,\n });\n return toolResultOutput(result.state);\n }\n\n const startedAt = Date.now();\n try {\n const output = await execute(callDecision.input, options);\n const result = await runToolResultHandlers({\n elapsedMs: Date.now() - startedAt,\n history,\n input: callDecision.input,\n initialState: { output, status: \"done\" },\n options,\n scope,\n signal,\n tool,\n });\n return toolResultOutput(result.state);\n } catch (error) {\n const result = await runToolResultHandlers({\n elapsedMs: Date.now() - startedAt,\n history,\n input: callDecision.input,\n initialState: { error: errorMessage(error), status: \"error\" },\n options,\n scope,\n signal,\n tool,\n });\n if (!result.replaced) {\n throw error;\n }\n return toolResultOutput(result.state);\n }\n}\n\nasync function runExclusiveToolHooks<T>(\n scope: AgentPluginScope,\n callback: () => Promise<T>\n): Promise<T> {\n const previous = toolHookQueues.get(scope) ?? Promise.resolve();\n let release: () => void = () => undefined;\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n toolHookQueues.set(\n scope,\n previous.then(() => current)\n );\n\n await previous;\n try {\n return await callback();\n } finally {\n release();\n }\n}\n\nfunction hasToolHookHandlers(scope: AgentPluginScope): boolean {\n return (\n (scope.eventHandlers?.get(\"tool.call\")?.length ?? 0) > 0 ||\n (scope.eventHandlers?.get(\"tool.result\")?.length ?? 0) > 0\n );\n}\n"],"mappings":";;;;AAgCA,MAAM,iCAAiB,IAAI,QAAyC;AAEpE,SAAgB,yBAAyB,EACvC,SACA,QACA,SAC2C;CAC3C,MAAM,QAAQ,0BAA0B;CACxC,IAAI,EAAE,SAAS,SAAS,oBAAoB,KAAK,IAC/C,OAAO;CAGT,MAAM,UAAmB,CAAC;CAC1B,KAAK,MAAM,YAAY,OAAO,KAAK,KAAK,GAAG;EACzC,MAAM,cAAc,MAAM;EAC1B,MAAM,UAAU,aAAa;EAC7B,IAAI,CAAC,eAAe,OAAO,YAAY,YAAY;GACjD,IAAI,aACF,QAAQ,YAAY;GAEtB;EACF;EAEA,QAAQ,YAAY;GAClB,GAAG;GACH,UAAU,OAAgB,YACxB,qBAAqB;IACnB;IACA;IACA;IACA;IACA;IACA;IACA,MAAM;GACR,CAAC;EACL;CACF;CAEA,OAAO;AACT;AAEA,SAAS,qBACP,SACkB;CAClB,OAAO,sBAAsB,QAAQ,aACnC,wBAAwB,QAAQ,aAC9B,2BAA2B,OAAO,CACpC,CACF;AACF;AAEA,eAAe,2BAA2B,EACxC,SACA,SACA,OACA,SACA,OACA,QACA,QACgD;CAChD,MAAM,eAAe,MAAM,oBAAoB;EAC7C;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,IAAI,aAAa,SAAS,SACxB,MAAM,IAAI,2BAA2B,aAAa,OAAO;CAG3D,IAAI,aAAa,SAAS,aAUxB,OAAO,kBAAiB,MATH,sBAAsB;EACzC;EACA,OAAO,aAAa;EACpB,cAAc;GAAE,QAAQ,aAAa;GAAQ,QAAQ;EAAO;EAC5D;EACA;EACA;EACA;CACF,CAAC,GAC8B,KAAK;CAGtC,MAAM,YAAY,KAAK,IAAI;CAC3B,IAAI;EACF,MAAM,SAAS,MAAM,QAAQ,aAAa,OAAO,OAAO;EAWxD,OAAO,kBAAiB,MAVH,sBAAsB;GACzC,WAAW,KAAK,IAAI,IAAI;GACxB;GACA,OAAO,aAAa;GACpB,cAAc;IAAE;IAAQ,QAAQ;GAAO;GACvC;GACA;GACA;GACA;EACF,CAAC,GAC8B,KAAK;CACtC,SAAS,OAAO;EACd,MAAM,SAAS,MAAM,sBAAsB;GACzC,WAAW,KAAK,IAAI,IAAI;GACxB;GACA,OAAO,aAAa;GACpB,cAAc;IAAE,OAAO,aAAa,KAAK;IAAG,QAAQ;GAAQ;GAC5D;GACA;GACA;GACA;EACF,CAAC;EACD,IAAI,CAAC,OAAO,UACV,MAAM;EAER,OAAO,iBAAiB,OAAO,KAAK;CACtC;AACF;AAEA,eAAe,sBACb,OACA,UACY;CACZ,MAAM,WAAW,eAAe,IAAI,KAAK,KAAK,QAAQ,QAAQ;CAC9D,IAAI,gBAA4B,KAAA;CAChC,MAAM,UAAU,IAAI,SAAe,YAAY;EAC7C,UAAU;CACZ,CAAC;CACD,eAAe,IACb,OACA,SAAS,WAAW,OAAO,CAC7B;CAEA,MAAM;CACN,IAAI;EACF,OAAO,MAAM,SAAS;CACxB,UAAU;EACR,QAAQ;CACV;AACF;AAEA,SAAS,oBAAoB,OAAkC;CAC7D,QACG,MAAM,eAAe,IAAI,WAAW,GAAG,UAAU,KAAK,MACtD,MAAM,eAAe,IAAI,aAAa,GAAG,UAAU,KAAK;AAE7D"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { AgentInput, UserInput } from "../session/input.js";
|
|
2
|
+
import { AgentRun } from "../session/run.js";
|
|
3
|
+
import { SessionStore } from "../session/store/types.js";
|
|
4
|
+
import { ModelMessage, ToolSet } from "ai";
|
|
5
|
+
|
|
6
|
+
//#region src/plugins/types.d.ts
|
|
7
|
+
type AgentPluginMaybePromise<T> = Promise<T> | T;
|
|
8
|
+
type AgentContextTransform = (context: {
|
|
9
|
+
readonly history: readonly ModelMessage[];
|
|
10
|
+
readonly sessionKey: string;
|
|
11
|
+
readonly signal: AbortSignal;
|
|
12
|
+
}) => AgentPluginMaybePromise<readonly ModelMessage[]>;
|
|
13
|
+
declare const AGENT_PLUGIN_EVENT_NAMES: readonly ["turn.before", "step.before", "step.after", "turn.after", "tool.call", "tool.result"];
|
|
14
|
+
type AgentPluginEventName = (typeof AGENT_PLUGIN_EVENT_NAMES)[number];
|
|
15
|
+
type AgentPluginStepResult = "completed" | "continue";
|
|
16
|
+
type AgentPluginToolResultStatus = "cancelled" | "done" | "error";
|
|
17
|
+
type AgentPluginTurnResult = "aborted" | "completed";
|
|
18
|
+
type AgentPluginNoResult = ReturnType<() => void>;
|
|
19
|
+
interface AgentPluginToolSyntheticResult {
|
|
20
|
+
readonly exitCode?: number;
|
|
21
|
+
readonly output: unknown;
|
|
22
|
+
}
|
|
23
|
+
type AgentPluginToolCallResult = AgentPluginNoResult | {
|
|
24
|
+
readonly action: "allow";
|
|
25
|
+
} | {
|
|
26
|
+
readonly action: "error";
|
|
27
|
+
readonly message: string;
|
|
28
|
+
} | {
|
|
29
|
+
readonly action: "modify";
|
|
30
|
+
readonly input: unknown;
|
|
31
|
+
} | {
|
|
32
|
+
readonly action: "reject-and-continue";
|
|
33
|
+
readonly message: string;
|
|
34
|
+
} | {
|
|
35
|
+
readonly action: "synthesize";
|
|
36
|
+
readonly result: AgentPluginToolSyntheticResult;
|
|
37
|
+
};
|
|
38
|
+
type AgentPluginToolResultResult = AgentPluginNoResult | {
|
|
39
|
+
readonly error?: string;
|
|
40
|
+
readonly output?: unknown;
|
|
41
|
+
readonly status: AgentPluginToolResultStatus;
|
|
42
|
+
};
|
|
43
|
+
interface AgentPluginBaseEvent {
|
|
44
|
+
readonly history: readonly ModelMessage[];
|
|
45
|
+
readonly overlay: (input: AgentInput) => Promise<AgentRun>;
|
|
46
|
+
readonly sessionKey: string;
|
|
47
|
+
readonly signal: AbortSignal;
|
|
48
|
+
readonly steer: (input: AgentInput) => Promise<AgentRun>;
|
|
49
|
+
readonly type: AgentPluginEventName;
|
|
50
|
+
}
|
|
51
|
+
interface AgentPluginTurnBeforeEvent extends AgentPluginBaseEvent {
|
|
52
|
+
readonly input: UserInput;
|
|
53
|
+
readonly type: "turn.before";
|
|
54
|
+
}
|
|
55
|
+
interface AgentPluginStepBeforeEvent extends AgentPluginBaseEvent {
|
|
56
|
+
readonly stepIndex: number;
|
|
57
|
+
readonly type: "step.before";
|
|
58
|
+
}
|
|
59
|
+
interface AgentPluginStepAfterEvent extends AgentPluginBaseEvent {
|
|
60
|
+
readonly result: AgentPluginStepResult;
|
|
61
|
+
readonly stepIndex: number;
|
|
62
|
+
readonly type: "step.after";
|
|
63
|
+
}
|
|
64
|
+
interface AgentPluginTurnAfterEvent extends AgentPluginBaseEvent {
|
|
65
|
+
readonly input: UserInput;
|
|
66
|
+
readonly result: AgentPluginTurnResult;
|
|
67
|
+
readonly type: "turn.after";
|
|
68
|
+
}
|
|
69
|
+
interface AgentPluginToolCallEvent extends AgentPluginBaseEvent {
|
|
70
|
+
readonly input: unknown;
|
|
71
|
+
readonly tool: string;
|
|
72
|
+
readonly toolCallId: string;
|
|
73
|
+
readonly type: "tool.call";
|
|
74
|
+
}
|
|
75
|
+
interface AgentPluginToolResultEvent extends AgentPluginBaseEvent {
|
|
76
|
+
readonly elapsedMs?: number;
|
|
77
|
+
readonly error?: string;
|
|
78
|
+
readonly input: unknown;
|
|
79
|
+
readonly output?: unknown;
|
|
80
|
+
readonly status: AgentPluginToolResultStatus;
|
|
81
|
+
readonly tool: string;
|
|
82
|
+
readonly toolCallId: string;
|
|
83
|
+
readonly type: "tool.result";
|
|
84
|
+
}
|
|
85
|
+
type AgentPluginEvent = AgentPluginStepAfterEvent | AgentPluginStepBeforeEvent | AgentPluginToolCallEvent | AgentPluginToolResultEvent | AgentPluginTurnAfterEvent | AgentPluginTurnBeforeEvent;
|
|
86
|
+
type AgentPluginEventFor<Name extends AgentPluginEventName> = Extract<AgentPluginEvent, {
|
|
87
|
+
readonly type: Name;
|
|
88
|
+
}>;
|
|
89
|
+
type AgentPluginHandlerResult<Event extends AgentPluginEvent> = Event extends AgentPluginToolCallEvent ? AgentPluginToolCallResult : Event extends AgentPluginToolResultEvent ? AgentPluginToolResultResult : AgentPluginNoResult;
|
|
90
|
+
type AgentPluginHandlerReturn<Event extends AgentPluginEvent> = Event extends AgentPluginToolCallEvent ? AgentPluginMaybePromise<AgentPluginToolCallResult> : Event extends AgentPluginToolResultEvent ? AgentPluginMaybePromise<AgentPluginToolResultResult> : AgentPluginMaybePromise<void>;
|
|
91
|
+
type AgentPluginHandler<Event extends AgentPluginEvent = AgentPluginEvent> = (event: Event) => AgentPluginHandlerReturn<Event>;
|
|
92
|
+
interface AgentPlugin {
|
|
93
|
+
readonly name: string;
|
|
94
|
+
setup(host: AgentPluginHost): AgentPluginMaybePromise<void>;
|
|
95
|
+
}
|
|
96
|
+
interface AgentPluginHost {
|
|
97
|
+
on<Name extends AgentPluginEventName>(event: Name, handler: AgentPluginHandler<AgentPluginEventFor<Name>>): void;
|
|
98
|
+
registerSessionStore(store: SessionStore): void;
|
|
99
|
+
registerTools(tools: ToolSet): void;
|
|
100
|
+
transformContext(handler: AgentContextTransform): void;
|
|
101
|
+
}
|
|
102
|
+
declare function definePlugin(plugin: AgentPlugin): AgentPlugin;
|
|
103
|
+
//#endregion
|
|
104
|
+
export { AgentContextTransform, AgentPlugin, AgentPluginEvent, AgentPluginEventFor, AgentPluginEventName, AgentPluginHandler, AgentPluginHandlerResult, AgentPluginHandlerReturn, AgentPluginHost, AgentPluginMaybePromise, AgentPluginStepAfterEvent, AgentPluginStepBeforeEvent, AgentPluginStepResult, AgentPluginToolCallEvent, AgentPluginToolCallResult, AgentPluginToolResultEvent, AgentPluginToolResultResult, AgentPluginToolResultStatus, AgentPluginToolSyntheticResult, AgentPluginTurnAfterEvent, AgentPluginTurnBeforeEvent, AgentPluginTurnResult, definePlugin };
|
|
105
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/plugins/types.ts
|
|
2
|
+
const AGENT_PLUGIN_EVENT_NAMES = [
|
|
3
|
+
"turn.before",
|
|
4
|
+
"step.before",
|
|
5
|
+
"step.after",
|
|
6
|
+
"turn.after",
|
|
7
|
+
"tool.call",
|
|
8
|
+
"tool.result"
|
|
9
|
+
];
|
|
10
|
+
function definePlugin(plugin) {
|
|
11
|
+
return plugin;
|
|
12
|
+
}
|
|
13
|
+
const agentPluginEventNameSet = new Set(AGENT_PLUGIN_EVENT_NAMES);
|
|
14
|
+
function isAgentPluginEventName(event) {
|
|
15
|
+
return typeof event === "string" && agentPluginEventNameSet.has(event);
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { definePlugin, isAgentPluginEventName };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../src/plugins/types.ts"],"sourcesContent":["import type { ModelMessage, ToolSet } from \"ai\";\nimport type { UserInput } from \"../session/events\";\nimport type { AgentInput } from \"../session/input\";\nimport type { AgentRun } from \"../session/run\";\nimport type { SessionStore } from \"../session/store/types\";\n\nexport type AgentPluginMaybePromise<T> = Promise<T> | T;\n\nexport type AgentContextTransform = (context: {\n readonly history: readonly ModelMessage[];\n readonly sessionKey: string;\n readonly signal: AbortSignal;\n}) => AgentPluginMaybePromise<readonly ModelMessage[]>;\n\nexport const AGENT_PLUGIN_EVENT_NAMES = [\n \"turn.before\",\n \"step.before\",\n \"step.after\",\n \"turn.after\",\n \"tool.call\",\n \"tool.result\",\n] as const;\n\nexport type AgentPluginEventName = (typeof AGENT_PLUGIN_EVENT_NAMES)[number];\n\nexport type AgentPluginStepResult = \"completed\" | \"continue\";\nexport type AgentPluginToolResultStatus = \"cancelled\" | \"done\" | \"error\";\nexport type AgentPluginTurnResult = \"aborted\" | \"completed\";\ntype AgentPluginNoResult = ReturnType<() => void>;\n\nexport interface AgentPluginToolSyntheticResult {\n readonly exitCode?: number;\n readonly output: unknown;\n}\n\nexport type AgentPluginToolCallResult =\n | AgentPluginNoResult\n | { readonly action: \"allow\" }\n | { readonly action: \"error\"; readonly message: string }\n | { readonly action: \"modify\"; readonly input: unknown }\n | { readonly action: \"reject-and-continue\"; readonly message: string }\n | {\n readonly action: \"synthesize\";\n readonly result: AgentPluginToolSyntheticResult;\n };\n\nexport type AgentPluginToolResultResult =\n | AgentPluginNoResult\n | {\n readonly error?: string;\n readonly output?: unknown;\n readonly status: AgentPluginToolResultStatus;\n };\n\ninterface AgentPluginBaseEvent {\n readonly history: readonly ModelMessage[];\n readonly overlay: (input: AgentInput) => Promise<AgentRun>;\n readonly sessionKey: string;\n readonly signal: AbortSignal;\n readonly steer: (input: AgentInput) => Promise<AgentRun>;\n readonly type: AgentPluginEventName;\n}\n\nexport interface AgentPluginTurnBeforeEvent extends AgentPluginBaseEvent {\n readonly input: UserInput;\n readonly type: \"turn.before\";\n}\n\nexport interface AgentPluginStepBeforeEvent extends AgentPluginBaseEvent {\n readonly stepIndex: number;\n readonly type: \"step.before\";\n}\n\nexport interface AgentPluginStepAfterEvent extends AgentPluginBaseEvent {\n readonly result: AgentPluginStepResult;\n readonly stepIndex: number;\n readonly type: \"step.after\";\n}\n\nexport interface AgentPluginTurnAfterEvent extends AgentPluginBaseEvent {\n readonly input: UserInput;\n readonly result: AgentPluginTurnResult;\n readonly type: \"turn.after\";\n}\n\nexport interface AgentPluginToolCallEvent extends AgentPluginBaseEvent {\n readonly input: unknown;\n readonly tool: string;\n readonly toolCallId: string;\n readonly type: \"tool.call\";\n}\n\nexport interface AgentPluginToolResultEvent extends AgentPluginBaseEvent {\n readonly elapsedMs?: number;\n readonly error?: string;\n readonly input: unknown;\n readonly output?: unknown;\n readonly status: AgentPluginToolResultStatus;\n readonly tool: string;\n readonly toolCallId: string;\n readonly type: \"tool.result\";\n}\n\nexport type AgentPluginEvent =\n | AgentPluginStepAfterEvent\n | AgentPluginStepBeforeEvent\n | AgentPluginToolCallEvent\n | AgentPluginToolResultEvent\n | AgentPluginTurnAfterEvent\n | AgentPluginTurnBeforeEvent;\n\nexport type AgentPluginEventFor<Name extends AgentPluginEventName> = Extract<\n AgentPluginEvent,\n { readonly type: Name }\n>;\n\nexport type AgentPluginHandlerResult<Event extends AgentPluginEvent> =\n Event extends AgentPluginToolCallEvent\n ? AgentPluginToolCallResult\n : Event extends AgentPluginToolResultEvent\n ? AgentPluginToolResultResult\n : AgentPluginNoResult;\n\nexport type AgentPluginHandlerReturn<Event extends AgentPluginEvent> =\n Event extends AgentPluginToolCallEvent\n ? AgentPluginMaybePromise<AgentPluginToolCallResult>\n : Event extends AgentPluginToolResultEvent\n ? AgentPluginMaybePromise<AgentPluginToolResultResult>\n : AgentPluginMaybePromise<void>;\n\nexport type AgentPluginHandler<\n Event extends AgentPluginEvent = AgentPluginEvent,\n> = (event: Event) => AgentPluginHandlerReturn<Event>;\n\nexport type AgentPluginStoredHandler<\n Event extends AgentPluginEvent = AgentPluginEvent,\n> = {\n bivarianceHack(event: Event): AgentPluginHandlerReturn<Event>;\n}[\"bivarianceHack\"];\n\nexport interface AgentPlugin {\n readonly name: string;\n setup(host: AgentPluginHost): AgentPluginMaybePromise<void>;\n}\n\nexport interface AgentPluginHost {\n on<Name extends AgentPluginEventName>(\n event: Name,\n handler: AgentPluginHandler<AgentPluginEventFor<Name>>\n ): void;\n registerSessionStore(store: SessionStore): void;\n registerTools(tools: ToolSet): void;\n transformContext(handler: AgentContextTransform): void;\n}\n\nexport function definePlugin(plugin: AgentPlugin): AgentPlugin {\n return plugin;\n}\n\nconst agentPluginEventNameSet: ReadonlySet<string> = new Set(\n AGENT_PLUGIN_EVENT_NAMES\n);\n\nexport function isAgentPluginEventName(\n event: unknown\n): event is AgentPluginEventName {\n return typeof event === \"string\" && agentPluginEventNameSet.has(event);\n}\n"],"mappings":";AAcA,MAAa,2BAA2B;CACtC;CACA;CACA;CACA;CACA;CACA;AACF;AAsIA,SAAgB,aAAa,QAAkC;CAC7D,OAAO;AACT;AAEA,MAAM,0BAA+C,IAAI,IACvD,wBACF;AAEA,SAAgB,uBACd,OAC+B;CAC/B,OAAO,OAAO,UAAU,YAAY,wBAAwB,IAAI,KAAK;AACvE"}
|
package/dist/session/events.d.ts
CHANGED
|
@@ -10,6 +10,23 @@ interface RuntimeInput {
|
|
|
10
10
|
placement: "turn-start" | "step-start" | "step-end";
|
|
11
11
|
type: "runtime-input";
|
|
12
12
|
}
|
|
13
|
+
type OverlayPlacement = "idle" | "step-end" | "step-start" | "turn-start";
|
|
14
|
+
interface OverlayInputSummary {
|
|
15
|
+
partCount?: number;
|
|
16
|
+
preview: string;
|
|
17
|
+
textLength?: number;
|
|
18
|
+
type: UserInput["type"];
|
|
19
|
+
}
|
|
20
|
+
interface OverlayAccepted {
|
|
21
|
+
input: OverlayInputSummary;
|
|
22
|
+
placement: OverlayPlacement;
|
|
23
|
+
type: "overlay-accepted";
|
|
24
|
+
}
|
|
25
|
+
interface OverlayExpired {
|
|
26
|
+
count: number;
|
|
27
|
+
reason: "kill" | "turn-abort" | "turn-end" | "turn-error";
|
|
28
|
+
type: "overlay-expired";
|
|
29
|
+
}
|
|
13
30
|
interface AssistantText {
|
|
14
31
|
text: string;
|
|
15
32
|
type: "assistant-text";
|
|
@@ -30,7 +47,7 @@ interface ToolResult {
|
|
|
30
47
|
toolName: string;
|
|
31
48
|
type: "tool-result";
|
|
32
49
|
}
|
|
33
|
-
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. */ | {
|
|
50
|
+
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 | OverlayAccepted | OverlayExpired /** A queued user input started running as a turn. */ | {
|
|
34
51
|
type: "turn-start";
|
|
35
52
|
} /** The active turn was interrupted before normal completion. */ | {
|
|
36
53
|
type: "turn-abort";
|
|
@@ -46,5 +63,5 @@ type AgentEvent = /** User input was accepted into the session queue. */UserText
|
|
|
46
63
|
};
|
|
47
64
|
type AgentEventListener = (event: AgentEvent) => void;
|
|
48
65
|
//#endregion
|
|
49
|
-
export { AgentEvent, AgentEventListener, AssistantReasoning, AssistantText, RuntimeInput, ToolCall, ToolResult };
|
|
66
|
+
export { AgentEvent, AgentEventListener, AssistantReasoning, AssistantText, OverlayAccepted, OverlayExpired, OverlayInputSummary, OverlayPlacement, RuntimeInput, ToolCall, ToolResult };
|
|
50
67
|
//# sourceMappingURL=events.d.ts.map
|
package/dist/session/input.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { UserModelMessage } from "ai";
|
|
2
|
+
|
|
1
3
|
//#region src/session/input.d.ts
|
|
2
4
|
type UserTextContent = string | readonly string[];
|
|
3
5
|
interface UserText {
|
|
@@ -34,8 +36,10 @@ interface UserMessageFilePart {
|
|
|
34
36
|
}
|
|
35
37
|
type UserMessageContentPart = UserMessageFilePart | UserMessageImagePart | UserMessageTextPart;
|
|
36
38
|
type UserMessageContent = readonly UserMessageContentPart[];
|
|
39
|
+
type UserMessageMetadata = UserModelMessage["providerOptions"];
|
|
37
40
|
interface UserMessage {
|
|
38
41
|
content: UserMessageContent;
|
|
42
|
+
metadata?: UserMessageMetadata;
|
|
39
43
|
type: "user-message";
|
|
40
44
|
}
|
|
41
45
|
type UserInput = UserMessage | UserText;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AgentPluginEventName } from "../plugins/types.js";
|
|
2
|
+
import { ModelMessage } from "ai";
|
|
3
|
+
|
|
4
|
+
//#region src/session/lifecycle.d.ts
|
|
5
|
+
interface AgentPluginHandlerError {
|
|
6
|
+
readonly eventName: AgentPluginEventName;
|
|
7
|
+
readonly reason: unknown;
|
|
8
|
+
}
|
|
9
|
+
type AgentPluginErrorHandler = (error: AgentPluginHandlerError) => Promise<void> | void;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { AgentPluginErrorHandler, AgentPluginHandlerError };
|
|
12
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { runWithAgentPluginScope } from "../plugins/scope.js";
|
|
2
|
+
//#region src/session/lifecycle.ts
|
|
3
|
+
function createRuntimeInputStepLifecycle({ lifecycle, runtimeInput, stepLifecycle, withSteeringPlacement }) {
|
|
4
|
+
const hasPluginStepHandlers = pluginHandlers(lifecycle, "step.after").length > 0 || pluginHandlers(lifecycle, "step.before").length > 0;
|
|
5
|
+
if (!(stepLifecycle || hasPluginStepHandlers)) return;
|
|
6
|
+
return {
|
|
7
|
+
...stepLifecycle,
|
|
8
|
+
afterStep: (context) => withSteeringPlacement("step-end", async () => {
|
|
9
|
+
await stepLifecycle?.afterStep?.(context);
|
|
10
|
+
await runPluginAfterStepHandlers(lifecycle, {
|
|
11
|
+
context,
|
|
12
|
+
runtimeInput
|
|
13
|
+
});
|
|
14
|
+
}),
|
|
15
|
+
beforeStep: (context) => withSteeringPlacement("step-start", async () => {
|
|
16
|
+
await stepLifecycle?.beforeStep?.(context);
|
|
17
|
+
await runPluginBeforeStepHandlers(lifecycle, {
|
|
18
|
+
context,
|
|
19
|
+
runtimeInput
|
|
20
|
+
});
|
|
21
|
+
})
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
async function runPluginBeforeTurnHandlers(lifecycle, { input, runtimeInput, signal }) {
|
|
25
|
+
const handlers = pluginHandlers(lifecycle, "turn.before");
|
|
26
|
+
if (handlers.length === 0) return false;
|
|
27
|
+
await runWithAgentPluginScope(lifecycle.createScope(signal), async () => {
|
|
28
|
+
for (const handler of handlers) await handler({
|
|
29
|
+
history: lifecycle.history(),
|
|
30
|
+
input,
|
|
31
|
+
overlay: lifecycle.overlaySession,
|
|
32
|
+
sessionKey: lifecycle.sessionKey,
|
|
33
|
+
signal,
|
|
34
|
+
steer: (nextInput) => lifecycle.steerCurrentRun(runtimeInput, nextInput),
|
|
35
|
+
type: "turn.before"
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
async function runPluginBeforeStepHandlers(lifecycle, { context, runtimeInput }) {
|
|
41
|
+
const handlers = pluginHandlers(lifecycle, "step.before");
|
|
42
|
+
if (handlers.length === 0) return false;
|
|
43
|
+
await runWithAgentPluginScope(lifecycle.createScope(context.signal), async () => {
|
|
44
|
+
for (const handler of handlers) await handler({
|
|
45
|
+
history: context.history,
|
|
46
|
+
overlay: lifecycle.overlaySession,
|
|
47
|
+
sessionKey: lifecycle.sessionKey,
|
|
48
|
+
signal: context.signal,
|
|
49
|
+
steer: (input) => lifecycle.steerCurrentRun(runtimeInput, input),
|
|
50
|
+
stepIndex: context.stepIndex,
|
|
51
|
+
type: "step.before"
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
async function runPluginAfterStepHandlers(lifecycle, { context, runtimeInput }) {
|
|
57
|
+
const handlers = pluginHandlers(lifecycle, "step.after");
|
|
58
|
+
if (handlers.length === 0) return false;
|
|
59
|
+
await logPluginHandlerRejections(lifecycle, "step.after", await runWithAgentPluginScope(lifecycle.createScope(context.signal), () => Promise.allSettled(handlers.map((handler) => Promise.resolve().then(() => handler({
|
|
60
|
+
history: context.history,
|
|
61
|
+
overlay: lifecycle.overlaySession,
|
|
62
|
+
result: context.result,
|
|
63
|
+
sessionKey: lifecycle.sessionKey,
|
|
64
|
+
signal: context.signal,
|
|
65
|
+
steer: (input) => lifecycle.steerCurrentRun(runtimeInput, input),
|
|
66
|
+
stepIndex: context.stepIndex,
|
|
67
|
+
type: "step.after"
|
|
68
|
+
}))))));
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
async function runPluginAfterTurnHandlers(lifecycle, { input, result, signal }) {
|
|
72
|
+
const handlers = pluginHandlers(lifecycle, "turn.after");
|
|
73
|
+
if (handlers.length === 0) return false;
|
|
74
|
+
const overlay = () => Promise.reject(/* @__PURE__ */ new Error("Agent plugin overlay cannot be used after turn end."));
|
|
75
|
+
await logPluginHandlerRejections(lifecycle, "turn.after", await runWithAgentPluginScope({
|
|
76
|
+
...lifecycle.createScope(signal),
|
|
77
|
+
overlay
|
|
78
|
+
}, () => Promise.allSettled(handlers.map((handler) => Promise.resolve().then(() => handler({
|
|
79
|
+
history: lifecycle.history(),
|
|
80
|
+
input,
|
|
81
|
+
overlay,
|
|
82
|
+
result,
|
|
83
|
+
sessionKey: lifecycle.sessionKey,
|
|
84
|
+
signal,
|
|
85
|
+
steer: lifecycle.steerSession,
|
|
86
|
+
type: "turn.after"
|
|
87
|
+
}))))));
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
function pluginHandlers(lifecycle, eventName) {
|
|
91
|
+
return lifecycle.plugins?.eventHandlers.get(eventName) ?? [];
|
|
92
|
+
}
|
|
93
|
+
async function logPluginHandlerRejections(lifecycle, eventName, settlements) {
|
|
94
|
+
await Promise.all(settlements.map((settlement) => {
|
|
95
|
+
if (settlement.status === "fulfilled") return Promise.resolve();
|
|
96
|
+
return reportPluginHandlerRejection(lifecycle, {
|
|
97
|
+
eventName,
|
|
98
|
+
reason: settlement.reason
|
|
99
|
+
});
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
async function reportPluginHandlerRejection(lifecycle, error) {
|
|
103
|
+
const onPluginError = lifecycle.onPluginError;
|
|
104
|
+
if (!onPluginError) {
|
|
105
|
+
reportPluginHandlerError(error);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
await onPluginError(error);
|
|
110
|
+
} catch (handlerError) {
|
|
111
|
+
reportPluginErrorHandlerError(handlerError);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function reportPluginHandlerError({ eventName, reason }) {
|
|
115
|
+
console.error(`Agent plugin ${eventName} handler failed: ${errorKind(reason)}`);
|
|
116
|
+
}
|
|
117
|
+
function errorKind(reason) {
|
|
118
|
+
return reason instanceof Error ? reason.name : typeof reason;
|
|
119
|
+
}
|
|
120
|
+
function reportPluginErrorHandlerError(reason) {
|
|
121
|
+
console.error(`Agent plugin error handler failed: ${errorKind(reason)}`);
|
|
122
|
+
}
|
|
123
|
+
//#endregion
|
|
124
|
+
export { createRuntimeInputStepLifecycle, runPluginAfterTurnHandlers, runPluginBeforeTurnHandlers };
|
|
125
|
+
|
|
126
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","names":[],"sources":["../../src/session/lifecycle.ts"],"sourcesContent":["import type { ModelMessage } from \"ai\";\nimport type {\n AgentAfterStepContext,\n AgentBeforeStepContext,\n AgentLoopResult,\n AgentStepLifecycle,\n} from \"../agent-loop\";\nimport type { ResolvedAgentPlugins } from \"../plugins/runner\";\nimport {\n type AgentPluginScope,\n runWithAgentPluginScope,\n} from \"../plugins/scope\";\nimport type { AgentPluginEventName } from \"../plugins/types\";\nimport type { AgentInput, UserInput } from \"./input\";\nimport type { AgentRun } from \"./run\";\nimport type { RuntimeInputPlacement, RuntimeInputState } from \"./runtime-input\";\n\nexport interface AgentSessionLifecycle {\n readonly createScope: (signal: AbortSignal) => AgentPluginScope;\n readonly history: () => ModelMessage[];\n readonly onPluginError?: AgentPluginErrorHandler;\n readonly overlaySession: (input: AgentInput) => Promise<AgentRun>;\n readonly plugins?: ResolvedAgentPlugins;\n readonly sessionKey: string;\n readonly steerCurrentRun: (\n runtimeInput: RuntimeInputState,\n input: AgentInput\n ) => Promise<AgentRun>;\n readonly steerSession: (input: AgentInput) => Promise<AgentRun>;\n}\n\nexport interface AgentPluginHandlerError {\n readonly eventName: AgentPluginEventName;\n readonly reason: unknown;\n}\n\nexport type AgentPluginErrorHandler = (\n error: AgentPluginHandlerError\n) => Promise<void> | void;\n\nexport function createRuntimeInputStepLifecycle({\n lifecycle,\n runtimeInput,\n stepLifecycle,\n withSteeringPlacement,\n}: {\n readonly lifecycle: AgentSessionLifecycle;\n readonly runtimeInput: RuntimeInputState;\n readonly stepLifecycle?: AgentStepLifecycle;\n readonly withSteeringPlacement: <T>(\n placement: RuntimeInputPlacement,\n callback: () => Promise<T>\n ) => Promise<T>;\n}): AgentStepLifecycle | undefined {\n const hasPluginStepHandlers =\n pluginHandlers(lifecycle, \"step.after\").length > 0 ||\n pluginHandlers(lifecycle, \"step.before\").length > 0;\n if (!(stepLifecycle || hasPluginStepHandlers)) {\n return;\n }\n\n return {\n ...stepLifecycle,\n afterStep: (context) =>\n withSteeringPlacement(\"step-end\", async () => {\n await stepLifecycle?.afterStep?.(context);\n await runPluginAfterStepHandlers(lifecycle, {\n context,\n runtimeInput,\n });\n }),\n beforeStep: (context) =>\n withSteeringPlacement(\"step-start\", async () => {\n await stepLifecycle?.beforeStep?.(context);\n await runPluginBeforeStepHandlers(lifecycle, {\n context,\n runtimeInput,\n });\n }),\n };\n}\n\nexport async function runPluginBeforeTurnHandlers(\n lifecycle: AgentSessionLifecycle,\n {\n input,\n runtimeInput,\n signal,\n }: {\n readonly input: UserInput;\n readonly runtimeInput: RuntimeInputState;\n readonly signal: AbortSignal;\n }\n): Promise<boolean> {\n const handlers = pluginHandlers(lifecycle, \"turn.before\");\n if (handlers.length === 0) {\n return false;\n }\n\n const scope = lifecycle.createScope(signal);\n await runWithAgentPluginScope(scope, async () => {\n for (const handler of handlers) {\n await handler({\n history: lifecycle.history(),\n input,\n overlay: lifecycle.overlaySession,\n sessionKey: lifecycle.sessionKey,\n signal,\n steer: (nextInput) =>\n lifecycle.steerCurrentRun(runtimeInput, nextInput),\n type: \"turn.before\",\n });\n }\n });\n return true;\n}\n\nexport async function runPluginBeforeStepHandlers(\n lifecycle: AgentSessionLifecycle,\n {\n context,\n runtimeInput,\n }: {\n readonly context: AgentBeforeStepContext;\n readonly runtimeInput: RuntimeInputState;\n }\n): Promise<boolean> {\n const handlers = pluginHandlers(lifecycle, \"step.before\");\n if (handlers.length === 0) {\n return false;\n }\n\n const scope = lifecycle.createScope(context.signal);\n await runWithAgentPluginScope(scope, async () => {\n for (const handler of handlers) {\n await handler({\n history: context.history,\n overlay: lifecycle.overlaySession,\n sessionKey: lifecycle.sessionKey,\n signal: context.signal,\n steer: (input) => lifecycle.steerCurrentRun(runtimeInput, input),\n stepIndex: context.stepIndex,\n type: \"step.before\",\n });\n }\n });\n return true;\n}\n\nexport async function runPluginAfterStepHandlers(\n lifecycle: AgentSessionLifecycle,\n {\n context,\n runtimeInput,\n }: {\n readonly context: AgentAfterStepContext;\n readonly runtimeInput: RuntimeInputState;\n }\n): Promise<boolean> {\n const handlers = pluginHandlers(lifecycle, \"step.after\");\n if (handlers.length === 0) {\n return false;\n }\n\n const scope = lifecycle.createScope(context.signal);\n const settlements = await runWithAgentPluginScope(scope, () =>\n Promise.allSettled(\n handlers.map((handler) =>\n Promise.resolve().then(() =>\n handler({\n history: context.history,\n overlay: lifecycle.overlaySession,\n result: context.result,\n sessionKey: lifecycle.sessionKey,\n signal: context.signal,\n steer: (input) => lifecycle.steerCurrentRun(runtimeInput, input),\n stepIndex: context.stepIndex,\n type: \"step.after\",\n })\n )\n )\n )\n );\n await logPluginHandlerRejections(lifecycle, \"step.after\", settlements);\n return true;\n}\n\nexport async function runPluginAfterTurnHandlers(\n lifecycle: AgentSessionLifecycle,\n {\n input,\n result,\n signal,\n }: {\n readonly input: UserInput;\n readonly result: AgentLoopResult;\n readonly signal: AbortSignal;\n }\n): Promise<boolean> {\n const handlers = pluginHandlers(lifecycle, \"turn.after\");\n if (handlers.length === 0) {\n return false;\n }\n\n const overlay = () =>\n Promise.reject(\n new Error(\"Agent plugin overlay cannot be used after turn end.\")\n );\n const scope = { ...lifecycle.createScope(signal), overlay };\n const settlements = await runWithAgentPluginScope(scope, () =>\n Promise.allSettled(\n handlers.map((handler) =>\n Promise.resolve().then(() =>\n handler({\n history: lifecycle.history(),\n input,\n overlay,\n result,\n sessionKey: lifecycle.sessionKey,\n signal,\n steer: lifecycle.steerSession,\n type: \"turn.after\",\n })\n )\n )\n )\n );\n await logPluginHandlerRejections(lifecycle, \"turn.after\", settlements);\n return true;\n}\n\nfunction pluginHandlers(\n lifecycle: AgentSessionLifecycle,\n eventName: AgentPluginEventName\n) {\n return lifecycle.plugins?.eventHandlers.get(eventName) ?? [];\n}\n\nasync function logPluginHandlerRejections(\n lifecycle: AgentSessionLifecycle,\n eventName: AgentPluginEventName,\n settlements: readonly PromiseSettledResult<unknown>[]\n): Promise<void> {\n await Promise.all(\n settlements.map((settlement) => {\n if (settlement.status === \"fulfilled\") {\n return Promise.resolve();\n }\n\n return reportPluginHandlerRejection(lifecycle, {\n eventName,\n reason: settlement.reason,\n });\n })\n );\n}\n\nasync function reportPluginHandlerRejection(\n lifecycle: AgentSessionLifecycle,\n error: AgentPluginHandlerError\n): Promise<void> {\n const onPluginError = lifecycle.onPluginError;\n if (!onPluginError) {\n reportPluginHandlerError(error);\n return;\n }\n\n try {\n await onPluginError(error);\n } catch (handlerError) {\n reportPluginErrorHandlerError(handlerError);\n }\n}\n\nfunction reportPluginHandlerError({\n eventName,\n reason,\n}: AgentPluginHandlerError): void {\n console.error(\n `Agent plugin ${eventName} handler failed: ${errorKind(reason)}`\n );\n}\n\nfunction errorKind(reason: unknown): string {\n return reason instanceof Error ? reason.name : typeof reason;\n}\n\nfunction reportPluginErrorHandlerError(reason: unknown): void {\n console.error(`Agent plugin error handler failed: ${errorKind(reason)}`);\n}\n"],"mappings":"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"}
|
package/dist/session/mapping.js
CHANGED
|
@@ -19,7 +19,8 @@ function userTextContentToUserContent(text) {
|
|
|
19
19
|
function userMessageToModelMessage(input) {
|
|
20
20
|
return {
|
|
21
21
|
role: "user",
|
|
22
|
-
content: userMessageContentToUserContent(input.content)
|
|
22
|
+
content: userMessageContentToUserContent(input.content),
|
|
23
|
+
...input.metadata === void 0 ? {} : { providerOptions: structuredClone(input.metadata) }
|
|
23
24
|
};
|
|
24
25
|
}
|
|
25
26
|
function userMessageContentToUserContent(content) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mapping.js","names":[],"sources":["../../src/session/mapping.ts"],"sourcesContent":["import type {\n AssistantContent,\n AssistantModelMessage,\n ModelMessage,\n ToolModelMessage,\n UserModelMessage,\n} from \"ai\";\nimport type {\n AssistantReasoning,\n AssistantText,\n ToolCall,\n ToolResult,\n UserMessage,\n UserMessageContent,\n UserMessageContentPart,\n UserMessageFileData,\n UserText,\n UserTextContent,\n} from \"./events\";\nimport type { UserInput } from \"./input\";\n\ntype AssistantContentPart = Exclude<AssistantContent, string>[number];\ntype ToolContentPart = ToolModelMessage[\"content\"][number];\ntype ModelEvent = AssistantReasoning | AssistantText | ToolCall | ToolResult;\n\n// UserInput -> AI SDK UserModelMessage\nexport function userInputToModelMessage(input: UserInput): UserModelMessage {\n if (input.type === \"user-message\") {\n return userMessageToModelMessage(input);\n }\n\n return userTextToModelMessage(input);\n}\n\nexport function userTextToModelMessage(input: UserText): UserModelMessage {\n return { role: \"user\", content: userTextContentToUserContent(input.text) };\n}\n\nfunction userTextContentToUserContent(\n text: UserTextContent\n): UserModelMessage[\"content\"] {\n if (typeof text === \"string\") {\n return text;\n }\n\n return text.map((part) => ({ type: \"text\", text: part }));\n}\n\nexport function userMessageToModelMessage(\n input: UserMessage\n): UserModelMessage {\n return {\n role: \"user\",\n content: userMessageContentToUserContent(input.content),\n };\n}\n\nfunction userMessageContentToUserContent(\n content: UserMessageContent\n): Exclude<UserModelMessage[\"content\"], string> {\n return content.map(userMessageContentPartToUserContentPart);\n}\n\nfunction userMessageContentPartToUserContentPart(\n part: UserMessageContentPart\n): Exclude<UserModelMessage[\"content\"], string>[number] {\n if (part.type === \"text\") {\n return { type: \"text\", text: part.text };\n }\n\n if (part.type === \"image\") {\n return {\n type: \"file\",\n data: part.image,\n mediaType: part.mediaType ?? \"image\",\n };\n }\n\n return {\n type: \"file\",\n data: userMessageFileDataToFileData(part.data),\n mediaType: part.mediaType,\n ...(part.filename === undefined ? {} : { filename: part.filename }),\n };\n}\n\nfunction userMessageFileDataToFileData(\n data: UserMessageFileData\n): Extract<\n Exclude<UserModelMessage[\"content\"], string>[number],\n { type: \"file\" }\n>[\"data\"] {\n if (typeof data === \"string\") {\n return data;\n }\n\n if (data.type === \"url\") {\n return data.url;\n }\n\n if (data.type === \"data\") {\n return { type: \"data\", data: data.data };\n }\n\n if (data.type === \"reference\") {\n return { type: \"reference\", reference: { ...data.reference } };\n }\n\n return { type: \"text\", text: data.text };\n}\n\n// AI SDK ModelMessage -> public agent events\nexport function modelMessageToAgentEvents(message: ModelMessage): ModelEvent[] {\n if (message.role === \"assistant\") {\n return assistantReasoningFirstParts(assistantContentParts(message)).flatMap(\n assistantContentPartToEvents\n );\n }\n\n if (message.role === \"tool\") {\n return message.content.flatMap(toolContentPartToEvents);\n }\n\n return [];\n}\n\nfunction assistantContentParts(\n message: AssistantModelMessage\n): AssistantContentPart[] {\n return typeof message.content === \"string\"\n ? [{ type: \"text\", text: message.content }]\n : message.content;\n}\n\nfunction assistantReasoningFirstParts(\n parts: AssistantContentPart[]\n): AssistantContentPart[] {\n return [\n ...parts.filter((part) => part.type === \"reasoning\"),\n ...parts.filter((part) => part.type !== \"reasoning\"),\n ];\n}\n\nfunction assistantContentPartToEvents(\n part: AssistantContentPart\n): ModelEvent[] {\n if (part.type === \"text\") {\n return part.text ? [{ type: \"assistant-text\", text: part.text }] : [];\n }\n\n if (part.type === \"reasoning\") {\n return part.text ? [{ type: \"assistant-reasoning\", text: part.text }] : [];\n }\n\n if (part.type === \"tool-call\") {\n return [\n {\n type: \"tool-call\",\n input: part.input,\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n },\n ];\n }\n\n return [];\n}\n\nfunction toolContentPartToEvents(part: ToolContentPart): ModelEvent[] {\n if (part.type === \"tool-result\") {\n return toolResultPartToEvents(part);\n }\n\n return [];\n}\n\nfunction toolResultPartToEvents(part: {\n output: unknown;\n toolCallId: string;\n toolName: string;\n type: \"tool-result\";\n}): ModelEvent[] {\n return [\n {\n type: \"tool-result\",\n output: part.output,\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n },\n ];\n}\n"],"mappings":";AA0BA,SAAgB,wBAAwB,OAAoC;CAC1E,IAAI,MAAM,SAAS,gBACjB,OAAO,0BAA0B,KAAK;CAGxC,OAAO,uBAAuB,KAAK;AACrC;AAEA,SAAgB,uBAAuB,OAAmC;CACxE,OAAO;EAAE,MAAM;EAAQ,SAAS,6BAA6B,MAAM,IAAI;CAAE;AAC3E;AAEA,SAAS,6BACP,MAC6B;CAC7B,IAAI,OAAO,SAAS,UAClB,OAAO;CAGT,OAAO,KAAK,KAAK,UAAU;EAAE,MAAM;EAAQ,MAAM;CAAK,EAAE;AAC1D;AAEA,SAAgB,0BACd,OACkB;CAClB,OAAO;EACL,MAAM;EACN,SAAS,gCAAgC,MAAM,OAAO;
|
|
1
|
+
{"version":3,"file":"mapping.js","names":[],"sources":["../../src/session/mapping.ts"],"sourcesContent":["import type {\n AssistantContent,\n AssistantModelMessage,\n ModelMessage,\n ToolModelMessage,\n UserModelMessage,\n} from \"ai\";\nimport type {\n AssistantReasoning,\n AssistantText,\n ToolCall,\n ToolResult,\n UserMessage,\n UserMessageContent,\n UserMessageContentPart,\n UserMessageFileData,\n UserText,\n UserTextContent,\n} from \"./events\";\nimport type { UserInput } from \"./input\";\n\ntype AssistantContentPart = Exclude<AssistantContent, string>[number];\ntype ToolContentPart = ToolModelMessage[\"content\"][number];\ntype ModelEvent = AssistantReasoning | AssistantText | ToolCall | ToolResult;\n\n// UserInput -> AI SDK UserModelMessage\nexport function userInputToModelMessage(input: UserInput): UserModelMessage {\n if (input.type === \"user-message\") {\n return userMessageToModelMessage(input);\n }\n\n return userTextToModelMessage(input);\n}\n\nexport function userTextToModelMessage(input: UserText): UserModelMessage {\n return { role: \"user\", content: userTextContentToUserContent(input.text) };\n}\n\nfunction userTextContentToUserContent(\n text: UserTextContent\n): UserModelMessage[\"content\"] {\n if (typeof text === \"string\") {\n return text;\n }\n\n return text.map((part) => ({ type: \"text\", text: part }));\n}\n\nexport function userMessageToModelMessage(\n input: UserMessage\n): UserModelMessage {\n return {\n role: \"user\",\n content: userMessageContentToUserContent(input.content),\n ...(input.metadata === undefined\n ? {}\n : { providerOptions: structuredClone(input.metadata) }),\n };\n}\n\nfunction userMessageContentToUserContent(\n content: UserMessageContent\n): Exclude<UserModelMessage[\"content\"], string> {\n return content.map(userMessageContentPartToUserContentPart);\n}\n\nfunction userMessageContentPartToUserContentPart(\n part: UserMessageContentPart\n): Exclude<UserModelMessage[\"content\"], string>[number] {\n if (part.type === \"text\") {\n return { type: \"text\", text: part.text };\n }\n\n if (part.type === \"image\") {\n return {\n type: \"file\",\n data: part.image,\n mediaType: part.mediaType ?? \"image\",\n };\n }\n\n return {\n type: \"file\",\n data: userMessageFileDataToFileData(part.data),\n mediaType: part.mediaType,\n ...(part.filename === undefined ? {} : { filename: part.filename }),\n };\n}\n\nfunction userMessageFileDataToFileData(\n data: UserMessageFileData\n): Extract<\n Exclude<UserModelMessage[\"content\"], string>[number],\n { type: \"file\" }\n>[\"data\"] {\n if (typeof data === \"string\") {\n return data;\n }\n\n if (data.type === \"url\") {\n return data.url;\n }\n\n if (data.type === \"data\") {\n return { type: \"data\", data: data.data };\n }\n\n if (data.type === \"reference\") {\n return { type: \"reference\", reference: { ...data.reference } };\n }\n\n return { type: \"text\", text: data.text };\n}\n\n// AI SDK ModelMessage -> public agent events\nexport function modelMessageToAgentEvents(message: ModelMessage): ModelEvent[] {\n if (message.role === \"assistant\") {\n return assistantReasoningFirstParts(assistantContentParts(message)).flatMap(\n assistantContentPartToEvents\n );\n }\n\n if (message.role === \"tool\") {\n return message.content.flatMap(toolContentPartToEvents);\n }\n\n return [];\n}\n\nfunction assistantContentParts(\n message: AssistantModelMessage\n): AssistantContentPart[] {\n return typeof message.content === \"string\"\n ? [{ type: \"text\", text: message.content }]\n : message.content;\n}\n\nfunction assistantReasoningFirstParts(\n parts: AssistantContentPart[]\n): AssistantContentPart[] {\n return [\n ...parts.filter((part) => part.type === \"reasoning\"),\n ...parts.filter((part) => part.type !== \"reasoning\"),\n ];\n}\n\nfunction assistantContentPartToEvents(\n part: AssistantContentPart\n): ModelEvent[] {\n if (part.type === \"text\") {\n return part.text ? [{ type: \"assistant-text\", text: part.text }] : [];\n }\n\n if (part.type === \"reasoning\") {\n return part.text ? [{ type: \"assistant-reasoning\", text: part.text }] : [];\n }\n\n if (part.type === \"tool-call\") {\n return [\n {\n type: \"tool-call\",\n input: part.input,\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n },\n ];\n }\n\n return [];\n}\n\nfunction toolContentPartToEvents(part: ToolContentPart): ModelEvent[] {\n if (part.type === \"tool-result\") {\n return toolResultPartToEvents(part);\n }\n\n return [];\n}\n\nfunction toolResultPartToEvents(part: {\n output: unknown;\n toolCallId: string;\n toolName: string;\n type: \"tool-result\";\n}): ModelEvent[] {\n return [\n {\n type: \"tool-result\",\n output: part.output,\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n },\n ];\n}\n"],"mappings":"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"}
|