@link-assistant/agent 0.0.9 → 0.0.12

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 (104) hide show
  1. package/EXAMPLES.md +36 -0
  2. package/MODELS.md +72 -24
  3. package/README.md +59 -2
  4. package/TOOLS.md +20 -0
  5. package/package.json +35 -2
  6. package/src/agent/agent.ts +68 -54
  7. package/src/auth/claude-oauth.ts +426 -0
  8. package/src/auth/index.ts +28 -26
  9. package/src/auth/plugins.ts +876 -0
  10. package/src/bun/index.ts +53 -43
  11. package/src/bus/global.ts +5 -5
  12. package/src/bus/index.ts +59 -53
  13. package/src/cli/bootstrap.js +12 -12
  14. package/src/cli/bootstrap.ts +6 -6
  15. package/src/cli/cmd/agent.ts +97 -92
  16. package/src/cli/cmd/auth.ts +469 -0
  17. package/src/cli/cmd/cmd.ts +2 -2
  18. package/src/cli/cmd/export.ts +41 -41
  19. package/src/cli/cmd/mcp.ts +144 -119
  20. package/src/cli/cmd/models.ts +30 -29
  21. package/src/cli/cmd/run.ts +269 -213
  22. package/src/cli/cmd/stats.ts +185 -146
  23. package/src/cli/error.ts +17 -13
  24. package/src/cli/ui.ts +39 -24
  25. package/src/command/index.ts +26 -26
  26. package/src/config/config.ts +528 -288
  27. package/src/config/markdown.ts +15 -15
  28. package/src/file/ripgrep.ts +201 -169
  29. package/src/file/time.ts +21 -18
  30. package/src/file/watcher.ts +51 -42
  31. package/src/file.ts +1 -1
  32. package/src/flag/flag.ts +26 -11
  33. package/src/format/formatter.ts +206 -162
  34. package/src/format/index.ts +61 -61
  35. package/src/global/index.ts +21 -21
  36. package/src/id/id.ts +47 -33
  37. package/src/index.js +346 -199
  38. package/src/json-standard/index.ts +67 -51
  39. package/src/mcp/index.ts +135 -128
  40. package/src/patch/index.ts +336 -267
  41. package/src/project/bootstrap.ts +15 -15
  42. package/src/project/instance.ts +43 -36
  43. package/src/project/project.ts +47 -47
  44. package/src/project/state.ts +37 -33
  45. package/src/provider/models-macro.ts +5 -5
  46. package/src/provider/models.ts +32 -32
  47. package/src/provider/opencode.js +19 -19
  48. package/src/provider/provider.ts +518 -277
  49. package/src/provider/transform.ts +143 -102
  50. package/src/server/project.ts +21 -21
  51. package/src/server/server.ts +111 -105
  52. package/src/session/agent.js +66 -60
  53. package/src/session/compaction.ts +136 -111
  54. package/src/session/index.ts +189 -156
  55. package/src/session/message-v2.ts +312 -268
  56. package/src/session/message.ts +73 -57
  57. package/src/session/processor.ts +180 -166
  58. package/src/session/prompt.ts +678 -533
  59. package/src/session/retry.ts +26 -23
  60. package/src/session/revert.ts +76 -62
  61. package/src/session/status.ts +26 -26
  62. package/src/session/summary.ts +97 -76
  63. package/src/session/system.ts +77 -63
  64. package/src/session/todo.ts +22 -16
  65. package/src/snapshot/index.ts +92 -76
  66. package/src/storage/storage.ts +157 -120
  67. package/src/tool/bash.ts +116 -106
  68. package/src/tool/batch.ts +73 -59
  69. package/src/tool/codesearch.ts +60 -53
  70. package/src/tool/edit.ts +319 -263
  71. package/src/tool/glob.ts +32 -28
  72. package/src/tool/grep.ts +72 -53
  73. package/src/tool/invalid.ts +7 -7
  74. package/src/tool/ls.ts +77 -64
  75. package/src/tool/multiedit.ts +30 -21
  76. package/src/tool/patch.ts +121 -94
  77. package/src/tool/read.ts +140 -122
  78. package/src/tool/registry.ts +38 -38
  79. package/src/tool/task.ts +93 -60
  80. package/src/tool/todo.ts +16 -16
  81. package/src/tool/tool.ts +45 -36
  82. package/src/tool/webfetch.ts +97 -74
  83. package/src/tool/websearch.ts +78 -64
  84. package/src/tool/write.ts +21 -15
  85. package/src/util/binary.ts +27 -19
  86. package/src/util/context.ts +8 -8
  87. package/src/util/defer.ts +7 -5
  88. package/src/util/error.ts +24 -19
  89. package/src/util/eventloop.ts +16 -10
  90. package/src/util/filesystem.ts +37 -33
  91. package/src/util/fn.ts +11 -8
  92. package/src/util/iife.ts +1 -1
  93. package/src/util/keybind.ts +44 -44
  94. package/src/util/lazy.ts +7 -7
  95. package/src/util/locale.ts +20 -16
  96. package/src/util/lock.ts +43 -38
  97. package/src/util/log.ts +95 -85
  98. package/src/util/queue.ts +8 -8
  99. package/src/util/rpc.ts +35 -23
  100. package/src/util/scrap.ts +4 -4
  101. package/src/util/signal.ts +5 -5
  102. package/src/util/timeout.ts +6 -6
  103. package/src/util/token.ts +2 -2
  104. package/src/util/wildcard.ts +38 -27
