@minpeter/pss-runtime 0.1.0-next.1 → 0.1.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/README.md +169 -28
  2. package/dist/agent-child-runs.js +16 -0
  3. package/dist/agent-child-runs.js.map +1 -0
  4. package/dist/agent-host-capabilities.js +9 -0
  5. package/dist/agent-host-capabilities.js.map +1 -0
  6. package/dist/agent-host-session-store.js +12 -0
  7. package/dist/agent-host-session-store.js.map +1 -0
  8. package/dist/agent-loop.js +58 -28
  9. package/dist/agent-loop.js.map +1 -1
  10. package/dist/agent-namespace.js +8 -1
  11. package/dist/agent-namespace.js.map +1 -1
  12. package/dist/agent-options.d.ts +35 -0
  13. package/dist/agent-options.js +16 -0
  14. package/dist/agent-options.js.map +1 -0
  15. package/dist/agent-resume.js +143 -0
  16. package/dist/agent-resume.js.map +1 -0
  17. package/dist/agent-session-entry.d.ts +13 -0
  18. package/dist/agent-validation.js +2 -2
  19. package/dist/agent-validation.js.map +1 -1
  20. package/dist/agent.d.ts +5 -41
  21. package/dist/agent.js +81 -49
  22. package/dist/agent.js.map +1 -1
  23. package/dist/execution/host.js +14 -0
  24. package/dist/execution/host.js.map +1 -0
  25. package/dist/execution/index.d.ts +4 -0
  26. package/dist/execution/index.js +3 -0
  27. package/dist/execution/memory-notifications.js +54 -0
  28. package/dist/execution/memory-notifications.js.map +1 -0
  29. package/dist/execution/memory-state.js +34 -0
  30. package/dist/execution/memory-state.js.map +1 -0
  31. package/dist/execution/memory-store.js +203 -0
  32. package/dist/execution/memory-store.js.map +1 -0
  33. package/dist/execution/memory.d.ts +7 -0
  34. package/dist/execution/memory.js +28 -0
  35. package/dist/execution/memory.js.map +1 -0
  36. package/dist/execution/run.js +55 -0
  37. package/dist/execution/run.js.map +1 -0
  38. package/dist/execution/types.d.ts +155 -0
  39. package/dist/index.d.ts +8 -5
  40. package/dist/llm-tool-execution.d.ts +35 -0
  41. package/dist/llm-tool-execution.js +126 -0
  42. package/dist/llm-tool-execution.js.map +1 -0
  43. package/dist/llm.d.ts +11 -15
  44. package/dist/llm.js +5 -3
  45. package/dist/llm.js.map +1 -1
  46. package/dist/plugins.d.ts +20 -0
  47. package/dist/plugins.js +14 -0
  48. package/dist/plugins.js.map +1 -0
  49. package/dist/session/events.d.ts +3 -0
  50. package/dist/session/runtime-input.js +5 -23
  51. package/dist/session/runtime-input.js.map +1 -1
  52. package/dist/session/session-errors.js +1 -6
  53. package/dist/session/session-errors.js.map +1 -1
  54. package/dist/session/session-events.js +59 -0
  55. package/dist/session/session-events.js.map +1 -0
  56. package/dist/session/session-execution.js +88 -0
  57. package/dist/session/session-execution.js.map +1 -0
  58. package/dist/session/session-notification.js +58 -0
  59. package/dist/session/session-notification.js.map +1 -0
  60. package/dist/session/session-runtime-drain.js +2 -2
  61. package/dist/session/session-runtime-drain.js.map +1 -1
  62. package/dist/session/session-turn-processor.js +135 -0
  63. package/dist/session/session-turn-processor.js.map +1 -0
  64. package/dist/session/session.js +73 -101
  65. package/dist/session/session.js.map +1 -1
  66. package/dist/session/snapshot.js.map +1 -1
  67. package/dist/subagent-background-child-run-state.js +51 -0
  68. package/dist/subagent-background-child-run-state.js.map +1 -0
  69. package/dist/subagent-background-child-run.js +103 -0
  70. package/dist/subagent-background-child-run.js.map +1 -0
  71. package/dist/subagent-background-in-process.js +98 -0
  72. package/dist/subagent-background-in-process.js.map +1 -0
  73. package/dist/subagent-background-notification-inbox.js +106 -0
  74. package/dist/subagent-background-notification-inbox.js.map +1 -0
  75. package/dist/subagent-background-notify.js +136 -0
  76. package/dist/subagent-background-notify.js.map +1 -0
  77. package/dist/subagent-background-resume-group.js +99 -0
  78. package/dist/subagent-background-resume-group.js.map +1 -0
  79. package/dist/subagent-background-runner.js +115 -0
  80. package/dist/subagent-background-runner.js.map +1 -0
  81. package/dist/subagent-background-schedule.js +43 -0
  82. package/dist/subagent-background-schedule.js.map +1 -0
  83. package/dist/subagent-child-run.js +68 -0
  84. package/dist/subagent-child-run.js.map +1 -0
  85. package/dist/subagent-job-cancel.js +60 -4
  86. package/dist/subagent-job-cancel.js.map +1 -1
  87. package/dist/subagent-job-observer.js +19 -0
  88. package/dist/subagent-job-observer.js.map +1 -0
  89. package/dist/subagent-job-output.js +28 -4
  90. package/dist/subagent-job-output.js.map +1 -1
  91. package/dist/subagent-job-state.js +66 -0
  92. package/dist/subagent-job-state.js.map +1 -0
  93. package/dist/subagent-jobs.js +78 -133
  94. package/dist/subagent-jobs.js.map +1 -1
  95. package/dist/subagent-run.js +4 -4
  96. package/dist/subagent-run.js.map +1 -1
  97. package/dist/subagents.js +68 -35
  98. package/dist/subagents.js.map +1 -1
  99. package/package.json +11 -1
  100. package/dist/hooks.d.ts +0 -32
  101. /package/dist/session/{runtime-input.d.ts → session-execution.d.ts} +0 -0
