@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.
- package/EXAMPLES.md +36 -0
- package/MODELS.md +72 -24
- package/README.md +59 -2
- package/TOOLS.md +20 -0
- package/package.json +35 -2
- package/src/agent/agent.ts +68 -54
- package/src/auth/claude-oauth.ts +426 -0
- package/src/auth/index.ts +28 -26
- package/src/auth/plugins.ts +876 -0
- package/src/bun/index.ts +53 -43
- package/src/bus/global.ts +5 -5
- package/src/bus/index.ts +59 -53
- package/src/cli/bootstrap.js +12 -12
- package/src/cli/bootstrap.ts +6 -6
- package/src/cli/cmd/agent.ts +97 -92
- package/src/cli/cmd/auth.ts +469 -0
- package/src/cli/cmd/cmd.ts +2 -2
- package/src/cli/cmd/export.ts +41 -41
- package/src/cli/cmd/mcp.ts +144 -119
- package/src/cli/cmd/models.ts +30 -29
- package/src/cli/cmd/run.ts +269 -213
- package/src/cli/cmd/stats.ts +185 -146
- package/src/cli/error.ts +17 -13
- package/src/cli/ui.ts +39 -24
- package/src/command/index.ts +26 -26
- package/src/config/config.ts +528 -288
- package/src/config/markdown.ts +15 -15
- package/src/file/ripgrep.ts +201 -169
- package/src/file/time.ts +21 -18
- package/src/file/watcher.ts +51 -42
- package/src/file.ts +1 -1
- package/src/flag/flag.ts +26 -11
- package/src/format/formatter.ts +206 -162
- package/src/format/index.ts +61 -61
- package/src/global/index.ts +21 -21
- package/src/id/id.ts +47 -33
- package/src/index.js +346 -199
- package/src/json-standard/index.ts +67 -51
- package/src/mcp/index.ts +135 -128
- package/src/patch/index.ts +336 -267
- package/src/project/bootstrap.ts +15 -15
- package/src/project/instance.ts +43 -36
- package/src/project/project.ts +47 -47
- package/src/project/state.ts +37 -33
- package/src/provider/models-macro.ts +5 -5
- package/src/provider/models.ts +32 -32
- package/src/provider/opencode.js +19 -19
- package/src/provider/provider.ts +518 -277
- package/src/provider/transform.ts +143 -102
- package/src/server/project.ts +21 -21
- package/src/server/server.ts +111 -105
- package/src/session/agent.js +66 -60
- package/src/session/compaction.ts +136 -111
- package/src/session/index.ts +189 -156
- package/src/session/message-v2.ts +312 -268
- package/src/session/message.ts +73 -57
- package/src/session/processor.ts +180 -166
- package/src/session/prompt.ts +678 -533
- package/src/session/retry.ts +26 -23
- package/src/session/revert.ts +76 -62
- package/src/session/status.ts +26 -26
- package/src/session/summary.ts +97 -76
- package/src/session/system.ts +77 -63
- package/src/session/todo.ts +22 -16
- package/src/snapshot/index.ts +92 -76
- package/src/storage/storage.ts +157 -120
- package/src/tool/bash.ts +116 -106
- package/src/tool/batch.ts +73 -59
- package/src/tool/codesearch.ts +60 -53
- package/src/tool/edit.ts +319 -263
- package/src/tool/glob.ts +32 -28
- package/src/tool/grep.ts +72 -53
- package/src/tool/invalid.ts +7 -7
- package/src/tool/ls.ts +77 -64
- package/src/tool/multiedit.ts +30 -21
- package/src/tool/patch.ts +121 -94
- package/src/tool/read.ts +140 -122
- package/src/tool/registry.ts +38 -38
- package/src/tool/task.ts +93 -60
- package/src/tool/todo.ts +16 -16
- package/src/tool/tool.ts +45 -36
- package/src/tool/webfetch.ts +97 -74
- package/src/tool/websearch.ts +78 -64
- package/src/tool/write.ts +21 -15
- package/src/util/binary.ts +27 -19
- package/src/util/context.ts +8 -8
- package/src/util/defer.ts +7 -5
- package/src/util/error.ts +24 -19
- package/src/util/eventloop.ts +16 -10
- package/src/util/filesystem.ts +37 -33
- package/src/util/fn.ts +11 -8
- package/src/util/iife.ts +1 -1
- package/src/util/keybind.ts +44 -44
- package/src/util/lazy.ts +7 -7
- package/src/util/locale.ts +20 -16
- package/src/util/lock.ts +43 -38
- package/src/util/log.ts +95 -85
- package/src/util/queue.ts +8 -8
- package/src/util/rpc.ts +35 -23
- package/src/util/scrap.ts +4 -4
- package/src/util/signal.ts +5 -5
- package/src/util/timeout.ts +6 -6
- package/src/util/token.ts +2 -2
- package/src/util/wildcard.ts +38 -27
package/src/session/processor.ts
CHANGED
|
@@ -1,164 +1,170 @@
|
|
|
1
|
-
import type { ModelsDev } from
|
|
2
|
-
import { MessageV2 } from
|
|
3
|
-
import { type StreamTextResult, type Tool as AITool, APICallError } from
|
|
4
|
-
import { Log } from
|
|
5
|
-
import { Identifier } from
|
|
6
|
-
import { Session } from
|
|
7
|
-
import { Agent } from
|
|
1
|
+
import type { ModelsDev } from '../provider/models';
|
|
2
|
+
import { MessageV2 } from './message-v2';
|
|
3
|
+
import { type StreamTextResult, type Tool as AITool, APICallError } from 'ai';
|
|
4
|
+
import { Log } from '../util/log';
|
|
5
|
+
import { Identifier } from '../id/id';
|
|
6
|
+
import { Session } from '.';
|
|
7
|
+
import { Agent } from '../agent/agent';
|
|
8
8
|
// Permission system removed - no restrictions
|
|
9
|
-
import { Snapshot } from
|
|
10
|
-
import { SessionSummary } from
|
|
11
|
-
import { Bus } from
|
|
12
|
-
import { SessionRetry } from
|
|
13
|
-
import { SessionStatus } from
|
|
9
|
+
import { Snapshot } from '../snapshot';
|
|
10
|
+
import { SessionSummary } from './summary';
|
|
11
|
+
import { Bus } from '../bus';
|
|
12
|
+
import { SessionRetry } from './retry';
|
|
13
|
+
import { SessionStatus } from './status';
|
|
14
14
|
|
|
15
15
|
export namespace SessionProcessor {
|
|
16
|
-
const DOOM_LOOP_THRESHOLD = 3
|
|
17
|
-
const log = Log.create({ service:
|
|
16
|
+
const DOOM_LOOP_THRESHOLD = 3;
|
|
17
|
+
const log = Log.create({ service: 'session.processor' });
|
|
18
18
|
|
|
19
|
-
export type Info = Awaited<ReturnType<typeof create
|
|
20
|
-
export type Result = Awaited<ReturnType<Info[
|
|
19
|
+
export type Info = Awaited<ReturnType<typeof create>>;
|
|
20
|
+
export type Result = Awaited<ReturnType<Info['process']>>;
|
|
21
21
|
|
|
22
22
|
export function create(input: {
|
|
23
|
-
assistantMessage: MessageV2.Assistant
|
|
24
|
-
sessionID: string
|
|
25
|
-
providerID: string
|
|
26
|
-
model: ModelsDev.Model
|
|
27
|
-
abort: AbortSignal
|
|
23
|
+
assistantMessage: MessageV2.Assistant;
|
|
24
|
+
sessionID: string;
|
|
25
|
+
providerID: string;
|
|
26
|
+
model: ModelsDev.Model;
|
|
27
|
+
abort: AbortSignal;
|
|
28
28
|
}) {
|
|
29
|
-
const toolcalls: Record<string, MessageV2.ToolPart> = {}
|
|
30
|
-
let snapshot: string | undefined
|
|
31
|
-
let blocked = false
|
|
32
|
-
let attempt = 0
|
|
29
|
+
const toolcalls: Record<string, MessageV2.ToolPart> = {};
|
|
30
|
+
let snapshot: string | undefined;
|
|
31
|
+
let blocked = false;
|
|
32
|
+
let attempt = 0;
|
|
33
33
|
|
|
34
34
|
const result = {
|
|
35
35
|
get message() {
|
|
36
|
-
return input.assistantMessage
|
|
36
|
+
return input.assistantMessage;
|
|
37
37
|
},
|
|
38
38
|
partFromToolCall(toolCallID: string) {
|
|
39
|
-
return toolcalls[toolCallID]
|
|
39
|
+
return toolcalls[toolCallID];
|
|
40
40
|
},
|
|
41
41
|
async process(fn: () => StreamTextResult<Record<string, AITool>, never>) {
|
|
42
|
-
log.info(
|
|
42
|
+
log.info('process');
|
|
43
43
|
while (true) {
|
|
44
44
|
try {
|
|
45
|
-
let currentText: MessageV2.TextPart | undefined
|
|
46
|
-
let reasoningMap: Record<string, MessageV2.ReasoningPart> = {}
|
|
47
|
-
const stream = fn()
|
|
45
|
+
let currentText: MessageV2.TextPart | undefined;
|
|
46
|
+
let reasoningMap: Record<string, MessageV2.ReasoningPart> = {};
|
|
47
|
+
const stream = fn();
|
|
48
48
|
|
|
49
49
|
for await (const value of stream.fullStream) {
|
|
50
|
-
input.abort.throwIfAborted()
|
|
50
|
+
input.abort.throwIfAborted();
|
|
51
51
|
switch (value.type) {
|
|
52
|
-
case
|
|
53
|
-
SessionStatus.set(input.sessionID, { type:
|
|
54
|
-
break
|
|
52
|
+
case 'start':
|
|
53
|
+
SessionStatus.set(input.sessionID, { type: 'busy' });
|
|
54
|
+
break;
|
|
55
55
|
|
|
56
|
-
case
|
|
56
|
+
case 'reasoning-start':
|
|
57
57
|
if (value.id in reasoningMap) {
|
|
58
|
-
continue
|
|
58
|
+
continue;
|
|
59
59
|
}
|
|
60
60
|
reasoningMap[value.id] = {
|
|
61
|
-
id: Identifier.ascending(
|
|
61
|
+
id: Identifier.ascending('part'),
|
|
62
62
|
messageID: input.assistantMessage.id,
|
|
63
63
|
sessionID: input.assistantMessage.sessionID,
|
|
64
|
-
type:
|
|
65
|
-
text:
|
|
64
|
+
type: 'reasoning',
|
|
65
|
+
text: '',
|
|
66
66
|
time: {
|
|
67
67
|
start: Date.now(),
|
|
68
68
|
},
|
|
69
69
|
metadata: value.providerMetadata,
|
|
70
|
-
}
|
|
71
|
-
break
|
|
70
|
+
};
|
|
71
|
+
break;
|
|
72
72
|
|
|
73
|
-
case
|
|
73
|
+
case 'reasoning-delta':
|
|
74
74
|
if (value.id in reasoningMap) {
|
|
75
|
-
const part = reasoningMap[value.id]
|
|
76
|
-
part.text += value.text
|
|
77
|
-
if (value.providerMetadata)
|
|
78
|
-
|
|
75
|
+
const part = reasoningMap[value.id];
|
|
76
|
+
part.text += value.text;
|
|
77
|
+
if (value.providerMetadata)
|
|
78
|
+
part.metadata = value.providerMetadata;
|
|
79
|
+
if (part.text)
|
|
80
|
+
await Session.updatePart({ part, delta: value.text });
|
|
79
81
|
}
|
|
80
|
-
break
|
|
82
|
+
break;
|
|
81
83
|
|
|
82
|
-
case
|
|
84
|
+
case 'reasoning-end':
|
|
83
85
|
if (value.id in reasoningMap) {
|
|
84
|
-
const part = reasoningMap[value.id]
|
|
85
|
-
part.text = part.text.trimEnd()
|
|
86
|
+
const part = reasoningMap[value.id];
|
|
87
|
+
part.text = part.text.trimEnd();
|
|
86
88
|
|
|
87
89
|
part.time = {
|
|
88
90
|
...part.time,
|
|
89
91
|
end: Date.now(),
|
|
90
|
-
}
|
|
91
|
-
if (value.providerMetadata)
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
};
|
|
93
|
+
if (value.providerMetadata)
|
|
94
|
+
part.metadata = value.providerMetadata;
|
|
95
|
+
await Session.updatePart(part);
|
|
96
|
+
delete reasoningMap[value.id];
|
|
94
97
|
}
|
|
95
|
-
break
|
|
98
|
+
break;
|
|
96
99
|
|
|
97
|
-
case
|
|
100
|
+
case 'tool-input-start':
|
|
98
101
|
const part = await Session.updatePart({
|
|
99
|
-
id: toolcalls[value.id]?.id ?? Identifier.ascending(
|
|
102
|
+
id: toolcalls[value.id]?.id ?? Identifier.ascending('part'),
|
|
100
103
|
messageID: input.assistantMessage.id,
|
|
101
104
|
sessionID: input.assistantMessage.sessionID,
|
|
102
|
-
type:
|
|
105
|
+
type: 'tool',
|
|
103
106
|
tool: value.toolName,
|
|
104
107
|
callID: value.id,
|
|
105
108
|
state: {
|
|
106
|
-
status:
|
|
109
|
+
status: 'pending',
|
|
107
110
|
input: {},
|
|
108
|
-
raw:
|
|
111
|
+
raw: '',
|
|
109
112
|
},
|
|
110
|
-
})
|
|
111
|
-
toolcalls[value.id] = part as MessageV2.ToolPart
|
|
112
|
-
break
|
|
113
|
+
});
|
|
114
|
+
toolcalls[value.id] = part as MessageV2.ToolPart;
|
|
115
|
+
break;
|
|
113
116
|
|
|
114
|
-
case
|
|
115
|
-
break
|
|
117
|
+
case 'tool-input-delta':
|
|
118
|
+
break;
|
|
116
119
|
|
|
117
|
-
case
|
|
118
|
-
break
|
|
120
|
+
case 'tool-input-end':
|
|
121
|
+
break;
|
|
119
122
|
|
|
120
|
-
case
|
|
121
|
-
const match = toolcalls[value.toolCallId]
|
|
123
|
+
case 'tool-call': {
|
|
124
|
+
const match = toolcalls[value.toolCallId];
|
|
122
125
|
if (match) {
|
|
123
126
|
const part = await Session.updatePart({
|
|
124
127
|
...match,
|
|
125
128
|
tool: value.toolName,
|
|
126
129
|
state: {
|
|
127
|
-
status:
|
|
130
|
+
status: 'running',
|
|
128
131
|
input: value.input,
|
|
129
132
|
time: {
|
|
130
133
|
start: Date.now(),
|
|
131
134
|
},
|
|
132
135
|
},
|
|
133
136
|
metadata: value.providerMetadata,
|
|
134
|
-
})
|
|
135
|
-
toolcalls[value.toolCallId] = part as MessageV2.ToolPart
|
|
137
|
+
});
|
|
138
|
+
toolcalls[value.toolCallId] = part as MessageV2.ToolPart;
|
|
136
139
|
|
|
137
|
-
const parts = await MessageV2.parts(
|
|
138
|
-
|
|
140
|
+
const parts = await MessageV2.parts(
|
|
141
|
+
input.assistantMessage.id
|
|
142
|
+
);
|
|
143
|
+
const lastThree = parts.slice(-DOOM_LOOP_THRESHOLD);
|
|
139
144
|
|
|
140
145
|
if (
|
|
141
146
|
lastThree.length === DOOM_LOOP_THRESHOLD &&
|
|
142
147
|
lastThree.every(
|
|
143
148
|
(p) =>
|
|
144
|
-
p.type ===
|
|
149
|
+
p.type === 'tool' &&
|
|
145
150
|
p.tool === value.toolName &&
|
|
146
|
-
p.state.status !==
|
|
147
|
-
JSON.stringify(p.state.input) ===
|
|
151
|
+
p.state.status !== 'pending' &&
|
|
152
|
+
JSON.stringify(p.state.input) ===
|
|
153
|
+
JSON.stringify(value.input)
|
|
148
154
|
)
|
|
149
155
|
) {
|
|
150
156
|
// Permission system removed - doom loop detection disabled
|
|
151
157
|
}
|
|
152
158
|
}
|
|
153
|
-
break
|
|
159
|
+
break;
|
|
154
160
|
}
|
|
155
|
-
case
|
|
156
|
-
const match = toolcalls[value.toolCallId]
|
|
157
|
-
if (match && match.state.status ===
|
|
161
|
+
case 'tool-result': {
|
|
162
|
+
const match = toolcalls[value.toolCallId];
|
|
163
|
+
if (match && match.state.status === 'running') {
|
|
158
164
|
await Session.updatePart({
|
|
159
165
|
...match,
|
|
160
166
|
state: {
|
|
161
|
-
status:
|
|
167
|
+
status: 'completed',
|
|
162
168
|
input: value.input,
|
|
163
169
|
output: value.output.output,
|
|
164
170
|
metadata: value.output.metadata,
|
|
@@ -169,20 +175,20 @@ export namespace SessionProcessor {
|
|
|
169
175
|
},
|
|
170
176
|
attachments: value.output.attachments,
|
|
171
177
|
},
|
|
172
|
-
})
|
|
178
|
+
});
|
|
173
179
|
|
|
174
|
-
delete toolcalls[value.toolCallId]
|
|
180
|
+
delete toolcalls[value.toolCallId];
|
|
175
181
|
}
|
|
176
|
-
break
|
|
182
|
+
break;
|
|
177
183
|
}
|
|
178
184
|
|
|
179
|
-
case
|
|
180
|
-
const match = toolcalls[value.toolCallId]
|
|
181
|
-
if (match && match.state.status ===
|
|
185
|
+
case 'tool-error': {
|
|
186
|
+
const match = toolcalls[value.toolCallId];
|
|
187
|
+
if (match && match.state.status === 'running') {
|
|
182
188
|
await Session.updatePart({
|
|
183
189
|
...match,
|
|
184
190
|
state: {
|
|
185
|
-
status:
|
|
191
|
+
status: 'error',
|
|
186
192
|
input: value.input,
|
|
187
193
|
error: (value.error as any).toString(),
|
|
188
194
|
metadata: undefined,
|
|
@@ -191,166 +197,174 @@ export namespace SessionProcessor {
|
|
|
191
197
|
end: Date.now(),
|
|
192
198
|
},
|
|
193
199
|
},
|
|
194
|
-
})
|
|
200
|
+
});
|
|
195
201
|
|
|
196
202
|
// Permission system removed
|
|
197
|
-
delete toolcalls[value.toolCallId]
|
|
203
|
+
delete toolcalls[value.toolCallId];
|
|
198
204
|
}
|
|
199
|
-
break
|
|
205
|
+
break;
|
|
200
206
|
}
|
|
201
|
-
case
|
|
202
|
-
throw value.error
|
|
207
|
+
case 'error':
|
|
208
|
+
throw value.error;
|
|
203
209
|
|
|
204
|
-
case
|
|
205
|
-
snapshot = await Snapshot.track()
|
|
210
|
+
case 'start-step':
|
|
211
|
+
snapshot = await Snapshot.track();
|
|
206
212
|
await Session.updatePart({
|
|
207
|
-
id: Identifier.ascending(
|
|
213
|
+
id: Identifier.ascending('part'),
|
|
208
214
|
messageID: input.assistantMessage.id,
|
|
209
215
|
sessionID: input.sessionID,
|
|
210
216
|
snapshot,
|
|
211
|
-
type:
|
|
212
|
-
})
|
|
213
|
-
break
|
|
217
|
+
type: 'step-start',
|
|
218
|
+
});
|
|
219
|
+
break;
|
|
214
220
|
|
|
215
|
-
case
|
|
221
|
+
case 'finish-step':
|
|
216
222
|
const usage = Session.getUsage({
|
|
217
223
|
model: input.model,
|
|
218
224
|
usage: value.usage,
|
|
219
225
|
metadata: value.providerMetadata,
|
|
220
|
-
})
|
|
221
|
-
input.assistantMessage.finish = value.finishReason
|
|
222
|
-
input.assistantMessage.cost += usage.cost
|
|
223
|
-
input.assistantMessage.tokens = usage.tokens
|
|
226
|
+
});
|
|
227
|
+
input.assistantMessage.finish = value.finishReason;
|
|
228
|
+
input.assistantMessage.cost += usage.cost;
|
|
229
|
+
input.assistantMessage.tokens = usage.tokens;
|
|
224
230
|
await Session.updatePart({
|
|
225
|
-
id: Identifier.ascending(
|
|
231
|
+
id: Identifier.ascending('part'),
|
|
226
232
|
reason: value.finishReason,
|
|
227
233
|
snapshot: await Snapshot.track(),
|
|
228
234
|
messageID: input.assistantMessage.id,
|
|
229
235
|
sessionID: input.assistantMessage.sessionID,
|
|
230
|
-
type:
|
|
236
|
+
type: 'step-finish',
|
|
231
237
|
tokens: usage.tokens,
|
|
232
238
|
cost: usage.cost,
|
|
233
|
-
})
|
|
234
|
-
await Session.updateMessage(input.assistantMessage)
|
|
239
|
+
});
|
|
240
|
+
await Session.updateMessage(input.assistantMessage);
|
|
235
241
|
if (snapshot) {
|
|
236
|
-
const patch = await Snapshot.patch(snapshot)
|
|
242
|
+
const patch = await Snapshot.patch(snapshot);
|
|
237
243
|
if (patch.files.length) {
|
|
238
244
|
await Session.updatePart({
|
|
239
|
-
id: Identifier.ascending(
|
|
245
|
+
id: Identifier.ascending('part'),
|
|
240
246
|
messageID: input.assistantMessage.id,
|
|
241
247
|
sessionID: input.sessionID,
|
|
242
|
-
type:
|
|
248
|
+
type: 'patch',
|
|
243
249
|
hash: patch.hash,
|
|
244
250
|
files: patch.files,
|
|
245
|
-
})
|
|
251
|
+
});
|
|
246
252
|
}
|
|
247
|
-
snapshot = undefined
|
|
253
|
+
snapshot = undefined;
|
|
248
254
|
}
|
|
249
255
|
SessionSummary.summarize({
|
|
250
256
|
sessionID: input.sessionID,
|
|
251
257
|
messageID: input.assistantMessage.parentID,
|
|
252
|
-
})
|
|
253
|
-
break
|
|
258
|
+
});
|
|
259
|
+
break;
|
|
254
260
|
|
|
255
|
-
case
|
|
261
|
+
case 'text-start':
|
|
256
262
|
currentText = {
|
|
257
|
-
id: Identifier.ascending(
|
|
263
|
+
id: Identifier.ascending('part'),
|
|
258
264
|
messageID: input.assistantMessage.id,
|
|
259
265
|
sessionID: input.assistantMessage.sessionID,
|
|
260
|
-
type:
|
|
261
|
-
text:
|
|
266
|
+
type: 'text',
|
|
267
|
+
text: '',
|
|
262
268
|
time: {
|
|
263
269
|
start: Date.now(),
|
|
264
270
|
},
|
|
265
271
|
metadata: value.providerMetadata,
|
|
266
|
-
}
|
|
267
|
-
break
|
|
272
|
+
};
|
|
273
|
+
break;
|
|
268
274
|
|
|
269
|
-
case
|
|
275
|
+
case 'text-delta':
|
|
270
276
|
if (currentText) {
|
|
271
|
-
currentText.text += value.text
|
|
272
|
-
if (value.providerMetadata)
|
|
277
|
+
currentText.text += value.text;
|
|
278
|
+
if (value.providerMetadata)
|
|
279
|
+
currentText.metadata = value.providerMetadata;
|
|
273
280
|
if (currentText.text)
|
|
274
281
|
await Session.updatePart({
|
|
275
282
|
part: currentText,
|
|
276
283
|
delta: value.text,
|
|
277
|
-
})
|
|
284
|
+
});
|
|
278
285
|
}
|
|
279
|
-
break
|
|
286
|
+
break;
|
|
280
287
|
|
|
281
|
-
case
|
|
288
|
+
case 'text-end':
|
|
282
289
|
if (currentText) {
|
|
283
|
-
currentText.text = currentText.text.trimEnd()
|
|
290
|
+
currentText.text = currentText.text.trimEnd();
|
|
284
291
|
currentText.time = {
|
|
285
292
|
start: Date.now(),
|
|
286
293
|
end: Date.now(),
|
|
287
|
-
}
|
|
288
|
-
if (value.providerMetadata)
|
|
289
|
-
|
|
294
|
+
};
|
|
295
|
+
if (value.providerMetadata)
|
|
296
|
+
currentText.metadata = value.providerMetadata;
|
|
297
|
+
await Session.updatePart(currentText);
|
|
290
298
|
}
|
|
291
|
-
currentText = undefined
|
|
292
|
-
break
|
|
299
|
+
currentText = undefined;
|
|
300
|
+
break;
|
|
293
301
|
|
|
294
|
-
case
|
|
295
|
-
input.assistantMessage.time.completed = Date.now()
|
|
296
|
-
await Session.updateMessage(input.assistantMessage)
|
|
297
|
-
break
|
|
302
|
+
case 'finish':
|
|
303
|
+
input.assistantMessage.time.completed = Date.now();
|
|
304
|
+
await Session.updateMessage(input.assistantMessage);
|
|
305
|
+
break;
|
|
298
306
|
|
|
299
307
|
default:
|
|
300
|
-
log.info(
|
|
308
|
+
log.info('unhandled', {
|
|
301
309
|
...value,
|
|
302
|
-
})
|
|
303
|
-
continue
|
|
310
|
+
});
|
|
311
|
+
continue;
|
|
304
312
|
}
|
|
305
313
|
}
|
|
306
314
|
} catch (e) {
|
|
307
|
-
log.error(
|
|
315
|
+
log.error('process', {
|
|
308
316
|
error: e,
|
|
309
|
-
})
|
|
310
|
-
const error = MessageV2.fromError(e, {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
317
|
+
});
|
|
318
|
+
const error = MessageV2.fromError(e, {
|
|
319
|
+
providerID: input.providerID,
|
|
320
|
+
});
|
|
321
|
+
if (error?.name === 'APIError' && error.data.isRetryable) {
|
|
322
|
+
attempt++;
|
|
323
|
+
const delay = SessionRetry.delay(error, attempt);
|
|
314
324
|
SessionStatus.set(input.sessionID, {
|
|
315
|
-
type:
|
|
325
|
+
type: 'retry',
|
|
316
326
|
attempt,
|
|
317
327
|
message: error.data.message,
|
|
318
328
|
next: Date.now() + delay,
|
|
319
|
-
})
|
|
320
|
-
await SessionRetry.sleep(delay, input.abort).catch(() => {})
|
|
321
|
-
continue
|
|
329
|
+
});
|
|
330
|
+
await SessionRetry.sleep(delay, input.abort).catch(() => {});
|
|
331
|
+
continue;
|
|
322
332
|
}
|
|
323
|
-
input.assistantMessage.error = error
|
|
333
|
+
input.assistantMessage.error = error;
|
|
324
334
|
Bus.publish(Session.Event.Error, {
|
|
325
335
|
sessionID: input.assistantMessage.sessionID,
|
|
326
336
|
error: input.assistantMessage.error,
|
|
327
|
-
})
|
|
337
|
+
});
|
|
328
338
|
}
|
|
329
|
-
const p = await MessageV2.parts(input.assistantMessage.id)
|
|
339
|
+
const p = await MessageV2.parts(input.assistantMessage.id);
|
|
330
340
|
for (const part of p) {
|
|
331
|
-
if (
|
|
341
|
+
if (
|
|
342
|
+
part.type === 'tool' &&
|
|
343
|
+
part.state.status !== 'completed' &&
|
|
344
|
+
part.state.status !== 'error'
|
|
345
|
+
) {
|
|
332
346
|
await Session.updatePart({
|
|
333
347
|
...part,
|
|
334
348
|
state: {
|
|
335
349
|
...part.state,
|
|
336
|
-
status:
|
|
337
|
-
error:
|
|
350
|
+
status: 'error',
|
|
351
|
+
error: 'Tool execution aborted',
|
|
338
352
|
time: {
|
|
339
353
|
start: Date.now(),
|
|
340
354
|
end: Date.now(),
|
|
341
355
|
},
|
|
342
356
|
},
|
|
343
|
-
})
|
|
357
|
+
});
|
|
344
358
|
}
|
|
345
359
|
}
|
|
346
|
-
input.assistantMessage.time.completed = Date.now()
|
|
347
|
-
await Session.updateMessage(input.assistantMessage)
|
|
348
|
-
if (blocked) return
|
|
349
|
-
if (input.assistantMessage.error) return
|
|
350
|
-
return
|
|
360
|
+
input.assistantMessage.time.completed = Date.now();
|
|
361
|
+
await Session.updateMessage(input.assistantMessage);
|
|
362
|
+
if (blocked) return 'stop';
|
|
363
|
+
if (input.assistantMessage.error) return 'stop';
|
|
364
|
+
return 'continue';
|
|
351
365
|
}
|
|
352
366
|
},
|
|
353
|
-
}
|
|
354
|
-
return result
|
|
367
|
+
};
|
|
368
|
+
return result;
|
|
355
369
|
}
|
|
356
370
|
}
|