@@ -1,60 +1,72 @@
1
- import z from "zod"
2
- import { Bus } from "../bus"
3
- import { NamedError } from "../util/error"
4
- import { Message } from "./message"
5
- import { APICallError, convertToModelMessages, LoadAPIKeyError, type ModelMessage, type UIMessage } from "ai"
6
- import { Identifier } from "../id/id"
7
- import { Snapshot } from "../snapshot"
8
- import { fn } from "../util/fn"
9
- import { Storage } from "../storage/storage"
1
+ import z from 'zod';
2
+ import { Bus } from '../bus';
3
+ import { NamedError } from '../util/error';
4
+ import { Message } from './message';
5
+ import {
6
+ APICallError,
7
+ convertToModelMessages,
8
+ LoadAPIKeyError,
9
+ type ModelMessage,
10
+ type UIMessage,
11
+ } from 'ai';
12
+ import { Identifier } from '../id/id';
13
+ import { Snapshot } from '../snapshot';
14
+ import { fn } from '../util/fn';
15
+ import { Storage } from '../storage/storage';
10
16
 
11
17
  export namespace MessageV2 {
12
- export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({}))
13
- export const AbortedError = NamedError.create("MessageAbortedError", z.object({ message: z.string() }))
18
+ export const OutputLengthError = NamedError.create(
19
+ 'MessageOutputLengthError',
20
+ z.object({})
21
+ );
22
+ export const AbortedError = NamedError.create(
23
+ 'MessageAbortedError',
24
+ z.object({ message: z.string() })
25
+ );
14
26
  export const AuthError = NamedError.create(
15
- "ProviderAuthError",
27
+ 'ProviderAuthError',
16
28
  z.object({
17
29
  providerID: z.string(),
18
30
  message: z.string(),
19
- }),
20
- )
31
+ })
32
+ );
21
33
  export const APIError = NamedError.create(
22
- "APIError",
34
+ 'APIError',
23
35
  z.object({
24
36
  message: z.string(),
25
37
  statusCode: z.number().optional(),
26
38
  isRetryable: z.boolean(),
27
39
  responseHeaders: z.record(z.string(), z.string()).optional(),
28
40
  responseBody: z.string().optional(),
29
- }),
30
- )
31
- export type APIError = z.infer<typeof APIError.Schema>
41
+ })
42
+ );
43
+ export type APIError = z.infer<typeof APIError.Schema>;
32
44
 
33
45
  const PartBase = z.object({
34
46
  id: z.string(),
35
47
  sessionID: z.string(),
36
48
  messageID: z.string(),
37
- })
49
+ });
38
50
 
39
51
  export const SnapshotPart = PartBase.extend({
40
- type: z.literal("snapshot"),
52
+ type: z.literal('snapshot'),
41
53
  snapshot: z.string(),
42
54
  }).meta({
43
- ref: "SnapshotPart",
44
- })
45
- export type SnapshotPart = z.infer<typeof SnapshotPart>
55
+ ref: 'SnapshotPart',
56
+ });
57
+ export type SnapshotPart = z.infer<typeof SnapshotPart>;
46
58
 
47
59
  export const PatchPart = PartBase.extend({
48
- type: z.literal("patch"),
60
+ type: z.literal('patch'),
49
61
  hash: z.string(),
50
62
  files: z.string().array(),
51
63
  }).meta({
52
- ref: "PatchPart",
53
- })
54
- export type PatchPart = z.infer<typeof PatchPart>
64
+ ref: 'PatchPart',
65
+ });
66
+ export type PatchPart = z.infer<typeof PatchPart>;
55
67
 
56
68
  export const TextPart = PartBase.extend({
57
- type: z.literal("text"),
69
+ type: z.literal('text'),
58
70
  text: z.string(),
59
71
  synthetic: z.boolean().optional(),
60
72
  time: z
@@ -65,12 +77,12 @@ export namespace MessageV2 {
65
77
  .optional(),
66
78
  metadata: z.record(z.string(), z.any()).optional(),
67
79
  }).meta({
68
- ref: "TextPart",
69
- })
70
- export type TextPart = z.infer<typeof TextPart>
80
+ ref: 'TextPart',
81
+ });
82
+ export type TextPart = z.infer<typeof TextPart>;
71
83
 
72
84
  export const ReasoningPart = PartBase.extend({
73
- type: z.literal("reasoning"),
85
+ type: z.literal('reasoning'),
74
86
  text: z.string(),
75
87
  metadata: z.record(z.string(), z.any()).optional(),
76
88
  time: z.object({
@@ -78,9 +90,9 @@ export namespace MessageV2 {
78
90
  end: z.number().optional(),
79
91
  }),
80
92
  }).meta({
81
- ref: "ReasoningPart",
82
- })
83
- export type ReasoningPart = z.infer<typeof ReasoningPart>
93
+ ref: 'ReasoningPart',
94
+ });
95
+ export type ReasoningPart = z.infer<typeof ReasoningPart>;
84
96
 