@@ -0,0 +1,126 @@
1
+ //#region src/llm-tool-execution.ts
2
+ const toolCallIdPrefix = "call_";
3
+ const publicToolCallIdPattern = /^call[-_]/;
4
+ var ToolExecutionNeedsRecoveryError = class extends Error {
5
+ idempotencyKey;
6
+ status = "needs-recovery";
7
+ toolCallId;
8
+ toolName;
9
+ constructor(checkpoint) {
10
+ super(`Tool ${checkpoint.toolName} requires manual recovery for ${checkpoint.idempotencyKey}`);
11
+ this.idempotencyKey = checkpoint.idempotencyKey;
12
+ this.name = "ToolExecutionNeedsRecoveryError";
13
+ this.toolCallId = checkpoint.toolCallId;
14
+ this.toolName = checkpoint.toolName;
15
+ }
16
+ };
17
+ function persistedToolExecutionCheckpoint(checkpoint) {
18
+ return {
19
+ attempt: checkpoint.attempt,
20
+ idempotencyKey: checkpoint.idempotencyKey,
21
+ policy: checkpoint.policy,
22
+ toolCallId: checkpoint.toolCallId,
23
+ toolName: checkpoint.toolName
24
+ };
25
+ }
26
+ function normalizeToolCallIds(tools, toolCallIds, toolExecution) {
27
+ if (!tools) return;
28
+ return Object.fromEntries(Object.entries(tools).map(([name, candidate]) => [name, wrapToolExecute(name, candidate, toolCallIds, toolExecution)]));
29
+ }
30
+ function rewriteMessageToolCallIds(message, toolCallIds) {
31
+ if (message.role === "assistant") return rewriteAssistantToolCallIds(message, toolCallIds);
32
+ if (message.role === "tool") return rewriteToolResultCallIds(message, toolCallIds);
33
+ return message;
34
+ }
35
+ function wrapToolExecute(toolName, toolDefinition, toolCallIds, toolExecution) {
36
+ if (!isExecutableToolDefinition(toolDefinition)) return toolDefinition;
37
+ const { execute } = toolDefinition;
38
+ if (!toolExecution) return {
39
+ ...toolDefinition,
40
+ execute: (input, options) => execute(input, {
41
+ ...options,
42
+ toolCallId: publicToolCallId(options.toolCallId, toolCallIds)
43
+ })
44
+ };
45
+ return {
46
+ ...toolDefinition,
47
+ execute: async (input, options) => {
48
+ const toolCallId = publicToolCallId(options.toolCallId, toolCallIds);
49
+ const checkpoint = toolCheckpoint({
50
+ input,
51
+ policy: toolRetryPolicy(toolDefinition),
52
+ toolCallId,
53
+ toolExecution,
54
+ toolName
55
+ });
56
+ if ((await toolExecution.beforeTool?.(checkpoint))?.status === "needs-recovery") throw new ToolExecutionNeedsRecoveryError(checkpoint);
57
+ const output = await execute(input, {
58
+ ...options,
59
+ attempt: checkpoint.attempt,
60
+ idempotencyKey: checkpoint.idempotencyKey,
61
+ retryPolicy: checkpoint.policy,
62
+ ...options.abortSignal === void 0 ? {} : { signal: options.abortSignal },
63
+ toolCallId
64
+ });
65
+ await toolExecution.afterTool?.({
66
+ ...checkpoint,
67
+ output
68
+ });
69
+ return output;
70
+ }
71
+ };
72
+ }
73
+ function isExecutableToolDefinition(value) {
74
+ return typeof value === "object" && value !== null && "execute" in value && typeof value.execute === "function";
75
+ }
76
+ function toolCheckpoint({ input, policy, toolCallId, toolExecution, toolName }) {
77
+ return {
78
+ attempt: toolExecution.attempt,
79
+ idempotencyKey: `${toolExecution.runId}:${toolCallId}`,
80
+ input,
81
+ policy,
82
+ toolCallId,
83
+ toolName
84
+ };
85
+ }
86
+ function toolRetryPolicy(toolDefinition) {
87
+ if (typeof toolDefinition === "object" && toolDefinition !== null && "retryPolicy" in toolDefinition && isToolRetryPolicy(toolDefinition.retryPolicy)) return toolDefinition.retryPolicy;
88
+ return "manual-recovery";
89
+ }
90
+ function isToolRetryPolicy(value) {
91
+ return value === "idempotent" || value === "manual-recovery" || value === "pure";
92
+ }
93
+ function rewriteAssistantToolCallIds(message, toolCallIds) {
94
+ if (typeof message.content === "string") return message;
95
+ return {
96
+ ...message,
97
+ content: message.content.map((part) => "toolCallId" in part ? {
98
+ ...part,
99
+ toolCallId: publicToolCallId(part.toolCallId, toolCallIds)
100
+ } : part)
101
+ };
102
+ }
103
+ function rewriteToolResultCallIds(message, toolCallIds) {
104
+ return {
105
+ ...message,
106
+ content: message.content.map((part) => "toolCallId" in part ? {
107
+ ...part,
108
+ toolCallId: publicToolCallId(part.toolCallId, toolCallIds)
109
+ } : part)
110
+ };
111
+ }
112
+ function publicToolCallId(toolCallId, toolCallIds) {
113
+ if (publicToolCallIdPattern.test(toolCallId)) return toolCallId;
114
+ const existing = toolCallIds.get(toolCallId);
115
+ if (existing) return existing;
116
+ const generated = createToolCallId();
117
+ toolCallIds.set(toolCallId, generated);
118
+ return generated;
119
+ }
120
+ function createToolCallId() {
121
+ return `${toolCallIdPrefix}${crypto.randomUUID().replaceAll("-", "")}`;
122
+ }
123
+ //#endregion
124
+ export { ToolExecutionNeedsRecoveryError, normalizeToolCallIds, persistedToolExecutionCheckpoint, rewriteMessageToolCallIds };
125
+
126
+ //# sourceMappingURL=llm-tool-execution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-tool-execution.js","names":[],"sources":["../src/llm-tool-execution.ts"],"sourcesContent":["import type { AssistantModelMessage, ToolModelMessage, ToolSet } from \"ai\";\nimport type { RuntimeLlmOutput } from \"./llm\";\n\nconst toolCallIdPrefix = \"call_\";\nconst publicToolCallIdPattern = /^call[-_]/;\n\ntype RuntimeLlmMessage = RuntimeLlmOutput[number];\n\nexport type RuntimeToolRetryPolicy = \"idempotent\" | \"manual-recovery\" | \"pure\";\n\nexport interface RuntimeToolExecutionCheckpointMetadata {\n readonly attempt: number;\n readonly idempotencyKey: string;\n readonly policy: RuntimeToolRetryPolicy;\n readonly toolCallId: string;\n readonly toolName: string;\n}\n\nexport interface RuntimeToolExecutionCheckpoint\n extends RuntimeToolExecutionCheckpointMetadata {\n readonly input: unknown;\n}\n\nexport type RuntimePersistedToolExecutionCheckpoint =\n RuntimeToolExecutionCheckpointMetadata;\n\nexport type RuntimeToolExecutionDecision =\n | { readonly status: \"needs-recovery\" }\n | undefined;\n\nexport interface RuntimeToolExecutionContext {\n readonly afterTool?: (\n checkpoint: RuntimeToolExecutionCheckpoint & { readonly output: unknown }\n ) => Promise<void> | void;\n readonly attempt: number;\n readonly beforeTool?: (\n checkpoint: RuntimeToolExecutionCheckpoint\n ) => Promise<RuntimeToolExecutionDecision> | RuntimeToolExecutionDecision;\n readonly runId: string;\n}\n\nexport class ToolExecutionNeedsRecoveryError extends Error {\n readonly idempotencyKey: string;\n readonly status = \"needs-recovery\";\n readonly toolCallId: string;\n readonly toolName: string;\n\n constructor(checkpoint: RuntimeToolExecutionCheckpointMetadata) {\n super(\n `Tool ${checkpoint.toolName} requires manual recovery for ${checkpoint.idempotencyKey}`\n );\n this.idempotencyKey = checkpoint.idempotencyKey;\n this.name = \"ToolExecutionNeedsRecoveryError\";\n this.toolCallId = checkpoint.toolCallId;\n this.toolName = checkpoint.toolName;\n }\n}\n\nexport function persistedToolExecutionCheckpoint(\n checkpoint: RuntimeToolExecutionCheckpointMetadata\n): RuntimePersistedToolExecutionCheckpoint {\n return {\n attempt: checkpoint.attempt,\n idempotencyKey: checkpoint.idempotencyKey,\n policy: checkpoint.policy,\n toolCallId: checkpoint.toolCallId,\n toolName: checkpoint.toolName,\n };\n}\n\nexport function normalizeToolCallIds(\n tools: ToolSet | undefined,\n toolCallIds: Map<string, string>,\n toolExecution: RuntimeToolExecutionContext | undefined\n): ToolSet | undefined {\n if (!tools) {\n return;\n }\n\n return Object.fromEntries(\n Object.entries(tools).map(([name, candidate]) => [\n name,\n wrapToolExecute(name, candidate, toolCallIds, toolExecution),\n ])\n ) as ToolSet;\n}\n\nexport function rewriteMessageToolCallIds(\n message: RuntimeLlmMessage,\n toolCallIds: Map<string, string>\n): RuntimeLlmMessage {\n if (message.role === \"assistant\") {\n return rewriteAssistantToolCallIds(message, toolCallIds);\n }\n\n if (message.role === \"tool\") {\n return rewriteToolResultCallIds(message, toolCallIds);\n }\n\n return message;\n}\n\nfunction wrapToolExecute(\n toolName: string,\n toolDefinition: unknown,\n toolCallIds: Map<string, string>,\n toolExecution: RuntimeToolExecutionContext | undefined\n): unknown {\n if (!isExecutableToolDefinition(toolDefinition)) {\n return toolDefinition;\n }\n\n const { execute } = toolDefinition;\n if (!toolExecution) {\n return {\n ...toolDefinition,\n execute: (input: unknown, options: ToolExecutionOptionsLike) =>\n execute(input, {\n ...options,\n toolCallId: publicToolCallId(options.toolCallId, toolCallIds),\n }),\n };\n }\n\n return {\n ...toolDefinition,\n execute: async (input: unknown, options: ToolExecutionOptionsLike) => {\n const toolCallId = publicToolCallId(options.toolCallId, toolCallIds);\n const checkpoint = toolCheckpoint({\n input,\n policy: toolRetryPolicy(toolDefinition),\n toolCallId,\n toolExecution,\n toolName,\n });\n const decision = await toolExecution.beforeTool?.(checkpoint);\n if (decision?.status === \"needs-recovery\") {\n throw new ToolExecutionNeedsRecoveryError(checkpoint);\n }\n\n const output = await execute(input, {\n ...options,\n attempt: checkpoint.attempt,\n idempotencyKey: checkpoint.idempotencyKey,\n retryPolicy: checkpoint.policy,\n ...(options.abortSignal === undefined\n ? {}\n : { signal: options.abortSignal }),\n toolCallId,\n });\n await toolExecution.afterTool?.({ ...checkpoint, output });\n return output;\n },\n };\n}\n\nfunction isExecutableToolDefinition(value: unknown): value is {\n readonly execute: (\n input: unknown,\n options: RuntimeToolExecutionOptionsLike | ToolExecutionOptionsLike\n ) => unknown;\n} {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"execute\" in value &&\n typeof value.execute === \"function\"\n );\n}\n\ninterface ToolExecutionOptionsLike {\n readonly abortSignal?: AbortSignal;\n readonly toolCallId: string;\n}\n\ninterface RuntimeToolExecutionOptionsLike extends ToolExecutionOptionsLike {\n readonly attempt: number;\n readonly idempotencyKey: string;\n readonly retryPolicy: RuntimeToolRetryPolicy;\n readonly signal?: AbortSignal;\n}\n\nfunction toolCheckpoint({\n input,\n policy,\n toolCallId,\n toolExecution,\n toolName,\n}: {\n readonly input: unknown;\n readonly policy: RuntimeToolRetryPolicy;\n readonly toolCallId: string;\n readonly toolExecution: RuntimeToolExecutionContext;\n readonly toolName: string;\n}): RuntimeToolExecutionCheckpoint {\n return {\n attempt: toolExecution.attempt,\n idempotencyKey: `${toolExecution.runId}:${toolCallId}`,\n input,\n policy,\n toolCallId,\n toolName,\n };\n}\n\nfunction toolRetryPolicy(toolDefinition: unknown): RuntimeToolRetryPolicy {\n if (\n typeof toolDefinition === \"object\" &&\n toolDefinition !== null &&\n \"retryPolicy\" in toolDefinition &&\n isToolRetryPolicy(toolDefinition.retryPolicy)\n ) {\n return toolDefinition.retryPolicy;\n }\n\n return \"manual-recovery\";\n}\n\nfunction isToolRetryPolicy(value: unknown): value is RuntimeToolRetryPolicy {\n return (\n value === \"idempotent\" || value === \"manual-recovery\" || value === \"pure\"\n );\n}\n\nfunction rewriteAssistantToolCallIds(\n message: AssistantModelMessage,\n toolCallIds: Map<string, string>\n): AssistantModelMessage {\n if (typeof message.content === \"string\") {\n return message;\n }\n\n return {\n ...message,\n content: message.content.map((part) =>\n \"toolCallId\" in part\n ? {\n ...part,\n toolCallId: publicToolCallId(part.toolCallId, toolCallIds),\n }\n : part\n ),\n };\n}\n\nfunction rewriteToolResultCallIds(\n message: ToolModelMessage,\n toolCallIds: Map<string, string>\n): ToolModelMessage {\n return {\n ...message,\n content: message.content.map((part) =>\n \"toolCallId\" in part\n ? {\n ...part,\n toolCallId: publicToolCallId(part.toolCallId, toolCallIds),\n }\n : part\n ),\n };\n}\n\nfunction publicToolCallId(\n toolCallId: string,\n toolCallIds: Map<string, string>\n): string {\n if (publicToolCallIdPattern.test(toolCallId)) {\n return toolCallId;\n }\n\n const existing = toolCallIds.get(toolCallId);\n if (existing) {\n return existing;\n }\n\n const generated = createToolCallId();\n toolCallIds.set(toolCallId, generated);\n return generated;\n}\n\nfunction createToolCallId(): string {\n return `${toolCallIdPrefix}${crypto.randomUUID().replaceAll(\"-\", \"\")}`;\n}\n"],"mappings":";AAGA,MAAM,mBAAmB;AACzB,MAAM,0BAA0B;AAqChC,IAAa,kCAAb,cAAqD,MAAM;CACzD;CACA,SAAkB;CAClB;CACA;CAEA,YAAY,YAAoD;EAC9D,MACE,QAAQ,WAAW,SAAS,gCAAgC,WAAW,gBACzE;EACA,KAAK,iBAAiB,WAAW;EACjC,KAAK,OAAO;EACZ,KAAK,aAAa,WAAW;EAC7B,KAAK,WAAW,WAAW;CAC7B;AACF;AAEA,SAAgB,iCACd,YACyC;CACzC,OAAO;EACL,SAAS,WAAW;EACpB,gBAAgB,WAAW;EAC3B,QAAQ,WAAW;EACnB,YAAY,WAAW;EACvB,UAAU,WAAW;CACvB;AACF;AAEA,SAAgB,qBACd,OACA,aACA,eACqB;CACrB,IAAI,CAAC,OACH;CAGF,OAAO,OAAO,YACZ,OAAO,QAAQ,KAAK,EAAE,KAAK,CAAC,MAAM,eAAe,CAC/C,MACA,gBAAgB,MAAM,WAAW,aAAa,aAAa,CAC7D,CAAC,CACH;AACF;AAEA,SAAgB,0BACd,SACA,aACmB;CACnB,IAAI,QAAQ,SAAS,aACnB,OAAO,4BAA4B,SAAS,WAAW;CAGzD,IAAI,QAAQ,SAAS,QACnB,OAAO,yBAAyB,SAAS,WAAW;CAGtD,OAAO;AACT;AAEA,SAAS,gBACP,UACA,gBACA,aACA,eACS;CACT,IAAI,CAAC,2BAA2B,cAAc,GAC5C,OAAO;CAGT,MAAM,EAAE,YAAY;CACpB,IAAI,CAAC,eACH,OAAO;EACL,GAAG;EACH,UAAU,OAAgB,YACxB,QAAQ,OAAO;GACb,GAAG;GACH,YAAY,iBAAiB,QAAQ,YAAY,WAAW;EAC9D,CAAC;CACL;CAGF,OAAO;EACL,GAAG;EACH,SAAS,OAAO,OAAgB,YAAsC;GACpE,MAAM,aAAa,iBAAiB,QAAQ,YAAY,WAAW;GACnE,MAAM,aAAa,eAAe;IAChC;IACA,QAAQ,gBAAgB,cAAc;IACtC;IACA;IACA;GACF,CAAC;GAED,KAAI,MADmB,cAAc,aAAa,UAAU,IAC9C,WAAW,kBACvB,MAAM,IAAI,gCAAgC,UAAU;GAGtD,MAAM,SAAS,MAAM,QAAQ,OAAO;IAClC,GAAG;IACH,SAAS,WAAW;IACpB,gBAAgB,WAAW;IAC3B,aAAa,WAAW;IACxB,GAAI,QAAQ,gBAAgB,KAAA,IACxB,CAAC,IACD,EAAE,QAAQ,QAAQ,YAAY;IAClC;GACF,CAAC;GACD,MAAM,cAAc,YAAY;IAAE,GAAG;IAAY;GAAO,CAAC;GACzD,OAAO;EACT;CACF;AACF;AAEA,SAAS,2BAA2B,OAKlC;CACA,OACE,OAAO,UAAU,YACjB,UAAU,QACV,aAAa,SACb,OAAO,MAAM,YAAY;AAE7B;AAcA,SAAS,eAAe,EACtB,OACA,QACA,YACA,eACA,YAOiC;CACjC,OAAO;EACL,SAAS,cAAc;EACvB,gBAAgB,GAAG,cAAc,MAAM,GAAG;EAC1C;EACA;EACA;EACA;CACF;AACF;AAEA,SAAS,gBAAgB,gBAAiD;CACxE,IACE,OAAO,mBAAmB,YAC1B,mBAAmB,QACnB,iBAAiB,kBACjB,kBAAkB,eAAe,WAAW,GAE5C,OAAO,eAAe;CAGxB,OAAO;AACT;AAEA,SAAS,kBAAkB,OAAiD;CAC1E,OACE,UAAU,gBAAgB,UAAU,qBAAqB,UAAU;AAEvE;AAEA,SAAS,4BACP,SACA,aACuB;CACvB,IAAI,OAAO,QAAQ,YAAY,UAC7B,OAAO;CAGT,OAAO;EACL,GAAG;EACH,SAAS,QAAQ,QAAQ,KAAK,SAC5B,gBAAgB,OACZ;GACE,GAAG;GACH,YAAY,iBAAiB,KAAK,YAAY,WAAW;EAC3D,IACA,IACN;CACF;AACF;AAEA,SAAS,yBACP,SACA,aACkB;CAClB,OAAO;EACL,GAAG;EACH,SAAS,QAAQ,QAAQ,KAAK,SAC5B,gBAAgB,OACZ;GACE,GAAG;GACH,YAAY,iBAAiB,KAAK,YAAY,WAAW;EAC3D,IACA,IACN;CACF;AACF;AAEA,SAAS,iBACP,YACA,aACQ;CACR,IAAI,wBAAwB,KAAK,UAAU,GACzC,OAAO;CAGT,MAAM,WAAW,YAAY,IAAI,UAAU;CAC3C,IAAI,UACF,OAAO;CAGT,MAAM,YAAY,iBAAiB;CACnC,YAAY,IAAI,YAAY,SAAS;CACrC,OAAO;AACT;AAEA,SAAS,mBAA2B;CAClC,OAAO,GAAG,mBAAmB,OAAO,WAAW,EAAE,WAAW,KAAK,EAAE;AACrE"}
package/dist/llm.d.ts CHANGED
@@ -1,32 +1,28 @@
1
- import { LanguageModel, ModelMessage, Tool, ToolExecutionOptions, ToolSet, generateText } from "ai";
1
+ import { RuntimeToolExecutionCheckpoint, RuntimeToolExecutionCheckpointMetadata, RuntimeToolExecutionContext, RuntimeToolExecutionDecision, RuntimeToolRetryPolicy } from "./llm-tool-execution.js";
2
+ import { LanguageModel, ModelMessage, ToolChoice, ToolSet, generateText } from "ai";
2
3
 
