@swirls/looms 0.0.2 → 0.1.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.
Files changed (256) hide show
  1. package/CHANGELOG.md +9 -2
  2. package/dist/actor/cell.d.ts +9 -4
  3. package/dist/actor/cell.js +7 -11
  4. package/dist/actor/host.d.ts +7 -3
  5. package/dist/actor/host.js +55 -32
  6. package/dist/actor/index.d.ts +1 -1
  7. package/dist/actor/index.js +1 -1
  8. package/dist/actor/routing.d.ts +12 -1
  9. package/dist/actor/routing.js +57 -51
  10. package/dist/agent/agent-session.d.ts +5 -0
  11. package/dist/agent/agent-session.js +270 -0
  12. package/dist/agent/definitions-store.d.ts +2 -3
  13. package/dist/agent/definitions-store.js +2 -4
  14. package/dist/agent/definitions.d.ts +46 -20
  15. package/dist/agent/definitions.js +36 -8
  16. package/dist/agent/effects.d.ts +359 -2
  17. package/dist/agent/effects.js +60 -34
  18. package/dist/agent/events.d.ts +175 -19
  19. package/dist/agent/events.js +45 -10
  20. package/dist/agent/index.d.ts +1 -0
  21. package/dist/agent/index.js +1 -0
  22. package/dist/agent/llm.d.ts +11 -2
  23. package/dist/agent/llm.js +13 -3
  24. package/dist/agent/module.d.ts +812 -78
  25. package/dist/agent/module.js +16 -4
  26. package/dist/agent/scope.d.ts +174 -18
  27. package/dist/agent/signals.d.ts +24 -1
  28. package/dist/agent/signals.js +77 -0
  29. package/dist/agent/threads.d.ts +3 -33
  30. package/dist/agent/threads.js +20 -25
  31. package/dist/agent/tool-schema.js +0 -1
  32. package/dist/agent/types.d.ts +49 -4
  33. package/dist/agent/types.js +5 -5
  34. package/dist/ai-vercel/index.d.ts +1 -0
  35. package/dist/ai-vercel/index.js +1 -0
  36. package/dist/ai-vercel/messages.js +22 -7
  37. package/dist/ai-vercel/vercel-evaluator.d.ts +23 -0
  38. package/dist/ai-vercel/vercel-evaluator.js +68 -0
  39. package/dist/ai-vercel/vercel-llm.js +64 -44
  40. package/dist/approval/effects.d.ts +89 -0
  41. package/dist/approval/module.d.ts +179 -29
  42. package/dist/approval/projections.d.ts +0 -14
  43. package/dist/approval/projections.js +20 -3
  44. package/dist/approval/signals.d.ts +2 -0
  45. package/dist/approval/signals.js +18 -2
  46. package/dist/cli/cli.js +2 -0
  47. package/dist/cli/commands.js +12 -16
  48. package/dist/client/client.d.ts +1195 -18
  49. package/dist/client/client.js +118 -120
  50. package/dist/client/index.d.ts +1 -1
  51. package/dist/client/index.js +1 -1
  52. package/dist/client/sse.d.ts +13 -0
  53. package/dist/client/sse.js +38 -44
  54. package/dist/cloudflare/alarm-scheduler.d.ts +12 -2
  55. package/dist/cloudflare/alarm-scheduler.js +34 -7
  56. package/dist/cloudflare/durable-object.d.ts +10 -2
  57. package/dist/cloudflare/durable-object.js +59 -28
  58. package/dist/cloudflare/event-store.d.ts +7 -2
  59. package/dist/cloudflare/event-store.js +8 -7
  60. package/dist/cloudflare/index.d.ts +2 -2
  61. package/dist/cloudflare/index.js +2 -2
  62. package/dist/cloudflare/router.js +13 -14
  63. package/dist/core/catalog.d.ts +3 -3
  64. package/dist/core/catalog.js +2 -5
  65. package/dist/core/coalesce.js +5 -3
  66. package/dist/core/compose.d.ts +2 -1
  67. package/dist/core/compose.js +18 -2
  68. package/dist/core/definition-store.d.ts +11 -0
  69. package/dist/core/definition-store.js +6 -0
  70. package/dist/core/effects.d.ts +127 -15
  71. package/dist/core/effects.js +89 -17
  72. package/dist/core/envelope.d.ts +27 -7
  73. package/dist/core/envelope.js +20 -6
  74. package/dist/core/event-codec.d.ts +4 -2
  75. package/dist/core/event-codec.js +10 -5
  76. package/dist/core/event-index.js +1 -3
  77. package/dist/core/fold.d.ts +3 -0
  78. package/dist/core/fold.js +171 -24
  79. package/dist/core/ids.d.ts +5 -0
  80. package/dist/core/ids.js +35 -2
  81. package/dist/core/index.d.ts +5 -1
  82. package/dist/core/index.js +5 -1
  83. package/dist/core/kind.d.ts +22 -0
  84. package/dist/core/kind.js +17 -0
  85. package/dist/core/limits.d.ts +34 -0
  86. package/dist/core/limits.js +46 -0
  87. package/dist/core/match.d.ts +1 -0
  88. package/dist/core/match.js +10 -1
  89. package/dist/core/module-scope.d.ts +22 -20
  90. package/dist/core/module-scope.js +38 -28
  91. package/dist/core/module.d.ts +16 -5
  92. package/dist/core/module.js +4 -0
  93. package/dist/core/projection.d.ts +13 -13
  94. package/dist/core/projection.js +9 -5
  95. package/dist/core/protocol.d.ts +68 -11
  96. package/dist/core/protocol.js +82 -11
  97. package/dist/core/replay.d.ts +312 -3
  98. package/dist/core/replay.js +11 -1
  99. package/dist/core/schema.d.ts +8 -19
  100. package/dist/core/schema.js +25 -80
  101. package/dist/core/serialize.js +2 -4
  102. package/dist/core/snapshot-store.d.ts +2 -1
  103. package/dist/core/snapshot-store.js +8 -2
  104. package/dist/core/snapshots.d.ts +5 -1
  105. package/dist/core/snapshots.js +10 -15
  106. package/dist/core/sqlite-store.js +56 -11
  107. package/dist/core/state.d.ts +142 -4
  108. package/dist/core/state.js +78 -0
  109. package/dist/core/store.d.ts +38 -3
  110. package/dist/core/store.js +77 -22
  111. package/dist/core/thread.d.ts +10 -9
  112. package/dist/core/types.d.ts +5 -8
  113. package/dist/core/types.js +28 -24
  114. package/dist/core/validate-event.js +14 -4
  115. package/dist/core/worker-callback.d.ts +17 -0
  116. package/dist/core/worker-callback.js +1 -0
  117. package/dist/debugger/components/event-stream.js +9 -10
  118. package/dist/debugger/events/protocol-summarize.js +26 -0
  119. package/dist/debugger/lib/event-meta.js +1 -2
  120. package/dist/evaluator/definitions-store.d.ts +11 -0
  121. package/dist/evaluator/definitions-store.js +8 -0
  122. package/dist/evaluator/definitions.d.ts +18 -0
  123. package/dist/evaluator/definitions.js +4 -0
  124. package/dist/evaluator/effects.d.ts +226 -0
  125. package/dist/evaluator/effects.js +132 -0
  126. package/dist/evaluator/evaluator.d.ts +24 -0
  127. package/dist/evaluator/evaluator.js +67 -0
  128. package/dist/evaluator/events.d.ts +59 -0
  129. package/dist/evaluator/events.js +21 -0
  130. package/dist/evaluator/index.d.ts +11 -0
  131. package/dist/evaluator/index.js +11 -0
  132. package/dist/evaluator/module.d.ts +606 -0
  133. package/dist/evaluator/module.js +25 -0
  134. package/dist/evaluator/projections.d.ts +50 -0
  135. package/dist/evaluator/projections.js +20 -0
  136. package/dist/evaluator/scope.d.ts +59 -0
  137. package/dist/evaluator/scope.js +7 -0
  138. package/dist/evaluator/signals.d.ts +3 -0
  139. package/dist/evaluator/signals.js +17 -0
  140. package/dist/evaluator/threads.d.ts +62 -0
  141. package/dist/evaluator/threads.js +117 -0
  142. package/dist/evaluator/types.d.ts +125 -0
  143. package/dist/evaluator/types.js +51 -0
  144. package/dist/projectors/delivery.d.ts +83 -0
  145. package/dist/projectors/delivery.js +182 -0
  146. package/dist/projectors/index-model.d.ts +1 -1
  147. package/dist/projectors/index-model.js +4 -6
  148. package/dist/projectors/index.d.ts +2 -0
  149. package/dist/projectors/index.js +2 -0
  150. package/dist/projectors/memory.d.ts +1 -1
  151. package/dist/projectors/memory.js +10 -8
  152. package/dist/projectors/postgres.js +44 -58
  153. package/dist/projectors/projector.d.ts +17 -0
  154. package/dist/projectors/projector.js +26 -1
  155. package/dist/projectors/sqlite-delivery.d.ts +4 -0
  156. package/dist/projectors/sqlite-delivery.js +147 -0
  157. package/dist/projectors/sqlite.js +23 -23
  158. package/dist/projectors/with-projectors.d.ts +7 -2
  159. package/dist/projectors/with-projectors.js +27 -28
  160. package/dist/react/notify.js +11 -8
  161. package/dist/react/react.d.ts +2 -3
  162. package/dist/react/react.js +14 -30
  163. package/dist/react/sse.d.ts +1 -1
  164. package/dist/react/sse.js +1 -1
  165. package/dist/react/store.d.ts +2 -2
  166. package/dist/react/store.js +109 -119
  167. package/dist/runtime/cancellation.d.ts +16 -0
  168. package/dist/runtime/cancellation.js +129 -0
  169. package/dist/runtime/deadline-transition-planner.d.ts +31 -0
  170. package/dist/runtime/deadline-transition-planner.js +139 -0
  171. package/dist/runtime/dispatch-effect.d.ts +3 -2
  172. package/dist/runtime/dispatch-effect.js +7 -13
  173. package/dist/runtime/errors.d.ts +51 -0
  174. package/dist/runtime/errors.js +39 -0
  175. package/dist/runtime/{runtime-helpers.d.ts → helpers.d.ts} +24 -4
  176. package/dist/runtime/{runtime-helpers.js → helpers.js} +56 -19
  177. package/dist/runtime/index.d.ts +3 -3
  178. package/dist/runtime/index.js +3 -3
  179. package/dist/runtime/ingress.d.ts +15 -0
  180. package/dist/runtime/ingress.js +42 -0
  181. package/dist/runtime/local-effect-executor.d.ts +21 -0
  182. package/dist/runtime/local-effect-executor.js +137 -0
  183. package/dist/runtime/looms.d.ts +22 -4
  184. package/dist/runtime/looms.js +54 -36
  185. package/dist/runtime/observer.d.ts +45 -0
  186. package/dist/runtime/observer.js +11 -0
  187. package/dist/runtime/repository.d.ts +55 -0
  188. package/dist/runtime/repository.js +278 -0
  189. package/dist/runtime/retry-policy.d.ts +16 -0
  190. package/dist/runtime/retry-policy.js +29 -0
  191. package/dist/runtime/run-execution-context.d.ts +30 -0
  192. package/dist/runtime/run-execution-context.js +56 -0
  193. package/dist/runtime/run-start.d.ts +4 -0
  194. package/dist/runtime/run-start.js +44 -0
  195. package/dist/runtime/runtime.d.ts +6 -87
  196. package/dist/runtime/runtime.js +233 -470
  197. package/dist/runtime/server/auth.d.ts +40 -0
  198. package/dist/runtime/server/auth.js +40 -0
  199. package/dist/runtime/server/fetch-handler.d.ts +14 -0
  200. package/dist/runtime/server/fetch-handler.js +51 -0
  201. package/dist/runtime/server/http.d.ts +37 -0
  202. package/dist/runtime/server/http.js +62 -0
  203. package/dist/runtime/server/route-table.d.ts +55 -0
  204. package/dist/runtime/server/route-table.js +74 -0
  205. package/dist/runtime/server/routes/effects.d.ts +3 -0
  206. package/dist/runtime/server/routes/effects.js +59 -0
  207. package/dist/runtime/server/routes/operations.d.ts +3 -0
  208. package/dist/runtime/server/routes/operations.js +14 -0
  209. package/dist/runtime/server/routes/runs.d.ts +3 -0
  210. package/dist/runtime/server/routes/runs.js +192 -0
  211. package/dist/runtime/server.d.ts +2 -8
  212. package/dist/runtime/server.js +4 -211
  213. package/dist/runtime/sse.d.ts +2 -1
  214. package/dist/runtime/sse.js +24 -17
  215. package/dist/runtime/types.d.ts +115 -0
  216. package/dist/runtime/types.js +1 -0
  217. package/dist/runtime/wake-engine.d.ts +20 -0
  218. package/dist/runtime/wake-engine.js +311 -0
  219. package/dist/runtime/wake-scheduler.d.ts +3 -4
  220. package/dist/runtime/wake-scheduler.js +25 -31
  221. package/dist/runtime/worker-callbacks.d.ts +16 -0
  222. package/dist/runtime/worker-callbacks.js +167 -0
  223. package/dist/runtime/worker-effect-dispatch.d.ts +36 -0
  224. package/dist/runtime/worker-effect-dispatch.js +126 -0
  225. package/dist/s2/config.d.ts +1 -1
  226. package/dist/s2/config.js +1 -1
  227. package/dist/s2/lite.js +70 -82
  228. package/dist/s2/pagination.d.ts +15 -0
  229. package/dist/s2/pagination.js +36 -0
  230. package/dist/s2/projector.js +6 -5
  231. package/dist/s2/snapshot-store.js +148 -163
  232. package/dist/s2/store.d.ts +3 -21
  233. package/dist/s2/store.js +71 -165
  234. package/dist/testing/index.d.ts +15 -0
  235. package/dist/testing/index.js +53 -16
  236. package/dist/workflow/definitions-store.d.ts +2 -3
  237. package/dist/workflow/definitions-store.js +2 -2
  238. package/dist/workflow/definitions.d.ts +78 -22
  239. package/dist/workflow/definitions.js +80 -14
  240. package/dist/workflow/effects.d.ts +453 -107
  241. package/dist/workflow/effects.js +214 -115
  242. package/dist/workflow/events.d.ts +149 -5
  243. package/dist/workflow/events.js +27 -5
  244. package/dist/workflow/graph.d.ts +56 -0
  245. package/dist/workflow/graph.js +207 -0
  246. package/dist/workflow/index.d.ts +1 -0
  247. package/dist/workflow/index.js +1 -0
  248. package/dist/workflow/module.d.ts +1047 -266
  249. package/dist/workflow/projections.d.ts +14 -12
  250. package/dist/workflow/projections.js +30 -8
  251. package/dist/workflow/scope.d.ts +146 -4
  252. package/dist/workflow/threads.d.ts +383 -155
  253. package/dist/workflow/threads.js +308 -110
  254. package/package.json +7 -2
  255. package/dist/runtime/events-api.d.ts +0 -4
  256. package/dist/runtime/events-api.js +0 -84