85
97
  const FilePartSourceBase = z.object({
86
98
  text: z
@@ -90,19 +102,19 @@ export namespace MessageV2 {
90
102
  end: z.number().int(),
91
103
  })
92
104
  .meta({
93
- ref: "FilePartSourceText",
105
+ ref: 'FilePartSourceText',
94
106
  }),
95
- })
107
+ });
96
108
 
97
109
  export const FileSource = FilePartSourceBase.extend({
98
- type: z.literal("file"),
110
+ type: z.literal('file'),
99
111
  path: z.string(),
100
112
  }).meta({
101
- ref: "FileSource",
102
- })
113
+ ref: 'FileSource',
114
+ });
103
115
 
104
116
  export const SymbolSource = FilePartSourceBase.extend({
105
- type: z.literal("symbol"),
117
+ type: z.literal('symbol'),
106
118
  path: z.string(),
107
119
  range: z.object({
108
120
  start: z.object({ line: z.number(), character: z.number() }),
@@ -111,26 +123,28 @@ export namespace MessageV2 {
111
123
  name: z.string(),
112
124
  kind: z.number().int(),
113
125
  }).meta({
114
- ref: "SymbolSource",
115
- })
126
+ ref: 'SymbolSource',
127
+ });
116
128
 
117
- export const FilePartSource = z.discriminatedUnion("type", [FileSource, SymbolSource]).meta({
118
- ref: "FilePartSource",
119
- })
129
+ export const FilePartSource = z
130
+ .discriminatedUnion('type', [FileSource, SymbolSource])
131
+ .meta({
132
+ ref: 'FilePartSource',
133
+ });
120
134
 
121
135
  export const FilePart = PartBase.extend({
122
- type: z.literal("file"),
136
+ type: z.literal('file'),
123
137
  mime: z.string(),
124
138
  filename: z.string().optional(),
125
139
  url: z.string(),
126
140
  source: FilePartSource.optional(),
127
141
  }).meta({
128
- ref: "FilePart",
129
- })
130
- export type FilePart = z.infer<typeof FilePart>
142
+ ref: 'FilePart',
143
+ });
144
+ export type FilePart = z.infer<typeof FilePart>;
131
145
 
132
146
  export const AgentPart = PartBase.extend({
133
- type: z.literal("agent"),
147
+ type: z.literal('agent'),
134
148
  name: z.string(),
135
149
  source: z
136
150
  .object({
@@ -140,47 +154,47 @@ export namespace MessageV2 {
140
154
  })
141
155
  .optional(),
142
156
  }).meta({
143
- ref: "AgentPart",
144
- })
145
- export type AgentPart = z.infer<typeof AgentPart>
157
+ ref: 'AgentPart',
158
+ });
159
+ export type AgentPart = z.infer<typeof AgentPart>;
146
160
 
147
161
  export const CompactionPart = PartBase.extend({
148
- type: z.literal("compaction"),
162
+ type: z.literal('compaction'),
149
163
  }).meta({
150
- ref: "CompactionPart",
151
- })
152
- export type CompactionPart = z.infer<typeof CompactionPart>
164
+ ref: 'CompactionPart',
165
+ });
166
+ export type CompactionPart = z.infer<typeof CompactionPart>;
153
167
 
154
168
  export const SubtaskPart = PartBase.extend({
155
- type: z.literal("subtask"),
169
+ type: z.literal('subtask'),
156
170
  prompt: z.string(),
157
171
  description: z.string(),
158
172
  agent: z.string(),
159
- })
160
- export type SubtaskPart = z.infer<typeof SubtaskPart>
173
+ });
174
+ export type SubtaskPart = z.infer<typeof SubtaskPart>;
161
175
 
162
176
  export const RetryPart = PartBase.extend({
163
- type: z.literal("retry"),
177
+ type: z.literal('retry'),
164
178
  attempt: z.number(),
165
179
  error: APIError.Schema,
166
180
  time: z.object({
167
181
  created: z.number(),
168
182
  }),
169
183
  }).meta({
170
- ref: "RetryPart",
171
- })
172
- export type RetryPart = z.infer<typeof RetryPart>
184
+ ref: 'RetryPart',
185
+ });
186
+ export type RetryPart = z.infer<typeof RetryPart>;
173
187
 
174
188
  export const StepStartPart = PartBase.extend({
175
- type: z.literal("step-start"),
189
+ type: z.literal('step-start'),
176
190
  snapshot: z.string().optional(),
177
191
  }).meta({
178
- ref: "StepStartPart",
179
- })
180
- export type StepStartPart = z.infer<typeof StepStartPart>
192
+ ref: 'StepStartPart',
193
+ });
194
+ export type StepStartPart = z.infer<typeof StepStartPart>;
181
195
 
