@yolk-sdk/agent 0.0.1-canary.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 (161) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -0
  3. package/dist/client/index.d.mts +3 -0
  4. package/dist/client/index.mjs +3 -0
  5. package/dist/client/state.d.mts +99 -0
  6. package/dist/client/state.d.mts.map +1 -0
  7. package/dist/client/state.mjs +245 -0
  8. package/dist/client/state.mjs.map +1 -0
  9. package/dist/client/transport.d.mts +67 -0
  10. package/dist/client/transport.d.mts.map +1 -0
  11. package/dist/client/transport.mjs +219 -0
  12. package/dist/client/transport.mjs.map +1 -0
  13. package/dist/index.d.mts +1 -0
  14. package/dist/index.mjs +1 -0
  15. package/dist/loop/accumulator.d.mts +11 -0
  16. package/dist/loop/accumulator.d.mts.map +1 -0
  17. package/dist/loop/accumulator.mjs +40 -0
  18. package/dist/loop/accumulator.mjs.map +1 -0
  19. package/dist/loop/error.d.mts +36 -0
  20. package/dist/loop/error.d.mts.map +1 -0
  21. package/dist/loop/error.mjs +84 -0
  22. package/dist/loop/error.mjs.map +1 -0
  23. package/dist/loop/index.d.mts +9 -0
  24. package/dist/loop/index.mjs +9 -0
  25. package/dist/loop/llm-event.d.mts +44 -0
  26. package/dist/loop/llm-event.d.mts.map +1 -0
  27. package/dist/loop/llm-event.mjs +34 -0
  28. package/dist/loop/llm-event.mjs.map +1 -0
  29. package/dist/loop/run.d.mts +37 -0
  30. package/dist/loop/run.d.mts.map +1 -0
  31. package/dist/loop/run.mjs +624 -0
  32. package/dist/loop/run.mjs.map +1 -0
  33. package/dist/loop/services/context-transformer.d.mts +18 -0
  34. package/dist/loop/services/context-transformer.d.mts.map +1 -0
  35. package/dist/loop/services/context-transformer.mjs +12 -0
  36. package/dist/loop/services/context-transformer.mjs.map +1 -0
  37. package/dist/loop/services/llm-provider.d.mts +20 -0
  38. package/dist/loop/services/llm-provider.d.mts.map +1 -0
  39. package/dist/loop/services/llm-provider.mjs +7 -0
  40. package/dist/loop/services/llm-provider.mjs.map +1 -0
  41. package/dist/loop/services/loop-config.d.mts +17 -0
  42. package/dist/loop/services/loop-config.d.mts.map +1 -0
  43. package/dist/loop/services/loop-config.mjs +15 -0
  44. package/dist/loop/services/loop-config.mjs.map +1 -0
  45. package/dist/loop/services/tool-executor.d.mts +12 -0
  46. package/dist/loop/services/tool-executor.d.mts.map +1 -0
  47. package/dist/loop/services/tool-executor.mjs +7 -0
  48. package/dist/loop/services/tool-executor.mjs.map +1 -0
  49. package/dist/loop/testing/faux-provider.d.mts +31 -0
  50. package/dist/loop/testing/faux-provider.d.mts.map +1 -0
  51. package/dist/loop/testing/faux-provider.mjs +47 -0
  52. package/dist/loop/testing/faux-provider.mjs.map +1 -0
  53. package/dist/loop/testing/index.d.mts +3 -0
  54. package/dist/loop/testing/index.mjs +3 -0
  55. package/dist/loop/testing/test-tool-executor.d.mts +10 -0
  56. package/dist/loop/testing/test-tool-executor.d.mts.map +1 -0
  57. package/dist/loop/testing/test-tool-executor.mjs +21 -0
  58. package/dist/loop/testing/test-tool-executor.mjs.map +1 -0
  59. package/dist/protocol/capability.d.mts +20 -0
  60. package/dist/protocol/capability.d.mts.map +1 -0
  61. package/dist/protocol/capability.mjs +34 -0
  62. package/dist/protocol/capability.mjs.map +1 -0
  63. package/dist/protocol/content.d.mts +31 -0
  64. package/dist/protocol/content.d.mts.map +1 -0
  65. package/dist/protocol/content.mjs +52 -0
  66. package/dist/protocol/content.mjs.map +1 -0
  67. package/dist/protocol/event.d.mts +228 -0
  68. package/dist/protocol/event.d.mts.map +1 -0
  69. package/dist/protocol/event.mjs +217 -0
  70. package/dist/protocol/event.mjs.map +1 -0
  71. package/dist/protocol/index.d.mts +14 -0
  72. package/dist/protocol/index.d.mts.map +1 -0
  73. package/dist/protocol/index.mjs +9 -0
  74. package/dist/protocol/message.d.mts +53 -0
  75. package/dist/protocol/message.d.mts.map +1 -0
  76. package/dist/protocol/message.mjs +49 -0
  77. package/dist/protocol/message.mjs.map +1 -0
  78. package/dist/protocol/reasoning.d.mts +8 -0
  79. package/dist/protocol/reasoning.d.mts.map +1 -0
  80. package/dist/protocol/reasoning.mjs +13 -0
  81. package/dist/protocol/reasoning.mjs.map +1 -0
  82. package/dist/protocol/session.d.mts +39 -0
  83. package/dist/protocol/session.d.mts.map +1 -0
  84. package/dist/protocol/session.mjs +38 -0
  85. package/dist/protocol/session.mjs.map +1 -0
  86. package/dist/protocol/tool.d.mts +101 -0
  87. package/dist/protocol/tool.d.mts.map +1 -0
  88. package/dist/protocol/tool.mjs +102 -0
  89. package/dist/protocol/tool.mjs.map +1 -0
  90. package/dist/protocol/usage.d.mts +26 -0
  91. package/dist/protocol/usage.d.mts.map +1 -0
  92. package/dist/protocol/usage.mjs +40 -0
  93. package/dist/protocol/usage.mjs.map +1 -0
  94. package/dist/runtime/error.d.mts +29 -0
  95. package/dist/runtime/error.d.mts.map +1 -0
  96. package/dist/runtime/error.mjs +46 -0
  97. package/dist/runtime/error.mjs.map +1 -0
  98. package/dist/runtime/index.d.mts +9 -0
  99. package/dist/runtime/index.d.mts.map +1 -0
  100. package/dist/runtime/index.mjs +4 -0
  101. package/dist/runtime/run-runtime.d.mts +47 -0
  102. package/dist/runtime/run-runtime.d.mts.map +1 -0
  103. package/dist/runtime/run-runtime.mjs +112 -0
  104. package/dist/runtime/run-runtime.mjs.map +1 -0
  105. package/dist/runtime/session-event-store.d.mts +75 -0
  106. package/dist/runtime/session-event-store.d.mts.map +1 -0
  107. package/dist/runtime/session-event-store.mjs +124 -0
  108. package/dist/runtime/session-event-store.mjs.map +1 -0
  109. package/dist/tools/index.d.mts +4 -0
  110. package/dist/tools/index.mjs +4 -0
  111. package/dist/tools/question.d.mts +21 -0
  112. package/dist/tools/question.d.mts.map +1 -0
  113. package/dist/tools/question.mjs +41 -0
  114. package/dist/tools/question.mjs.map +1 -0
  115. package/dist/tools/registry.d.mts +61 -0
  116. package/dist/tools/registry.d.mts.map +1 -0
  117. package/dist/tools/registry.mjs +113 -0
  118. package/dist/tools/registry.mjs.map +1 -0
  119. package/dist/tools/task.d.mts +34 -0
  120. package/dist/tools/task.d.mts.map +1 -0
  121. package/dist/tools/task.mjs +81 -0
  122. package/dist/tools/task.mjs.map +1 -0
  123. package/package.json +86 -0
  124. package/src/client/README.md +23 -0
  125. package/src/client/index.ts +43 -0
  126. package/src/client/state.ts +380 -0
  127. package/src/client/transport.ts +517 -0
  128. package/src/index.ts +2 -0
  129. package/src/loop/README.md +23 -0
  130. package/src/loop/accumulator.ts +71 -0
  131. package/src/loop/error.ts +105 -0
  132. package/src/loop/index.ts +35 -0
  133. package/src/loop/llm-event.ts +52 -0
  134. package/src/loop/run.ts +1237 -0
  135. package/src/loop/services/context-transformer.ts +24 -0
  136. package/src/loop/services/llm-provider.ts +20 -0
  137. package/src/loop/services/loop-config.ts +20 -0
  138. package/src/loop/services/tool-executor.ts +11 -0
  139. package/src/loop/testing/faux-provider.ts +94 -0
  140. package/src/loop/testing/index.ts +3 -0
  141. package/src/loop/testing/test-tool-executor.ts +28 -0
  142. package/src/protocol/README.md +24 -0
  143. package/src/protocol/capability.ts +29 -0
  144. package/src/protocol/content.ts +76 -0
  145. package/src/protocol/event.ts +286 -0
  146. package/src/protocol/index.ts +109 -0
  147. package/src/protocol/message.ts +86 -0
  148. package/src/protocol/reasoning.ts +4 -0
  149. package/src/protocol/session.ts +47 -0
  150. package/src/protocol/tool.ts +154 -0
  151. package/src/protocol/usage.ts +48 -0
  152. package/src/runtime/README.md +44 -0
  153. package/src/runtime/error.ts +70 -0
  154. package/src/runtime/index.ts +43 -0
  155. package/src/runtime/run-runtime.ts +307 -0
  156. package/src/runtime/session-event-store.ts +254 -0
  157. package/src/tools/README.md +22 -0
  158. package/src/tools/index.ts +29 -0
  159. package/src/tools/question.ts +58 -0
  160. package/src/tools/registry.ts +228 -0
  161. package/src/tools/task.ts +132 -0