@@ -0,0 +1,270 @@
1
+ import { Predicate } from 'effect';
2
+ import { cancel, createWaitId, deterministicThreadId, emit, spawn, wait, } from '@swirls/looms/core';
3
+ import { agentModule } from './scope.js';
4
+ function objectPayload(event) {
5
+ return Predicate.isObject(event.payload) ? event.payload : {};
6
+ }
7
+ function messageFrom(value) {
8
+ const payload = Predicate.isObject(value) ? value : {};
9
+ return Predicate.isString(payload.messageId) && Predicate.isString(payload.text)
10
+ ? {
11
+ messageId: payload.messageId,
12
+ text: payload.text,
13
+ delivery: payload.delivery === 'steer' ||
14
+ payload.delivery === 'followUp' ||
15
+ payload.delivery === 'nextTurn'
16
+ ? payload.delivery
17
+ : undefined,
18
+ }
19
+ : null;
20
+ }
21
+ function consumedIds(event) {
22
+ const payload = objectPayload(event);
23
+ const embedded = Predicate.isObject(payload.event) ? payload.event : {};
24
+ const embeddedPayload = Predicate.isObject(embedded.payload) ? embedded.payload : {};
25
+ const output = Predicate.isObject(embeddedPayload.output) ? embeddedPayload.output : {};
26
+ const ids = output.consumedSteerMessageIds;
27
+ return Array.isArray(ids) ? ids.filter(Predicate.isString) : [];
28
+ }
29
+ function closureStatus(event) {
30
+ const payload = objectPayload(event);
31
+ const embedded = Predicate.isObject(payload.event) ? payload.event : {};
32
+ const embeddedPayload = Predicate.isObject(embedded.payload) ? embedded.payload : {};
33
+ const status = embedded.type === 'runtime.thread.completed'
34
+ ? 'completed'
35
+ : embedded.type === 'runtime.thread.cancelled'
36
+ ? 'cancelled'
37
+ : 'failed';
38
+ const error = Predicate.isString(embeddedPayload.error) ? embeddedPayload.error : undefined;
39
+ return { status, error };
40
+ }
41
+ function close(messageId, status, error) {
42
+ return error === undefined ? { messageId, status } : { messageId, status, error };
43
+ }
44
+ export function createAgentSessionThread(definitions) {
45
+ return agentModule.thread({
46
+ kind: 'agent-session',
47
+ initialState: (ctx) => {
48
+ const definition = definitions.get(ctx.definitionName, ctx.definitionVersion);
49
+ return {
50
+ definitionName: ctx.definitionName,
51
+ definitionVersion: ctx.definitionVersion,
52
+ pendingMessages: [],
53
+ nextTurnMessages: [],
54
+ processedMessageIds: [],
55
+ activeTurn: null,
56
+ pendingSteerDeliveries: [],
57
+ pendingClosures: [],
58
+ lastSequence: 0,
59
+ idleTimeoutMs: definition?.idleTimeoutMs ?? 0,
60
+ idleDeadlineAt: null,
61
+ parked: false,
62
+ cancelling: false,
63
+ };
64
+ },
65
+ step(state, event) {
66
+ switch (event.type) {
67
+ case 'runtime.thread.started': {
68
+ const initial = messageFrom(objectPayload(event).input);
69
+ const idleDeadlineAt = state.idleTimeoutMs > 0 ? event.ts + state.idleTimeoutMs : null;
70
+ if (!initial || state.processedMessageIds.includes(initial.messageId)) {
71
+ return { ...state, idleDeadlineAt };
72
+ }
73
+ return {
74
+ ...state,
75
+ pendingMessages: [initial],
76
+ processedMessageIds: [initial.messageId],
77
+ idleDeadlineAt,
78
+ };
79
+ }
80
+ case 'agent.session.message.submitted': {
81
+ const payload = objectPayload(event);
82
+ const message = messageFrom(payload);
83
+ if (!message || state.processedMessageIds.includes(message.messageId)) {
84
+ return state;
85
+ }
86
+ const processedMessageIds = [...state.processedMessageIds, message.messageId];
87
+ const idleDeadlineAt = state.idleTimeoutMs > 0 ? event.ts + state.idleTimeoutMs : null;
88
+ if (message.delivery === 'nextTurn') {
89
+ return {
90
+ ...state,
91
+ nextTurnMessages: [...state.nextTurnMessages, message],
92
+ processedMessageIds,
93
+ idleDeadlineAt,
94
+ parked: false,
95
+ };
96
+ }
97
+ const queued = message.delivery === 'steer' && state.activeTurn
98
+ ? { ...message, steeredIntoMessageId: state.activeTurn.messageId }
99
+ : message;
100
+ return {
101
+ ...state,
102
+ pendingMessages: [...state.pendingMessages, queued],
103
+ pendingSteerDeliveries: queued.steeredIntoMessageId &&
104
+ state.activeTurn &&
105
+ payload.activeChildThreadId !== state.activeTurn.childThreadId
106
+ ? [...state.pendingSteerDeliveries, queued]
107
+ : state.pendingSteerDeliveries,
108
+ processedMessageIds,
109
+ idleDeadlineAt,
110
+ parked: false,
111
+ };
112
+ }
113
+ case 'agent.session.turn.started': {
114
+ const messageId = event.payload.messageId;
115
+ const admitted = state.pendingMessages.find((message) => message.messageId === messageId);
116
+ const text = [...state.nextTurnMessages, ...(admitted ? [admitted] : [])]
117
+ .map((message) => message.text)
118
+ .join('\n');
119
+ return {
120
+ ...state,
121
+ pendingMessages: state.pendingMessages.filter((message) => message.messageId !== messageId),
122
+ activeTurn: {
123
+ messageId,
124
+ childThreadId: event.payload.childThreadId,
125
+ text,
126
+ },
127
+ nextTurnMessages: [],
128
+ lastSequence: state.lastSequence + 1,
129
+ cancelling: false,
130
+ };
131
+ }
132
+ case 'agent.session.steer.delivered':
133
+ return {
134
+ ...state,
135
+ pendingSteerDeliveries: state.pendingSteerDeliveries.filter((message) => message.messageId !== event.payload.messageId),
136
+ };
137
+ case 'agent.session.turn.closed':
138
+ return {
139
+ ...state,
140
+ pendingClosures: state.pendingClosures.filter((closure) => closure.messageId !== event.payload.messageId),
141
+ };
142
+ case 'agent.session.cancel.requested':
143
+ case 'runtime.thread.cancel.requested':
144
+ return state.activeTurn ? { ...state, cancelling: true } : state;
145
+ case 'runtime.wait.satisfied': {
146
+ const payload = objectPayload(event);
147
+ const tag = Predicate.isObject(payload.tag) ? payload.tag : {};
148
+ if (tag.kind === 'agent-session-idle') {
149
+ if (tag.deadlineAt === state.idleDeadlineAt && state.activeTurn === null) {
150
+ return { ...state, parked: true, idleDeadlineAt: null };
151
+ }
152
+ return state;
153
+ }
154
+ if (tag.kind !== 'agent-session-turn' || !state.activeTurn) {
155
+ return state;
156
+ }
157
+ const active = state.activeTurn;
158
+ const consumed = new Set(consumedIds(event));
159
+ const result = closureStatus(event);
160
+ const pendingClosures = [
161
+ ...state.pendingClosures,
162
+ close(active.messageId, result.status, result.error),
163
+ ...[...consumed].map((messageId) => close(messageId, result.status, result.error)),
164
+ ];
165
+ return {
166
+ ...state,
167
+ pendingMessages: state.pendingMessages.flatMap((message) => {
168
+ if (consumed.has(message.messageId)) {
169
+ return [];
170
+ }
171
+ return message.steeredIntoMessageId === active.messageId
172
+ ? [{ ...message, steeredIntoMessageId: undefined }]
173
+ : [message];
174
+ }),
175
+ pendingSteerDeliveries: state.pendingSteerDeliveries.filter((message) => !consumed.has(message.messageId) &&
176
+ message.steeredIntoMessageId !== active.messageId),
177
+ pendingClosures,
178
+ activeTurn: null,
179
+ lastSequence: state.lastSequence + 1,
180
+ cancelling: false,
181
+ idleDeadlineAt: state.idleTimeoutMs > 0 ? event.ts + state.idleTimeoutMs : null,
182
+ };
183
+ }
184
+ default:
185
+ return state;
186
+ }
187
+ },
188
+ effects(state, ctx) {
189
+ const effects = [];
190
+ for (const closure of state.pendingClosures) {
191
+ effects.push(emit(agentModule.input('session.turn.closed', { messageId: closure.messageId, status: closure.status, error: closure.error }, { threadId: ctx.threadId }), `session_close_${closure.messageId}`));
192
+ }
193
+ for (const message of state.pendingSteerDeliveries) {
194
+ if (!state.activeTurn || message.steeredIntoMessageId !== state.activeTurn.messageId) {
195
+ continue;
196
+ }
197
+ effects.push(emit(agentModule.input('steered', {
198
+ turn: 0,
199
+ messageId: message.messageId,
200
+ message: { role: 'user', content: message.text },
201
+ interrupt: true,
202
+ }, { threadId: state.activeTurn.childThreadId }), `session_steer_${message.messageId}`), emit(agentModule.input('session.steer.delivered', { messageId: message.messageId, activeMessageId: state.activeTurn.messageId }, { threadId: ctx.threadId }), `session_steer_delivered_${message.messageId}`));
203
+ }
204
+ if (state.activeTurn) {
205
+ const { childThreadId: turnThreadId, messageId, text } = state.activeTurn;
206
+ const definition = definitions.get(state.definitionName, state.definitionVersion);
207
+ if (state.cancelling) {
208
+ effects.push(cancel(turnThreadId));
209
+ }
210
+ else if (definition) {
211
+ effects.push(spawn({
212
+ childThreadId: turnThreadId,
213
+ kind: 'agent',
214
+ definitionName: definition.agent.name,
215
+ definitionVersion: definition.agent.version,
216
+ input: { text },
217
+ }));
218
+ }
219
+ // The turn wait must survive cancellation: the child's cancelled event is what closes it.
220
+ effects.push(wait({
221
+ waitId: createWaitId(ctx.threadId, `turn_${messageId}`),
222
+ on: {
223
+ type: [
224
+ 'runtime.thread.completed',
225
+ 'runtime.thread.failed',
226
+ 'runtime.thread.cancelled',
227
+ ],
228
+ match: { threadId: turnThreadId },
229
+ },
230
+ tag: { kind: 'agent-session-turn', messageId },
231
+ }));
232
+ return effects;
233
+ }
234
+ const next = state.pendingMessages.find((message) => message.steeredIntoMessageId === undefined);
235
+ if (next) {
236
+ effects.push(emit(agentModule.input('session.turn.started', {
237
+ messageId: next.messageId,
238
+ childThreadId: deterministicThreadId(ctx.threadId, 'turn', next.messageId),
239
+ }, { threadId: ctx.threadId }), `session_admit_${next.messageId}`));
240
+ return effects;
241
+ }
242
+ if (state.parked || state.idleTimeoutMs === 0 || state.idleDeadlineAt === null) {
243
+ effects.push(wait({
244
+ waitId: createWaitId(ctx.threadId, 'mailbox'),
245
+ on: { type: 'agent.session.message.submitted', match: { threadId: ctx.threadId } },
246
+ tag: { kind: 'agent-session-mailbox' },
247
+ }));
248
+ }
249
+ else {
250
+ effects.push(wait({
251
+ waitId: createWaitId(ctx.threadId, `idle_${state.idleDeadlineAt}`),
252
+ on: { timerAt: state.idleDeadlineAt },
253
+ tag: { kind: 'agent-session-idle', deadlineAt: state.idleDeadlineAt },
254
+ }));
255
+ }
256
+ return effects;
257
+ },
258
+ });
259
+ }
260
+ export function agentSessionSnapshot(state) {
261
+ return {
262
+ activeTurnId: state.activeTurn?.messageId ?? null,
263
+ activeChildThreadId: state.activeTurn?.childThreadId ?? null,
264
+ pendingMessageCount: state.pendingMessages.length,
265
+ nextTurnHeldCount: state.nextTurnMessages.length,
266
+ processedMessageIds: state.processedMessageIds,
267
+ lastSequence: state.lastSequence,
268
+ parked: state.parked,
269
+ };
270
+ }
@@ -1,8 +1,7 @@
1
1
  import { Context, Layer } from 'effect';