182
196
  export const StepFinishPart = PartBase.extend({
183
- type: z.literal("step-finish"),
197
+ type: z.literal('step-finish'),
184
198
  reason: z.string(),
185
199
  snapshot: z.string().optional(),
186
200
  cost: z.number(),
@@ -194,25 +208,25 @@ export namespace MessageV2 {
194
208
  }),
195
209
  }),
196
210
  }).meta({
197
- ref: "StepFinishPart",
198
- })
199
- export type StepFinishPart = z.infer<typeof StepFinishPart>
211
+ ref: 'StepFinishPart',
212
+ });
213
+ export type StepFinishPart = z.infer<typeof StepFinishPart>;
200
214
 
201
215
  export const ToolStatePending = z
202
216
  .object({
203
- status: z.literal("pending"),
217
+ status: z.literal('pending'),
204
218
  input: z.record(z.string(), z.any()),
205
219
  raw: z.string(),
206
220
  })
207
221
  .meta({
208
- ref: "ToolStatePending",
209
- })
222
+ ref: 'ToolStatePending',
223
+ });
210
224
 
211
- export type ToolStatePending = z.infer<typeof ToolStatePending>
225
+ export type ToolStatePending = z.infer<typeof ToolStatePending>;
212
226
 
213
227
  export const ToolStateRunning = z
214
228
  .object({
215
- status: z.literal("running"),
229
+ status: z.literal('running'),
216
230
  input: z.record(z.string(), z.any()),
217
231
  title: z.string().optional(),
218
232
  metadata: z.record(z.string(), z.any()).optional(),
@@ -221,13 +235,13 @@ export namespace MessageV2 {
221
235
  }),
222
236
  })
223
237
  .meta({
224
- ref: "ToolStateRunning",
225
- })
226
- export type ToolStateRunning = z.infer<typeof ToolStateRunning>
238
+ ref: 'ToolStateRunning',
239
+ });
240
+ export type ToolStateRunning = z.infer<typeof ToolStateRunning>;
227
241
 
228
242
  export const ToolStateCompleted = z
229
243
  .object({
230
- status: z.literal("completed"),
244
+ status: z.literal('completed'),
231
245
  input: z.record(z.string(), z.any()),
232
246
  output: z.string(),
233
247
  title: z.string(),
@@ -240,13 +254,13 @@ export namespace MessageV2 {
240
254
  attachments: FilePart.array().optional(),
241
255
  })
242
256
  .meta({
243
- ref: "ToolStateCompleted",
244
- })
245
- export type ToolStateCompleted = z.infer<typeof ToolStateCompleted>
257
+ ref: 'ToolStateCompleted',
258
+ });
259
+ export type ToolStateCompleted = z.infer<typeof ToolStateCompleted>;
246
260
 
247
261
  export const ToolStateError = z
248
262
  .object({
249
- status: z.literal("error"),
263
+ status: z.literal('error'),
250
264
  input: z.record(z.string(), z.any()),
251
265
  error: z.string(),
252
266
  metadata: z.record(z.string(), z.any()).optional(),
@@ -256,34 +270,39 @@ export namespace MessageV2 {
256
270
  }),
257
271
  })
258
272
  .meta({
259
- ref: "ToolStateError",
260
- })
261
- export type ToolStateError = z.infer<typeof ToolStateError>
273
+ ref: 'ToolStateError',
274
+ });
275
+ export type ToolStateError = z.infer<typeof ToolStateError>;
262
276
 
263
277
  export const ToolState = z
264
- .discriminatedUnion("status", [ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError])
278
+ .discriminatedUnion('status', [
279
+ ToolStatePending,
280
+ ToolStateRunning,
281
+ ToolStateCompleted,
282
+ ToolStateError,
283
+ ])
265
284
  .meta({
266
- ref: "ToolState",
267
- })
285
+ ref: 'ToolState',
286
+ });
268
287
 
269
288
  export const ToolPart = PartBase.extend({
270
- type: z.literal("tool"),
289
+ type: z.literal('tool'),
271
290
  callID: z.string(),
272
291
  tool: z.string(),
273
292
  state: ToolState,
274
293
  metadata: z.record(z.string(), z.any()).optional(),
275
294
  }).meta({
276
- ref: "ToolPart",
277
- })
278
- export type ToolPart = z.infer<typeof ToolPart>
295
+ ref: 'ToolPart',
296
+ });
297
+ export type ToolPart = z.infer<typeof ToolPart>;
279
298
 
280
299
  const Base = z.object({
281
300
  id: z.string(),
282
301
  sessionID: z.string(),
283
- })
302
+ });
284
303
 
285
304
  export const User = Base.extend({
286
- role: z.literal("user"),
305
+ role: z.literal('user'),
287
306
  time: z.object({
288
307
  created: z.number(),
289
308
  }),
@@ -303,12 +322,12 @@ export namespace MessageV2 {
303
322
  appendSystem: z.string().optional(),
304
323
  tools: z.record(z.string(), z.boolean()).optional(),
305
324
  }).meta({
306
- ref: "UserMessage",
307
- })
308
- export type User = z.infer<typeof User>
325
+ ref: 'UserMessage',
326
+ });
327
+ export type User = z.infer<typeof User>;
309
328
 
