@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/server/server.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { Log } from
|
|
2
|
-
import { describeRoute, validator, resolver } from
|
|
3
|
-
import { Hono } from
|
|
4
|
-
import { cors } from
|
|
5
|
-
import { stream } from
|
|
6
|
-
import { Session } from
|
|
7
|
-
import z from
|
|
8
|
-
import { NamedError } from
|
|
9
|
-
import { MessageV2 } from
|
|
10
|
-
import { Instance } from
|
|
11
|
-
import { SessionPrompt } from
|
|
12
|
-
import { Storage } from
|
|
13
|
-
import type { ContentfulStatusCode } from
|
|
14
|
-
import { lazy } from
|
|
1
|
+
import { Log } from '../util/log';
|
|
2
|
+
import { describeRoute, validator, resolver } from 'hono-openapi';
|
|
3
|
+
import { Hono } from 'hono';
|
|
4
|
+
import { cors } from 'hono/cors';
|
|
5
|
+
import { stream } from 'hono/streaming';
|
|
6
|
+
import { Session } from '../session';
|
|
7
|
+
import z from 'zod';
|
|
8
|
+
import { NamedError } from '../util/error';
|
|
9
|
+
import { MessageV2 } from '../session/message-v2';
|
|
10
|
+
import { Instance } from '../project/instance';
|
|
11
|
+
import { SessionPrompt } from '../session/prompt';
|
|
12
|
+
import { Storage } from '../storage/storage';
|
|
13
|
+
import type { ContentfulStatusCode } from 'hono/utils/http-status';
|
|
14
|
+
import { lazy } from '../util/lazy';
|
|
15
15
|
|
|
16
16
|
const ERRORS = {
|
|
17
17
|
400: {
|
|
18
|
-
description:
|
|
18
|
+
description: 'Bad request',
|
|
19
19
|
content: {
|
|
20
|
-
|
|
20
|
+
'application/json': {
|
|
21
21
|
schema: resolver(
|
|
22
22
|
z
|
|
23
23
|
.object({
|
|
@@ -26,98 +26,104 @@ const ERRORS = {
|
|
|
26
26
|
success: z.literal(false),
|
|
27
27
|
})
|
|
28
28
|
.meta({
|
|
29
|
-
ref:
|
|
30
|
-
})
|
|
29
|
+
ref: 'BadRequestError',
|
|
30
|
+
})
|
|
31
31
|
),
|
|
32
32
|
},
|
|
33
33
|
},
|
|
34
34
|
},
|
|
35
35
|
404: {
|
|
36
|
-
description:
|
|
36
|
+
description: 'Not found',
|
|
37
37
|
content: {
|
|
38
|
-
|
|
38
|
+
'application/json': {
|
|
39
39
|
schema: resolver(Storage.NotFoundError.Schema),
|
|
40
40
|
},
|
|
41
41
|
},
|
|
42
42
|
},
|
|
43
|
-
} as const
|
|
43
|
+
} as const;
|
|
44
44
|
|
|
45
45
|
function errors(...codes: number[]) {
|
|
46
|
-
return Object.fromEntries(
|
|
46
|
+
return Object.fromEntries(
|
|
47
|
+
codes.map((code) => [code, ERRORS[code as keyof typeof ERRORS]])
|
|
48
|
+
);
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
export namespace Server {
|
|
50
|
-
const log = Log.create({ service:
|
|
52
|
+
const log = Log.create({ service: 'server' });
|
|
51
53
|
|
|
52
|
-
const app = new Hono()
|
|
54
|
+
const app = new Hono();
|
|
53
55
|
export const App = lazy(() =>
|
|
54
56
|
app
|
|
55
57
|
.onError((err, c) => {
|
|
56
|
-
log.error(
|
|
58
|
+
log.error('failed', {
|
|
57
59
|
error: err,
|
|
58
|
-
})
|
|
60
|
+
});
|
|
59
61
|
if (err instanceof NamedError) {
|
|
60
|
-
let status: ContentfulStatusCode
|
|
61
|
-
if (err instanceof Storage.NotFoundError) status = 404
|
|
62
|
-
else status = 500
|
|
63
|
-
return c.json(err.toObject(), { status })
|
|
62
|
+
let status: ContentfulStatusCode;
|
|
63
|
+
if (err instanceof Storage.NotFoundError) status = 404;
|
|
64
|
+
else status = 500;
|
|
65
|
+
return c.json(err.toObject(), { status });
|
|
64
66
|
}
|
|
65
|
-
const message =
|
|
67
|
+
const message =
|
|
68
|
+
err instanceof Error && err.stack ? err.stack : err.toString();
|
|
66
69
|
return c.json(new NamedError.Unknown({ message }).toObject(), {
|
|
67
70
|
status: 500,
|
|
68
|
-
})
|
|
71
|
+
});
|
|
69
72
|
})
|
|
70
73
|
.use(async (c, next) => {
|
|
71
|
-
log.info(
|
|
74
|
+
log.info('request', {
|
|
72
75
|
method: c.req.method,
|
|
73
76
|
path: c.req.path,
|
|
74
|
-
})
|
|
75
|
-
const timer = log.time(
|
|
77
|
+
});
|
|
78
|
+
const timer = log.time('request', {
|
|
76
79
|
method: c.req.method,
|
|
77
80
|
path: c.req.path,
|
|
78
|
-
})
|
|
79
|
-
await next()
|
|
80
|
-
timer.stop()
|
|
81
|
+
});
|
|
82
|
+
await next();
|
|
83
|
+
timer.stop();
|
|
81
84
|
})
|
|
82
85
|
.use(cors())
|
|
83
|
-
.get(
|
|
84
|
-
return c.json({ status:
|
|
86
|
+
.get('/health', (c) => {
|
|
87
|
+
return c.json({ status: 'ok' });
|
|
85
88
|
})
|
|
86
89
|
.post(
|
|
87
|
-
|
|
90
|
+
'/session',
|
|
88
91
|
describeRoute({
|
|
89
|
-
description:
|
|
90
|
-
operationId:
|
|
92
|
+
description: 'Create a new session',
|
|
93
|
+
operationId: 'session.create',
|
|
91
94
|
responses: {
|
|
92
95
|
200: {
|
|
93
|
-
description:
|
|
96
|
+
description: 'Created session',
|
|
94
97
|
content: {
|
|
95
|
-
|
|
98
|
+
'application/json': {
|
|
96
99
|
schema: resolver(Session.Info),
|
|
97
100
|
},
|
|
98
101
|
},
|
|
99
102
|
},
|
|
100
103
|
},
|
|
101
104
|
}),
|
|
102
|
-
validator(
|
|
105
|
+
validator(
|
|
106
|
+
'json',
|
|
107
|
+
z.object({ title: z.string().optional() }).optional()
|
|
108
|
+
),
|
|
103
109
|
async (c) => {
|
|
104
|
-
const body = c.req.valid(
|
|
110
|
+
const body = c.req.valid('json') || {};
|
|
105
111
|
const session = await Session.create({
|
|
106
112
|
title: body.title,
|
|
107
|
-
})
|
|
108
|
-
return c.json(session)
|
|
109
|
-
}
|
|
113
|
+
});
|
|
114
|
+
return c.json(session);
|
|
115
|
+
}
|
|
110
116
|
)
|
|
111
117
|
.get(
|
|
112
|
-
|
|
118
|
+
'/session',
|
|
113
119
|
describeRoute({
|
|
114
|
-
description:
|
|
115
|
-
operationId:
|
|
120
|
+
description: 'List all sessions',
|
|
121
|
+
operationId: 'session.list',
|
|
116
122
|
responses: {
|
|
117
123
|
200: {
|
|
118
|
-
description:
|
|
124
|
+
description: 'List of sessions',
|
|
119
125
|
content: {
|
|
120
|
-
|
|
126
|
+
'application/json': {
|
|
121
127
|
schema: resolver(Session.Info.array()),
|
|
122
128
|
},
|
|
123
129
|
},
|
|
@@ -125,20 +131,20 @@ export namespace Server {
|
|
|
125
131
|
},
|
|
126
132
|
}),
|
|
127
133
|
async (c) => {
|
|
128
|
-
const sessions = await Session.list()
|
|
129
|
-
return c.json(sessions)
|
|
130
|
-
}
|
|
134
|
+
const sessions = await Session.list();
|
|
135
|
+
return c.json(sessions);
|
|
136
|
+
}
|
|
131
137
|
)
|
|
132
138
|
.get(
|
|
133
|
-
|
|
139
|
+
'/session/:id',
|
|
134
140
|
describeRoute({
|
|
135
|
-
description:
|
|
136
|
-
operationId:
|
|
141
|
+
description: 'Get a session',
|
|
142
|
+
operationId: 'session.get',
|
|
137
143
|
responses: {
|
|
138
144
|
200: {
|
|
139
|
-
description:
|
|
145
|
+
description: 'Session info',
|
|
140
146
|
content: {
|
|
141
|
-
|
|
147
|
+
'application/json': {
|
|
142
148
|
schema: resolver(Session.Info),
|
|
143
149
|
},
|
|
144
150
|
},
|
|
@@ -147,31 +153,31 @@ export namespace Server {
|
|
|
147
153
|
},
|
|
148
154
|
}),
|
|
149
155
|
validator(
|
|
150
|
-
|
|
156
|
+
'param',
|
|
151
157
|
z.object({
|
|
152
158
|
id: z.string(),
|
|
153
|
-
})
|
|
159
|
+
})
|
|
154
160
|
),
|
|
155
161
|
async (c) => {
|
|
156
|
-
const session = await Session.get(c.req.valid(
|
|
157
|
-
return c.json(session)
|
|
158
|
-
}
|
|
162
|
+
const session = await Session.get(c.req.valid('param').id);
|
|
163
|
+
return c.json(session);
|
|
164
|
+
}
|
|
159
165
|
)
|
|
160
166
|
.post(
|
|
161
|
-
|
|
167
|
+
'/session/:id/message',
|
|
162
168
|
describeRoute({
|
|
163
|
-
description:
|
|
164
|
-
operationId:
|
|
169
|
+
description: 'Create and send a new message to a session',
|
|
170
|
+
operationId: 'session.prompt',
|
|
165
171
|
responses: {
|
|
166
172
|
200: {
|
|
167
|
-
description:
|
|
173
|
+
description: 'Created message',
|
|
168
174
|
content: {
|
|
169
|
-
|
|
175
|
+
'application/json': {
|
|
170
176
|
schema: resolver(
|
|
171
177
|
z.object({
|
|
172
178
|
info: MessageV2.Assistant,
|
|
173
179
|
parts: MessageV2.Part.array(),
|
|
174
|
-
})
|
|
180
|
+
})
|
|
175
181
|
),
|
|
176
182
|
},
|
|
177
183
|
},
|
|
@@ -180,33 +186,33 @@ export namespace Server {
|
|
|
180
186
|
},
|
|
181
187
|
}),
|
|
182
188
|
validator(
|
|
183
|
-
|
|
189
|
+
'param',
|
|
184
190
|
z.object({
|
|
185
|
-
id: z.string().meta({ description:
|
|
186
|
-
})
|
|
191
|
+
id: z.string().meta({ description: 'Session ID' }),
|
|
192
|
+
})
|
|
187
193
|
),
|
|
188
|
-
validator(
|
|
194
|
+
validator('json', SessionPrompt.PromptInput.omit({ sessionID: true })),
|
|
189
195
|
async (c) => {
|
|
190
|
-
c.status(200)
|
|
191
|
-
c.header(
|
|
196
|
+
c.status(200);
|
|
197
|
+
c.header('Content-Type', 'application/json');
|
|
192
198
|
return stream(c, async (stream) => {
|
|
193
|
-
const sessionID = c.req.valid(
|
|
194
|
-
const body = c.req.valid(
|
|
195
|
-
const msg = await SessionPrompt.prompt({ ...body, sessionID })
|
|
196
|
-
stream.write(JSON.stringify(msg))
|
|
197
|
-
})
|
|
198
|
-
}
|
|
199
|
+
const sessionID = c.req.valid('param').id;
|
|
200
|
+
const body = c.req.valid('json');
|
|
201
|
+
const msg = await SessionPrompt.prompt({ ...body, sessionID });
|
|
202
|
+
stream.write(JSON.stringify(msg));
|
|
203
|
+
});
|
|
204
|
+
}
|
|
199
205
|
)
|
|
200
206
|
.get(
|
|
201
|
-
|
|
207
|
+
'/session/:id/message',
|
|
202
208
|
describeRoute({
|
|
203
|
-
description:
|
|
204
|
-
operationId:
|
|
209
|
+
description: 'List messages for a session',
|
|
210
|
+
operationId: 'session.messages',
|
|
205
211
|
responses: {
|
|
206
212
|
200: {
|
|
207
|
-
description:
|
|
213
|
+
description: 'List of messages',
|
|
208
214
|
content: {
|
|
209
|
-
|
|
215
|
+
'application/json': {
|
|
210
216
|
schema: resolver(MessageV2.WithParts.array()),
|
|
211
217
|
},
|
|
212
218
|
},
|
|
@@ -215,27 +221,27 @@ export namespace Server {
|
|
|
215
221
|
},
|
|
216
222
|
}),
|
|
217
223
|
validator(
|
|
218
|
-
|
|
224
|
+
'param',
|
|
219
225
|
z.object({
|
|
220
|
-
id: z.string().meta({ description:
|
|
221
|
-
})
|
|
226
|
+
id: z.string().meta({ description: 'Session ID' }),
|
|
227
|
+
})
|
|
222
228
|
),
|
|
223
229
|
validator(
|
|
224
|
-
|
|
230
|
+
'query',
|
|
225
231
|
z.object({
|
|
226
232
|
limit: z.coerce.number().optional(),
|
|
227
|
-
})
|
|
233
|
+
})
|
|
228
234
|
),
|
|
229
235
|
async (c) => {
|
|
230
|
-
const query = c.req.valid(
|
|
236
|
+
const query = c.req.valid('query');
|
|
231
237
|
const messages = await Session.messages({
|
|
232
|
-
sessionID: c.req.valid(
|
|
238
|
+
sessionID: c.req.valid('param').id,
|
|
233
239
|
limit: query.limit,
|
|
234
|
-
})
|
|
235
|
-
return c.json(messages)
|
|
236
|
-
}
|
|
237
|
-
)
|
|
238
|
-
)
|
|
240
|
+
});
|
|
241
|
+
return c.json(messages);
|
|
242
|
+
}
|
|
243
|
+
)
|
|
244
|
+
);
|
|
239
245
|
|
|
240
246
|
export function listen(opts: { port: number; hostname: string }) {
|
|
241
247
|
const server = Bun.serve({
|
|
@@ -243,7 +249,7 @@ export namespace Server {
|
|
|
243
249
|
hostname: opts.hostname,
|
|
244
250
|
idleTimeout: 0,
|
|
245
251
|
fetch: App().fetch,
|
|
246
|
-
})
|
|
247
|
-
return server
|
|
252
|
+
});
|
|
253
|
+
return server;
|
|
248
254
|
}
|
|
249
255
|
}
|
package/src/session/agent.js
CHANGED
|
@@ -2,27 +2,27 @@
|
|
|
2
2
|
// Permalink: https://github.com/sst/opencode/blob/main/packages/opencode/src/session/index.ts
|
|
3
3
|
// Permalink: https://github.com/sst/opencode/blob/main/packages/opencode/src/provider/provider.ts
|
|
4
4
|
|
|
5
|
-
import { ToolRegistry } from '../tool/registry.ts'
|
|
5
|
+
import { ToolRegistry } from '../tool/registry.ts';
|
|
6
6
|
|
|
7
7
|
export class Agent {
|
|
8
8
|
constructor() {
|
|
9
9
|
// Generate IDs in the same format as opencode
|
|
10
|
-
const randomId = Math.random().toString(36).substring(2, 15)
|
|
11
|
-
this.sessionID = `ses_${Date.now().toString(36)}${randomId}
|
|
12
|
-
this.messageID = `msg_${Date.now().toString(36)}${randomId}
|
|
13
|
-
this.partCounter = 0
|
|
10
|
+
const randomId = Math.random().toString(36).substring(2, 15);
|
|
11
|
+
this.sessionID = `ses_${Date.now().toString(36)}${randomId}`;
|
|
12
|
+
this.messageID = `msg_${Date.now().toString(36)}${randomId}`;
|
|
13
|
+
this.partCounter = 0;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
generatePartId() {
|
|
17
|
-
return `prt_${Date.now().toString(36)}${Math.random().toString(36).substring(2, 15)}
|
|
17
|
+
return `prt_${Date.now().toString(36)}${Math.random().toString(36).substring(2, 15)}`;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
async process(request) {
|
|
21
|
-
const message = request.message ||
|
|
22
|
-
const sessionID = this.sessionID
|
|
21
|
+
const message = request.message || 'hi';
|
|
22
|
+
const sessionID = this.sessionID;
|
|
23
23
|
|
|
24
24
|
// Generate snapshot hash (mock)
|
|
25
|
-
const snapshot = Math.random().toString(16).substring(2, 42)
|
|
25
|
+
const snapshot = Math.random().toString(16).substring(2, 42);
|
|
26
26
|
|
|
27
27
|
// Emit step_start like opencode
|
|
28
28
|
this.emitEvent('step_start', {
|
|
@@ -31,21 +31,21 @@ export class Agent {
|
|
|
31
31
|
sessionID,
|
|
32
32
|
messageID: this.messageID,
|
|
33
33
|
type: 'step-start',
|
|
34
|
-
snapshot
|
|
35
|
-
}
|
|
36
|
-
})
|
|
34
|
+
snapshot,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
37
|
|
|
38
38
|
// Check if this is a tool request
|
|
39
39
|
if (request.tools && request.tools.length > 0) {
|
|
40
40
|
// Handle tool execution
|
|
41
|
-
const toolsList = await ToolRegistry.tools('', '')
|
|
42
|
-
const toolsMap = Object.fromEntries(toolsList.map(t => [t.id, t]))
|
|
41
|
+
const toolsList = await ToolRegistry.tools('', '');
|
|
42
|
+
const toolsMap = Object.fromEntries(toolsList.map((t) => [t.id, t]));
|
|
43
43
|
for (const tool of request.tools) {
|
|
44
|
-
const toolFn = toolsMap[tool.name]
|
|
44
|
+
const toolFn = toolsMap[tool.name];
|
|
45
45
|
if (toolFn) {
|
|
46
46
|
try {
|
|
47
|
-
const startTime = Date.now()
|
|
48
|
-
const callID = `call_${Math.floor(Math.random() * 100000000)}
|
|
47
|
+
const startTime = Date.now();
|
|
48
|
+
const callID = `call_${Math.floor(Math.random() * 100000000)}`;
|
|
49
49
|
|
|
50
50
|
// Create OpenCode-compatible context
|
|
51
51
|
const ctx = {
|
|
@@ -54,13 +54,13 @@ export class Agent {
|
|
|
54
54
|
agent: 'default',
|
|
55
55
|
callID,
|
|
56
56
|
abort: new AbortController().signal,
|
|
57
|
-
metadata: (
|
|
57
|
+
metadata: (_data) => {
|
|
58
58
|
// Handle metadata updates during execution
|
|
59
|
-
}
|
|
60
|
-
}
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
61
|
|
|
62
|
-
const result = await toolFn.execute(tool.params, ctx)
|
|
63
|
-
const endTime = Date.now()
|
|
62
|
+
const result = await toolFn.execute(tool.params, ctx);
|
|
63
|
+
const endTime = Date.now();
|
|
64
64
|
|
|
65
65
|
// Emit tool_use event
|
|
66
66
|
this.emitEvent('tool_use', {
|
|
@@ -75,25 +75,29 @@ export class Agent {
|
|
|
75
75
|
status: 'completed',
|
|
76
76
|
input: tool.params,
|
|
77
77
|
output: result.output,
|
|
78
|
-
title:
|
|
78
|
+
title:
|
|
79
|
+
result.title ||
|
|
80
|
+
`${tool.name} ${JSON.stringify(tool.params)}`,
|
|
79
81
|
metadata: result.metadata || {
|
|
80
82
|
output: result.output,
|
|
81
83
|
exit: result.exitCode || 0,
|
|
82
|
-
...(tool.params.description && {
|
|
84
|
+
...(tool.params.description && {
|
|
85
|
+
description: tool.params.description,
|
|
86
|
+
}),
|
|
83
87
|
},
|
|
84
88
|
time: {
|
|
85
89
|
start: startTime,
|
|
86
|
-
end: endTime
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
})
|
|
90
|
+
end: endTime,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
});
|
|
91
95
|
} catch (error) {
|
|
92
|
-
const errorTime = Date.now()
|
|
93
|
-
const callID = `call_${Math.floor(Math.random() * 100000000)}
|
|
96
|
+
const errorTime = Date.now();
|
|
97
|
+
const callID = `call_${Math.floor(Math.random() * 100000000)}`;
|
|
94
98
|
|
|
95
99
|
// Log full error to stderr for debugging
|
|
96
|
-
console.error('Tool execution error:', error)
|
|
100
|
+
console.error('Tool execution error:', error);
|
|
97
101
|
|
|
98
102
|
// Emit tool_use event with error
|
|
99
103
|
this.emitEvent('tool_use', {
|
|
@@ -110,11 +114,11 @@ export class Agent {
|
|
|
110
114
|
error: error.message || String(error),
|
|
111
115
|
time: {
|
|
112
116
|
start: errorTime,
|
|
113
|
-
end: errorTime
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
})
|
|
117
|
+
end: errorTime,
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
});
|
|
118
122
|
}
|
|
119
123
|
}
|
|
120
124
|
}
|
|
@@ -133,23 +137,23 @@ export class Agent {
|
|
|
133
137
|
input: 1273,
|
|
134
138
|
output: 2,
|
|
135
139
|
reasoning: 173,
|
|
136
|
-
cache: { read: 9536, write: 0 }
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
})
|
|
140
|
+
cache: { read: 9536, write: 0 },
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
});
|
|
140
144
|
|
|
141
145
|
return {
|
|
142
146
|
sessionID,
|
|
143
|
-
timestamp: Date.now()
|
|
144
|
-
}
|
|
147
|
+
timestamp: Date.now(),
|
|
148
|
+
};
|
|
145
149
|
}
|
|
146
150
|
|
|
147
151
|
// Regular message processing
|
|
148
152
|
// Simulate processing delay
|
|
149
|
-
await new Promise(resolve => setTimeout(resolve, 100))
|
|
153
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
150
154
|
|
|
151
155
|
// Emit text response like opencode
|
|
152
|
-
const responseText = message ===
|
|
156
|
+
const responseText = message === 'hi' ? 'Hi!' : `You said: "${message}"`;
|
|
153
157
|
this.emitEvent('text', {
|
|
154
158
|
part: {
|
|
155
159
|
id: this.generatePartId(),
|
|
@@ -159,10 +163,10 @@ export class Agent {
|
|
|
159
163
|
text: responseText,
|
|
160
164
|
time: {
|
|
161
165
|
start: Date.now(),
|
|
162
|
-
end: Date.now()
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
})
|
|
166
|
+
end: Date.now(),
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
});
|
|
166
170
|
|
|
167
171
|
// Emit step_finish with cost and tokens like opencode
|
|
168
172
|
this.emitEvent('step_finish', {
|
|
@@ -178,15 +182,15 @@ export class Agent {
|
|
|
178
182
|
input: 1273,
|
|
179
183
|
output: 2,
|
|
180
184
|
reasoning: 173,
|
|
181
|
-
cache: { read: 9536, write: 0 }
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
})
|
|
185
|
+
cache: { read: 9536, write: 0 },
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
});
|
|
185
189
|
|
|
186
190
|
return {
|
|
187
191
|
sessionID,
|
|
188
|
-
timestamp: Date.now()
|
|
189
|
-
}
|
|
192
|
+
timestamp: Date.now(),
|
|
193
|
+
};
|
|
190
194
|
}
|
|
191
195
|
|
|
192
196
|
emitEvent(type, data) {
|
|
@@ -194,11 +198,13 @@ export class Agent {
|
|
|
194
198
|
type,
|
|
195
199
|
timestamp: Date.now(),
|
|
196
200
|
sessionID: this.sessionID,
|
|
197
|
-
...data
|
|
198
|
-
}
|
|
201
|
+
...data,
|
|
202
|
+
};
|
|
199
203
|
// Pretty-print JSON for human readability, compact for programmatic use
|
|
200
204
|
// Use AGENT_CLI_COMPACT=1 for compact output (tests, automation)
|
|
201
|
-
const compact = process.env.AGENT_CLI_COMPACT === '1'
|
|
202
|
-
console.log(
|
|
205
|
+
const compact = process.env.AGENT_CLI_COMPACT === '1';
|
|
206
|
+
console.log(
|
|
207
|
+
compact ? JSON.stringify(event) : JSON.stringify(event, null, 2)
|
|
208
|
+
);
|
|
203
209
|
}
|
|
204
|
-
}
|
|
210
|
+
}
|