2
+ import { type DefinitionStore } from '@swirls/looms/core';
2
3
  import type { AgentDefinition } from './definitions';
3
- export interface AgentDefinitionStore {
4
- get(name: string): AgentDefinition | undefined;
5
- }
4
+ export type AgentDefinitionStore = DefinitionStore<AgentDefinition>;
6
5
  declare const AgentDefinitionsTag_base: Context.ServiceClass<AgentDefinitionsTag, "looms/AgentDefinitions", AgentDefinitionStore>;
7
6
  export declare class AgentDefinitionsTag extends AgentDefinitionsTag_base {
8
7
  }
@@ -1,10 +1,8 @@
1
1
  import { Context, Layer } from 'effect';
2
+ import { makeDefinitionStore } from '@swirls/looms/core';
2
3
  export class AgentDefinitionsTag extends Context.Service()('looms/AgentDefinitions') {
3
4
  }
4
5
  export function makeAgentDefinitionStore(definitions) {
5
- const map = new Map(definitions.map((def) => [def.name, def]));
6
- return {
7
- get: (name) => map.get(name),
8
- };
6
+ return makeDefinitionStore('agent', definitions);
9
7
  }
10
8
  export const AgentDefinitionsLive = (definitions) => Layer.succeed(AgentDefinitionsTag, makeAgentDefinitionStore(definitions));
