@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/tool/registry.ts
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
import { BashTool } from
|
|
2
|
-
import { EditTool } from
|
|
3
|
-
import { GlobTool } from
|
|
4
|
-
import { GrepTool } from
|
|
5
|
-
import { ListTool } from
|
|
6
|
-
import { BatchTool } from
|
|
7
|
-
import { ReadTool } from
|
|
8
|
-
import { TaskTool } from
|
|
9
|
-
import { TodoWriteTool, TodoReadTool } from
|
|
10
|
-
import { WebFetchTool } from
|
|
11
|
-
import { WriteTool } from
|
|
12
|
-
import { InvalidTool } from
|
|
13
|
-
import type { Agent } from
|
|
14
|
-
import { Tool } from
|
|
15
|
-
import { Instance } from
|
|
16
|
-
import { Config } from
|
|
17
|
-
import { WebSearchTool } from
|
|
18
|
-
import { CodeSearchTool } from
|
|
19
|
-
import { Flag } from
|
|
1
|
+
import { BashTool } from './bash';
|
|
2
|
+
import { EditTool } from './edit';
|
|
3
|
+
import { GlobTool } from './glob';
|
|
4
|
+
import { GrepTool } from './grep';
|
|
5
|
+
import { ListTool } from './ls';
|
|
6
|
+
import { BatchTool } from './batch';
|
|
7
|
+
import { ReadTool } from './read';
|
|
8
|
+
import { TaskTool } from './task';
|
|
9
|
+
import { TodoWriteTool, TodoReadTool } from './todo';
|
|
10
|
+
import { WebFetchTool } from './webfetch';
|
|
11
|
+
import { WriteTool } from './write';
|
|
12
|
+
import { InvalidTool } from './invalid';
|
|
13
|
+
import type { Agent } from '../agent/agent';
|
|
14
|
+
import { Tool } from './tool';
|
|
15
|
+
import { Instance } from '../project/instance';
|
|
16
|
+
import { Config } from '../config/config';
|
|
17
|
+
import { WebSearchTool } from './websearch';
|
|
18
|
+
import { CodeSearchTool } from './codesearch';
|
|
19
|
+
import { Flag } from '../flag/flag';
|
|
20
20
|
|
|
21
21
|
export namespace ToolRegistry {
|
|
22
22
|
export const state = Instance.state(async () => {
|
|
23
|
-
const custom = [] as Tool.Info[]
|
|
24
|
-
return { custom }
|
|
25
|
-
})
|
|
23
|
+
const custom = [] as Tool.Info[];
|
|
24
|
+
return { custom };
|
|
25
|
+
});
|
|
26
26
|
|
|
27
27
|
export async function register(tool: Tool.Info) {
|
|
28
|
-
const { custom } = await state()
|
|
29
|
-
const idx = custom.findIndex((t) => t.id === tool.id)
|
|
28
|
+
const { custom } = await state();
|
|
29
|
+
const idx = custom.findIndex((t) => t.id === tool.id);
|
|
30
30
|
if (idx >= 0) {
|
|
31
|
-
custom.splice(idx, 1, tool)
|
|
32
|
-
return
|
|
31
|
+
custom.splice(idx, 1, tool);
|
|
32
|
+
return;
|
|
33
33
|
}
|
|
34
|
-
custom.push(tool)
|
|
34
|
+
custom.push(tool);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
async function all(): Promise<Tool.Info[]> {
|
|
38
|
-
const custom = await state().then((x) => x.custom)
|
|
39
|
-
const config = await Config.get()
|
|
38
|
+
const custom = await state().then((x) => x.custom);
|
|
39
|
+
const config = await Config.get();
|
|
40
40
|
|
|
41
41
|
return [
|
|
42
42
|
InvalidTool,
|
|
@@ -55,33 +55,33 @@ export namespace ToolRegistry {
|
|
|
55
55
|
TodoWriteTool,
|
|
56
56
|
TodoReadTool,
|
|
57
57
|
...custom,
|
|
58
|
-
]
|
|
58
|
+
];
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
export async function ids() {
|
|
62
|
-
return all().then((x) => x.map((t) => t.id))
|
|
62
|
+
return all().then((x) => x.map((t) => t.id));
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
export async function tools(_providerID: string, _modelID: string) {
|
|
66
|
-
const tools = await all()
|
|
66
|
+
const tools = await all();
|
|
67
67
|
const result = await Promise.all(
|
|
68
68
|
tools.map(async (t) => ({
|
|
69
69
|
id: t.id,
|
|
70
70
|
...(await t.init()),
|
|
71
|
-
}))
|
|
72
|
-
)
|
|
73
|
-
return result
|
|
71
|
+
}))
|
|
72
|
+
);
|
|
73
|
+
return result;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
export async function enabled(
|
|
77
77
|
_providerID: string,
|
|
78
78
|
_modelID: string,
|
|
79
|
-
agent: Agent.Info
|
|
79
|
+
agent: Agent.Info
|
|
80
80
|
): Promise<Record<string, boolean>> {
|
|
81
|
-
const result: Record<string, boolean> = {}
|
|
81
|
+
const result: Record<string, boolean> = {};
|
|
82
82
|
|
|
83
83
|
// Permission system removed - all tools enabled by default
|
|
84
84
|
|
|
85
|
-
return result
|
|
85
|
+
return result;
|
|
86
86
|
}
|
|
87
87
|
}
|
package/src/tool/task.ts
CHANGED
|
@@ -1,54 +1,72 @@
|
|
|
1
|
-
import { Tool } from
|
|
2
|
-
import DESCRIPTION from
|
|
3
|
-
import z from
|
|
4
|
-
import { Session } from
|
|
5
|
-
import { Bus } from
|
|
6
|
-
import { MessageV2 } from
|
|
7
|
-
import { Identifier } from
|
|
8
|
-
import { Agent } from
|
|
9
|
-
import { SessionPrompt } from
|
|
10
|
-
import { iife } from
|
|
11
|
-
import { defer } from
|
|
1
|
+
import { Tool } from './tool';
|
|
2
|
+
import DESCRIPTION from './task.txt';
|
|
3
|
+
import z from 'zod';
|
|
4
|
+
import { Session } from '../session';
|
|
5
|
+
import { Bus } from '../bus';
|
|
6
|
+
import { MessageV2 } from '../session/message-v2';
|
|
7
|
+
import { Identifier } from '../id/id';
|
|
8
|
+
import { Agent } from '../agent/agent';
|
|
9
|
+
import { SessionPrompt } from '../session/prompt';
|
|
10
|
+
import { iife } from '../util/iife';
|
|
11
|
+
import { defer } from '../util/defer';
|
|
12
12
|
|
|
13
|
-
export const TaskTool = Tool.define(
|
|
14
|
-
const agents = await Agent.list().then((x) =>
|
|
13
|
+
export const TaskTool = Tool.define('task', async () => {
|
|
14
|
+
const agents = await Agent.list().then((x) =>
|
|
15
|
+
x.filter((a) => a.mode !== 'primary')
|
|
16
|
+
);
|
|
15
17
|
const description = DESCRIPTION.replace(
|
|
16
|
-
|
|
18
|
+
'{agents}',
|
|
17
19
|
agents
|
|
18
|
-
.map(
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
.map(
|
|
21
|
+
(a) =>
|
|
22
|
+
`- ${a.name}: ${a.description ?? 'This subagent should only be called manually by the user.'}`
|
|
23
|
+
)
|
|
24
|
+
.join('\n')
|
|
25
|
+
);
|
|
21
26
|
return {
|
|
22
27
|
description,
|
|
23
28
|
parameters: z.object({
|
|
24
|
-
description: z
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
description: z
|
|
30
|
+
.string()
|
|
31
|
+
.describe('A short (3-5 words) description of the task'),
|
|
32
|
+
prompt: z.string().describe('The task for the agent to perform'),
|
|
33
|
+
subagent_type: z
|
|
34
|
+
.string()
|
|
35
|
+
.describe('The type of specialized agent to use for this task'),
|
|
36
|
+
session_id: z
|
|
37
|
+
.string()
|
|
38
|
+
.describe('Existing Task session to continue')
|
|
39
|
+
.optional(),
|
|
28
40
|
}),
|
|
29
41
|
async execute(params, ctx) {
|
|
30
|
-
const agent = await Agent.get(params.subagent_type)
|
|
31
|
-
if (!agent)
|
|
42
|
+
const agent = await Agent.get(params.subagent_type);
|
|
43
|
+
if (!agent)
|
|
44
|
+
throw new Error(
|
|
45
|
+
`Unknown agent type: ${params.subagent_type} is not a valid agent type`
|
|
46
|
+
);
|
|
32
47
|
const session = await iife(async () => {
|
|
33
48
|
if (params.session_id) {
|
|
34
|
-
const found = await Session.get(params.session_id).catch(() => {})
|
|
35
|
-
if (found) return found
|
|
49
|
+
const found = await Session.get(params.session_id).catch(() => {});
|
|
50
|
+
if (found) return found;
|
|
36
51
|
}
|
|
37
52
|
|
|
38
53
|
return await Session.create({
|
|
39
54
|
parentID: ctx.sessionID,
|
|
40
55
|
title: params.description + ` (@${agent.name} subagent)`,
|
|
41
|
-
})
|
|
42
|
-
})
|
|
56
|
+
});
|
|
57
|
+
});
|
|
43
58
|
// Try to get parent message for model info, but use defaults if not available
|
|
44
|
-
let parentModel: { modelID: string; providerID: string } | undefined
|
|
59
|
+
let parentModel: { modelID: string; providerID: string } | undefined;
|
|
45
60
|
try {
|
|
46
|
-
const msg = await MessageV2.get({
|
|
47
|
-
|
|
61
|
+
const msg = await MessageV2.get({
|
|
62
|
+
sessionID: ctx.sessionID,
|
|
63
|
+
messageID: ctx.messageID,
|
|
64
|
+
});
|
|
65
|
+
if (msg.info.role === 'assistant') {
|
|
48
66
|
parentModel = {
|
|
49
67
|
modelID: msg.info.modelID,
|
|
50
68
|
providerID: msg.info.providerID,
|
|
51
|
-
}
|
|
69
|
+
};
|
|
52
70
|
}
|
|
53
71
|
} catch (e) {
|
|
54
72
|
// Parent message not in storage, will use agent model or default
|
|
@@ -59,35 +77,38 @@ export const TaskTool = Tool.define("task", async () => {
|
|
|
59
77
|
metadata: {
|
|
60
78
|
sessionId: session.id,
|
|
61
79
|
},
|
|
62
|
-
})
|
|
80
|
+
});
|
|
63
81
|
|
|
64
|
-
const messageID = Identifier.ascending(
|
|
65
|
-
const parts: Record<string, MessageV2.ToolPart> = {}
|
|
82
|
+
const messageID = Identifier.ascending('message');
|
|
83
|
+
const parts: Record<string, MessageV2.ToolPart> = {};
|
|
66
84
|
const unsub = Bus.subscribe(MessageV2.Event.PartUpdated, async (evt) => {
|
|
67
|
-
if (evt.properties.part.sessionID !== session.id) return
|
|
68
|
-
if (evt.properties.part.messageID === messageID) return
|
|
69
|
-
if (evt.properties.part.type !==
|
|
70
|
-
parts[evt.properties.part.id] = evt.properties.part
|
|
85
|
+
if (evt.properties.part.sessionID !== session.id) return;
|
|
86
|
+
if (evt.properties.part.messageID === messageID) return;
|
|
87
|
+
if (evt.properties.part.type !== 'tool') return;
|
|
88
|
+
parts[evt.properties.part.id] = evt.properties.part;
|
|
71
89
|
ctx.metadata({
|
|
72
90
|
title: params.description,
|
|
73
91
|
metadata: {
|
|
74
|
-
summary: Object.values(parts).sort((a, b) =>
|
|
92
|
+
summary: Object.values(parts).sort((a, b) =>
|
|
93
|
+
a.id?.localeCompare(b.id)
|
|
94
|
+
),
|
|
75
95
|
sessionId: session.id,
|
|
76
96
|
},
|
|
77
|
-
})
|
|
78
|
-
})
|
|
97
|
+
});
|
|
98
|
+
});
|
|
79
99
|
|
|
80
|
-
const model = agent.model ??
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
100
|
+
const model = agent.model ??
|
|
101
|
+
parentModel ?? {
|
|
102
|
+
modelID: 'grok-code',
|
|
103
|
+
providerID: 'opencode',
|
|
104
|
+
};
|
|
84
105
|
|
|
85
106
|
function cancel() {
|
|
86
|
-
SessionPrompt.cancel(session.id)
|
|
107
|
+
SessionPrompt.cancel(session.id);
|
|
87
108
|
}
|
|
88
|
-
ctx.abort.addEventListener(
|
|
89
|
-
using _ = defer(() => ctx.abort.removeEventListener(
|
|
90
|
-
const promptParts = await SessionPrompt.resolvePromptParts(params.prompt)
|
|
109
|
+
ctx.abort.addEventListener('abort', cancel);
|
|
110
|
+
using _ = defer(() => ctx.abort.removeEventListener('abort', cancel));
|
|
111
|
+
const promptParts = await SessionPrompt.resolvePromptParts(params.prompt);
|
|
91
112
|
const result = await SessionPrompt.prompt({
|
|
92
113
|
messageID,
|
|
93
114
|
sessionID: session.id,
|
|
@@ -103,15 +124,27 @@ export const TaskTool = Tool.define("task", async () => {
|
|
|
103
124
|
...agent.tools,
|
|
104
125
|
},
|
|
105
126
|
parts: promptParts,
|
|
106
|
-
})
|
|
107
|
-
unsub()
|
|
108
|
-
let all
|
|
109
|
-
all = await Session.messages({ sessionID: session.id })
|
|
110
|
-
all = all.filter((x) => x.info.role ===
|
|
111
|
-
all = all.flatMap(
|
|
112
|
-
|
|
127
|
+
});
|
|
128
|
+
unsub();
|
|
129
|
+
let all;
|
|
130
|
+
all = await Session.messages({ sessionID: session.id });
|
|
131
|
+
all = all.filter((x) => x.info.role === 'assistant');
|
|
132
|
+
all = all.flatMap(
|
|
133
|
+
(msg) =>
|
|
134
|
+
msg.parts.filter(
|
|
135
|
+
(x: any) => x.type === 'tool'
|
|
136
|
+
) as MessageV2.ToolPart[]
|
|
137
|
+
);
|
|
138
|
+
const text = result.parts.findLast((x) => x.type === 'text')?.text ?? '';
|
|
113
139
|
|
|
114
|
-
const output =
|
|
140
|
+
const output =
|
|
141
|
+
text +
|
|
142
|
+
'\n\n' +
|
|
143
|
+
[
|
|
144
|
+
'<task_metadata>',
|
|
145
|
+
`session_id: ${session.id}`,
|
|
146
|
+
'</task_metadata>',
|
|
147
|
+
].join('\n');
|
|
115
148
|
|
|
116
149
|
return {
|
|
117
150
|
title: params.description,
|
|
@@ -120,7 +153,7 @@ export const TaskTool = Tool.define("task", async () => {
|
|
|
120
153
|
sessionId: session.id,
|
|
121
154
|
},
|
|
122
155
|
output,
|
|
123
|
-
}
|
|
156
|
+
};
|
|
124
157
|
},
|
|
125
|
-
}
|
|
126
|
-
})
|
|
158
|
+
};
|
|
159
|
+
});
|
package/src/tool/todo.ts
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import z from
|
|
2
|
-
import { Tool } from
|
|
3
|
-
import DESCRIPTION_WRITE from
|
|
4
|
-
import { Todo } from
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import { Tool } from './tool';
|
|
3
|
+
import DESCRIPTION_WRITE from './todowrite.txt';
|
|
4
|
+
import { Todo } from '../session/todo';
|
|
5
5
|
|
|
6
|
-
export const TodoWriteTool = Tool.define(
|
|
6
|
+
export const TodoWriteTool = Tool.define('todowrite', {
|
|
7
7
|
description: DESCRIPTION_WRITE,
|
|
8
8
|
parameters: z.object({
|
|
9
|
-
todos: z.array(z.object(Todo.Info.shape)).describe(
|
|
9
|
+
todos: z.array(z.object(Todo.Info.shape)).describe('The updated todo list'),
|
|
10
10
|
}),
|
|
11
11
|
async execute(params, opts) {
|
|
12
12
|
await Todo.update({
|
|
13
13
|
sessionID: opts.sessionID,
|
|
14
14
|
todos: params.todos,
|
|
15
|
-
})
|
|
15
|
+
});
|
|
16
16
|
return {
|
|
17
|
-
title: `${params.todos.filter((x) => x.status !==
|
|
17
|
+
title: `${params.todos.filter((x) => x.status !== 'completed').length} todos`,
|
|
18
18
|
output: JSON.stringify(params.todos, null, 2),
|
|
19
19
|
metadata: {
|
|
20
20
|
todos: params.todos,
|
|
21
21
|
},
|
|
22
|
-
}
|
|
22
|
+
};
|
|
23
23
|
},
|
|
24
|
-
})
|
|
24
|
+
});
|
|
25
25
|
|
|
26
|
-
export const TodoReadTool = Tool.define(
|
|
27
|
-
description:
|
|
26
|
+
export const TodoReadTool = Tool.define('todoread', {
|
|
27
|
+
description: 'Use this tool to read your todo list',
|
|
28
28
|
parameters: z.object({}),
|
|
29
29
|
async execute(_params, opts) {
|
|
30
|
-
const todos = await Todo.get(opts.sessionID)
|
|
30
|
+
const todos = await Todo.get(opts.sessionID);
|
|
31
31
|
return {
|
|
32
|
-
title: `${todos.filter((x) => x.status !==
|
|
32
|
+
title: `${todos.filter((x) => x.status !== 'completed').length} todos`,
|
|
33
33
|
metadata: {
|
|
34
34
|
todos,
|
|
35
35
|
},
|
|
36
36
|
output: JSON.stringify(todos, null, 2),
|
|
37
|
-
}
|
|
37
|
+
};
|
|
38
38
|
},
|
|
39
|
-
})
|
|
39
|
+
});
|
package/src/tool/tool.ts
CHANGED
|
@@ -1,66 +1,75 @@
|
|
|
1
|
-
import z from
|
|
2
|
-
import type { MessageV2 } from
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import type { MessageV2 } from '../session/message-v2';
|
|
3
3
|
|
|
4
4
|
export namespace Tool {
|
|
5
5
|
interface Metadata {
|
|
6
|
-
[key: string]: any
|
|
6
|
+
[key: string]: any;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export type Context<M extends Metadata = Metadata> = {
|
|
10
|
-
sessionID: string
|
|
11
|
-
messageID: string
|
|
12
|
-
agent: string
|
|
13
|
-
abort: AbortSignal
|
|
14
|
-
callID?: string
|
|
15
|
-
extra?: { [key: string]: any }
|
|
16
|
-
metadata(input: { title?: string; metadata?: M }): void
|
|
17
|
-
}
|
|
18
|
-
export interface Info<
|
|
19
|
-
|
|
10
|
+
sessionID: string;
|
|
11
|
+
messageID: string;
|
|
12
|
+
agent: string;
|
|
13
|
+
abort: AbortSignal;
|
|
14
|
+
callID?: string;
|
|
15
|
+
extra?: { [key: string]: any };
|
|
16
|
+
metadata(input: { title?: string; metadata?: M }): void;
|
|
17
|
+
};
|
|
18
|
+
export interface Info<
|
|
19
|
+
Parameters extends z.ZodType = z.ZodType,
|
|
20
|
+
M extends Metadata = Metadata,
|
|
21
|
+
> {
|
|
22
|
+
id: string;
|
|
20
23
|
init: () => Promise<{
|
|
21
|
-
description: string
|
|
22
|
-
parameters: Parameters
|
|
24
|
+
description: string;
|
|
25
|
+
parameters: Parameters;
|
|
23
26
|
execute(
|
|
24
27
|
args: z.infer<Parameters>,
|
|
25
|
-
ctx: Context
|
|
28
|
+
ctx: Context
|
|
26
29
|
): Promise<{
|
|
27
|
-
title: string
|
|
28
|
-
metadata: M
|
|
29
|
-
output: string
|
|
30
|
-
attachments?: MessageV2.FilePart[]
|
|
31
|
-
}
|
|
32
|
-
formatValidationError?(error: z.ZodError): string
|
|
33
|
-
}
|
|
30
|
+
title: string;
|
|
31
|
+
metadata: M;
|
|
32
|
+
output: string;
|
|
33
|
+
attachments?: MessageV2.FilePart[];
|
|
34
|
+
}>;
|
|
35
|
+
formatValidationError?(error: z.ZodError): string;
|
|
36
|
+
}>;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
|
-
export type InferParameters<T extends Info> =
|
|
37
|
-
|
|
39
|
+
export type InferParameters<T extends Info> =
|
|
40
|
+
T extends Info<infer P> ? z.infer<P> : never;
|
|
41
|
+
export type InferMetadata<T extends Info> =
|
|
42
|
+
T extends Info<any, infer M> ? M : never;
|
|
38
43
|
|
|
39
44
|
export function define<Parameters extends z.ZodType, Result extends Metadata>(
|
|
40
45
|
id: string,
|
|
41
|
-
init:
|
|
46
|
+
init:
|
|
47
|
+
| Info<Parameters, Result>['init']
|
|
48
|
+
| Awaited<ReturnType<Info<Parameters, Result>['init']>>
|
|
42
49
|
): Info<Parameters, Result> {
|
|
43
50
|
return {
|
|
44
51
|
id,
|
|
45
52
|
init: async () => {
|
|
46
|
-
const toolInfo = init instanceof Function ? await init() : init
|
|
47
|
-
const execute = toolInfo.execute
|
|
53
|
+
const toolInfo = init instanceof Function ? await init() : init;
|
|
54
|
+
const execute = toolInfo.execute;
|
|
48
55
|
toolInfo.execute = (args, ctx) => {
|
|
49
56
|
try {
|
|
50
|
-
toolInfo.parameters.parse(args)
|
|
57
|
+
toolInfo.parameters.parse(args);
|
|
51
58
|
} catch (error) {
|
|
52
59
|
if (error instanceof z.ZodError && toolInfo.formatValidationError) {
|
|
53
|
-
throw new Error(toolInfo.formatValidationError(error), {
|
|
60
|
+
throw new Error(toolInfo.formatValidationError(error), {
|
|
61
|
+
cause: error,
|
|
62
|
+
});
|
|
54
63
|
}
|
|
55
64
|
throw new Error(
|
|
56
65
|
`The ${id} tool was called with invalid arguments: ${error}.\nPlease rewrite the input so it satisfies the expected schema.`,
|
|
57
|
-
{ cause: error }
|
|
58
|
-
)
|
|
66
|
+
{ cause: error }
|
|
67
|
+
);
|
|
59
68
|
}
|
|
60
|
-
return execute(args, ctx)
|
|
61
|
-
}
|
|
62
|
-
return toolInfo
|
|
69
|
+
return execute(args, ctx);
|
|
70
|
+
};
|
|
71
|
+
return toolInfo;
|
|
63
72
|
},
|
|
64
|
-
}
|
|
73
|
+
};
|
|
65
74
|
}
|
|
66
75
|
}
|