3
4
  //#region src/llm.d.ts
4
- type AgentToolExecutionOptions = ToolExecutionOptions<unknown>;
5
- type AgentToolExecute = NonNullable<Tool["execute"]>;
6
- type AgentToolChoice = "auto" | "required";
7
- type LlmOutput = Awaited<ReturnType<typeof generateText>>["responseMessages"];
8
- type LlmOutputPart = LlmOutput[number];
9
- interface LlmContext {
5
+ type AgentToolChoice = ToolChoice<ToolSet>;
6
+ type RuntimeLlmOutput = Awaited<ReturnType<typeof generateText>>["responseMessages"];
7
+ type RuntimeLlmOutputPart = RuntimeLlmOutput[number];
8
+ interface RuntimeLlmContext {
10
9
  history: readonly ModelMessage[];
11
10
  signal: AbortSignal;
11
+ toolExecution?: RuntimeToolExecutionContext;
12
12
  }
13
- type Llm = (context: LlmContext) => Promise<LlmOutput>;
14
- interface CreateLlmOptions {
13
+ type RuntimeLlm = (context: RuntimeLlmContext) => Promise<RuntimeLlmOutput>;
14
+ interface RuntimeCreateLlmOptions {
15
15
  instructions?: string;
16
16
  model: LanguageModel;
17
17
  toolChoice?: AgentToolChoice;
18
18
  tools?: ToolSet;
19
19
  }
20
- type RuntimeCreateLlmOptions = CreateLlmOptions;
21
- type RuntimeLlm = Llm;
22
- type RuntimeLlmContext = LlmContext;
23
- type RuntimeLlmOutput = LlmOutput;
24
20
  declare function createLlm({
25
21
  model,
26
22
  instructions,
27
23
  toolChoice,
28
24
  tools
29
- }: CreateLlmOptions): Llm;
25
+ }: RuntimeCreateLlmOptions): RuntimeLlm;
30
26
  //#endregion
31
- export { AgentToolChoice, AgentToolExecute, AgentToolExecutionOptions, Llm, LlmOutputPart, RuntimeCreateLlmOptions, RuntimeLlm, RuntimeLlmContext, RuntimeLlmOutput, createLlm };
27
+ export { AgentToolChoice, RuntimeCreateLlmOptions, RuntimeLlm, RuntimeLlmContext, RuntimeLlmOutput, RuntimeLlmOutputPart, createLlm };
32
28
  //# sourceMappingURL=llm.d.ts.map
package/dist/llm.js CHANGED
@@ -1,16 +1,18 @@
1
+ import { normalizeToolCallIds, rewriteMessageToolCallIds } from "./llm-tool-execution.js";
1
2
  import { generateText } from "ai";
2
3
  //#region src/llm.ts
