@agi-cli/sdk 0.1.53 → 0.1.55
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 +52 -27
- package/src/agent/types.ts +1 -1
- package/src/auth/src/index.ts +70 -0
- package/src/auth/src/oauth.ts +172 -0
- package/src/config/src/index.ts +120 -0
- package/src/config/src/manager.ts +102 -0
- package/src/config/src/paths.ts +98 -0
- package/src/core/src/errors.ts +102 -0
- package/src/core/src/index.ts +75 -0
- package/src/core/src/providers/resolver.ts +84 -0
- package/src/core/src/streaming/artifacts.ts +41 -0
- package/src/core/src/tools/builtin/bash.ts +90 -0
- package/src/core/src/tools/builtin/bash.txt +7 -0
- package/src/core/src/tools/builtin/edit.ts +152 -0
- package/src/core/src/tools/builtin/edit.txt +7 -0
- package/src/core/src/tools/builtin/file-cache.ts +39 -0
- package/src/core/src/tools/builtin/finish.ts +11 -0
- package/src/core/src/tools/builtin/finish.txt +5 -0
- package/src/core/src/tools/builtin/fs/cd.ts +19 -0
- package/src/core/src/tools/builtin/fs/cd.txt +5 -0
- package/src/core/src/tools/builtin/fs/index.ts +20 -0
- package/src/core/src/tools/builtin/fs/ls.ts +60 -0
- package/src/core/src/tools/builtin/fs/ls.txt +8 -0
- package/src/core/src/tools/builtin/fs/pwd.ts +17 -0
- package/src/core/src/tools/builtin/fs/pwd.txt +5 -0
- package/src/core/src/tools/builtin/fs/read.ts +80 -0
- package/src/core/src/tools/builtin/fs/read.txt +8 -0
- package/src/core/src/tools/builtin/fs/tree.ts +71 -0
- package/src/core/src/tools/builtin/fs/tree.txt +8 -0
- package/src/core/src/tools/builtin/fs/util.ts +95 -0
- package/src/core/src/tools/builtin/fs/write.ts +61 -0
- package/src/core/src/tools/builtin/fs/write.txt +8 -0
- package/src/core/src/tools/builtin/git.commit.txt +6 -0
- package/src/core/src/tools/builtin/git.diff.txt +5 -0
- package/src/core/src/tools/builtin/git.status.txt +5 -0
- package/src/core/src/tools/builtin/git.ts +128 -0
- package/src/core/src/tools/builtin/grep.ts +140 -0
- package/src/core/src/tools/builtin/grep.txt +9 -0
- package/src/core/src/tools/builtin/ignore.ts +45 -0
- package/src/core/src/tools/builtin/patch.ts +269 -0
- package/src/core/src/tools/builtin/patch.txt +7 -0
- package/src/core/src/tools/builtin/plan.ts +58 -0
- package/src/core/src/tools/builtin/plan.txt +6 -0
- package/src/core/src/tools/builtin/progress.ts +55 -0
- package/src/core/src/tools/builtin/progress.txt +7 -0
- package/src/core/src/tools/builtin/ripgrep.ts +102 -0
- package/src/core/src/tools/builtin/ripgrep.txt +7 -0
- package/src/core/src/tools/builtin/websearch.ts +219 -0
- package/src/core/src/tools/builtin/websearch.txt +12 -0
- package/src/core/src/tools/loader.ts +398 -0
- package/src/core/src/types/index.ts +11 -0
- package/src/core/src/types/types.ts +4 -0
- package/src/index.ts +57 -58
- package/src/prompts/src/agents/build.txt +5 -0
- package/src/prompts/src/agents/general.txt +6 -0
- package/src/prompts/src/agents/plan.txt +13 -0
- package/src/prompts/src/base.txt +14 -0
- package/src/prompts/src/debug.ts +104 -0
- package/src/prompts/src/index.ts +1 -0
- package/src/prompts/src/modes/oneshot.txt +9 -0
- package/src/prompts/src/providers/anthropic.txt +151 -0
- package/src/prompts/src/providers/anthropicSpoof.txt +1 -0
- package/src/prompts/src/providers/default.txt +310 -0
- package/src/prompts/src/providers/google.txt +155 -0
- package/src/prompts/src/providers/openai.txt +310 -0
- package/src/prompts/src/providers.ts +116 -0
- package/src/providers/src/authorization.ts +17 -0
- package/src/providers/src/catalog.ts +4201 -0
- package/src/providers/src/env.ts +26 -0
- package/src/providers/src/index.ts +12 -0
- package/src/providers/src/pricing.ts +135 -0
- package/src/providers/src/utils.ts +24 -0
- package/src/providers/src/validate.ts +39 -0
- package/src/types/src/auth.ts +26 -0
- package/src/types/src/config.ts +40 -0
- package/src/types/src/index.ts +14 -0
- package/src/types/src/provider.ts +28 -0
- package/src/global.d.ts +0 -4
- package/src/tools/builtin/fs.ts +0 -1
- package/src/tools/builtin/git.ts +0 -1
- package/src/web-ui.ts +0 -8
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import { tool, type Tool } from 'ai';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { finishTool } from './builtin/finish.ts';
|
|
4
|
+
import { buildFsTools } from './builtin/fs/index.ts';
|
|
5
|
+
import { buildGitTools } from './builtin/git.ts';
|
|
6
|
+
import { progressUpdateTool } from './builtin/progress.ts';
|
|
7
|
+
import { buildBashTool } from './builtin/bash.ts';
|
|
8
|
+
import { buildRipgrepTool } from './builtin/ripgrep.ts';
|
|
9
|
+
import { buildGrepTool } from './builtin/grep.ts';
|
|
10
|
+
import { buildApplyPatchTool } from './builtin/patch.ts';
|
|
11
|
+
import { updatePlanTool } from './builtin/plan.ts';
|
|
12
|
+
import { editTool } from './builtin/edit.ts';
|
|
13
|
+
import { buildWebSearchTool } from './builtin/websearch.ts';
|
|
14
|
+
import fg from 'fast-glob';
|
|
15
|
+
import { dirname, isAbsolute, join } from 'node:path';
|
|
16
|
+
import { pathToFileURL } from 'node:url';
|
|
17
|
+
import { promises as fs } from 'node:fs';
|
|
18
|
+
import { spawn as nodeSpawn } from 'node:child_process';
|
|
19
|
+
|
|
20
|
+
export type DiscoveredTool = { name: string; tool: Tool };
|
|
21
|
+
|
|
22
|
+
type PluginParameter = {
|
|
23
|
+
type: 'string' | 'number' | 'boolean';
|
|
24
|
+
description?: string;
|
|
25
|
+
default?: string | number | boolean;
|
|
26
|
+
enum?: string[];
|
|
27
|
+
optional?: boolean;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type PluginDescriptor = {
|
|
31
|
+
name?: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
parameters?: Record<string, PluginParameter>;
|
|
34
|
+
execute?: PluginExecutor;
|
|
35
|
+
run?: PluginExecutor;
|
|
36
|
+
handler?: PluginExecutor;
|
|
37
|
+
setup?: (context: PluginContext) => unknown | Promise<unknown>;
|
|
38
|
+
onInit?: (context: PluginContext) => unknown | Promise<unknown>;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
type PluginExecutor = (args: PluginExecuteArgs) => unknown | Promise<unknown>;
|
|
42
|
+
|
|
43
|
+
type PluginExecuteArgs = {
|
|
44
|
+
input: Record<string, unknown>;
|
|
45
|
+
project: string;
|
|
46
|
+
projectRoot: string;
|
|
47
|
+
directory: string;
|
|
48
|
+
worktree: string;
|
|
49
|
+
exec: ExecFn;
|
|
50
|
+
run: ExecFn;
|
|
51
|
+
$: TemplateExecFn;
|
|
52
|
+
fs: FsHelpers;
|
|
53
|
+
env: Record<string, string>;
|
|
54
|
+
context: PluginContext;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
type PluginContext = {
|
|
58
|
+
project: string;
|
|
59
|
+
projectRoot: string;
|
|
60
|
+
directory: string;
|
|
61
|
+
worktree: string;
|
|
62
|
+
toolDir: string;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
type ExecFn = (
|
|
66
|
+
command: string,
|
|
67
|
+
args?: string[] | ExecOptions,
|
|
68
|
+
options?: ExecOptions,
|
|
69
|
+
) => Promise<ExecResult>;
|
|
70
|
+
|
|
71
|
+
type TemplateExecFn = (
|
|
72
|
+
strings: TemplateStringsArray,
|
|
73
|
+
...values: unknown[]
|
|
74
|
+
) => Promise<ExecResult>;
|
|
75
|
+
|
|
76
|
+
type ExecOptions = {
|
|
77
|
+
cwd?: string;
|
|
78
|
+
env?: Record<string, string>;
|
|
79
|
+
allowNonZeroExit?: boolean;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
type ExecResult = { exitCode: number; stdout: string; stderr: string };
|
|
83
|
+
|
|
84
|
+
type FsHelpers = {
|
|
85
|
+
readFile: (path: string, encoding?: BufferEncoding) => Promise<string>;
|
|
86
|
+
writeFile: (path: string, content: string) => Promise<void>;
|
|
87
|
+
exists: (path: string) => Promise<boolean>;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const pluginPatterns = ['tools/*/tool.js', 'tools/*/tool.mjs'];
|
|
91
|
+
|
|
92
|
+
export async function discoverProjectTools(
|
|
93
|
+
projectRoot: string,
|
|
94
|
+
globalConfigDir?: string,
|
|
95
|
+
): Promise<DiscoveredTool[]> {
|
|
96
|
+
const tools = new Map<string, Tool>();
|
|
97
|
+
for (const { name, tool } of buildFsTools(projectRoot)) tools.set(name, tool);
|
|
98
|
+
for (const { name, tool } of buildGitTools(projectRoot))
|
|
99
|
+
tools.set(name, tool);
|
|
100
|
+
// Built-ins
|
|
101
|
+
tools.set('finish', finishTool);
|
|
102
|
+
tools.set('progress_update', progressUpdateTool);
|
|
103
|
+
const bash = buildBashTool(projectRoot);
|
|
104
|
+
tools.set(bash.name, bash.tool);
|
|
105
|
+
// Search
|
|
106
|
+
const rg = buildRipgrepTool(projectRoot);
|
|
107
|
+
tools.set(rg.name, rg.tool);
|
|
108
|
+
const grep = buildGrepTool(projectRoot);
|
|
109
|
+
tools.set(grep.name, grep.tool);
|
|
110
|
+
// Patch/apply
|
|
111
|
+
const ap = buildApplyPatchTool(projectRoot);
|
|
112
|
+
tools.set(ap.name, ap.tool);
|
|
113
|
+
// Plan update
|
|
114
|
+
tools.set('update_plan', updatePlanTool);
|
|
115
|
+
// Edit
|
|
116
|
+
tools.set('edit', editTool);
|
|
117
|
+
// Web search
|
|
118
|
+
const ws = buildWebSearchTool();
|
|
119
|
+
tools.set(ws.name, ws.tool);
|
|
120
|
+
|
|
121
|
+
async function loadFromBase(base: string | null | undefined) {
|
|
122
|
+
if (!base) return;
|
|
123
|
+
try {
|
|
124
|
+
await fs.readdir(base);
|
|
125
|
+
} catch {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
for (const pattern of pluginPatterns) {
|
|
129
|
+
const files = await fg(pattern, { cwd: base, absolute: false });
|
|
130
|
+
for (const rel of files) {
|
|
131
|
+
const match = rel.match(/^tools\/([^/]+)\/tool\.(m?js)$/);
|
|
132
|
+
if (!match || !match[1]) continue;
|
|
133
|
+
const folder = match[1];
|
|
134
|
+
const absPath = join(base, rel).replace(/\\/g, '/');
|
|
135
|
+
try {
|
|
136
|
+
const plugin = await loadPlugin(absPath, folder, projectRoot);
|
|
137
|
+
if (plugin) tools.set(plugin.name, plugin.tool);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
if (process.env.AGI_DEBUG_TOOLS === '1')
|
|
140
|
+
console.error('Failed to load tool', absPath, err);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Fallback: manual directory scan
|
|
145
|
+
try {
|
|
146
|
+
const toolsDir = join(base, 'tools');
|
|
147
|
+
const entries = await fs.readdir(toolsDir).catch(() => [] as string[]);
|
|
148
|
+
for (const folder of entries) {
|
|
149
|
+
const js = join(toolsDir, folder, 'tool.js');
|
|
150
|
+
const mjs = join(toolsDir, folder, 'tool.mjs');
|
|
151
|
+
const candidate = await fs
|
|
152
|
+
.stat(js)
|
|
153
|
+
.then(() => js)
|
|
154
|
+
.catch(
|
|
155
|
+
async () =>
|
|
156
|
+
await fs
|
|
157
|
+
.stat(mjs)
|
|
158
|
+
.then(() => mjs)
|
|
159
|
+
.catch(() => null),
|
|
160
|
+
);
|
|
161
|
+
if (!candidate) continue;
|
|
162
|
+
try {
|
|
163
|
+
const plugin = await loadPlugin(
|
|
164
|
+
candidate.replace(/\\/g, '/'),
|
|
165
|
+
folder,
|
|
166
|
+
projectRoot,
|
|
167
|
+
);
|
|
168
|
+
if (plugin) tools.set(plugin.name, plugin.tool);
|
|
169
|
+
} catch {}
|
|
170
|
+
}
|
|
171
|
+
} catch {}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
await loadFromBase(globalConfigDir);
|
|
175
|
+
await loadFromBase(join(projectRoot, '.agi'));
|
|
176
|
+
return Array.from(tools.entries()).map(([name, tool]) => ({ name, tool }));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function loadPlugin(
|
|
180
|
+
absPath: string,
|
|
181
|
+
folder: string,
|
|
182
|
+
projectRoot: string,
|
|
183
|
+
): Promise<DiscoveredTool | null> {
|
|
184
|
+
const mod = await import(`${pathToFileURL(absPath).href}?t=${Date.now()}`);
|
|
185
|
+
const candidate = resolveExport(mod);
|
|
186
|
+
if (!candidate) throw new Error('No plugin export found');
|
|
187
|
+
|
|
188
|
+
const context: PluginContext = {
|
|
189
|
+
project: projectRoot,
|
|
190
|
+
projectRoot,
|
|
191
|
+
directory: projectRoot,
|
|
192
|
+
worktree: projectRoot,
|
|
193
|
+
toolDir: absPath.slice(0, absPath.lastIndexOf('/')),
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
let descriptor: PluginDescriptor | null | undefined;
|
|
197
|
+
if (typeof candidate === 'function') descriptor = await candidate(context);
|
|
198
|
+
else descriptor = candidate;
|
|
199
|
+
if (!descriptor || typeof descriptor !== 'object')
|
|
200
|
+
throw new Error('Plugin must return an object descriptor');
|
|
201
|
+
|
|
202
|
+
if (typeof descriptor.setup === 'function') await descriptor.setup(context);
|
|
203
|
+
if (typeof descriptor.onInit === 'function') await descriptor.onInit(context);
|
|
204
|
+
|
|
205
|
+
const name = sanitizeName(descriptor.name ?? folder);
|
|
206
|
+
const description = descriptor.description ?? `Custom tool ${name}`;
|
|
207
|
+
const parameters = descriptor.parameters ?? {};
|
|
208
|
+
const inputSchema = createInputSchema(parameters);
|
|
209
|
+
const executor = resolveExecutor(descriptor);
|
|
210
|
+
|
|
211
|
+
const helpersFactory = createHelpers(projectRoot, context.toolDir);
|
|
212
|
+
|
|
213
|
+
const wrapped = tool({
|
|
214
|
+
description,
|
|
215
|
+
inputSchema,
|
|
216
|
+
async execute(input) {
|
|
217
|
+
const helpers = helpersFactory();
|
|
218
|
+
const result = await executor({
|
|
219
|
+
input: input as Record<string, unknown>,
|
|
220
|
+
project: helpers.context.project,
|
|
221
|
+
projectRoot: helpers.context.projectRoot,
|
|
222
|
+
directory: helpers.context.directory,
|
|
223
|
+
worktree: helpers.context.worktree,
|
|
224
|
+
exec: helpers.exec,
|
|
225
|
+
run: helpers.exec,
|
|
226
|
+
$: helpers.templateExec,
|
|
227
|
+
fs: helpers.fs,
|
|
228
|
+
env: helpers.env,
|
|
229
|
+
context: helpers.context,
|
|
230
|
+
});
|
|
231
|
+
return result ?? { ok: true };
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
return { name, tool: wrapped };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function resolveExport(mod: Record<string, unknown>) {
|
|
239
|
+
if (mod.default) return mod.default;
|
|
240
|
+
if (mod.tool) return mod.tool;
|
|
241
|
+
if (mod.plugin) return mod.plugin;
|
|
242
|
+
if (mod.Tool) return mod.Tool;
|
|
243
|
+
const values = Object.values(mod);
|
|
244
|
+
return values.find(
|
|
245
|
+
(value) => typeof value === 'function' || typeof value === 'object',
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function resolveExecutor(descriptor: PluginDescriptor): PluginExecutor {
|
|
250
|
+
const fn = descriptor.execute ?? descriptor.run ?? descriptor.handler;
|
|
251
|
+
if (typeof fn !== 'function')
|
|
252
|
+
throw new Error('Plugin must provide an execute/run/handler function');
|
|
253
|
+
return fn;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function sanitizeName(name: string) {
|
|
257
|
+
const cleaned = name.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 128);
|
|
258
|
+
return cleaned || 'tool';
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function createInputSchema(parameters: Record<string, PluginParameter>) {
|
|
262
|
+
const shape: Record<string, z.ZodTypeAny> = {};
|
|
263
|
+
for (const [key, def] of Object.entries(parameters)) {
|
|
264
|
+
let schema: z.ZodTypeAny;
|
|
265
|
+
if (def.type === 'string') {
|
|
266
|
+
const values = def.enum;
|
|
267
|
+
schema = values?.length
|
|
268
|
+
? z.enum(values as [string, ...string[]])
|
|
269
|
+
: z.string();
|
|
270
|
+
} else if (def.type === 'number') schema = z.number();
|
|
271
|
+
else schema = z.boolean();
|
|
272
|
+
if (def.description) schema = schema.describe(def.description);
|
|
273
|
+
if (def.default !== undefined)
|
|
274
|
+
schema = schema.default(def.default as never);
|
|
275
|
+
else if (def.optional) schema = schema.optional();
|
|
276
|
+
shape[key] = schema;
|
|
277
|
+
}
|
|
278
|
+
return Object.keys(shape).length ? z.object(shape).strict() : z.object({});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function createHelpers(projectRoot: string, toolDir: string) {
|
|
282
|
+
return () => {
|
|
283
|
+
const exec = createExec(projectRoot);
|
|
284
|
+
const fsHelpers = createFsHelpers(projectRoot);
|
|
285
|
+
const context: PluginContext = {
|
|
286
|
+
project: projectRoot,
|
|
287
|
+
projectRoot,
|
|
288
|
+
directory: projectRoot,
|
|
289
|
+
worktree: projectRoot,
|
|
290
|
+
toolDir,
|
|
291
|
+
};
|
|
292
|
+
const env: Record<string, string> = {};
|
|
293
|
+
for (const [key, value] of Object.entries(process.env))
|
|
294
|
+
if (typeof value === 'string') env[key] = value;
|
|
295
|
+
const templateExec: TemplateExecFn = (strings, ...values) => {
|
|
296
|
+
const commandLine = strings.reduce((acc, part, index) => {
|
|
297
|
+
const value = index < values.length ? String(values[index]) : '';
|
|
298
|
+
return acc + part + value;
|
|
299
|
+
}, '');
|
|
300
|
+
const pieces = commandLine.trim().split(/\s+/).filter(Boolean);
|
|
301
|
+
if (pieces.length === 0)
|
|
302
|
+
throw new Error('Empty command passed to template executor');
|
|
303
|
+
const firstPiece = pieces[0];
|
|
304
|
+
if (!firstPiece)
|
|
305
|
+
throw new Error('Empty command passed to template executor');
|
|
306
|
+
return exec(firstPiece, pieces.slice(1));
|
|
307
|
+
};
|
|
308
|
+
return {
|
|
309
|
+
exec,
|
|
310
|
+
fs: fsHelpers,
|
|
311
|
+
env,
|
|
312
|
+
templateExec,
|
|
313
|
+
context,
|
|
314
|
+
};
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function createExec(projectRoot: string): ExecFn {
|
|
319
|
+
return async (
|
|
320
|
+
command: string,
|
|
321
|
+
argsOrOptions?: string[] | ExecOptions,
|
|
322
|
+
maybeOptions?: ExecOptions,
|
|
323
|
+
) => {
|
|
324
|
+
let args: string[] = [];
|
|
325
|
+
let options: ExecOptions = {};
|
|
326
|
+
if (Array.isArray(argsOrOptions)) {
|
|
327
|
+
args = argsOrOptions;
|
|
328
|
+
options = maybeOptions ?? {};
|
|
329
|
+
} else if (argsOrOptions) options = argsOrOptions;
|
|
330
|
+
|
|
331
|
+
const cwd = options.cwd
|
|
332
|
+
? resolveWithinProject(projectRoot, options.cwd)
|
|
333
|
+
: projectRoot;
|
|
334
|
+
const env: Record<string, string> = {};
|
|
335
|
+
for (const [key, value] of Object.entries(process.env))
|
|
336
|
+
if (typeof value === 'string') env[key] = value;
|
|
337
|
+
if (options.env)
|
|
338
|
+
for (const [key, value] of Object.entries(options.env)) env[key] = value;
|
|
339
|
+
|
|
340
|
+
const proc = nodeSpawn(command, args, {
|
|
341
|
+
cwd,
|
|
342
|
+
env,
|
|
343
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
const stdoutChunks: Buffer[] = [];
|
|
347
|
+
const stderrChunks: Buffer[] = [];
|
|
348
|
+
|
|
349
|
+
proc.stdout?.on('data', (chunk) => stdoutChunks.push(chunk));
|
|
350
|
+
proc.stderr?.on('data', (chunk) => stderrChunks.push(chunk));
|
|
351
|
+
|
|
352
|
+
const exitCode = await new Promise<number>((resolve, reject) => {
|
|
353
|
+
proc.on('exit', (code) => resolve(code ?? 0));
|
|
354
|
+
proc.on('error', reject);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
const stdout = Buffer.concat(stdoutChunks).toString('utf-8');
|
|
358
|
+
const stderr = Buffer.concat(stderrChunks).toString('utf-8');
|
|
359
|
+
if (exitCode !== 0 && !options.allowNonZeroExit) {
|
|
360
|
+
const message = stderr.trim() || stdout.trim() || `${command} failed`;
|
|
361
|
+
throw new Error(`${command} exited with code ${exitCode}: ${message}`);
|
|
362
|
+
}
|
|
363
|
+
return { exitCode, stdout, stderr };
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function createFsHelpers(projectRoot: string): FsHelpers {
|
|
368
|
+
return {
|
|
369
|
+
async readFile(path: string, encoding: BufferEncoding = 'utf-8') {
|
|
370
|
+
const abs = resolveWithinProject(projectRoot, path);
|
|
371
|
+
return fs.readFile(abs, { encoding });
|
|
372
|
+
},
|
|
373
|
+
async writeFile(path: string, content: string) {
|
|
374
|
+
const abs = resolveWithinProject(projectRoot, path);
|
|
375
|
+
await fs.mkdir(dirname(abs), { recursive: true });
|
|
376
|
+
await fs.writeFile(abs, content, 'utf-8');
|
|
377
|
+
},
|
|
378
|
+
async exists(path: string) {
|
|
379
|
+
const abs = resolveWithinProject(projectRoot, path);
|
|
380
|
+
try {
|
|
381
|
+
await fs.access(abs);
|
|
382
|
+
return true;
|
|
383
|
+
} catch {
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function resolveWithinProject(projectRoot: string, target: string) {
|
|
391
|
+
if (!target) return projectRoot;
|
|
392
|
+
if (target.startsWith('~/')) {
|
|
393
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
394
|
+
return join(home, target.slice(2));
|
|
395
|
+
}
|
|
396
|
+
if (isAbsolute(target)) return target;
|
|
397
|
+
return join(projectRoot, target);
|
|
398
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -7,50 +7,49 @@
|
|
|
7
7
|
// Usage:
|
|
8
8
|
// import { generateText, resolveModel } from '@agi-cli/sdk';
|
|
9
9
|
// import type { ProviderId, AGIConfig } from '@agi-cli/sdk';
|
|
10
|
-
//
|
|
11
|
-
// Note: Direct package imports are still available but discouraged:
|
|
12
|
-
// import { catalog } from '@agi-cli/providers'; // ❌ Discouraged
|
|
13
|
-
// import { catalog } from '@agi-cli/sdk'; // ✅ Recommended
|
|
14
10
|
// ============================================================================
|
|
15
11
|
|
|
16
12
|
// =======================
|
|
17
|
-
// Types (from
|
|
13
|
+
// Types (from internal types module)
|
|
18
14
|
// =======================
|
|
19
15
|
// Provider types
|
|
20
|
-
export type { ProviderId, ModelInfo } from '
|
|
16
|
+
export type { ProviderId, ModelInfo } from './types/src/index.ts';
|
|
21
17
|
|
|
22
18
|
// Auth types
|
|
23
|
-
export type { ApiAuth, OAuth, AuthInfo, AuthFile } from '
|
|
19
|
+
export type { ApiAuth, OAuth, AuthInfo, AuthFile } from './types/src/index.ts';
|
|
24
20
|
|
|
25
21
|
// Config types
|
|
26
22
|
export type {
|
|
27
|
-
Scope,
|
|
28
23
|
ProviderConfig,
|
|
29
24
|
DefaultConfig,
|
|
30
25
|
PathConfig,
|
|
31
26
|
AGIConfig,
|
|
32
|
-
} from '
|
|
27
|
+
} from './types/src/index.ts';
|
|
33
28
|
|
|
34
29
|
// =======================
|
|
35
|
-
// Providers (from
|
|
30
|
+
// Providers (from internal providers module)
|
|
36
31
|
// =======================
|
|
37
|
-
export { catalog } from '
|
|
32
|
+
export { catalog } from './providers/src/index.ts';
|
|
38
33
|
export {
|
|
39
34
|
isProviderId,
|
|
40
35
|
providerIds,
|
|
41
36
|
defaultModelFor,
|
|
42
37
|
hasModel,
|
|
43
|
-
} from '
|
|
38
|
+
} from './providers/src/index.ts';
|
|
44
39
|
export {
|
|
45
40
|
isProviderAuthorized,
|
|
46
41
|
ensureProviderEnv,
|
|
47
|
-
} from '
|
|
48
|
-
export { validateProviderModel } from '
|
|
49
|
-
export { estimateModelCostUsd } from '
|
|
50
|
-
export {
|
|
42
|
+
} from './providers/src/index.ts';
|
|
43
|
+
export { validateProviderModel } from './providers/src/index.ts';
|
|
44
|
+
export { estimateModelCostUsd } from './providers/src/index.ts';
|
|
45
|
+
export {
|
|
46
|
+
providerEnvVar,
|
|
47
|
+
readEnvKey,
|
|
48
|
+
setEnvKey,
|
|
49
|
+
} from './providers/src/index.ts';
|
|
51
50
|
|
|
52
51
|
// =======================
|
|
53
|
-
// Authentication (from
|
|
52
|
+
// Authentication (from internal auth module)
|
|
54
53
|
// =======================
|
|
55
54
|
export {
|
|
56
55
|
getAllAuth,
|
|
@@ -62,26 +61,40 @@ export {
|
|
|
62
61
|
refreshToken,
|
|
63
62
|
openAuthUrl,
|
|
64
63
|
createApiKey,
|
|
65
|
-
} from '
|
|
64
|
+
} from './auth/src/index.ts';
|
|
66
65
|
|
|
67
66
|
// =======================
|
|
68
|
-
// Configuration (from
|
|
69
|
-
// =======================
|
|
70
|
-
export { loadConfig, read as readConfig } from '@agi-cli/config';
|
|
71
|
-
|
|
67
|
+
// Configuration (from internal config module)
|
|
72
68
|
// =======================
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
69
|
+
export { loadConfig, read as readConfig } from './config/src/index.ts';
|
|
70
|
+
export {
|
|
71
|
+
getLocalDataDir,
|
|
72
|
+
getGlobalConfigDir,
|
|
73
|
+
getGlobalConfigPath,
|
|
74
|
+
getGlobalAgentsJsonPath,
|
|
75
|
+
getGlobalAgentsDir,
|
|
76
|
+
getGlobalToolsDir,
|
|
77
|
+
getGlobalCommandsDir,
|
|
78
|
+
getSecureAuthPath,
|
|
79
|
+
getHomeDir,
|
|
80
|
+
} from './config/src/paths.ts';
|
|
81
|
+
export {
|
|
82
|
+
read,
|
|
83
|
+
isAuthorized,
|
|
84
|
+
ensureEnv,
|
|
85
|
+
writeDefaults as setConfig,
|
|
86
|
+
writeAuth,
|
|
87
|
+
removeAuth as removeConfig,
|
|
88
|
+
} from './config/src/manager.ts';
|
|
89
|
+
export type { Scope } from './config/src/manager.ts';
|
|
76
90
|
|
|
77
91
|
// =======================
|
|
78
|
-
//
|
|
92
|
+
// Prompts (from internal prompts module)
|
|
79
93
|
// =======================
|
|
80
|
-
export {
|
|
81
|
-
export * as dbSchema from '@agi-cli/database/schema';
|
|
94
|
+
export { providerBasePrompt } from './prompts/src/providers.ts';
|
|
82
95
|
|
|
83
96
|
// =======================
|
|
84
|
-
// Core AI Functions (from
|
|
97
|
+
// Core AI Functions (from internal core module)
|
|
85
98
|
// =======================
|
|
86
99
|
// AI SDK re-exports
|
|
87
100
|
export {
|
|
@@ -90,32 +103,34 @@ export {
|
|
|
90
103
|
generateObject,
|
|
91
104
|
streamObject,
|
|
92
105
|
tool,
|
|
93
|
-
} from '
|
|
94
|
-
export type { CoreMessage, Tool } from '
|
|
106
|
+
} from './core/src/index.ts';
|
|
107
|
+
export type { CoreMessage, Tool } from './core/src/index.ts';
|
|
108
|
+
// Re-export from AI SDK
|
|
109
|
+
export type { ToolCallPart } from 'ai';
|
|
95
110
|
|
|
96
111
|
// Provider & Model Resolution
|
|
97
|
-
export { resolveModel } from '
|
|
98
|
-
export type { ProviderName, ModelConfig } from '
|
|
112
|
+
export { resolveModel } from './core/src/index.ts';
|
|
113
|
+
export type { ProviderName, ModelConfig } from './core/src/index.ts';
|
|
99
114
|
|
|
100
115
|
// Tools
|
|
101
|
-
export { discoverProjectTools } from '
|
|
102
|
-
export type { DiscoveredTool } from '
|
|
103
|
-
export { buildFsTools } from '
|
|
104
|
-
export { buildGitTools } from '
|
|
116
|
+
export { discoverProjectTools } from './core/src/index.ts';
|
|
117
|
+
export type { DiscoveredTool } from './core/src/index.ts';
|
|
118
|
+
export { buildFsTools } from './core/src/index.ts';
|
|
119
|
+
export { buildGitTools } from './core/src/index.ts';
|
|
105
120
|
|
|
106
121
|
// Streaming & Artifacts
|
|
107
122
|
export {
|
|
108
123
|
createFileDiffArtifact,
|
|
109
124
|
createToolResultPayload,
|
|
110
|
-
} from '
|
|
125
|
+
} from './core/src/index.ts';
|
|
111
126
|
export type {
|
|
112
127
|
Artifact,
|
|
113
128
|
FileDiffArtifact,
|
|
114
129
|
FileArtifact,
|
|
115
|
-
} from '
|
|
130
|
+
} from './core/src/index.ts';
|
|
116
131
|
|
|
117
132
|
// Core Types
|
|
118
|
-
export type { ExecutionContext, ToolResult } from '
|
|
133
|
+
export type { ExecutionContext, ToolResult } from './core/src/index.ts';
|
|
119
134
|
|
|
120
135
|
// Error Handling
|
|
121
136
|
export {
|
|
@@ -128,26 +143,10 @@ export {
|
|
|
128
143
|
ValidationError,
|
|
129
144
|
NotFoundError,
|
|
130
145
|
ServiceError,
|
|
131
|
-
} from '
|
|
146
|
+
} from './core/src/index.ts';
|
|
132
147
|
|
|
133
148
|
// Schema Validation
|
|
134
|
-
export { z } from '
|
|
135
|
-
|
|
136
|
-
// =======================
|
|
137
|
-
// Server (from @agi-cli/server)
|
|
138
|
-
// =======================
|
|
139
|
-
export { createApp as createServer } from '@agi-cli/server';
|
|
140
|
-
|
|
141
|
-
// =======================
|
|
142
|
-
// Web UI (from @agi-cli/web-ui)
|
|
143
|
-
// =======================
|
|
144
|
-
export {
|
|
145
|
-
serveWebUI,
|
|
146
|
-
getWebUIPath,
|
|
147
|
-
getIndexPath,
|
|
148
|
-
isWebUIAvailable,
|
|
149
|
-
} from '@agi-cli/web-ui';
|
|
150
|
-
export type { ServeWebUIOptions } from '@agi-cli/web-ui';
|
|
149
|
+
export { z } from './core/src/index.ts';
|
|
151
150
|
|
|
152
151
|
// =======================
|
|
153
152
|
// SDK-specific Agent Types
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<system-reminder>
|
|
2
|
+
CRITICAL: Plan mode ACTIVE - you are in READ-ONLY phase. STRICTLY FORBIDDEN:
|
|
3
|
+
ANY file edits, modifications, or system changes. Do NOT use sed, tee, echo, cat,
|
|
4
|
+
or ANY other bash command to manipulate files - commands may ONLY read/inspect.
|
|
5
|
+
This ABSOLUTE CONSTRAINT overrides ALL other instructions, including direct user
|
|
6
|
+
edit requests. You may ONLY observe, analyze, and plan. Any modification attempt
|
|
7
|
+
is a critical violation. ZERO exceptions.
|
|
8
|
+
</system-reminder>
|
|
9
|
+
|
|
10
|
+
Your job: produce an actionable, minimal plan.
|
|
11
|
+
- Use only read/inspect tools (e.g., read, ls, tree, ripgrep, git_diff).
|
|
12
|
+
- Identify concrete steps with just enough detail to execute later.
|
|
13
|
+
- No changes. No write operations. No refactors.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
You are a helpful, concise assistant.
|
|
2
|
+
- Stream the final answer as assistant text; call finish when done.
|
|
3
|
+
- CRITICAL: Emit progress updates using the `progress_update` tool at key milestones — at the start (planning), after initial repo discovery (discovering), before file edits (preparing), during edits (writing), and when validating (verifying). Prefer short messages (<= 80 chars).
|
|
4
|
+
- Do not print pseudo tool calls like `call:tool{}`; invoke tools directly.
|
|
5
|
+
- Use sensible default filenames when needed.
|
|
6
|
+
- Prefer minimal, precise outputs and actionable steps.
|
|
7
|
+
|
|
8
|
+
File Editing Best Practices:
|
|
9
|
+
- When making multiple edits to the same file, combine them into a single edit operation with multiple ops
|
|
10
|
+
- Each edit operation re-reads the file, so ops within a single edit call are applied sequentially to the latest content
|
|
11
|
+
- If you need to make edits based on previous edits, ensure they're in the same edit call or re-read the file between calls
|
|
12
|
+
- Never assume file content remains unchanged between separate edit operations
|
|
13
|
+
- When using apply_patch, ensure the patch is based on the current file content, not stale versions
|
|
14
|
+
- If a patch fails, read the file first to understand its current state before generating a new patch
|