310
329
  export const Part = z
311
- .discriminatedUnion("type", [
330
+ .discriminatedUnion('type', [
312
331
  TextPart,
313
332
  SubtaskPart,
314
333
  ReasoningPart,
@@ -323,18 +342,18 @@ export namespace MessageV2 {
323
342
  CompactionPart,
324
343
  ])
325
344
  .meta({
326
- ref: "Part",
327
- })
328
- export type Part = z.infer<typeof Part>
345
+ ref: 'Part',
346
+ });
347
+ export type Part = z.infer<typeof Part>;
329
348
 
330
349
  export const Assistant = Base.extend({
331
- role: z.literal("assistant"),
350
+ role: z.literal('assistant'),
332
351
  time: z.object({
333
352
  created: z.number(),
334
353
  completed: z.number().optional(),
335
354
  }),
336
355
  error: z
337
- .discriminatedUnion("name", [
356
+ .discriminatedUnion('name', [
338
357
  AuthError.Schema,
339
358
  NamedError.Unknown.Schema,
340
359
  OutputLengthError.Schema,
@@ -363,59 +382,59 @@ export namespace MessageV2 {
363
382
  }),
364
383
  finish: z.string().optional(),
365
384
  }).meta({
366
- ref: "AssistantMessage",
367
- })
368
- export type Assistant = z.infer<typeof Assistant>
385
+ ref: 'AssistantMessage',
386
+ });
387
+ export type Assistant = z.infer<typeof Assistant>;
369
388
 
370
- export const Info = z.discriminatedUnion("role", [User, Assistant]).meta({
371
- ref: "Message",
372
- })
373
- export type Info = z.infer<typeof Info>
389
+ export const Info = z.discriminatedUnion('role', [User, Assistant]).meta({
390
+ ref: 'Message',
391
+ });
392
+ export type Info = z.infer<typeof Info>;
374
393
 
375
394
  export const Event = {
376
395
  Updated: Bus.event(
377
- "message.updated",
396
+ 'message.updated',
378
397
  z.object({
379
398
  info: Info,
380
- }),
399
+ })
381
400
  ),
382
401
  Removed: Bus.event(
383
- "message.removed",
402
+ 'message.removed',
384
403
  z.object({
385
404
  sessionID: z.string(),
386
405
  messageID: z.string(),
387
- }),
406
+ })
388
407
  ),
389
408
  PartUpdated: Bus.event(
390
- "message.part.updated",
409
+ 'message.part.updated',
391
410
  z.object({
392
411
  part: Part,
393
412
  delta: z.string().optional(),
394
- }),
413
+ })
395
414
  ),
396
415
  PartRemoved: Bus.event(
397
- "message.part.removed",
416
+ 'message.part.removed',
398
417
  z.object({
399
418
  sessionID: z.string(),
400
419
  messageID: z.string(),
401
420
  partID: z.string(),
402
- }),
421
+ })
403
422
  ),
404
- }
423
+ };
405
424
 
406
425
  export const WithParts = z.object({
407
426
  info: Info,
408
427
  parts: z.array(Part),
409
- })
410
- export type WithParts = z.infer<typeof WithParts>
428
+ });
429
+ export type WithParts = z.infer<typeof WithParts>;
411
430
 