3
4
  function createLlm({ model, instructions, toolChoice, tools }) {
4
- return async ({ history, signal }) => {
5
+ return async ({ history, signal, toolExecution }) => {
6
+ const toolCallIds = /* @__PURE__ */ new Map();
5
7
  const { responseMessages } = await generateText({
6
8
  abortSignal: signal,
7
9
  instructions,
8
10
  messages: [...history],
9
11
  model,
10
12
  toolChoice,
11
- tools
13
+ tools: normalizeToolCallIds(tools, toolCallIds, toolExecution)
12
14
  });
13
- return responseMessages;
15
+ return responseMessages.map((message) => rewriteMessageToolCallIds(message, toolCallIds));
14
16
  };
15
17
  }
16
18
  //#endregion
package/dist/llm.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"llm.js","names":[],"sources":["../src/llm.ts"],"sourcesContent":["import type {\n LanguageModel,\n ModelMessage,\n Tool,\n ToolExecutionOptions,\n ToolSet,\n} from \"ai\";\nimport { generateText } from \"ai\";\n\nexport type AgentToolExecutionOptions = ToolExecutionOptions<unknown>;\nexport type AgentToolExecute = NonNullable<Tool[\"execute\"]>;\nexport type AgentToolChoice = \"auto\" | \"required\";\nexport type LlmOutput = Awaited<\n ReturnType<typeof generateText>\n>[\"responseMessages\"];\nexport type LlmOutputPart = LlmOutput[number];\n\nexport interface LlmContext {\n history: readonly ModelMessage[];\n signal: AbortSignal;\n}\n\nexport type Llm = (context: LlmContext) => Promise<LlmOutput>;\n\nexport interface CreateLlmOptions {\n instructions?: string;\n model: LanguageModel;\n toolChoice?: AgentToolChoice;\n tools?: ToolSet;\n}\n\nexport type RuntimeCreateLlmOptions = CreateLlmOptions;\nexport type RuntimeLlm = Llm;\nexport type RuntimeLlmContext = LlmContext;\nexport type RuntimeLlmOutput = LlmOutput;\n\nexport function createLlm({\n model,\n instructions,\n toolChoice,\n tools,\n}: CreateLlmOptions): Llm {\n return async ({ history, signal }) => {\n const { responseMessages } = await generateText({\n abortSignal: signal,\n instructions,\n messages: [...history],\n model,\n toolChoice,\n tools,\n });\n\n return responseMessages;\n };\n}\n"],"mappings":";;AAoCA,SAAgB,UAAU,EACxB,OACA,cACA,YACA,SACwB;CACxB,OAAO,OAAO,EAAE,SAAS,aAAa;EACpC,MAAM,EAAE,qBAAqB,MAAM,aAAa;GAC9C,aAAa;GACb;GACA,UAAU,CAAC,GAAG,OAAO;GACrB;GACA;GACA;EACF,CAAC;EAED,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"llm.js","names":[],"sources":["../src/llm.ts"],"sourcesContent":["import type { LanguageModel, ModelMessage, ToolChoice, ToolSet } from \"ai\";\nimport { generateText } from \"ai\";\nimport type { RuntimeToolExecutionContext } from \"./llm-tool-execution\";\nimport {\n normalizeToolCallIds,\n rewriteMessageToolCallIds,\n} from \"./llm-tool-execution\";\n\nexport type {\n RuntimePersistedToolExecutionCheckpoint,\n RuntimeToolExecutionCheckpoint,\n RuntimeToolExecutionCheckpointMetadata,\n RuntimeToolExecutionContext,\n RuntimeToolExecutionDecision,\n RuntimeToolRetryPolicy,\n} from \"./llm-tool-execution\";\n\nexport type AgentToolChoice = ToolChoice<ToolSet>;\nexport type RuntimeLlmOutput = Awaited<\n ReturnType<typeof generateText>\n>[\"responseMessages\"];\nexport type RuntimeLlmOutputPart = RuntimeLlmOutput[number];\n\nexport interface RuntimeLlmContext {\n history: readonly ModelMessage[];\n signal: AbortSignal;\n toolExecution?: RuntimeToolExecutionContext;\n}\n\nexport type RuntimeLlm = (\n context: RuntimeLlmContext\n) => Promise<RuntimeLlmOutput>;\n\nexport interface RuntimeCreateLlmOptions {\n instructions?: string;\n model: LanguageModel;\n toolChoice?: AgentToolChoice;\n tools?: ToolSet;\n}\n\nexport function createLlm({\n model,\n instructions,\n toolChoice,\n tools,\n}: RuntimeCreateLlmOptions): RuntimeLlm {\n return async ({ history, signal, toolExecution }) => {\n const toolCallIds = new Map<string, string>();\n const { responseMessages } = await generateText({\n abortSignal: signal,\n instructions,\n messages: [...history],\n model,\n toolChoice,\n tools: normalizeToolCallIds(tools, toolCallIds, toolExecution),\n });\n\n return responseMessages.map((message) =>\n rewriteMessageToolCallIds(message, toolCallIds)\n );\n };\n}\n"],"mappings":";;;AAwCA,SAAgB,UAAU,EACxB,OACA,cACA,YACA,SACsC;CACtC,OAAO,OAAO,EAAE,SAAS,QAAQ,oBAAoB;EACnD,MAAM,8BAAc,IAAI,IAAoB;EAC5C,MAAM,EAAE,qBAAqB,MAAM,aAAa;GAC9C,aAAa;GACb;GACA,UAAU,CAAC,GAAG,OAAO;GACrB;GACA;GACA,OAAO,qBAAqB,OAAO,aAAa,aAAa;EAC/D,CAAC;EAED,OAAO,iBAAiB,KAAK,YAC3B,0BAA0B,SAAS,WAAW,CAChD;CACF;AACF"}
@@ -0,0 +1,20 @@
1
+ import { RuntimeLlmContext } from "./llm.js";
2
+ import { AgentEvent } from "./session/events.js";
3
+
4
+ //#region src/plugins.d.ts
5
+ type MaybePromise<T> = PromiseLike<T> | T;
6
+ type AgentEventHistory = RuntimeLlmContext["history"];
7
+ interface AgentEventContext {
8
+ readonly event: AgentEvent;
9
+ readonly history: AgentEventHistory;
10
+ readonly signal?: AbortSignal;
11
+ }
12
+ interface AgentPlugin {
13
+ readonly events?: {
14
+ readonly on?: (context: AgentEventContext) => MaybePromise<void>;
15
+ };
16
+ readonly name?: string;
17
+ }
18
+ //#endregion
19
+ export { AgentEventContext, AgentPlugin };
20
+ //# sourceMappingURL=plugins.d.ts.map
@@ -0,0 +1,14 @@
1
+ //#region src/plugins.ts
2
+ function runEventPlugins(plugins, context) {
3
+ return runPluginHandlers(plugins, (plugin) => plugin.events?.on, context);
4
+ }
5
+ async function runPluginHandlers(plugins, handlerFor, context) {
6
+ for (const plugin of plugins) {
7
+ const handler = handlerFor(plugin);
8
+ if (handler) await handler(context);
9
+ }
10
+ }
11
+ //#endregion
12
+ export { runEventPlugins };
13
+
14
+ //# sourceMappingURL=plugins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins.js","names":[],"sources":["../src/plugins.ts"],"sourcesContent":["import type { RuntimeLlmContext } from \"./llm\";\nimport type { AgentEvent } from \"./session/events\";\n\ntype MaybePromise<T> = PromiseLike<T> | T;\ntype AgentEventHistory = RuntimeLlmContext[\"history\"];\n\nexport interface AgentEventContext {\n readonly event: AgentEvent;\n readonly history: AgentEventHistory;\n readonly signal?: AbortSignal;\n}\n\nexport interface AgentPlugin {\n readonly events?: {\n readonly on?: (context: AgentEventContext) => MaybePromise<void>;\n };\n readonly name?: string;\n}\n\nexport function runEventPlugins(\n plugins: readonly AgentPlugin[],\n context: AgentEventContext\n): Promise<void> {\n return runPluginHandlers(plugins, (plugin) => plugin.events?.on, context);\n}\n\nasync function runPluginHandlers<Context>(\n plugins: readonly AgentPlugin[],\n handlerFor: (\n plugin: AgentPlugin\n ) => ((context: Context) => MaybePromise<void>) | undefined,\n context: Context\n): Promise<void> {\n for (const plugin of plugins) {\n const handler = handlerFor(plugin);\n if (handler) {\n await handler(context);\n }\n }\n}\n"],"mappings":";AAmBA,SAAgB,gBACd,SACA,SACe;CACf,OAAO,kBAAkB,UAAU,WAAW,OAAO,QAAQ,IAAI,OAAO;AAC1E;AAEA,eAAe,kBACb,SACA,YAGA,SACe;CACf,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,UAAU,WAAW,MAAM;EACjC,IAAI,SACF,MAAM,QAAQ,OAAO;CAEzB;AACF"}
@@ -44,12 +44,14 @@ type AgentEvent = /** User input was accepted into the session queue. */UserText
44
44
  type: "step-start";
45
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
46
  description?: string;
47
+ delegateToolCallId?: string;
47
48
  run_in_background: boolean;
48
49
  subagent: string;
49
50
  task_id?: string;
50
51
  type: "subagent-job-start";