@@ -0,0 +1,380 @@
1
+ import {
2
+ type AgentEvent,
3
+ type AgentMessage,
4
+ type QuestionRequest,
5
+ type QuestionResponse,
6
+ type ToolCall,
7
+ type ToolResult,
8
+ type UserMessage
9
+ } from '@yolk-sdk/agent/protocol'
10
+
11
+ export type AgentRunStatus = 'idle' | 'running' | 'waiting' | 'done' | 'error' | 'aborted'
12
+
13
+ export type AgentToolRun =
14
+ | {
15
+ readonly _tag: 'InputStreaming'
16
+ readonly id: string
17
+ readonly name?: string
18
+ readonly input: string
19
+ }
20
+ | { readonly _tag: 'InputReady'; readonly call: ToolCall }
21
+ | { readonly _tag: 'ApprovalRequested'; readonly call: ToolCall }
22
+ | { readonly _tag: 'Denied'; readonly toolCallId: string; readonly reason: string }
23
+ | { readonly _tag: 'QuestionRequested'; readonly request: QuestionRequest }
24
+ | { readonly _tag: 'QuestionAnswered'; readonly response: QuestionResponse }
25
+ | { readonly _tag: 'QuestionCancelled'; readonly response: QuestionResponse }
26
+ | { readonly _tag: 'Executing'; readonly call: ToolCall; readonly startedAtMs: number }
27
+ | {
28
+ readonly _tag: 'Completed'
29
+ readonly call: ToolCall
30
+ readonly result: ToolResult
31
+ readonly startedAtMs: number
32
+ readonly endedAtMs: number
33
+ }
34
+ | {
35
+ readonly _tag: 'Errored'
36
+ readonly call: ToolCall
37
+ readonly message: string
38
+ readonly endedAtMs: number
39
+ }
40
+ | { readonly _tag: 'ProviderCompleted'; readonly call: ToolCall; readonly result: ToolResult }
41
+
42
+ type StartedAgentToolRun = Extract<AgentToolRun, { readonly _tag: 'Executing' | 'Completed' }>
43
+
44
+ export type AgentClientState = {
45
+ readonly status: AgentRunStatus
46
+ readonly messages: ReadonlyArray<AgentMessage>
47
+ readonly liveMessages: ReadonlyArray<AgentMessage>
48
+ readonly text: string
49
+ readonly reasoning: string
50
+ readonly toolRuns: ReadonlyArray<AgentToolRun>
51
+ readonly error: string | null
52
+ readonly seenEventIds: ReadonlyArray<string>
53
+ }
54
+
55
+ export type ApplyAgentEventOptions = {
56
+ readonly nowMs?: number
57
+ }
58
+
59
+ export type AgentTranscript = readonly [AgentMessage, ...Array<AgentMessage>]
60
+
61
+ export const initialAgentClientState: AgentClientState = {
62
+ status: 'idle',
63
+ messages: [],
64
+ liveMessages: [],
65
+ text: '',
66
+ reasoning: '',
67
+ toolRuns: [],
68
+ error: null,
69
+ seenEventIds: []
70
+ }
71
+
72
+ const hasSeenEvent = (state: AgentClientState, event: AgentEvent) =>
73
+ event.eventId !== undefined && state.seenEventIds.includes(event.eventId)
74
+
75
+ const rememberEvent = (state: AgentClientState, event: AgentEvent): AgentClientState =>
76
+ event.eventId === undefined
77
+ ? state
78
+ : { ...state, seenEventIds: [...state.seenEventIds, event.eventId] }
79
+
80
+ const toolRunId = (run: AgentToolRun) => {
81
+ switch (run._tag) {
82
+ case 'InputStreaming':
83
+ return run.id
84
+ case 'Denied':
85
+ return run.toolCallId
86
+ case 'QuestionRequested':
87
+ return run.request.toolCallId
88
+ case 'QuestionAnswered':
89
+ case 'QuestionCancelled':
90
+ return run.response.toolCallId
91
+ case 'InputReady':
92
+ case 'ApprovalRequested':
93
+ case 'Executing':
94
+ case 'Completed':
95
+ case 'Errored':
96
+ case 'ProviderCompleted':
97
+ return run.call.id
98
+ }
99
+ }
100
+
101
+ export const isActiveToolRun = (run: AgentToolRun) =>
102
+ run._tag !== 'Completed' &&
103
+ run._tag !== 'Errored' &&
104
+ run._tag !== 'Denied' &&
105
+ run._tag !== 'QuestionAnswered' &&
106
+ run._tag !== 'QuestionCancelled' &&
107
+ run._tag !== 'ProviderCompleted'
108
+
109
+ export const completedToolRuns = (runs: ReadonlyArray<AgentToolRun>) =>
110
+ runs.filter(run => run._tag === 'Completed')
111
+
112
+ const replaceToolRun = (
113
+ runs: ReadonlyArray<AgentToolRun>,
114
+ run: AgentToolRun
115
+ ): ReadonlyArray<AgentToolRun> => {
116
+ const id = toolRunId(run)
117
+ const replaceIndex = runs.findIndex(current => toolRunId(current) === id)
118
+
119
+ if (replaceIndex === -1) {
120
+ return [...runs, run]
121
+ }
122
+
123
+ return runs.flatMap((current, index) => {
124
+ if (toolRunId(current) !== id) {
125
+ return [current]
126
+ }
127
+
128
+ return index === replaceIndex ? [run] : []
129
+ })
130
+ }
131
+
132
+ const isStartedToolRun = (run: AgentToolRun): run is StartedAgentToolRun =>
133
+ run._tag === 'Executing' || run._tag === 'Completed'
134
+
135
+ const startedAtMsFor = (runs: ReadonlyArray<AgentToolRun>, toolCallId: string) =>
136
+ runs.filter(isStartedToolRun).find(run => run.call.id === toolCallId)?.startedAtMs
137
+
138
+ const appendToolInputDelta = (
139
+ runs: ReadonlyArray<AgentToolRun>,
140
+ id: string,
141
+ delta: string
142
+ ): ReadonlyArray<AgentToolRun> =>
143
+ runs.map(run =>
144
+ run._tag === 'InputStreaming' && run.id === id ? { ...run, input: `${run.input}${delta}` } : run
145
+ )
146
+
147
+ export const appendAgentMessage = (
148
+ messages: ReadonlyArray<AgentMessage>,
149
+ message: AgentMessage
150
+ ): AgentTranscript => {
151
+ const first = messages[0]
152
+
153
+ if (first === undefined) {
154
+ return [message]
155
+ }
156
+
157
+ return [first, ...messages.slice(1), message]
158
+ }
159
+
160
+ export const applyAgentEvent = (state: AgentClientState, event: AgentEvent): AgentClientState => {
161
+ const nowMs = 0
162
+
163
+ return applyAgentEventWithOptions(state, event, { nowMs })
164
+ }
165
+
166
+ export const applyAgentEventWithOptions = (
167
+ state: AgentClientState,
168
+ event: AgentEvent,
169
+ options: ApplyAgentEventOptions = {}
170
+ ): AgentClientState => {
171
+ const nowMs = options.nowMs ?? 0
172
+
173
+ if (hasSeenEvent(state, event)) {
174
+ return state
175
+ }
176
+
177
+ return rememberEvent(applyAgentEventUnchecked(state, event, nowMs), event)
178
+ }
179
+
180
+ const applyAgentEventUnchecked = (
181
+ state: AgentClientState,
182
+ event: AgentEvent,
183
+ nowMs: number
184
+ ): AgentClientState => {
185
+ switch (event._tag) {
186
+ case 'AgentStart':
187
+ return {
188
+ ...state,
189
+ status: 'running',
190
+ text: '',
191
+ reasoning: '',
192
+ liveMessages: [],
193
+ toolRuns: completedToolRuns(state.toolRuns),
194
+ error: null
195
+ }
196
+ case 'AgentError':
197
+ return markAgentError(state, event.message)
198
+ case 'LLMTextDelta':
199
+ return { ...state, text: `${state.text}${event.text}` }
200
+ case 'LLMReasoningDelta':
201
+ return { ...state, reasoning: `${state.reasoning}${event.text}` }
202
+ case 'ToolInputStart':
203
+ return {
204
+ ...state,
205
+ toolRuns: replaceToolRun(state.toolRuns, {
206
+ _tag: 'InputStreaming',
207
+ id: event.id,
208
+ name: event.name,
209
+ input: ''
210
+ })
211
+ }
212
+ case 'ToolInputDelta':
213
+ return { ...state, toolRuns: appendToolInputDelta(state.toolRuns, event.id, event.delta) }
214
+ case 'ToolInputEnd':
215
+ return {
216
+ ...state,
217
+ toolRuns: replaceToolRun(state.toolRuns, { _tag: 'InputReady', call: event.call })
218
+ }
219
+ case 'ToolApprovalRequested':
220
+ return {
221
+ ...state,
222
+ toolRuns: replaceToolRun(state.toolRuns, { _tag: 'ApprovalRequested', call: event.call })
223
+ }
224
+ case 'ToolApprovalGranted':
225
+ return state
226
+ case 'ToolApprovalDenied':
227
+ return {
228
+ ...state,
229
+ toolRuns: replaceToolRun(state.toolRuns, {
230
+ _tag: 'Denied',
231
+ toolCallId: event.toolCallId,
232
+ reason: event.reason
233
+ })
234
+ }
235
+ case 'QuestionRequested':
236
+ return {
237
+ ...state,
238
+ toolRuns: replaceToolRun(state.toolRuns, {
239
+ _tag: 'QuestionRequested',
240
+ request: event.request
241
+ })
242
+ }
243
+ case 'QuestionAnswered':
244
+ return {
245
+ ...state,
246
+ toolRuns: replaceToolRun(state.toolRuns, {
247
+ _tag: 'QuestionAnswered',
248
+ response: event.response
249
+ })
250
+ }
251
+ case 'QuestionCancelled':
252
+ return {
253
+ ...state,
254
+ toolRuns: replaceToolRun(state.toolRuns, {
255
+ _tag: 'QuestionCancelled',
256
+ response: event.response
257
+ })
258
+ }
259
+ case 'ToolExecutionStarted':
260
+ return {
261
+ ...state,
262
+ toolRuns: replaceToolRun(state.toolRuns, {
263
+ _tag: 'Executing',
264
+ call: event.call,
265
+ startedAtMs: nowMs
266
+ })
267
+ }
268
+ case 'ToolExecutionCompleted': {
269
+ const endedAtMs = nowMs
270
+ const startedAtMs = startedAtMsFor(state.toolRuns, event.call.id) ?? endedAtMs
271
+
272
+ return {
273
+ ...state,
274
+ toolRuns: replaceToolRun(state.toolRuns, {
275
+ _tag: 'Completed',
276
+ call: event.call,
277
+ result: event.result,
278
+ startedAtMs,
279
+ endedAtMs
280
+ })
281
+ }
282
+ }
283
+ case 'ToolExecutionError':
284
+ return {
285
+ ...state,
286
+ toolRuns: replaceToolRun(state.toolRuns, {
287
+ _tag: 'Errored',
288
+ call: event.call,
289
+ message: event.message,
290
+ endedAtMs: nowMs
291
+ })
292
+ }
293
+ case 'ProviderToolResult':
294
+ return {
295
+ ...state,
296
+ toolRuns: replaceToolRun(state.toolRuns, {
297
+ _tag: 'ProviderCompleted',
298
+ call: event.call,
299
+ result: event.result
300
+ })
301
+ }
302
+ case 'AssistantMessage':
303
+ return {
304
+ ...state,
305
+ liveMessages: [...state.liveMessages, event.message],
306
+ text: '',
307
+ reasoning: ''
308
+ }
309
+ case 'AgentEnd':
310
+ return {
311
+ ...state,
312
+ status: 'done',
313
+ messages: [...state.messages, ...event.messages],
314
+ liveMessages: [],
315
+ text: '',
316
+ reasoning: '',
317
+ toolRuns: completedToolRuns(state.toolRuns)
318
+ }
319
+ case 'AgentAwaitingInput':
320
+ return {
321
+ ...state,
322
+ status: 'waiting',
323
+ messages: [...state.messages, ...event.messages],
324
+ liveMessages: [],
325
+ text: '',
326
+ reasoning: '',
327
+ error: null
328
+ }
329
+ case 'AgentRetry':
330
+ case 'CompactionEnd':
331
+ case 'CompactionStart':
332
+ case 'LLMStreamEnd':
333
+ case 'LLMStreamStart':
334
+ case 'SubagentCompleted':
335
+ case 'SubagentStarted':
336
+ case 'TurnEnd':
337
+ case 'TurnStart':
338
+ case 'UsageUpdate':
339
+ return state
340
+ }
341
+ }
342
+
343
+ export const submitAgentUserMessage = (
344
+ state: AgentClientState,
345
+ message: UserMessage
346
+ ): AgentClientState => ({
347
+ ...state,
348
+ status: 'running',
349
+ messages: appendAgentMessage(state.messages, message),
350
+ liveMessages: [],
351
+ text: '',
352
+ reasoning: '',
353
+ toolRuns: completedToolRuns(state.toolRuns),
354
+ error: null,
355
+ seenEventIds: []
356
+ })
357
+
358
+ export const markAgentError = (
359
+ state: AgentClientState,
360
+ message = 'Agent request failed'
361
+ ): AgentClientState => ({
362
+ ...state,
363
+ status: 'error',
364
+ toolRuns: completedToolRuns(state.toolRuns),
365
+ error: message
366
+ })
367
+
368
+ export const markAgentAborted = (state: AgentClientState): AgentClientState => ({
369
+ ...state,
370
+ status: 'aborted',
371
+ toolRuns: completedToolRuns(state.toolRuns),
372
+ error: null
373
+ })
374
+
375
+ export const reduceAgentEvents = (
376
+ events: ReadonlyArray<AgentEvent>,
377
+ initialState: AgentClientState = initialAgentClientState,
378
+ options: ApplyAgentEventOptions = {}
379
+ ) =>
380
+ events.reduce((state, event) => applyAgentEventWithOptions(state, event, options), initialState)