412
431
  export function fromV1(v1: Message.Info) {
413
- if (v1.role === "assistant") {
432
+ if (v1.role === 'assistant') {
414
433
  const info: Assistant = {
415
434
  id: v1.id,
416
- parentID: "",
435
+ parentID: '',
417
436
  sessionID: v1.metadata.sessionID,
418
- role: "assistant",
437
+ role: 'assistant',
419
438
  time: {
420
439
  created: v1.metadata.time.created,
421
440
  completed: v1.metadata.time.completed,
@@ -426,318 +445,337 @@ export namespace MessageV2 {
426
445
  tokens: v1.metadata.assistant!.tokens,
427
446
  modelID: v1.metadata.assistant!.modelID,
428
447
  providerID: v1.metadata.assistant!.providerID,
429
- mode: "build",
448
+ mode: 'build',
430
449
  error: v1.metadata.error,
431
- }
450
+ };
432
451
  const parts = v1.parts.flatMap((part): Part[] => {
433
452
  const base = {
434
- id: Identifier.ascending("part"),
453
+ id: Identifier.ascending('part'),
435
454
  messageID: v1.id,
436
455
  sessionID: v1.metadata.sessionID,
437
- }
438
- if (part.type === "text") {
456
+ };
457
+ if (part.type === 'text') {
439
458
  return [
440
459
  {
441
460
  ...base,
442
- type: "text",
461
+ type: 'text',
443
462
  text: part.text,
444
463
  },
445
- ]
464
+ ];
446
465
  }
447
- if (part.type === "step-start") {
466
+ if (part.type === 'step-start') {
448
467
  return [
449
468
  {
450
469
  ...base,
451
- type: "step-start",
470
+ type: 'step-start',
452
471
  },
453
- ]
472
+ ];
454
473
  }
455
- if (part.type === "tool-invocation") {
474
+ if (part.type === 'tool-invocation') {
456
475
  return [
457
476
  {
458
477
  ...base,
459
- type: "tool",
478
+ type: 'tool',
460
479
  callID: part.toolInvocation.toolCallId,
461
480
  tool: part.toolInvocation.toolName,
462
481
  state: (() => {
463
- if (part.toolInvocation.state === "partial-call") {
482
+ if (part.toolInvocation.state === 'partial-call') {
464
483
  return {
465
- status: "pending",
484
+ status: 'pending',
466
485
  input: {},
467
- raw: "",
468
- }
486
+ raw: '',
487
+ };
469
488
  }
470
489
 
471
- const { title, time, ...metadata } = v1.metadata.tool[part.toolInvocation.toolCallId] ?? {}
472
- if (part.toolInvocation.state === "call") {
490
+ const { title, time, ...metadata } =
491
+ v1.metadata.tool[part.toolInvocation.toolCallId] ?? {};
492
+ if (part.toolInvocation.state === 'call') {
473
493
  return {
474
- status: "running",
494
+ status: 'running',
475
495
  input: part.toolInvocation.args,
476
496
  time: {
477
497
  start: time?.start,
478
498
  },
479
- }
499
+ };
480
500
  }
481
501
 
482
- if (part.toolInvocation.state === "result") {
502
+ if (part.toolInvocation.state === 'result') {
483
503
  return {
484
- status: "completed",
504
+ status: 'completed',
485
505
  input: part.toolInvocation.args,
486
506
  output: part.toolInvocation.result,
487
507
  title,
488
508
  time,
489
509
  metadata,
490
- }
510
+ };
491
511
  }
492
- throw new Error("unknown tool invocation state")
512
+ throw new Error('unknown tool invocation state');
493
513
  })(),
494
514
  },
495
- ]
515
+ ];
496
516
  }
497
- return []
498
- })
517
+ return [];
518
+ });
499
519
  return {
500
520
  info,
501
521
  parts,
502
- }
522
+ };
503
523
  }
504
524
 
505
- if (v1.role === "user") {
525
+ if (v1.role === 'user') {
506
526
  const info: User = {
507
527
  id: v1.id,
508
528
  sessionID: v1.metadata.sessionID,
509
- role: "user",
529
+ role: 'user',
510
530
  time: {
511
531
  created: v1.metadata.time.created,
512
532
  },
513
- agent: "build",
533
+ agent: 'build',
514
534
  model: {
515
- providerID: "opencode",
516
- modelID: "opencode",
535
+ providerID: 'opencode',
536
+ modelID: 'opencode',
517
537
  },
518
- }
538
+ };
519
539
  const parts = v1.parts.flatMap((part): Part[] => {
520
540
  const base = {
521
- id: Identifier.ascending("part"),
541
+ id: Identifier.ascending('part'),
522
542
  messageID: v1.id,
523
543
  sessionID: v1.metadata.sessionID,
524
- }
525
- if (part.type === "text") {
544
+ };
545
+ if (part.type === 'text') {
526
546
  return [
527
547
  {
528
548
  ...base,
529
- type: "text",
549
+ type: 'text',
530
550
  text: part.text,
531
551
  },
532
- ]
552
+ ];
533
553
  }
534
- if (part.type === "file") {
554
+ if (part.type === 'file') {
535
555
  return [
536
556
  {
537
557
  ...base,
538
- type: "file",
558
+ type: 'file',
539
559
  mime: part.mediaType,
540
560
  filename: part.filename,
541
561
  url: part.url,
542
562
  },
543
- ]
563
+ ];
544
564
  }
545
- return []
546
- })
547
- return { info, parts }
565
+ return [];
566
+ });
567
+ return { info, parts };
548
568
  }
549
569
 
550
- throw new Error("unknown message type")
570
+ throw new Error('unknown message type');
551
571
  }
552
572
 
553
573
  export function toModelMessage(
554
574
  input: {
555
- info: Info
556
- parts: Part[]
557
- }[],
575
+ info: Info;
576
+ parts: Part[];
577
+ }[]
558
578
  ): ModelMessage[] {
559
- const result: UIMessage[] = []
579
+ const result: UIMessage[] = [];
560
580
 
561
581
  for (const msg of input) {
562
- if (msg.parts.length === 0) continue
582
+ if (msg.parts.length === 0) continue;
563
583
 
564
- if (msg.info.role === "user") {
584
+ if (msg.info.role === 'user') {
565
585
  const userMessage: UIMessage = {
566
586
  id: msg.info.id,
567
- role: "user",
587
+ role: 'user',
568
588
  parts: [],
569
- }
570
- result.push(userMessage)
589
+ };
590
+ result.push(userMessage);
571
591
  for (const part of msg.parts) {
572
- if (part.type === "text")
592
+ if (part.type === 'text')
573
593
  userMessage.parts.push({
574
- type: "text",
594
+ type: 'text',
575
595
  text: part.text,
576
- })
596
+ });
577
597
  // text/plain and directory files are converted into text parts, ignore them
578
- if (part.type === "file" && part.mime !== "text/plain" && part.mime !== "application/x-directory")
598
+ if (
599
+ part.type === 'file' &&
600
+ part.mime !== 'text/plain' &&
601
+ part.mime !== 'application/x-directory'
602
+ )
579
603
  userMessage.parts.push({
580
- type: "file",
604
+ type: 'file',
581
605
  url: part.url,
582
606
  mediaType: part.mime,
583
607
  filename: part.filename,
584
- })
608
+ });
585
609
 