51
52
  } | {
52
53
  eventType?: AgentEvent["type"];
54
+ delegateToolCallId?: string;
53
55
  status: SubagentJobStatus;
54
56
  subagent: string;
55
57
  task_id: string;
@@ -57,6 +59,7 @@ type AgentEvent = /** User input was accepted into the session queue. */UserText
57
59
  } | {
58
60
  error?: string;
59
61
  eventCount: number;
62
+ delegateToolCallId?: string;
60
63
  status: Exclude<SubagentJobStatus, "pending" | "running">;
61
64
  subagent: string;
62
65
  task_id?: string;
@@ -9,7 +9,7 @@ function createRuntimeInputState(queue) {
9
9
  function addSteeringInput(runtimeInput, input) {
10
10
  const next = runtimeInput.pending.then(() => {
11
11
  if (runtimeInput.closedReason) throw runtimeInputClosedError(runtimeInput.closedReason);
12
- runtimeInput.queue.push({
12
+ queueRuntimeInput(runtimeInput, {
13
13
  input: normalizeAgentInput(input),
14
14
  placement: runtimeInput.steerPlacement ?? runtimeInput.placement ?? "step-end"
15
15
  });
@@ -34,36 +34,18 @@ async function withRuntimeInputWindow(runtimeInput, placement, callback) {
34
34
  runtimeInput.steerPlacement = previousSteerPlacement;
35
35
  }
36
36
  }
37
- async function withSteeringPlacement(runtimeInput, placement, callback) {
38
- const previousSteerPlacement = runtimeInput.steerPlacement;
39
- runtimeInput.steerPlacement = placement;
40
- try {
41
- return await callback();
42
- } finally {
43
- runtimeInput.steerPlacement = previousSteerPlacement;
44
- }
45
- }
46
- function hooksForRuntimeInput(hooks, runtimeInput) {
47
- if (!hooks) return;
48
- return {
49
- ...hooks,
50
- afterStep: (context) => withSteeringPlacement(runtimeInput, "step-end", async () => {
51
- await hooks.afterStep?.(context);
52
- }),
53
- beforeStep: (context) => withSteeringPlacement(runtimeInput, "step-start", async () => {
54
- await hooks.beforeStep?.(context);
55
- })
56
- };
57
- }
58
37
  function shiftRuntimeInput(runtimeInput, placement) {
59
38
  const index = runtimeInput.queue.findIndex((input) => input.placement === placement);
60
39
  if (index === -1) return;
61
40
  return runtimeInput.queue.splice(index, 1)[0];
62
41
  }
42
+ function queueRuntimeInput(runtimeInput, input) {
43
+ runtimeInput.queue.push(input);
44
+ }
63
45
  function runtimeInputClosedError(reason) {
64
46
  return /* @__PURE__ */ new Error(`session.steer() cannot be used after ${reason}`);
65
47
  }
66
48
  //#endregion
67
- export { addSteeringInput, closeRuntimeInput, createRuntimeInputState, hooksForRuntimeInput, shiftRuntimeInput, withRuntimeInputWindow, withSteeringPlacement };
49
+ export { addSteeringInput, closeRuntimeInput, createRuntimeInputState, queueRuntimeInput, shiftRuntimeInput, withRuntimeInputWindow };
68
50
 
69
51
  //# sourceMappingURL=runtime-input.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-input.js","names":[],"sources":["../../src/session/runtime-input.ts"],"sourcesContent":["import type { AgentHooks } from \"../hooks\";\nimport type { RuntimeInput } from \"./events\";\nimport type { AgentInput, UserInput } from \"./input\";\nimport { normalizeAgentInput } from \"./input-normalization\";\nimport type { BufferedAgentRun } from \"./run\";\n\nexport type RuntimeInputPlacement = RuntimeInput[\"placement\"];\n\nexport interface QueuedRuntimeInput {\n readonly input: UserInput;\n readonly placement: RuntimeInputPlacement;\n}\n\nexport interface RuntimeInputState {\n closedReason?: string;\n pending: Promise<void>;\n placement?: RuntimeInputPlacement;\n readonly queue: QueuedRuntimeInput[];\n steerPlacement?: RuntimeInputPlacement;\n}\n\nexport interface QueuedInput {\n readonly input: UserInput;\n readonly run: BufferedAgentRun;\n readonly runtimeInput: RuntimeInputState;\n}\n\nexport function createRuntimeInputState(\n queue: QueuedRuntimeInput[]\n): RuntimeInputState {\n return {\n pending: Promise.resolve(),\n queue,\n };\n}\n\nexport function addSteeringInput(\n runtimeInput: RuntimeInputState,\n input: AgentInput\n): Promise<void> {\n const next = runtimeInput.pending.then(() => {\n if (runtimeInput.closedReason) {\n throw runtimeInputClosedError(runtimeInput.closedReason);\n }\n\n runtimeInput.queue.push({\n input: normalizeAgentInput(input),\n placement:\n runtimeInput.steerPlacement ?? runtimeInput.placement ?? \"step-end\",\n });\n });\n runtimeInput.pending = next.catch(() => undefined);\n return next;\n}\n\nexport function closeRuntimeInput(\n runtimeInput: RuntimeInputState | undefined,\n reason = \"the run reached a terminal state\"\n): void {\n if (runtimeInput && !runtimeInput.closedReason) {\n runtimeInput.closedReason = reason;\n runtimeInput.placement = undefined;\n }\n}\n\nexport async function withRuntimeInputWindow<T>(\n runtimeInput: RuntimeInputState,\n placement: RuntimeInputPlacement,\n callback: () => Promise<T>\n): Promise<T> {\n const previousSteerPlacement = runtimeInput.steerPlacement;\n runtimeInput.placement = placement;\n runtimeInput.steerPlacement = placement;\n try {\n return await callback();\n } finally {\n runtimeInput.placement = undefined;\n runtimeInput.steerPlacement = previousSteerPlacement;\n }\n}\n\nexport async function withSteeringPlacement<T>(\n runtimeInput: RuntimeInputState,\n placement: RuntimeInputPlacement,\n callback: () => Promise<T>\n): Promise<T> {\n const previousSteerPlacement = runtimeInput.steerPlacement;\n runtimeInput.steerPlacement = placement;\n try {\n return await callback();\n } finally {\n runtimeInput.steerPlacement = previousSteerPlacement;\n }\n}\n\nexport function hooksForRuntimeInput(\n hooks: AgentHooks | undefined,\n runtimeInput: RuntimeInputState\n): AgentHooks | undefined {\n if (!hooks) {\n return;\n }\n\n return {\n ...hooks,\n afterStep: (context) =>\n withSteeringPlacement(runtimeInput, \"step-end\", async () => {\n await hooks.afterStep?.(context);\n }),\n beforeStep: (context) =>\n withSteeringPlacement(runtimeInput, \"step-start\", async () => {\n await hooks.beforeStep?.(context);\n }),\n };\n}\n\nexport function shiftRuntimeInput(\n runtimeInput: RuntimeInputState,\n placement: RuntimeInputPlacement\n): QueuedRuntimeInput | undefined {\n const index = runtimeInput.queue.findIndex(\n (input) => input.placement === placement\n );\n if (index === -1) {\n return;\n }\n\n return runtimeInput.queue.splice(index, 1)[0];\n}\n\nfunction runtimeInputClosedError(reason: string): Error {\n return new Error(`session.steer() cannot be used after ${reason}`);\n}\n"],"mappings":";;AA2BA,SAAgB,wBACd,OACmB;CACnB,OAAO;EACL,SAAS,QAAQ,QAAQ;EACzB;CACF;AACF;AAEA,SAAgB,iBACd,cACA,OACe;CACf,MAAM,OAAO,aAAa,QAAQ,WAAW;EAC3C,IAAI,aAAa,cACf,MAAM,wBAAwB,aAAa,YAAY;EAGzD,aAAa,MAAM,KAAK;GACtB,OAAO,oBAAoB,KAAK;GAChC,WACE,aAAa,kBAAkB,aAAa,aAAa;EAC7D,CAAC;CACH,CAAC;CACD,aAAa,UAAU,KAAK,YAAY,KAAA,CAAS;CACjD,OAAO;AACT;AAEA,SAAgB,kBACd,cACA,SAAS,oCACH;CACN,IAAI,gBAAgB,CAAC,aAAa,cAAc;EAC9C,aAAa,eAAe;EAC5B,aAAa,YAAY,KAAA;CAC3B;AACF;AAEA,eAAsB,uBACpB,cACA,WACA,UACY;CACZ,MAAM,yBAAyB,aAAa;CAC5C,aAAa,YAAY;CACzB,aAAa,iBAAiB;CAC9B,IAAI;EACF,OAAO,MAAM,SAAS;CACxB,UAAU;EACR,aAAa,YAAY,KAAA;EACzB,aAAa,iBAAiB;CAChC;AACF;AAEA,eAAsB,sBACpB,cACA,WACA,UACY;CACZ,MAAM,yBAAyB,aAAa;CAC5C,aAAa,iBAAiB;CAC9B,IAAI;EACF,OAAO,MAAM,SAAS;CACxB,UAAU;EACR,aAAa,iBAAiB;CAChC;AACF;AAEA,SAAgB,qBACd,OACA,cACwB;CACxB,IAAI,CAAC,OACH;CAGF,OAAO;EACL,GAAG;EACH,YAAY,YACV,sBAAsB,cAAc,YAAY,YAAY;GAC1D,MAAM,MAAM,YAAY,OAAO;EACjC,CAAC;EACH,aAAa,YACX,sBAAsB,cAAc,cAAc,YAAY;GAC5D,MAAM,MAAM,aAAa,OAAO;EAClC,CAAC;CACL;AACF;AAEA,SAAgB,kBACd,cACA,WACgC;CAChC,MAAM,QAAQ,aAAa,MAAM,WAC9B,UAAU,MAAM,cAAc,SACjC;CACA,IAAI,UAAU,IACZ;CAGF,OAAO,aAAa,MAAM,OAAO,OAAO,CAAC,EAAE;AAC7C;AAEA,SAAS,wBAAwB,QAAuB;CACtD,uBAAO,IAAI,MAAM,wCAAwC,QAAQ;AACnE"}
1
+ {"version":3,"file":"runtime-input.js","names":[],"sources":["../../src/session/runtime-input.ts"],"sourcesContent":["import type { AgentEvent, RuntimeInput } from \"./events\";\nimport type { AgentInput, UserInput } from \"./input\";\nimport { normalizeAgentInput } from \"./input-normalization\";\nimport type { BufferedAgentRun } from \"./run\";\n\nexport type RuntimeInputPlacement = RuntimeInput[\"placement\"];\n\nexport interface QueuedRuntimeInput {\n readonly input: UserInput;\n readonly placement: RuntimeInputPlacement;\n}\n\nexport interface RuntimeInputState {\n closedReason?: string;\n pending: Promise<void>;\n placement?: RuntimeInputPlacement;\n readonly queue: QueuedRuntimeInput[];\n steerPlacement?: RuntimeInputPlacement;\n}\n\nexport interface QueuedInput {\n readonly initialEvents: AgentEvent[];\n readonly input?: UserInput;\n readonly preUserRuntimeInputs: QueuedRuntimeInput[];\n readonly run: BufferedAgentRun;\n readonly runtimeInput: RuntimeInputState;\n}\n\nexport function createRuntimeInputState(\n queue: QueuedRuntimeInput[]\n): RuntimeInputState {\n return {\n pending: Promise.resolve(),\n queue,\n };\n}\n\nexport function addSteeringInput(\n runtimeInput: RuntimeInputState,\n input: AgentInput\n): Promise<void> {\n const next = runtimeInput.pending.then(() => {\n if (runtimeInput.closedReason) {\n throw runtimeInputClosedError(runtimeInput.closedReason);\n }\n\n queueRuntimeInput(runtimeInput, {\n input: normalizeAgentInput(input),\n placement:\n runtimeInput.steerPlacement ?? runtimeInput.placement ?? \"step-end\",\n });\n });\n runtimeInput.pending = next.catch(() => undefined);\n return next;\n}\n\nexport function closeRuntimeInput(\n runtimeInput: RuntimeInputState | undefined,\n reason = \"the run reached a terminal state\"\n): void {\n if (runtimeInput && !runtimeInput.closedReason) {\n runtimeInput.closedReason = reason;\n runtimeInput.placement = undefined;\n }\n}\n\nexport async function withRuntimeInputWindow<T>(\n runtimeInput: RuntimeInputState,\n placement: RuntimeInputPlacement,\n callback: () => Promise<T>\n): Promise<T> {\n const previousSteerPlacement = runtimeInput.steerPlacement;\n runtimeInput.placement = placement;\n runtimeInput.steerPlacement = placement;\n try {\n return await callback();\n } finally {\n runtimeInput.placement = undefined;\n runtimeInput.steerPlacement = previousSteerPlacement;\n }\n}\n\nexport async function withSteeringPlacement<T>(\n runtimeInput: RuntimeInputState,\n placement: RuntimeInputPlacement,\n callback: () => Promise<T>\n): Promise<T> {\n const previousSteerPlacement = runtimeInput.steerPlacement;\n runtimeInput.steerPlacement = placement;\n try {\n return await callback();\n } finally {\n runtimeInput.steerPlacement = previousSteerPlacement;\n }\n}\n\nexport function shiftRuntimeInput(\n runtimeInput: RuntimeInputState,\n placement: RuntimeInputPlacement\n): QueuedRuntimeInput | undefined {\n const index = runtimeInput.queue.findIndex(\n (input) => input.placement === placement\n );\n if (index === -1) {\n return;\n }\n\n return runtimeInput.queue.splice(index, 1)[0];\n}\n\nexport function queueRuntimeInput(\n runtimeInput: RuntimeInputState,\n input: QueuedRuntimeInput\n): void {\n runtimeInput.queue.push(input);\n}\n\nfunction runtimeInputClosedError(reason: string): Error {\n return new Error(`session.steer() cannot be used after ${reason}`);\n}\n"],"mappings":";;AA4BA,SAAgB,wBACd,OACmB;CACnB,OAAO;EACL,SAAS,QAAQ,QAAQ;EACzB;CACF;AACF;AAEA,SAAgB,iBACd,cACA,OACe;CACf,MAAM,OAAO,aAAa,QAAQ,WAAW;EAC3C,IAAI,aAAa,cACf,MAAM,wBAAwB,aAAa,YAAY;EAGzD,kBAAkB,cAAc;GAC9B,OAAO,oBAAoB,KAAK;GAChC,WACE,aAAa,kBAAkB,aAAa,aAAa;EAC7D,CAAC;CACH,CAAC;CACD,aAAa,UAAU,KAAK,YAAY,KAAA,CAAS;CACjD,OAAO;AACT;AAEA,SAAgB,kBACd,cACA,SAAS,oCACH;CACN,IAAI,gBAAgB,CAAC,aAAa,cAAc;EAC9C,aAAa,eAAe;EAC5B,aAAa,YAAY,KAAA;CAC3B;AACF;AAEA,eAAsB,uBACpB,cACA,WACA,UACY;CACZ,MAAM,yBAAyB,aAAa;CAC5C,aAAa,YAAY;CACzB,aAAa,iBAAiB;CAC9B,IAAI;EACF,OAAO,MAAM,SAAS;CACxB,UAAU;EACR,aAAa,YAAY,KAAA;EACzB,aAAa,iBAAiB;CAChC;AACF;AAgBA,SAAgB,kBACd,cACA,WACgC;CAChC,MAAM,QAAQ,aAAa,MAAM,WAC9B,UAAU,MAAM,cAAc,SACjC;CACA,IAAI,UAAU,IACZ;CAGF,OAAO,aAAa,MAAM,OAAO,OAAO,CAAC,EAAE;AAC7C;AAEA,SAAgB,kBACd,cACA,OACM;CACN,aAAa,MAAM,KAAK,KAAK;AAC/B;AAEA,SAAS,wBAAwB,QAAuB;CACtD,uBAAO,IAAI,MAAM,wCAAwC,QAAQ;AACnE"}
@@ -1,9 +1,4 @@
1
1
  //#region src/session/session-errors.ts
2
- async function runAfterTurnHook(hooks, context) {
3
- const hook = hooks?.afterTurn;
4
- if (!hook) return;
5
- await Promise.allSettled([Promise.resolve().then(() => hook(context))]);
6
- }
7
2
  function errorMessage(error) {
8
3
  if (error instanceof Error) return error.message;
9
4
  return String(error);
@@ -18,6 +13,6 @@ function sessionTerminalError(killed) {
18
13
  return killed ? sessionKilledError() : sessionDeleteInProgressError();
19
14
  }
20
15
  //#endregion
21
- export { errorMessage, runAfterTurnHook, sessionKilledError, sessionTerminalError };
16
+ export { errorMessage, sessionKilledError, sessionTerminalError };
22
17
 
23
18
  //# sourceMappingURL=session-errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-errors.js","names":[],"sources":["../../src/session/session-errors.ts"],"sourcesContent":["import type { AgentHooks } from \"../hooks\";\n\nexport async function runAfterTurnHook(\n hooks: AgentHooks | undefined,\n context: Parameters<NonNullable<AgentHooks[\"afterTurn\"]>>[0]\n): Promise<void> {\n const hook = hooks?.afterTurn;\n if (!hook) {\n return;\n }\n\n await Promise.allSettled([Promise.resolve().then(() => hook(context))]);\n}\n\nexport function errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n}\n\nexport function sessionKilledError(): Error {\n return new Error(\"Session killed\");\n}\n\nexport function sessionDeleteInProgressError(): Error {\n return new Error(\"Session delete in progress\");\n}\n\nexport function sessionTerminalError(killed: boolean): Error {\n return killed ? sessionKilledError() : sessionDeleteInProgressError();\n}\n"],"mappings":";AAEA,eAAsB,iBACpB,OACA,SACe;CACf,MAAM,OAAO,OAAO;CACpB,IAAI,CAAC,MACH;CAGF,MAAM,QAAQ,WAAW,CAAC,QAAQ,QAAQ,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC;AACxE;AAEA,SAAgB,aAAa,OAAwB;CACnD,IAAI,iBAAiB,OACnB,OAAO,MAAM;CAGf,OAAO,OAAO,KAAK;AACrB;AAEA,SAAgB,qBAA4B;CAC1C,uBAAO,IAAI,MAAM,gBAAgB;AACnC;AAEA,SAAgB,+BAAsC;CACpD,uBAAO,IAAI,MAAM,4BAA4B;AAC/C;AAEA,SAAgB,qBAAqB,QAAwB;CAC3D,OAAO,SAAS,mBAAmB,IAAI,6BAA6B;AACtE"}
1
+ {"version":3,"file":"session-errors.js","names":[],"sources":["../../src/session/session-errors.ts"],"sourcesContent":["export function errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n}\n\nexport function sessionKilledError(): Error {\n return new Error(\"Session killed\");\n}\n\nexport function sessionDeleteInProgressError(): Error {\n return new Error(\"Session delete in progress\");\n}\n\nexport function sessionTerminalError(killed: boolean): Error {\n return killed ? sessionKilledError() : sessionDeleteInProgressError();\n}\n"],"mappings":";AAAA,SAAgB,aAAa,OAAwB;CACnD,IAAI,iBAAiB,OACnB,OAAO,MAAM;CAGf,OAAO,OAAO,KAAK;AACrB;AAEA,SAAgB,qBAA4B;CAC1C,uBAAO,IAAI,MAAM,gBAAgB;AACnC;AAEA,SAAgB,+BAAsC;CACpD,uBAAO,IAAI,MAAM,4BAA4B;AAC/C;AAEA,SAAgB,qBAAqB,QAAwB;CAC3D,OAAO,SAAS,mBAAmB,IAAI,6BAA6B;AACtE"}
@@ -0,0 +1,59 @@
1
+ import { runEventPlugins } from "../plugins.js";
2
+ //#region src/session/session-events.ts
3
+ var SessionEventDispatcher = class {
4
+ #history;
5
+ #observerEventBuffer;
6
+ #plugins;
7
+ #signal;
8
+ constructor(options) {
9
+ this.#history = options.history;
10
+ this.#plugins = options.plugins;
11
+ this.#signal = options.signal;
12
+ }
13
+ async captureObserverEvents(run, callback) {
14
+ const previousBuffer = this.#observerEventBuffer;
15
+ const buffer = [];
16
+ this.#observerEventBuffer = buffer;
17
+ try {
18
+ return {
19
+ events: buffer,
20
+ release: () => {
21
+ if (this.#observerEventBuffer === buffer) this.#observerEventBuffer = previousBuffer;
22
+ },
23
+ value: await callback()
24
+ };
25
+ } catch (error) {
26
+ for (const event of buffer.splice(0)) await this.emitRunEvent(run, event);
27
+ this.#observerEventBuffer = previousBuffer;
28
+ throw error;
29
+ }
30
+ }
31
+ emitObserverEvent(activeRun, event) {
32
+ const observerEventBuffer = this.#observerEventBuffer;
33
+ if (observerEventBuffer) {
34
+ observerEventBuffer.push(structuredClone(event));
35
+ return Promise.resolve();
36
+ }
37
+ if (!activeRun) return Promise.resolve();
38
+ return this.emitRunEvent(activeRun, event);
39
+ }
40
+ async emitRunBoundaryEvent(run, event) {
41
+ await this.#runPlugins(event);
42
+ await run.emitBoundary(event);
43
+ }
44
+ async emitRunEvent(run, event) {
45
+ await this.#runPlugins(event);
46
+ run.emit(event);
47
+ }
48
+ #runPlugins(event) {
49
+ return runEventPlugins(this.#plugins, {
50
+ event,
51
+ history: this.#history(),
52
+ signal: this.#signal()
53
+ });
54
+ }
55
+ };
56
+ //#endregion
57
+ export { SessionEventDispatcher };
58
+
59
+ //# sourceMappingURL=session-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-events.js","names":["#history","#plugins","#signal","#observerEventBuffer","#runPlugins"],"sources":["../../src/session/session-events.ts"],"sourcesContent":["import type { RuntimeLlmContext } from \"../llm\";\nimport { type AgentPlugin, runEventPlugins } from \"../plugins\";\nimport type { AgentEvent } from \"./events\";\nimport type { BufferedAgentRun } from \"./run\";\n\ninterface SessionEventDispatcherOptions {\n readonly history: () => RuntimeLlmContext[\"history\"];\n readonly plugins: readonly AgentPlugin[];\n readonly signal: () => AbortSignal | undefined;\n}\n\nexport class SessionEventDispatcher {\n readonly #history: () => RuntimeLlmContext[\"history\"];\n #observerEventBuffer?: AgentEvent[];\n readonly #plugins: readonly AgentPlugin[];\n readonly #signal: () => AbortSignal | undefined;\n\n constructor(options: SessionEventDispatcherOptions) {\n this.#history = options.history;\n this.#plugins = options.plugins;\n this.#signal = options.signal;\n }\n\n async captureObserverEvents<T>(\n run: BufferedAgentRun,\n callback: () => Promise<T>\n ): Promise<{\n readonly events: AgentEvent[];\n readonly release: () => void;\n readonly value: T;\n }> {\n const previousBuffer = this.#observerEventBuffer;\n const buffer: AgentEvent[] = [];\n this.#observerEventBuffer = buffer;\n try {\n const value = await callback();\n return {\n events: buffer,\n release: () => {\n if (this.#observerEventBuffer === buffer) {\n this.#observerEventBuffer = previousBuffer;\n }\n },\n value,\n };\n } catch (error) {\n for (const event of buffer.splice(0)) {\n await this.emitRunEvent(run, event);\n }\n this.#observerEventBuffer = previousBuffer;\n throw error;\n }\n }\n\n emitObserverEvent(\n activeRun: BufferedAgentRun | undefined,\n event: AgentEvent\n ): Promise<void> {\n const observerEventBuffer = this.#observerEventBuffer;\n if (observerEventBuffer) {\n observerEventBuffer.push(structuredClone(event));\n return Promise.resolve();\n }\n\n if (!activeRun) {\n return Promise.resolve();\n }\n\n return this.emitRunEvent(activeRun, event);\n }\n\n async emitRunBoundaryEvent(\n run: BufferedAgentRun,\n event: AgentEvent\n ): Promise<void> {\n await this.#runPlugins(event);\n await run.emitBoundary(event);\n }\n\n async emitRunEvent(run: BufferedAgentRun, event: AgentEvent): Promise<void> {\n await this.#runPlugins(event);\n run.emit(event);\n }\n\n #runPlugins(event: AgentEvent): Promise<void> {\n return runEventPlugins(this.#plugins, {\n event,\n history: this.#history(),\n signal: this.#signal(),\n });\n }\n}\n"],"mappings":";;AAWA,IAAa,yBAAb,MAAoC;CAClC;CACA;CACA;CACA;CAEA,YAAY,SAAwC;EAClD,KAAKA,WAAW,QAAQ;EACxB,KAAKC,WAAW,QAAQ;EACxB,KAAKC,UAAU,QAAQ;CACzB;CAEA,MAAM,sBACJ,KACA,UAKC;EACD,MAAM,iBAAiB,KAAKC;EAC5B,MAAM,SAAuB,CAAC;EAC9B,KAAKA,uBAAuB;EAC5B,IAAI;GAEF,OAAO;IACL,QAAQ;IACR,eAAe;KACb,IAAI,KAAKA,yBAAyB,QAChC,KAAKA,uBAAuB;IAEhC;IACA,OAAA,MARkB,SAAS;GAS7B;EACF,SAAS,OAAO;GACd,KAAK,MAAM,SAAS,OAAO,OAAO,CAAC,GACjC,MAAM,KAAK,aAAa,KAAK,KAAK;GAEpC,KAAKA,uBAAuB;GAC5B,MAAM;EACR;CACF;CAEA,kBACE,WACA,OACe;EACf,MAAM,sBAAsB,KAAKA;EACjC,IAAI,qBAAqB;GACvB,oBAAoB,KAAK,gBAAgB,KAAK,CAAC;GAC/C,OAAO,QAAQ,QAAQ;EACzB;EAEA,IAAI,CAAC,WACH,OAAO,QAAQ,QAAQ;EAGzB,OAAO,KAAK,aAAa,WAAW,KAAK;CAC3C;CAEA,MAAM,qBACJ,KACA,OACe;EACf,MAAM,KAAKC,YAAY,KAAK;EAC5B,MAAM,IAAI,aAAa,KAAK;CAC9B;CAEA,MAAM,aAAa,KAAuB,OAAkC;EAC1E,MAAM,KAAKA,YAAY,KAAK;EAC5B,IAAI,KAAK,KAAK;CAChB;CAEA,YAAY,OAAkC;EAC5C,OAAO,gBAAgB,KAAKH,UAAU;GACpC;GACA,SAAS,KAAKD,SAAS;GACvB,QAAQ,KAAKE,QAAQ;EACvB,CAAC;CACH;AACF"}
@@ -0,0 +1,88 @@
1
+ import { persistedToolExecutionCheckpoint } from "../llm-tool-execution.js";
2
+ //#region src/session/session-execution.ts
3
+ const maxCheckpointWriteAttempts = 5;
4
+ var SessionExecutionCheckpointError = class extends Error {
5
+ constructor(runId, expectedVersion, currentVersion) {
6
+ super(`Session execution run ${runId} checkpoint conflict: expected ${expectedVersion}, got ${currentVersion}`);
7
+ this.name = "SessionExecutionCheckpointError";
8
+ }
9
+ };
10
+ async function startSessionExecutionRun({ executionHost, sessionKey, state, turnId }) {
11
+ if (!executionHost) return;
12
+ const runId = `turn:${sessionKey}:${turnId}`;
13
+ const run = {
14
+ checkpointVersion: 0,
15
+ dedupeKey: runId,
16
+ kind: "user-turn",
17
+ rootRunId: runId,
18
+ runId,
19
+ sessionKey,
20
+ status: "running"
21
+ };
22
+ await executionHost.store.runs.create(run);
23
+ return {
24
+ complete: (status) => completeSessionExecutionRun({
25
+ executionHost,
26
+ runId,
27
+ status
28
+ }),
29
+ runId,
30
+ toolExecution: {
31
+ attempt: 1,
32
+ afterTool: (checkpoint) => appendToolExecutionCheckpoint({
33
+ executionHost,
34
+ phase: "after-tool",
35
+ runId,
36
+ state,
37
+ toolCall: checkpoint
38
+ }),
39
+ beforeTool: async (checkpoint) => {
40
+ await appendToolExecutionCheckpoint({
41
+ executionHost,
42
+ phase: "before-tool",
43
+ runId,
44
+ state,
45
+ toolCall: checkpoint
46
+ });
47
+ },
48
+ runId
49
+ }
50
+ };
51
+ }
52
+ async function appendToolExecutionCheckpoint({ executionHost, phase, runId, state, toolCall }) {
53
+ let lastConflict;
54
+ for (let attempt = 0; attempt < maxCheckpointWriteAttempts; attempt += 1) {
55
+ const run = await executionHost.store.runs.get(runId);
56
+ if (!run) throw new Error(`Session execution run ${runId} is missing.`);
57
+ const result = await executionHost.store.checkpoints.append({
58
+ checkpointId: crypto.randomUUID(),
59
+ pendingToolCall: persistedToolExecutionCheckpoint(toolCall),
60
+ phase,
61
+ runId,
62
+ runtimeState: {
63
+ toolCallId: toolCall.toolCallId,
64
+ toolName: toolCall.toolName
65
+ },
66
+ sessionSnapshot: { history: state.modelSnapshot() },
67
+ version: run.checkpointVersion + 1
68
+ }, { expectedVersion: run.checkpointVersion });
69
+ if (result.ok) return;
70
+ lastConflict = {
71
+ current: result.currentVersion,
72
+ expected: run.checkpointVersion
73
+ };
74
+ }
75
+ throw new SessionExecutionCheckpointError(runId, lastConflict?.expected ?? 0, lastConflict?.current ?? 0);
76
+ }
77
+ async function completeSessionExecutionRun({ executionHost, runId, status }) {
78
+ const run = await executionHost.store.runs.get(runId);
79
+ if (!run) return;
80
+ await executionHost.store.runs.update({
81
+ ...run,
82
+ status
83
+ });
84
+ }
85
+ //#endregion
86
+ export { startSessionExecutionRun };
87
+
88
+ //# sourceMappingURL=session-execution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-execution.js","names":[],"sources":["../../src/session/session-execution.ts"],"sourcesContent":["import type {\n CheckpointPhase,\n ExecutionHost,\n RunRecord,\n RunStatus,\n} from \"../execution/types\";\nimport type {\n RuntimeToolExecutionCheckpoint,\n RuntimeToolExecutionContext,\n} from \"../llm\";\nimport { persistedToolExecutionCheckpoint } from \"../llm-tool-execution\";\nimport type { SessionState } from \"./session-state\";\n\nconst maxCheckpointWriteAttempts = 5;\n\nexport interface SessionExecutionOptions {\n readonly executionHost?: ExecutionHost;\n}\n\nexport interface SessionExecutionRun {\n complete(status: SessionExecutionTerminalStatus): Promise<void>;\n readonly runId: string;\n readonly toolExecution: RuntimeToolExecutionContext;\n}\n\nexport type SessionExecutionTerminalStatus = Extract<\n RunStatus,\n \"cancelled\" | \"completed\" | \"error\" | \"needs-recovery\"\n>;\n\nexport class SessionExecutionCheckpointError extends Error {\n constructor(runId: string, expectedVersion: number, currentVersion: number) {\n super(\n `Session execution run ${runId} checkpoint conflict: expected ${expectedVersion}, got ${currentVersion}`\n );\n this.name = \"SessionExecutionCheckpointError\";\n }\n}\n\nexport async function startSessionExecutionRun({\n executionHost,\n sessionKey,\n state,\n turnId,\n}: {\n readonly executionHost?: ExecutionHost;\n readonly sessionKey: string;\n readonly state: SessionState;\n readonly turnId: string;\n}): Promise<SessionExecutionRun | undefined> {\n if (!executionHost) {\n return;\n }\n\n const runId = `turn:${sessionKey}:${turnId}`;\n const run: RunRecord = {\n checkpointVersion: 0,\n dedupeKey: runId,\n kind: \"user-turn\",\n rootRunId: runId,\n runId,\n sessionKey,\n status: \"running\",\n };\n await executionHost.store.runs.create(run);\n\n return {\n complete: (status) =>\n completeSessionExecutionRun({ executionHost, runId, status }),\n runId,\n toolExecution: {\n attempt: 1,\n afterTool: (checkpoint) =>\n appendToolExecutionCheckpoint({\n executionHost,\n phase: \"after-tool\",\n runId,\n state,\n toolCall: checkpoint,\n }),\n beforeTool: async (checkpoint) => {\n await appendToolExecutionCheckpoint({\n executionHost,\n phase: \"before-tool\",\n runId,\n state,\n toolCall: checkpoint,\n });\n return;\n },\n runId,\n },\n };\n}\n\nasync function appendToolExecutionCheckpoint({\n executionHost,\n phase,\n runId,\n state,\n toolCall,\n}: {\n readonly executionHost: ExecutionHost;\n readonly phase: Extract<CheckpointPhase, \"after-tool\" | \"before-tool\">;\n readonly runId: string;\n readonly state: SessionState;\n readonly toolCall: RuntimeToolExecutionCheckpoint & {\n readonly output?: unknown;\n };\n}): Promise<void> {\n let lastConflict:\n | { readonly current: number; readonly expected: number }\n | undefined;\n for (let attempt = 0; attempt < maxCheckpointWriteAttempts; attempt += 1) {\n const run = await executionHost.store.runs.get(runId);\n if (!run) {\n throw new Error(`Session execution run ${runId} is missing.`);\n }\n\n const result = await executionHost.store.checkpoints.append(\n {\n checkpointId: crypto.randomUUID(),\n pendingToolCall: persistedToolExecutionCheckpoint(toolCall),\n phase,\n runId,\n runtimeState: {\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n },\n sessionSnapshot: { history: state.modelSnapshot() },\n version: run.checkpointVersion + 1,\n },\n { expectedVersion: run.checkpointVersion }\n );\n\n if (result.ok) {\n return;\n }\n\n lastConflict = {\n current: result.currentVersion,\n expected: run.checkpointVersion,\n };\n }\n\n throw new SessionExecutionCheckpointError(\n runId,\n lastConflict?.expected ?? 0,\n lastConflict?.current ?? 0\n );\n}\n\nasync function completeSessionExecutionRun({\n executionHost,\n runId,\n status,\n}: {\n readonly executionHost: ExecutionHost;\n readonly runId: string;\n readonly status: SessionExecutionTerminalStatus;\n}): Promise<void> {\n const run = await executionHost.store.runs.get(runId);\n if (!run) {\n return;\n }\n\n await executionHost.store.runs.update({ ...run, status });\n}\n"],"mappings":";;AAaA,MAAM,6BAA6B;AAiBnC,IAAa,kCAAb,cAAqD,MAAM;CACzD,YAAY,OAAe,iBAAyB,gBAAwB;EAC1E,MACE,yBAAyB,MAAM,iCAAiC,gBAAgB,QAAQ,gBAC1F;EACA,KAAK,OAAO;CACd;AACF;AAEA,eAAsB,yBAAyB,EAC7C,eACA,YACA,OACA,UAM2C;CAC3C,IAAI,CAAC,eACH;CAGF,MAAM,QAAQ,QAAQ,WAAW,GAAG;CACpC,MAAM,MAAiB;EACrB,mBAAmB;EACnB,WAAW;EACX,MAAM;EACN,WAAW;EACX;EACA;EACA,QAAQ;CACV;CACA,MAAM,cAAc,MAAM,KAAK,OAAO,GAAG;CAEzC,OAAO;EACL,WAAW,WACT,4BAA4B;GAAE;GAAe;GAAO;EAAO,CAAC;EAC9D;EACA,eAAe;GACb,SAAS;GACT,YAAY,eACV,8BAA8B;IAC5B;IACA,OAAO;IACP;IACA;IACA,UAAU;GACZ,CAAC;GACH,YAAY,OAAO,eAAe;IAChC,MAAM,8BAA8B;KAClC;KACA,OAAO;KACP;KACA;KACA,UAAU;IACZ,CAAC;GAEH;GACA;EACF;CACF;AACF;AAEA,eAAe,8BAA8B,EAC3C,eACA,OACA,OACA,OACA,YASgB;CAChB,IAAI;CAGJ,KAAK,IAAI,UAAU,GAAG,UAAU,4BAA4B,WAAW,GAAG;EACxE,MAAM,MAAM,MAAM,cAAc,MAAM,KAAK,IAAI,KAAK;EACpD,IAAI,CAAC,KACH,MAAM,IAAI,MAAM,yBAAyB,MAAM,aAAa;EAG9D,MAAM,SAAS,MAAM,cAAc,MAAM,YAAY,OACnD;GACE,cAAc,OAAO,WAAW;GAChC,iBAAiB,iCAAiC,QAAQ;GAC1D;GACA;GACA,cAAc;IACZ,YAAY,SAAS;IACrB,UAAU,SAAS;GACrB;GACA,iBAAiB,EAAE,SAAS,MAAM,cAAc,EAAE;GAClD,SAAS,IAAI,oBAAoB;EACnC,GACA,EAAE,iBAAiB,IAAI,kBAAkB,CAC3C;EAEA,IAAI,OAAO,IACT;EAGF,eAAe;GACb,SAAS,OAAO;GAChB,UAAU,IAAI;EAChB;CACF;CAEA,MAAM,IAAI,gCACR,OACA,cAAc,YAAY,GAC1B,cAAc,WAAW,CAC3B;AACF;AAEA,eAAe,4BAA4B,EACzC,eACA,OACA,UAKgB;CAChB,MAAM,MAAM,MAAM,cAAc,MAAM,KAAK,IAAI,KAAK;CACpD,IAAI,CAAC,KACH;CAGF,MAAM,cAAc,MAAM,KAAK,OAAO;EAAE,GAAG;EAAK;CAAO,CAAC;AAC1D"}
@@ -0,0 +1,58 @@
1
+ import { BufferedAgentRun } from "./run.js";
2
+ import { normalizeAgentInput } from "./input-normalization.js";
3
+ import { createRuntimeInputState, queueRuntimeInput } from "./runtime-input.js";
4
+ import { errorMessage } from "./session-errors.js";
5
+ //#region src/session/session-notification.ts
6
+ function queueSessionNotification(input, options, state) {
7
+ const queuedRuntimeInput = {
8
+ input: normalizeAgentInput(input),
9
+ placement: "turn-start"
10
+ };
11
+ const observerEvents = cloneObserverEvents(options.observerEvents ?? []);
12
+ const queuedTurn = state.inputQueue[0];
13
+ if (queuedTurn) {
14
+ queuedTurn.initialEvents.push(...observerEvents);
15
+ queuedTurn.preUserRuntimeInputs.push(queuedRuntimeInput);
16
+ return queuedTurn.run;
17
+ }
18
+ const activeRun = state.activeRun;
19
+ const runtimeInput = state.activeRuntimeInput;
20
+ if (runtimeInput && activeRun && !runtimeInput.closedReason) {
21
+ queueRuntimeInput(runtimeInput, {
22
+ input: structuredClone(queuedRuntimeInput.input),
23
+ placement: "step-end"
24
+ });
25
+ return activeRun;
26
+ }
27
+ if (options.deferWhenUnobserved === true) {
28
+ state.pendingRuntimeInputs.push(queuedRuntimeInput);
29
+ const deferredRun = new BufferedAgentRun();
30
+ deferredRun.close();
31
+ return deferredRun;
32
+ }
33
+ const run = new BufferedAgentRun();
34
+ state.inputQueue.push({
35
+ initialEvents: observerEvents,
36
+ preUserRuntimeInputs: [],
37
+ run,
38
+ runtimeInput: createRuntimeInputState([queuedRuntimeInput])
39
+ });
40
+ startSessionQueueDrain(run, state.drain);
41
+ return run;
42
+ }
43
+ function startSessionQueueDrain(run, drain) {
44
+ drain().catch((error) => {
45
+ run.emit({
46
+ type: "turn-error",
47
+ message: errorMessage(error)
48
+ });
49
+ run.close();
50
+ });
51
+ }
52
+ function cloneObserverEvents(events) {
53
+ return events.map((event) => structuredClone(event));
54
+ }
55
+ //#endregion
56
+ export { queueSessionNotification, startSessionQueueDrain };
57
+
58
+ //# sourceMappingURL=session-notification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-notification.js","names":[],"sources":["../../src/session/session-notification.ts"],"sourcesContent":["import type { AgentEvent } from \"./events\";\nimport type { AgentInput } from \"./input\";\nimport { normalizeAgentInput } from \"./input-normalization\";\nimport { type AgentRun, BufferedAgentRun } from \"./run\";\nimport {\n createRuntimeInputState,\n type QueuedInput,\n type QueuedRuntimeInput,\n queueRuntimeInput,\n type RuntimeInputState,\n} from \"./runtime-input\";\nimport { errorMessage } from \"./session-errors\";\n\nexport interface NotifyOptions {\n readonly deferWhenUnobserved?: boolean;\n readonly observerEvents?: readonly AgentEvent[];\n}\n\ninterface QueueSessionNotificationOptions {\n readonly activeRun: BufferedAgentRun | undefined;\n readonly activeRuntimeInput: RuntimeInputState | undefined;\n readonly drain: () => Promise<void>;\n readonly inputQueue: QueuedInput[];\n readonly pendingRuntimeInputs: QueuedRuntimeInput[];\n}\n\nexport function queueSessionNotification(\n input: AgentInput,\n options: NotifyOptions,\n state: QueueSessionNotificationOptions\n): AgentRun {\n const queuedRuntimeInput: QueuedRuntimeInput = {\n input: normalizeAgentInput(input),\n placement: \"turn-start\",\n };\n const observerEvents = cloneObserverEvents(options.observerEvents ?? []);\n const queuedTurn = state.inputQueue[0];\n if (queuedTurn) {\n queuedTurn.initialEvents.push(...observerEvents);\n queuedTurn.preUserRuntimeInputs.push(queuedRuntimeInput);\n return queuedTurn.run;\n }\n\n const activeRun = state.activeRun;\n const runtimeInput = state.activeRuntimeInput;\n if (runtimeInput && activeRun && !runtimeInput.closedReason) {\n queueRuntimeInput(runtimeInput, {\n input: structuredClone(queuedRuntimeInput.input),\n placement: \"step-end\",\n });\n return activeRun;\n }\n\n if (options.deferWhenUnobserved === true) {\n state.pendingRuntimeInputs.push(queuedRuntimeInput);\n const deferredRun = new BufferedAgentRun();\n deferredRun.close();\n return deferredRun;\n }\n\n const run = new BufferedAgentRun();\n state.inputQueue.push({\n initialEvents: observerEvents,\n preUserRuntimeInputs: [],\n run,\n runtimeInput: createRuntimeInputState([queuedRuntimeInput]),\n });\n startSessionQueueDrain(run, state.drain);\n return run;\n}\n\nexport function startSessionQueueDrain(\n run: BufferedAgentRun,\n drain: () => Promise<void>\n): void {\n drain().catch((error: unknown) => {\n run.emit({ type: \"turn-error\", message: errorMessage(error) });\n run.close();\n });\n}\n\nfunction cloneObserverEvents(events: readonly AgentEvent[]): AgentEvent[] {\n return events.map((event) => structuredClone(event));\n}\n"],"mappings":";;;;;AA0BA,SAAgB,yBACd,OACA,SACA,OACU;CACV,MAAM,qBAAyC;EAC7C,OAAO,oBAAoB,KAAK;EAChC,WAAW;CACb;CACA,MAAM,iBAAiB,oBAAoB,QAAQ,kBAAkB,CAAC,CAAC;CACvE,MAAM,aAAa,MAAM,WAAW;CACpC,IAAI,YAAY;EACd,WAAW,cAAc,KAAK,GAAG,cAAc;EAC/C,WAAW,qBAAqB,KAAK,kBAAkB;EACvD,OAAO,WAAW;CACpB;CAEA,MAAM,YAAY,MAAM;CACxB,MAAM,eAAe,MAAM;CAC3B,IAAI,gBAAgB,aAAa,CAAC,aAAa,cAAc;EAC3D,kBAAkB,cAAc;GAC9B,OAAO,gBAAgB,mBAAmB,KAAK;GAC/C,WAAW;EACb,CAAC;EACD,OAAO;CACT;CAEA,IAAI,QAAQ,wBAAwB,MAAM;EACxC,MAAM,qBAAqB,KAAK,kBAAkB;EAClD,MAAM,cAAc,IAAI,iBAAiB;EACzC,YAAY,MAAM;EAClB,OAAO;CACT;CAEA,MAAM,MAAM,IAAI,iBAAiB;CACjC,MAAM,WAAW,KAAK;EACpB,eAAe;EACf,sBAAsB,CAAC;EACvB;EACA,cAAc,wBAAwB,CAAC,kBAAkB,CAAC;CAC5D,CAAC;CACD,uBAAuB,KAAK,MAAM,KAAK;CACvC,OAAO;AACT;AAEA,SAAgB,uBACd,KACA,OACM;CACN,MAAM,EAAE,OAAO,UAAmB;EAChC,IAAI,KAAK;GAAE,MAAM;GAAc,SAAS,aAAa,KAAK;EAAE,CAAC;EAC7D,IAAI,MAAM;CACZ,CAAC;AACH;AAEA,SAAS,oBAAoB,QAA6C;CACxE,OAAO,OAAO,KAAK,UAAU,gBAAgB,KAAK,CAAC;AACrD"}