@@ -1,6 +1,6 @@
1
1
  import type { StandardSchemaV1 } from '@standard-schema/spec';
2
2
  import type { Schema } from 'effect';
3
- import type { InferDefinedSchema, JsonValue, RuntimeEffect, SchemaInput } from '@swirls/looms/core';
3
+ import { type JsonValue, type RuntimeEffect, type SchemaInput } from '@swirls/looms/core';
4
4
  import type { StopWhen } from './stop-when';
5
5
  import type { Message, ToolCall } from './types';
6
6
  export interface ToolContext {
@@ -12,7 +12,7 @@ export interface FunctionTool<TName extends string = string, TInput = JsonValue,
12
12
  readonly kind: 'function';
13
13
  readonly name: TName;
14
14
  readonly description: string;
15
- readonly input?: StandardSchemaV1<any, TInput> | Schema.Schema<TInput>;
15
+ readonly input?: StandardSchemaV1<any, TInput> | Schema.ConstraintDecoder<TInput>;
16
16
  readonly inputSchema?: JsonValue;
17
17
  handler(input: TInput, ctx: ToolContext): Promise<TOutput> | TOutput;
18
18
  }
@@ -24,9 +24,11 @@ export interface ThreadTool {
24
24
  readonly inputSchema?: JsonValue;
25
25
  readonly childKind: string;
26
26
  readonly childName: string;
27
+ readonly childVersion: string;
27
28
  readonly child: {
28
29
  kind: string;
29
30
  name: string;
31
+ version?: string;
30
32
  };
31
33
  mapInput?(input: JsonValue): JsonValue;
32
34
  }