586
- if (part.type === "compaction") {
610
+ if (part.type === 'compaction') {
587
611
  userMessage.parts.push({
588
- type: "text",
589
- text: "What did we do so far?",
590
- })
612
+ type: 'text',
613
+ text: 'What did we do so far?',
614
+ });
591
615
  }
592
- if (part.type === "subtask") {
616
+ if (part.type === 'subtask') {
593
617
  userMessage.parts.push({
594
- type: "text",
595
- text: "The following tool was executed by the user",
596
- })
618
+ type: 'text',
619
+ text: 'The following tool was executed by the user',
620
+ });
597
621
  }
598
622
  }
599
623
  }
600
624
 
601
- if (msg.info.role === "assistant") {
625
+ if (msg.info.role === 'assistant') {
602
626
  const assistantMessage: UIMessage = {
603
627
  id: msg.info.id,
604
- role: "assistant",
628
+ role: 'assistant',
605
629
  parts: [],
606
- }
607
- result.push(assistantMessage)
630
+ };
631
+ result.push(assistantMessage);
608
632
  for (const part of msg.parts) {
609
- if (part.type === "text")
633
+ if (part.type === 'text')
610
634
  assistantMessage.parts.push({
611
- type: "text",
635
+ type: 'text',
612
636
  text: part.text,
613
637
  providerMetadata: part.metadata,
614
- })
615
- if (part.type === "step-start")
638
+ });
639
+ if (part.type === 'step-start')
616
640
  assistantMessage.parts.push({
617
- type: "step-start",
618
- })
619
- if (part.type === "tool") {
620
- if (part.state.status === "completed") {
641
+ type: 'step-start',
642
+ });
643
+ if (part.type === 'tool') {
644
+ if (part.state.status === 'completed') {
621
645
  if (part.state.attachments?.length) {
622
646
  result.push({
623
- id: Identifier.ascending("message"),
624
- role: "user",
647
+ id: Identifier.ascending('message'),
648
+ role: 'user',
625
649
  parts: [
626
650
  {
627
- type: "text",
651
+ type: 'text',
628
652
  text: `Tool ${part.tool} returned an attachment:`,
629
653
  },
630
654
  ...part.state.attachments.map((attachment) => ({
631
- type: "file" as const,
655
+ type: 'file' as const,
632
656
  url: attachment.url,
633
657
  mediaType: attachment.mime,
634
658
  filename: attachment.filename,
635
659
  })),
636
660
  ],
637
- })
661
+ });
638
662
  }
639
663
  assistantMessage.parts.push({
640
- type: ("tool-" + part.tool) as `tool-${string}`,
641
- state: "output-available",
664
+ type: ('tool-' + part.tool) as `tool-${string}`,
665
+ state: 'output-available',
642
666
  toolCallId: part.callID,
643
667
  input: part.state.input,
644
- output: part.state.time.compacted ? "[Old tool result content cleared]" : part.state.output,
668
+ output: part.state.time.compacted
669
+ ? '[Old tool result content cleared]'
670
+ : part.state.output,
645
671
  callProviderMetadata: part.metadata,
646
- })
672
+ });
647
673
  }
648
- if (part.state.status === "error")
674
+ if (part.state.status === 'error')
649
675
  assistantMessage.parts.push({
650
- type: ("tool-" + part.tool) as `tool-${string}`,
651
- state: "output-error",
676
+ type: ('tool-' + part.tool) as `tool-${string}`,
677
+ state: 'output-error',
652
678
  toolCallId: part.callID,
653
679
  input: part.state.input,
654
680
  errorText: part.state.error,
655
681
  callProviderMetadata: part.metadata,
656
- })
682
+ });
657
683
  }
658
- if (part.type === "reasoning") {
684
+ if (part.type === 'reasoning') {
659
685
  assistantMessage.parts.push({
660
- type: "reasoning",
686
+ type: 'reasoning',
661
687
  text: part.text,
662
688
  providerMetadata: part.metadata,
663
- })
689
+ });
664
690
  }
665
691
  }
666
692
  }
667
693
  }
668
694
 
669
- return convertToModelMessages(result)
695
+ return convertToModelMessages(result);
670
696
  }
671
697
 
