@link-assistant/agent 0.26.8 → 0.26.10
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/package.json +17 -17
- package/src/session/message-v2.ts +8 -1
- package/src/session/processor.ts +3 -7
- package/src/session/prompt.ts +32 -26
- package/src/tool/bash.ts +49 -16
- package/src/tool/batch.ts +6 -8
- package/src/tool/grep.ts +1 -1
- package/src/tool/process-result.ts +18 -0
- package/src/tool/tool.ts +46 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@link-assistant/agent",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.10",
|
|
4
4
|
"description": "A minimal, public domain AI CLI agent compatible with OpenCode's JSON interface. Bun-only runtime.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -51,18 +51,18 @@
|
|
|
51
51
|
],
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@agentclientprotocol/sdk": "^1.5.1",
|
|
54
|
-
"@ai-sdk/amazon-bedrock": "^5.0.
|
|
55
|
-
"@ai-sdk/anthropic": "^4.0.
|
|
56
|
-
"@ai-sdk/azure": "^4.0.
|
|
57
|
-
"@ai-sdk/google": "^4.0.
|
|
58
|
-
"@ai-sdk/google-vertex": "^5.0.
|
|
59
|
-
"@ai-sdk/groq": "^4.0.
|
|
60
|
-
"@ai-sdk/mcp": "^2.0.
|
|
61
|
-
"@ai-sdk/mistral": "^4.0.
|
|
62
|
-
"@ai-sdk/openai": "^4.0.
|
|
63
|
-
"@ai-sdk/openai-compatible": "^3.0.
|
|
64
|
-
"@ai-sdk/provider": "^4.0.
|
|
65
|
-
"@ai-sdk/xai": "^5.0.
|
|
54
|
+
"@ai-sdk/amazon-bedrock": "^5.0.102",
|
|
55
|
+
"@ai-sdk/anthropic": "^4.0.69",
|
|
56
|
+
"@ai-sdk/azure": "^4.0.86",
|
|
57
|
+
"@ai-sdk/google": "^4.0.86",
|
|
58
|
+
"@ai-sdk/google-vertex": "^5.0.99",
|
|
59
|
+
"@ai-sdk/groq": "^4.0.53",
|
|
60
|
+
"@ai-sdk/mcp": "^2.0.63",
|
|
61
|
+
"@ai-sdk/mistral": "^4.0.55",
|
|
62
|
+
"@ai-sdk/openai": "^4.0.82",
|
|
63
|
+
"@ai-sdk/openai-compatible": "^3.0.60",
|
|
64
|
+
"@ai-sdk/provider": "^4.0.20",
|
|
65
|
+
"@ai-sdk/xai": "^5.0.13",
|
|
66
66
|
"@clack/prompts": "^1.8.1",
|
|
67
67
|
"@hono/standard-validator": "^0.4.0",
|
|
68
68
|
"@hono/zod-validator": "^0.9.1",
|
|
@@ -72,14 +72,14 @@
|
|
|
72
72
|
"@openauthjs/openauth": "^0.4.3",
|
|
73
73
|
"@opencode-ai/sdk": "^1.18.33",
|
|
74
74
|
"@openrouter/ai-sdk-provider": "^3.1.0",
|
|
75
|
-
"@opentui/core": "0.5.
|
|
76
|
-
"@opentui/solid": "0.5.
|
|
75
|
+
"@opentui/core": "0.5.13",
|
|
76
|
+
"@opentui/solid": "0.5.13",
|
|
77
77
|
"@parcel/watcher": "^2.6.0",
|
|
78
78
|
"@solid-primitives/event-bus": "^1.1.4",
|
|
79
79
|
"@standard-community/standard-json": "^0.3.6",
|
|
80
80
|
"@standard-community/standard-openapi": "^0.2.10",
|
|
81
81
|
"@zip.js/zip.js": "^2.18.2",
|
|
82
|
-
"ai": "^7.0.
|
|
82
|
+
"ai": "^7.0.123",
|
|
83
83
|
"chokidar": "^5.0.0",
|
|
84
84
|
"clipboardy": "^5.3.2",
|
|
85
85
|
"command-stream": "^1.3.0",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"glob": "^13.0.6",
|
|
90
90
|
"gpt-tokenizer": "^4.0.0",
|
|
91
91
|
"gray-matter": "^4.0.3",
|
|
92
|
-
"hono": "^4.13.
|
|
92
|
+
"hono": "^4.13.12",
|
|
93
93
|
"hono-openapi": "^1.3.3",
|
|
94
94
|
"ignore": "^7.0.10",
|
|
95
95
|
"jsonc-parser": "^3.3.1",
|
|
@@ -338,6 +338,8 @@ export namespace MessageV2 {
|
|
|
338
338
|
status: z.literal('error'),
|
|
339
339
|
input: z.record(z.string(), z.any()),
|
|
340
340
|
error: z.string(),
|
|
341
|
+
title: z.string().optional(),
|
|
342
|
+
attachments: FilePart.array().optional(),
|
|
341
343
|
metadata: z.record(z.string(), z.any()).optional(),
|
|
342
344
|
time: z.object({
|
|
343
345
|
start: z.number(),
|
|
@@ -734,7 +736,10 @@ export namespace MessageV2 {
|
|
|
734
736
|
type: 'step-start',
|
|
735
737
|
});
|
|
736
738
|
if (part.type === 'tool') {
|
|
737
|
-
if (
|
|
739
|
+
if (
|
|
740
|
+
part.state.status === 'completed' ||
|
|
741
|
+
part.state.status === 'error'
|
|
742
|
+
) {
|
|
738
743
|
if (part.state.attachments?.length) {
|
|
739
744
|
result.push({
|
|
740
745
|
id: Identifier.ascending('message'),
|
|
@@ -753,6 +758,8 @@ export namespace MessageV2 {
|
|
|
753
758
|
],
|
|
754
759
|
});
|
|
755
760
|
}
|
|
761
|
+
}
|
|
762
|
+
if (part.state.status === 'completed') {
|
|
756
763
|
assistantMessage.parts.push({
|
|
757
764
|
type: ('tool-' + part.tool) as `tool-${string}`,
|
|
758
765
|
state: 'output-available',
|
package/src/session/processor.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { SessionStatus } from './status';
|
|
|
19
19
|
import { config, isVerbose } from '../config/config';
|
|
20
20
|
import { SessionCompaction } from './compaction';
|
|
21
21
|
import { SSEUsageExtractor } from '../util/sse-usage-extractor';
|
|
22
|
+
import { Tool } from '../tool/tool';
|
|
22
23
|
|
|
23
24
|
export namespace SessionProcessor {
|
|
24
25
|
const DOOM_LOOP_THRESHOLD = 3;
|
|
@@ -233,18 +234,13 @@ export namespace SessionProcessor {
|
|
|
233
234
|
if (match && match.state.status === 'running') {
|
|
234
235
|
await Session.updatePart({
|
|
235
236
|
...match,
|
|
236
|
-
state: {
|
|
237
|
-
status: 'completed',
|
|
237
|
+
state: Tool.toState(value.output, {
|
|
238
238
|
input: value.input,
|
|
239
|
-
output: value.output.output,
|
|
240
|
-
metadata: value.output.metadata,
|
|
241
|
-
title: value.output.title,
|
|
242
239
|
time: {
|
|
243
240
|
start: match.state.time.start,
|
|
244
241
|
end: Date.now(),
|
|
245
242
|
},
|
|
246
|
-
|
|
247
|
-
},
|
|
243
|
+
}),
|
|
248
244
|
});
|
|
249
245
|
|
|
250
246
|
delete toolcalls[value.toolCallId];
|
package/src/session/prompt.ts
CHANGED
|
@@ -48,6 +48,8 @@ import { fn } from '../util/fn';
|
|
|
48
48
|
import { SessionProcessor } from './processor';
|
|
49
49
|
import { TaskTool } from '../tool/task';
|
|
50
50
|
import { SessionStatus } from './status';
|
|
51
|
+
import { Tool } from '../tool/tool';
|
|
52
|
+
import { processResult } from '../tool/process-result';
|
|
51
53
|
|
|
52
54
|
export namespace SessionPrompt {
|
|
53
55
|
const log = Log.create({ service: 'session.prompt' });
|
|
@@ -1198,12 +1200,7 @@ export namespace SessionPrompt {
|
|
|
1198
1200
|
});
|
|
1199
1201
|
return result;
|
|
1200
1202
|
},
|
|
1201
|
-
toModelOutput
|
|
1202
|
-
return {
|
|
1203
|
-
type: 'text',
|
|
1204
|
-
value: result.output,
|
|
1205
|
-
};
|
|
1206
|
-
},
|
|
1203
|
+
toModelOutput: Tool.toModelOutput,
|
|
1207
1204
|
});
|
|
1208
1205
|
}
|
|
1209
1206
|
|
|
@@ -1260,14 +1257,10 @@ export namespace SessionPrompt {
|
|
|
1260
1257
|
output: textParts.join('\n\n'),
|
|
1261
1258
|
attachments,
|
|
1262
1259
|
content: result.content, // directly return content to preserve ordering when outputting to model
|
|
1260
|
+
isError: result.isError,
|
|
1263
1261
|
};
|
|
1264
1262
|
};
|
|
1265
|
-
item.toModelOutput =
|
|
1266
|
-
return {
|
|
1267
|
-
type: 'text',
|
|
1268
|
-
value: result.output,
|
|
1269
|
-
};
|
|
1270
|
-
};
|
|
1263
|
+
item.toModelOutput = Tool.toModelOutput;
|
|
1271
1264
|
tools[key] = item;
|
|
1272
1265
|
}
|
|
1273
1266
|
return tools;
|
|
@@ -1723,20 +1716,29 @@ export namespace SessionPrompt {
|
|
|
1723
1716
|
msg.time.completed = Date.now();
|
|
1724
1717
|
await Session.updateMessage(msg);
|
|
1725
1718
|
if (part.state.status === 'running') {
|
|
1726
|
-
part.state =
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
...
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1719
|
+
part.state = Tool.toState(
|
|
1720
|
+
{
|
|
1721
|
+
title: '',
|
|
1722
|
+
...processResult({
|
|
1723
|
+
output,
|
|
1724
|
+
exit: proc.exitCode,
|
|
1725
|
+
signal: proc.signalCode,
|
|
1726
|
+
}),
|
|
1727
|
+
metadata: {
|
|
1728
|
+
output,
|
|
1729
|
+
exit: proc.exitCode,
|
|
1730
|
+
signal: proc.signalCode,
|
|
1731
|
+
description: '',
|
|
1732
|
+
},
|
|
1737
1733
|
},
|
|
1738
|
-
|
|
1739
|
-
|
|
1734
|
+
{
|
|
1735
|
+
time: {
|
|
1736
|
+
...part.state.time,
|
|
1737
|
+
end: Date.now(),
|
|
1738
|
+
},
|
|
1739
|
+
input: part.state.input,
|
|
1740
|
+
}
|
|
1741
|
+
);
|
|
1740
1742
|
await Session.updatePart(part);
|
|
1741
1743
|
}
|
|
1742
1744
|
return { info: msg, parts: [part] };
|
|
@@ -1794,7 +1796,11 @@ export namespace SessionPrompt {
|
|
|
1794
1796
|
const results = await Promise.all(
|
|
1795
1797
|
shell.map(async ([, cmd]) => {
|
|
1796
1798
|
try {
|
|
1797
|
-
|
|
1799
|
+
const result = await $`${{ raw: cmd }}`.nothrow();
|
|
1800
|
+
return processResult({
|
|
1801
|
+
output: result.text(),
|
|
1802
|
+
exit: result.exitCode,
|
|
1803
|
+
}).output;
|
|
1798
1804
|
} catch (error) {
|
|
1799
1805
|
return `Error executing command: ${error instanceof Error ? error.message : String(error)}`;
|
|
1800
1806
|
}
|
package/src/tool/bash.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { $ } from 'bun';
|
|
|
11
11
|
import { Filesystem } from '../util/filesystem';
|
|
12
12
|
import { Permission } from '../permission';
|
|
13
13
|
import { fileURLToPath } from 'url';
|
|
14
|
+
import { processResult } from './process-result';
|
|
14
15
|
|
|
15
16
|
const MAX_OUTPUT_LENGTH = 30_000;
|
|
16
17
|
const DEFAULT_TIMEOUT = 1 * 60 * 1000;
|
|
@@ -28,13 +29,18 @@ const resolveWasm = (asset: string) => {
|
|
|
28
29
|
|
|
29
30
|
const parser = lazy(async () => {
|
|
30
31
|
const { Parser } = await import('web-tree-sitter');
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
// web-tree-sitter renamed its runtime WASM in 0.26. Resolve the current
|
|
33
|
+
// export while retaining 0.25 compatibility until OpenTUI lifts its peer pin.
|
|
34
|
+
let treePath: string;
|
|
35
|
+
try {
|
|
36
|
+
treePath = resolveWasm(
|
|
37
|
+
import.meta.resolve('web-tree-sitter/web-tree-sitter.wasm')
|
|
38
|
+
);
|
|
39
|
+
} catch {
|
|
40
|
+
treePath = resolveWasm(
|
|
41
|
+
import.meta.resolve('web-tree-sitter/tree-sitter.wasm')
|
|
42
|
+
);
|
|
43
|
+
}
|
|
38
44
|
await Parser.init({
|
|
39
45
|
locateFile() {
|
|
40
46
|
return treePath;
|
|
@@ -149,10 +155,11 @@ export const BashTool = Tool.define('bash', {
|
|
|
149
155
|
let timedOut = false;
|
|
150
156
|
let aborted = false;
|
|
151
157
|
let exited = false;
|
|
158
|
+
let closed = false;
|
|
152
159
|
|
|
153
160
|
const killTree = async () => {
|
|
154
161
|
const pid = proc.pid;
|
|
155
|
-
if (!pid ||
|
|
162
|
+
if (!pid || closed) {
|
|
156
163
|
return;
|
|
157
164
|
}
|
|
158
165
|
|
|
@@ -170,7 +177,9 @@ export const BashTool = Tool.define('bash', {
|
|
|
170
177
|
try {
|
|
171
178
|
process.kill(-pid, 'SIGTERM');
|
|
172
179
|
await Bun.sleep(SIGKILL_TIMEOUT_MS);
|
|
173
|
-
|
|
180
|
+
// The shell may exit before a child that ignores SIGTERM. The
|
|
181
|
+
// process group still needs SIGKILL until its output pipes close.
|
|
182
|
+
if (!closed) {
|
|
174
183
|
process.kill(-pid, 'SIGKILL');
|
|
175
184
|
}
|
|
176
185
|
} catch (_e) {
|
|
@@ -182,11 +191,6 @@ export const BashTool = Tool.define('bash', {
|
|
|
182
191
|
}
|
|
183
192
|
};
|
|
184
193
|
|
|
185
|
-
if (ctx.abort.aborted) {
|
|
186
|
-
aborted = true;
|
|
187
|
-
await killTree();
|
|
188
|
-
}
|
|
189
|
-
|
|
190
194
|
const abortHandler = () => {
|
|
191
195
|
aborted = true;
|
|
192
196
|
void killTree();
|
|
@@ -199,7 +203,7 @@ export const BashTool = Tool.define('bash', {
|
|
|
199
203
|
void killTree();
|
|
200
204
|
}, timeout);
|
|
201
205
|
|
|
202
|
-
|
|
206
|
+
const completion = new Promise<void>((resolve, reject) => {
|
|
203
207
|
const cleanup = () => {
|
|
204
208
|
clearTimeout(timeoutTimer);
|
|
205
209
|
ctx.abort.removeEventListener('abort', abortHandler);
|
|
@@ -207,6 +211,12 @@ export const BashTool = Tool.define('bash', {
|
|
|
207
211
|
|
|
208
212
|
proc.once('exit', () => {
|
|
209
213
|
exited = true;
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// close follows exit after stdout/stderr have drained. Install these
|
|
217
|
+
// listeners before killing an already-aborted process.
|
|
218
|
+
proc.once('close', () => {
|
|
219
|
+
closed = true;
|
|
210
220
|
cleanup();
|
|
211
221
|
resolve();
|
|
212
222
|
});
|
|
@@ -218,6 +228,9 @@ export const BashTool = Tool.define('bash', {
|
|
|
218
228
|
});
|
|
219
229
|
});
|
|
220
230
|
|
|
231
|
+
if (ctx.abort.aborted) abortHandler();
|
|
232
|
+
await completion;
|
|
233
|
+
|
|
221
234
|
if (output.length > MAX_OUTPUT_LENGTH) {
|
|
222
235
|
output = output.slice(0, MAX_OUTPUT_LENGTH);
|
|
223
236
|
output += '\n\n(Output was truncated due to length limit)';
|
|
@@ -231,14 +244,34 @@ export const BashTool = Tool.define('bash', {
|
|
|
231
244
|
output += '\n\n(Command was aborted)';
|
|
232
245
|
}
|
|
233
246
|
|
|
247
|
+
const result = processResult({
|
|
248
|
+
output,
|
|
249
|
+
exit: proc.exitCode,
|
|
250
|
+
signal: proc.signalCode,
|
|
251
|
+
timedOut,
|
|
252
|
+
aborted,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
log.debug(() => ({
|
|
256
|
+
message: 'command finished',
|
|
257
|
+
exit: proc.exitCode,
|
|
258
|
+
signal: proc.signalCode,
|
|
259
|
+
timedOut,
|
|
260
|
+
aborted,
|
|
261
|
+
isError: result.isError,
|
|
262
|
+
}));
|
|
263
|
+
|
|
234
264
|
return {
|
|
235
265
|
title: params.command,
|
|
236
266
|
metadata: {
|
|
237
267
|
output,
|
|
238
268
|
exit: proc.exitCode,
|
|
269
|
+
signal: proc.signalCode,
|
|
270
|
+
timedOut,
|
|
271
|
+
aborted,
|
|
239
272
|
description: params.description,
|
|
240
273
|
},
|
|
241
|
-
|
|
274
|
+
...result,
|
|
242
275
|
};
|
|
243
276
|
},
|
|
244
277
|
});
|
package/src/tool/batch.ts
CHANGED
|
@@ -101,21 +101,18 @@ export const BatchTool = Tool.define('batch', async () => {
|
|
|
101
101
|
type: 'tool',
|
|
102
102
|
tool: call.tool,
|
|
103
103
|
callID: partID,
|
|
104
|
-
state: {
|
|
105
|
-
status: 'completed',
|
|
104
|
+
state: Tool.toState(result, {
|
|
106
105
|
input: call.parameters,
|
|
107
|
-
output: result.output,
|
|
108
|
-
title: result.title,
|
|
109
|
-
metadata: result.metadata,
|
|
110
|
-
attachments: result.attachments,
|
|
111
106
|
time: {
|
|
112
107
|
start: callStartTime,
|
|
113
108
|
end: Date.now(),
|
|
114
109
|
},
|
|
115
|
-
},
|
|
110
|
+
}),
|
|
116
111
|
});
|
|
117
112
|
|
|
118
|
-
return
|
|
113
|
+
return result.isError
|
|
114
|
+
? { success: false as const, tool: call.tool, error: result.output }
|
|
115
|
+
: { success: true as const, tool: call.tool, result };
|
|
119
116
|
} catch (error) {
|
|
120
117
|
await Session.updatePart({
|
|
121
118
|
id: partID,
|
|
@@ -179,6 +176,7 @@ export const BatchTool = Tool.define('batch', async () => {
|
|
|
179
176
|
return {
|
|
180
177
|
title: `Batch execution (${successfulCalls}/${results.length} successful)`,
|
|
181
178
|
output: outputMessage,
|
|
179
|
+
isError: failedCalls > 0,
|
|
182
180
|
attachments: results
|
|
183
181
|
.filter((result) => result.success)
|
|
184
182
|
.flatMap((r) => r.result.attachments ?? []),
|
package/src/tool/grep.ts
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Keep process status in the text sent to every provider, including those
|
|
2
|
+
* whose tool protocol has no separate error flag. */
|
|
3
|
+
export function processResult(input: {
|
|
4
|
+
output: string;
|
|
5
|
+
exit: number | null;
|
|
6
|
+
signal?: string | null;
|
|
7
|
+
timedOut?: boolean;
|
|
8
|
+
aborted?: boolean;
|
|
9
|
+
}) {
|
|
10
|
+
const isError = input.exit !== 0 || !!input.timedOut || !!input.aborted;
|
|
11
|
+
const status = input.signal ? ` (signal ${input.signal})` : '';
|
|
12
|
+
return {
|
|
13
|
+
output: isError
|
|
14
|
+
? `Exit code ${input.exit ?? 'unavailable'}${status}\n${input.output}`
|
|
15
|
+
: input.output,
|
|
16
|
+
isError,
|
|
17
|
+
};
|
|
18
|
+
}
|
package/src/tool/tool.ts
CHANGED
|
@@ -1,11 +1,56 @@
|
|
|
1
1
|
import z from 'zod';
|
|
2
2
|
import type { MessageV2 } from '../session/message-v2';
|
|
3
|
+
import type { ToolResultOutput } from 'ai';
|
|
3
4
|
|
|
4
5
|
export namespace Tool {
|
|
5
6
|
interface Metadata {
|
|
6
7
|
[key: string]: any;
|
|
7
8
|
}
|
|
8
9
|
|
|
10
|
+
export interface Result<M extends Metadata = Metadata> {
|
|
11
|
+
title: string;
|
|
12
|
+
metadata: M;
|
|
13
|
+
output: string;
|
|
14
|
+
isError?: boolean;
|
|
15
|
+
attachments?: MessageV2.FilePart[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// AI SDK 7 passes an options object containing the execution output.
|
|
19
|
+
export function toModelOutput({
|
|
20
|
+
output: result,
|
|
21
|
+
}: {
|
|
22
|
+
output: Pick<Result, 'output' | 'isError'>;
|
|
23
|
+
}): ToolResultOutput {
|
|
24
|
+
return {
|
|
25
|
+
type: result.isError ? 'error-text' : 'text',
|
|
26
|
+
value: result.output,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function toState(
|
|
31
|
+
result: Result,
|
|
32
|
+
input: { input: Record<string, any>; time: { start: number; end: number } }
|
|
33
|
+
): MessageV2.ToolStateCompleted | MessageV2.ToolStateError {
|
|
34
|
+
if (result.isError) {
|
|
35
|
+
return {
|
|
36
|
+
...input,
|
|
37
|
+
status: 'error',
|
|
38
|
+
error: result.output,
|
|
39
|
+
metadata: result.metadata,
|
|
40
|
+
title: result.title,
|
|
41
|
+
attachments: result.attachments,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
...input,
|
|
46
|
+
status: 'completed',
|
|
47
|
+
output: result.output,
|
|
48
|
+
title: result.title,
|
|
49
|
+
metadata: result.metadata,
|
|
50
|
+
attachments: result.attachments,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
9
54
|
export type Context<M extends Metadata = Metadata> = {
|
|
10
55
|
sessionID: string;
|
|
11
56
|
messageID: string;
|
|
@@ -23,15 +68,7 @@ export namespace Tool {
|
|
|
23
68
|
init: () => Promise<{
|
|
24
69
|
description: string;
|
|
25
70
|
parameters: Parameters;
|
|
26
|
-
execute(
|
|
27
|
-
args: z.infer<Parameters>,
|
|
28
|
-
ctx: Context
|
|
29
|
-
): Promise<{
|
|
30
|
-
title: string;
|
|
31
|
-
metadata: M;
|
|
32
|
-
output: string;
|
|
33
|
-
attachments?: MessageV2.FilePart[];
|
|
34
|
-
}>;
|
|
71
|
+
execute(args: z.infer<Parameters>, ctx: Context): Promise<Result<M>>;
|
|
35
72
|
formatValidationError?(error: z.ZodError): string;
|
|
36
73
|
}>;
|
|
37
74
|
}
|