@@ -46,6 +48,7 @@ export type ToolLike = FunctionTool | ThreadTool | EffectsTool;
46
48
  export type AgentToolEntry = ToolLike | {
47
49
  kind: string;
48
50
  name: string;
51
+ version?: string;
49
52
  instructions?: string;
50
53
  description?: string;
51
54
  input?: SchemaInput;
@@ -57,6 +60,7 @@ export interface AgentTurnContext<TInput = JsonValue> {
57
60
  readonly input: TInput;
58
61
  readonly tools: ToolLike[];
59
62
  readonly instructions: string;
63
+ readonly signal?: AbortSignal;
60
64
  }
61
65
  export interface AgentTurnResult<TOutput extends JsonValue = JsonValue> {
62
66
  message: Message;
@@ -71,9 +75,10 @@ export interface AgentTurnResult<TOutput extends JsonValue = JsonValue> {
71
75
  export interface AgentDefinition<TName extends string = string, TInput = JsonValue, TOutput extends JsonValue = JsonValue> {
72
76
  readonly kind: 'agent';
73
77
  readonly name: TName;
78
+ readonly version: string;
74
79
  readonly model?: string;
75
80
  readonly instructions: string;
76
- readonly input?: StandardSchemaV1<any, TInput> | Schema.Schema<TInput>;
81
+ readonly input?: StandardSchemaV1<any, TInput> | Schema.ConstraintDecoder<TInput>;
77
82
  readonly tools?: ToolLike[];
78
83
  readonly maxTurns?: number;
79
84
  readonly conversational?: boolean;
@@ -81,24 +86,26 @@ export interface AgentDefinition<TName extends string = string, TInput = JsonVal
81
86
  runTurn?(ctx: AgentTurnContext<TInput>): Promise<AgentTurnResult<TOutput>> | AgentTurnResult<TOutput>;
82
87
  }
83
88
  export type AnyAgentDefinition = AgentDefinition;
89
+ export interface AgentSessionDefinition<TName extends string = string> {
90
+ readonly kind: 'agent-session';
91
+ readonly name: TName;
92
+ readonly version: string;
93
+ /** The agent definition is pinned when the session definition is created. */
94
+ readonly agent: Pick<AgentDefinition, 'kind' | 'name' | 'version'>;
95
+ /** Max idle milliseconds before parking. Zero waits indefinitely. */
96
+ readonly idleTimeoutMs: number;
97
+ }
98
+ export declare function defineAgentSession<TName extends string>(def: {
99
+ readonly name: TName;
100
+ readonly agent: Pick<AgentDefinition, 'kind' | 'name' | 'version'>;
101
+ readonly version?: string;
102
+ readonly idleTimeoutMs?: number;
103
+ }): AgentSessionDefinition<TName>;
84
104
  export declare function normalizeTools(tools?: ReadonlyArray<AgentToolEntry>): ToolLike[];
85
- export declare function defineTool<TName extends string, TSchema = undefined, TInput = InferDefinedSchema<TSchema>, TOutput extends JsonValue = JsonValue>(def: {
86
- name: TName;
87
- description: string;
88
- input?: TSchema;
89
- inputSchema?: JsonValue;
90
- handler: (input: TInput, ctx: ToolContext) => Promise<TOutput> | TOutput;
91
- }): FunctionTool<TName, TInput, TOutput>;
92
- export declare function defineAgent<TName extends string, TSchema = undefined, TInput = InferDefinedSchema<TSchema>, TOutput extends JsonValue = JsonValue>(def: {
93
- name: TName;
94
- model?: string;
95
- instructions: string;
96
- input?: TSchema;
97
- tools?: AgentToolEntry[];
98
- maxTurns?: number;
99
- conversational?: boolean;
100
- stopWhen?: StopWhen;
101
- runTurn?: (ctx: AgentTurnContext<TInput>) => Promise<AgentTurnResult<TOutput>> | AgentTurnResult<TOutput>;
105
+ export declare function defineTool<TName extends string, TInput = JsonValue, TOutput extends JsonValue = JsonValue>(def: Omit<FunctionTool<TName, TInput, TOutput>, 'kind'>): FunctionTool<TName, TInput, TOutput>;
106
+ export declare function defineAgent<TName extends string, TInput = JsonValue, TOutput extends JsonValue = JsonValue>(def: Omit<AgentDefinition<TName, TInput, TOutput>, 'kind' | 'version' | 'tools'> & {
107
+ readonly version?: string;
108
+ readonly tools?: AgentToolEntry[];
102
109
  }): AgentDefinition<TName, TInput, TOutput>;
103
110
  export declare function asThreadTool(def: {
104
111
  name?: string;
@@ -108,6 +115,7 @@ export declare function asThreadTool(def: {
108
115
  child: {
109
116
  kind: string;
110
117
  name: string;
118
+ version?: string;
111
119
  };
112
120
  mapInput?: (input: JsonValue) => JsonValue;
113
121
  }): ThreadTool;
@@ -119,12 +127,28 @@ export declare function asAgentTool(def: {
119
127
  agent: {
120
128
  kind: 'agent';
121
129
  name: string;
130
+ version?: string;
122
131
  instructions?: string;
123
132
  input?: SchemaInput;
124
133
  inputSchema?: JsonValue;
125
134
  };
126
135
  mapInput?: (input: JsonValue) => JsonValue;
127
136
  }): ThreadTool;
137
+ type EvaluatorToolTarget = {
138
+ kind: 'evaluator';
139
+ name: string;
140
+ description?: string;
141
+ input?: SchemaInput;
142
+ inputSchema?: JsonValue;
143
+ };
144
+ export declare function asEvaluatorTool(def: {
145
+ name?: string;
146
+ description?: string;
147
+ input?: SchemaInput;
148
+ inputSchema?: JsonValue;
149
+ evaluator: EvaluatorToolTarget;
150
+ mapInput?: (input: JsonValue) => JsonValue;
151
+ }): ThreadTool;
128
152
  export declare function asWorkflowTool(def: {
129
153
  name?: string;
130
154
  description?: string;
@@ -133,6 +157,7 @@ export declare function asWorkflowTool(def: {
133
157
  workflow: {
134
158
  kind: 'workflow';
135
159
  name: string;
160
+ version?: string;
136
161
  description?: string;
137
162
  input?: SchemaInput;
138
163
  inputSchema?: JsonValue;
@@ -150,3 +175,4 @@ export declare function asEffectsTool(def: {
150
175
  match?: JsonValue;
151
176
  };
152
177
  }): EffectsTool;
178
+ export {};
@@ -1,7 +1,26 @@
1
+ import { DEFAULT_DEFINITION_VERSION, } from '@swirls/looms/core';
2
+ export function defineAgentSession(def) {
3
+ return {
4
+ kind: 'agent-session',
5
+ name: def.name,
6
+ version: def.version ?? DEFAULT_DEFINITION_VERSION,
7
+ agent: {
8
+ kind: 'agent',
9
+ name: def.agent.name,
10
+ version: def.agent.version,
11
+ },
12
+ idleTimeoutMs: Math.max(0, def.idleTimeoutMs ?? 0),
13
+ };
14
+ }
1
15
  export function normalizeTools(tools = []) {
2
16
  return tools.map((entry) => {
3
- if (entry.kind === 'function' || entry.kind === 'thread' || entry.kind === 'effects') {
4
- // SAFETY: kind discriminant matches ToolLike.
17
+ if (entry.kind === 'function' && 'handler' in entry) {
18
+ return entry;
19
+ }
20
+ if (entry.kind === 'thread' && 'child' in entry) {
21
+ return entry;
22
+ }
23
+ if (entry.kind === 'effects' && 'effects' in entry) {
5
24
  return entry;
6
25
  }
7
26
  return asThreadTool({
@@ -16,15 +35,13 @@ export function normalizeTools(tools = []) {
16
35
  });
17
36
  }
18
37
  export function defineTool(def) {
19
- // SAFETY: factory fields match FunctionTool.
20
- return { kind: 'function', ...def, input: def.input };
38
+ return { kind: 'function', ...def };
21
39
  }
22
40
  export function defineAgent(def) {
23
- // SAFETY: factory fields match AgentDefinition.
24
41
  return {
25
42
  kind: 'agent',
26
43
  ...def,
27
- input: def.input,
44
+ version: def.version ?? DEFAULT_DEFINITION_VERSION,
28
45
  tools: def.tools ? normalizeTools(def.tools) : undefined,
29
46
  };
30
47
  }
@@ -37,6 +54,7 @@ export function asThreadTool(def) {
37
54
  inputSchema: def.inputSchema,
38
55
  childKind: def.child.kind,
39
56
  childName: def.child.name,
57
+ childVersion: def.child.version ?? DEFAULT_DEFINITION_VERSION,
40
58
  child: def.child,
41
59
  mapInput: def.mapInput,
42
60
  };
@@ -47,7 +65,17 @@ export function asAgentTool(def) {
47
65
  description: def.description ?? def.agent.instructions,
48
66
  input: def.input ?? def.agent.input,
49
67
  inputSchema: def.inputSchema ?? def.agent.inputSchema,
50
- child: { kind: 'agent', name: def.agent.name },
68
+ child: { kind: 'agent', name: def.agent.name, version: def.agent.version },
69
+ mapInput: def.mapInput,
70
+ });
71
+ }
72
+ export function asEvaluatorTool(def) {
73
+ return asThreadTool({
74
+ name: def.name,
75
+ description: def.description ?? def.evaluator.description,
76
+ input: def.input ?? def.evaluator.input,
77
+ inputSchema: def.inputSchema ?? def.evaluator.inputSchema,
78
+ child: { kind: 'evaluator', name: def.evaluator.name },
51
79
  mapInput: def.mapInput,
52
80
  });
53
81
  }
@@ -57,7 +85,7 @@ export function asWorkflowTool(def) {
57
85
  description: def.description ?? def.workflow.description,
58
86
  input: def.input ?? def.workflow.input,
59
87
  inputSchema: def.inputSchema ?? def.workflow.inputSchema,
60
- child: { kind: 'workflow', name: def.workflow.name },
88
+ child: { kind: 'workflow', name: def.workflow.name, version: def.workflow.version },
61
89
  mapInput: def.mapInput,
62
90
  });
63
91
  }