672
- export const stream = fn(Identifier.schema("session"), async function* (sessionID) {
673
- const list = await Array.fromAsync(await Storage.list(["message", sessionID]))
674
- for (let i = list.length - 1; i >= 0; i--) {
675
- yield await get({
676
- sessionID,
677
- messageID: list[i][2],
678
- })
698
+ export const stream = fn(
699
+ Identifier.schema('session'),
700
+ async function* (sessionID) {
701
+ const list = await Array.fromAsync(
702
+ await Storage.list(['message', sessionID])
703
+ );
704
+ for (let i = list.length - 1; i >= 0; i--) {
705
+ yield await get({
706
+ sessionID,
707
+ messageID: list[i][2],
708
+ });
709
+ }
679
710
  }
680
- })
711
+ );
681
712
 
682
- export const parts = fn(Identifier.schema("message"), async (messageID) => {
683
- const result = [] as MessageV2.Part[]
684
- for (const item of await Storage.list(["part", messageID])) {
685
- const read = await Storage.read<MessageV2.Part>(item)
686
- result.push(read)
713
+ export const parts = fn(Identifier.schema('message'), async (messageID) => {
714
+ const result = [] as MessageV2.Part[];
715
+ for (const item of await Storage.list(['part', messageID])) {
716
+ const read = await Storage.read<MessageV2.Part>(item);
717
+ result.push(read);
687
718
  }
688
- result.sort((a, b) => (a.id > b.id ? 1 : -1))
689
- return result
690
- })
719
+ result.sort((a, b) => (a.id > b.id ? 1 : -1));
720
+ return result;
721
+ });
691
722
 
692
723
  export const get = fn(
693
724
  z.object({
694
- sessionID: Identifier.schema("session"),
695
- messageID: Identifier.schema("message"),
725
+ sessionID: Identifier.schema('session'),
726
+ messageID: Identifier.schema('message'),
696
727
  }),
697
728
  async (input) => {
698
729
  return {
699
- info: await Storage.read<MessageV2.Info>(["message", input.sessionID, input.messageID]),
730
+ info: await Storage.read<MessageV2.Info>([
731
+ 'message',
732
+ input.sessionID,
733
+ input.messageID,
734
+ ]),
700
735
  parts: await parts(input.messageID),
701
- }
702
- },
703
- )
736
+ };
737
+ }
738
+ );
704
739
 
705
- export async function filterCompacted(stream: AsyncIterable<MessageV2.WithParts>) {
706
- const result = [] as MessageV2.WithParts[]
707
- const completed = new Set<string>()
740
+ export async function filterCompacted(
741
+ stream: AsyncIterable<MessageV2.WithParts>
742
+ ) {
743
+ const result = [] as MessageV2.WithParts[];
744
+ const completed = new Set<string>();
708
745
  for await (const msg of stream) {
709
- result.push(msg)
746
+ result.push(msg);
710
747
  if (
711
- msg.info.role === "user" &&
748
+ msg.info.role === 'user' &&
712
749
  completed.has(msg.info.id) &&
713
- msg.parts.some((part) => part.type === "compaction")
750
+ msg.parts.some((part) => part.type === 'compaction')
714
751
  )
715
- break
716
- if (msg.info.role === "assistant" && msg.info.summary && msg.info.finish) completed.add(msg.info.parentID)
752
+ break;
753
+ if (msg.info.role === 'assistant' && msg.info.summary && msg.info.finish)
754
+ completed.add(msg.info.parentID);
717
755
  }
718
- result.reverse()
719
- return result
756
+ result.reverse();
757
+ return result;
720
758
  }
721
759
 
722
760
  export function fromError(e: unknown, ctx: { providerID: string }) {
723
761
  switch (true) {
724
- case e instanceof DOMException && e.name === "AbortError":
762
+ case e instanceof DOMException && e.name === 'AbortError':
725
763
  return new MessageV2.AbortedError(
726
764
  { message: e.message },
727
765
  {
728
766
  cause: e,
729
- },
730
- ).toObject()
767
+ }
768
+ ).toObject();
731
769
  case MessageV2.OutputLengthError.isInstance(e):
732
- return e
770
+ return e;
733
771
  case LoadAPIKeyError.isInstance(e):
734
772
  return new MessageV2.AuthError(
735
773
  {
736
774
  providerID: ctx.providerID,
737
775
  message: e.message,
738
776
  },
739
- { cause: e },
740
- ).toObject()
777
+ { cause: e }
778
+ ).toObject();
741
779
  case APICallError.isInstance(e):
742
780
  return new MessageV2.APIError(
743
781
  {
@@ -747,12 +785,18 @@ export namespace MessageV2 {
747
785
  responseHeaders: e.responseHeaders,
748
786
  responseBody: e.responseBody,
749
787
  },
750
- { cause: e },
751
- ).toObject()
788
+ { cause: e }
789
+ ).toObject();
752
790
  case e instanceof Error:
753
- return new NamedError.Unknown({ message: e.toString() }, { cause: e }).toObject()
791
+ return new NamedError.Unknown(
792
+ { message: e.toString() },
793
+ { cause: e }
794
+ ).toObject();
754
795
  default:
755
- return new NamedError.Unknown({ message: JSON.stringify(e) }, { cause: e })
796
+ return new NamedError.Unknown(
797
+ { message: JSON.stringify(e) },
798
+ { cause: e }
799
+ );
756
800
  }
757
801
  }
758
802
  }