mini-coder 0.5.14 → 0.6.0
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/README.md +25 -109
- package/bin/mc.ts +8 -11
- package/bun.lock +79 -269
- package/package.json +17 -22
- package/src/agent.ts +237 -1403
- package/src/args.ts +289 -0
- package/src/headless.ts +43 -358
- package/src/index.ts +29 -1016
- package/src/oauth.ts +117 -0
- package/src/prompt.ts +227 -284
- package/src/session.ts +55 -1306
- package/src/shared.ts +117 -38
- package/src/tool-bash.ts +110 -0
- package/src/tool-edit.ts +133 -0
- package/src/tool-task.ts +114 -0
- package/src/tui-components.ts +150 -0
- package/src/tui-conversation.ts +262 -0
- package/src/tui-editor.ts +29 -0
- package/src/tui-overlay.ts +403 -0
- package/src/tui.ts +236 -0
- package/src/types.ts +160 -0
- package/tsconfig.json +17 -0
- package/BENCHMARK.md +0 -107
- package/LICENSE +0 -9
- package/PROGRESS.md +0 -5
- package/assets/icon-1-minimal.svg +0 -31
- package/assets/icon-2-dark-terminal.svg +0 -48
- package/assets/icon-3-gradient-modern.svg +0 -45
- package/assets/icon-4-filled-bold.svg +0 -54
- package/assets/icon-5-community-badge.svg +0 -63
- package/assets/mc-claude-smart.png +0 -0
- package/assets/mc-gpt-smart.png +0 -0
- package/assets/preview-0-5-0.png +0 -0
- package/assets/preview.gif +0 -0
- package/benchmark-baseline.sh +0 -15
- package/benchmark-loop.sh +0 -19
- package/skills-lock.json +0 -15
- package/src/assistant-output.ts +0 -73
- package/src/cli.ts +0 -134
- package/src/delegation.ts +0 -238
- package/src/errors.ts +0 -15
- package/src/git.ts +0 -247
- package/src/input.ts +0 -168
- package/src/mcp.ts +0 -609
- package/src/paths.ts +0 -37
- package/src/session-message.ts +0 -385
- package/src/settings.ts +0 -449
- package/src/skills.ts +0 -271
- package/src/submit.ts +0 -376
- package/src/text.ts +0 -71
- package/src/theme.ts +0 -330
- package/src/tool-common.ts +0 -93
- package/src/tool-delegate.ts +0 -125
- package/src/tool-grep.ts +0 -606
- package/src/tool-read.ts +0 -313
- package/src/tool-shell.ts +0 -1051
- package/src/tools.ts +0 -1179
- package/src/ui/agent.ts +0 -320
- package/src/ui/commands.test.ts +0 -957
- package/src/ui/commands.ts +0 -848
- package/src/ui/conversation.test.ts +0 -585
- package/src/ui/conversation.ts +0 -1836
- package/src/ui/help.ts +0 -158
- package/src/ui/input.test.ts +0 -64
- package/src/ui/input.ts +0 -138
- package/src/ui/overlay.ts +0 -59
- package/src/ui/runtime.ts +0 -69
- package/src/ui/status.ts +0 -220
- package/src/ui.ts +0 -1190
- package/src/version.ts +0 -48
package/src/theme.ts
DELETED
|
@@ -1,330 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* UI theme definition and default colors.
|
|
3
|
-
*
|
|
4
|
-
* All UI colors are read from the active {@link Theme} object — the UI
|
|
5
|
-
* never hardcodes colors. Theme overrides are merged left-to-right.
|
|
6
|
-
*
|
|
7
|
-
* Theme values are cel-tui {@link Color} palette references. The default
|
|
8
|
-
* theme prefers ANSI 16-color palette entries so it adapts cleanly to the
|
|
9
|
-
* user's terminal theme while still allowing restrained pill styling.
|
|
10
|
-
*
|
|
11
|
-
* @module
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import type { SyntaxHighlightTheme } from "@cel-tui/components";
|
|
15
|
-
import type { Color } from "@cel-tui/types";
|
|
16
|
-
|
|
17
|
-
/** A cel-tui palette color or the terminal default when undefined. */
|
|
18
|
-
type ThemeColor = Color | undefined;
|
|
19
|
-
|
|
20
|
-
type SyntaxThemeRegistration = Exclude<SyntaxHighlightTheme, string>;
|
|
21
|
-
type SyntaxThemeTokenColor = NonNullable<
|
|
22
|
-
SyntaxThemeRegistration["tokenColors"]
|
|
23
|
-
>[number];
|
|
24
|
-
type SyntaxThemeVariant = "markdown" | "code" | "shell";
|
|
25
|
-
|
|
26
|
-
/** ANSI16 fallback hex values for syntax-highlighter theme overrides. */
|
|
27
|
-
const ANSI_COLOR_HEX: Readonly<Record<Color, string>> = {
|
|
28
|
-
color00: "#000000",
|
|
29
|
-
color01: "#cd3131",
|
|
30
|
-
color02: "#0dbc79",
|
|
31
|
-
color03: "#e5e510",
|
|
32
|
-
color04: "#2472c8",
|
|
33
|
-
color05: "#bc3fbc",
|
|
34
|
-
color06: "#11a8cd",
|
|
35
|
-
color07: "#e5e5e5",
|
|
36
|
-
color08: "#666666",
|
|
37
|
-
color09: "#f14c4c",
|
|
38
|
-
color10: "#23d18b",
|
|
39
|
-
color11: "#f5f543",
|
|
40
|
-
color12: "#3b8eea",
|
|
41
|
-
color13: "#d670d6",
|
|
42
|
-
color14: "#29b8db",
|
|
43
|
-
color15: "#ffffff",
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const syntaxThemeCache: Record<
|
|
47
|
-
SyntaxThemeVariant,
|
|
48
|
-
WeakMap<Theme, SyntaxThemeRegistration>
|
|
49
|
-
> = {
|
|
50
|
-
markdown: new WeakMap(),
|
|
51
|
-
code: new WeakMap(),
|
|
52
|
-
shell: new WeakMap(),
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
|
-
// Types
|
|
57
|
-
// ---------------------------------------------------------------------------
|
|
58
|
-
|
|
59
|
-
/** Foreground/background pair for a single status pill tone. */
|
|
60
|
-
export interface StatusTone {
|
|
61
|
-
/** Pill foreground color. */
|
|
62
|
-
fg: ThemeColor;
|
|
63
|
-
/** Pill background color. */
|
|
64
|
-
bg: ThemeColor;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Complete set of UI colors.
|
|
69
|
-
*
|
|
70
|
-
* The default theme uses terminal palette indices so it adapts to the
|
|
71
|
-
* user's terminal color scheme automatically.
|
|
72
|
-
*/
|
|
73
|
-
export interface Theme {
|
|
74
|
-
/** User message background. */
|
|
75
|
-
userMsgBg: ThemeColor;
|
|
76
|
-
/** Muted informational text, placeholders, and helper copy. */
|
|
77
|
-
mutedText: ThemeColor;
|
|
78
|
-
/** Primary accent for important labels and interactive highlights. */
|
|
79
|
-
accentText: ThemeColor;
|
|
80
|
-
/** Secondary accent for supplementary labels like git status. */
|
|
81
|
-
secondaryAccentText: ThemeColor;
|
|
82
|
-
/** Tool output left border and text. */
|
|
83
|
-
toolBorder: ThemeColor;
|
|
84
|
-
/** Tool output text. */
|
|
85
|
-
toolText: ThemeColor;
|
|
86
|
-
/** Added/replacement edit preview text. */
|
|
87
|
-
diffAdded: ThemeColor;
|
|
88
|
-
/** Removed/original edit preview text. */
|
|
89
|
-
diffRemoved: ThemeColor;
|
|
90
|
-
/** Divider line color (idle state). */
|
|
91
|
-
divider: ThemeColor;
|
|
92
|
-
/** Divider scanning pulse highlight color (active state). */
|
|
93
|
-
dividerPulse: ThemeColor;
|
|
94
|
-
/** Neutral status pill tone for the inner CWD/git pills. */
|
|
95
|
-
statusSecondary: StatusTone;
|
|
96
|
-
/** Model/effort pill tones from low/cold to xhigh/warm. */
|
|
97
|
-
statusEffortScale: readonly [StatusTone, StatusTone, StatusTone, StatusTone];
|
|
98
|
-
/** Usage/context pill tones from empty/cold to near-full/hot. */
|
|
99
|
-
statusContextScale: readonly [
|
|
100
|
-
StatusTone,
|
|
101
|
-
StatusTone,
|
|
102
|
-
StatusTone,
|
|
103
|
-
StatusTone,
|
|
104
|
-
StatusTone,
|
|
105
|
-
];
|
|
106
|
-
/** Error text. */
|
|
107
|
-
error: ThemeColor;
|
|
108
|
-
/** Overlay modal background. */
|
|
109
|
-
overlayBg: ThemeColor;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// ---------------------------------------------------------------------------
|
|
113
|
-
// Default theme
|
|
114
|
-
// ---------------------------------------------------------------------------
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* The default theme.
|
|
118
|
-
*
|
|
119
|
-
* Uses terminal palette colors so it looks reasonable across light and
|
|
120
|
-
* dark terminal themes without any configuration. The inner status pills
|
|
121
|
-
* stay neutral, while the outer pills use stepped ANSI16 tone scales so
|
|
122
|
-
* reasoning effort and context pressure move through green, cyan, purple,
|
|
123
|
-
* and red as they trend from cold/dark to warm/bright.
|
|
124
|
-
*/
|
|
125
|
-
export const DEFAULT_THEME: Theme = {
|
|
126
|
-
userMsgBg: "color08",
|
|
127
|
-
mutedText: "color08",
|
|
128
|
-
accentText: "color04",
|
|
129
|
-
secondaryAccentText: "color05",
|
|
130
|
-
toolBorder: "color08",
|
|
131
|
-
toolText: "color08",
|
|
132
|
-
diffAdded: "color02",
|
|
133
|
-
diffRemoved: "color01",
|
|
134
|
-
divider: "color08",
|
|
135
|
-
dividerPulse: "color04",
|
|
136
|
-
statusSecondary: {
|
|
137
|
-
fg: "color15",
|
|
138
|
-
bg: "color08",
|
|
139
|
-
},
|
|
140
|
-
statusEffortScale: [
|
|
141
|
-
{ fg: "color00", bg: "color02" },
|
|
142
|
-
{ fg: "color00", bg: "color06" },
|
|
143
|
-
{ fg: "color15", bg: "color05" },
|
|
144
|
-
{ fg: "color00", bg: "color09" },
|
|
145
|
-
],
|
|
146
|
-
statusContextScale: [
|
|
147
|
-
{ fg: "color00", bg: "color02" },
|
|
148
|
-
{ fg: "color00", bg: "color06" },
|
|
149
|
-
{ fg: "color15", bg: "color05" },
|
|
150
|
-
{ fg: "color15", bg: "color01" },
|
|
151
|
-
{ fg: "color00", bg: "color09" },
|
|
152
|
-
],
|
|
153
|
-
error: "color01",
|
|
154
|
-
overlayBg: "color08",
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
// ---------------------------------------------------------------------------
|
|
158
|
-
// Theme merging
|
|
159
|
-
// ---------------------------------------------------------------------------
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Merge partial theme overrides on top of a base theme.
|
|
163
|
-
*
|
|
164
|
-
* Applies overrides left-to-right — later overrides win for the same key.
|
|
165
|
-
* This is a shallow merge, so nested status tones and tone scales are
|
|
166
|
-
* replaced as whole values. Returns a new {@link Theme}; the base is not
|
|
167
|
-
* mutated.
|
|
168
|
-
*
|
|
169
|
-
* @param base - The base theme to start from.
|
|
170
|
-
* @param overrides - Partial theme objects to merge.
|
|
171
|
-
* @returns A complete {@link Theme} with all overrides applied.
|
|
172
|
-
*/
|
|
173
|
-
export function mergeThemes(
|
|
174
|
-
base: Theme,
|
|
175
|
-
...overrides: Partial<Theme>[]
|
|
176
|
-
): Theme {
|
|
177
|
-
let merged = { ...base };
|
|
178
|
-
for (const override of overrides) {
|
|
179
|
-
merged = { ...merged, ...override };
|
|
180
|
-
}
|
|
181
|
-
return merged;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function colorToHex(color: ThemeColor): string | undefined {
|
|
185
|
-
return color ? ANSI_COLOR_HEX[color] : undefined;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function pushSyntaxTokenColor(
|
|
189
|
-
tokenColors: SyntaxThemeTokenColor[],
|
|
190
|
-
scope: string | readonly string[],
|
|
191
|
-
foreground: ThemeColor,
|
|
192
|
-
fontStyle?: string,
|
|
193
|
-
): void {
|
|
194
|
-
const foregroundHex = colorToHex(foreground);
|
|
195
|
-
if (!foregroundHex && !fontStyle) {
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
tokenColors.push({
|
|
200
|
-
scope,
|
|
201
|
-
settings: {
|
|
202
|
-
...(foregroundHex ? { foreground: foregroundHex } : {}),
|
|
203
|
-
...(fontStyle ? { fontStyle } : {}),
|
|
204
|
-
},
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function pushCodeSyntaxTokenColors(
|
|
209
|
-
tokenColors: SyntaxThemeTokenColor[],
|
|
210
|
-
theme: Theme,
|
|
211
|
-
): void {
|
|
212
|
-
pushSyntaxTokenColor(
|
|
213
|
-
tokenColors,
|
|
214
|
-
["comment", "quote", "doctag", "markup.quote"],
|
|
215
|
-
theme.mutedText,
|
|
216
|
-
"italic",
|
|
217
|
-
);
|
|
218
|
-
pushSyntaxTokenColor(
|
|
219
|
-
tokenColors,
|
|
220
|
-
["keyword", "operator"],
|
|
221
|
-
theme.secondaryAccentText,
|
|
222
|
-
);
|
|
223
|
-
pushSyntaxTokenColor(
|
|
224
|
-
tokenColors,
|
|
225
|
-
["command", "function_", "function", "title"],
|
|
226
|
-
theme.accentText,
|
|
227
|
-
);
|
|
228
|
-
pushSyntaxTokenColor(
|
|
229
|
-
tokenColors,
|
|
230
|
-
["builtin", "built_in", "class_", "class", "inherited__", "type"],
|
|
231
|
-
theme.accentText,
|
|
232
|
-
);
|
|
233
|
-
pushSyntaxTokenColor(
|
|
234
|
-
tokenColors,
|
|
235
|
-
["escape", "literal", "number", "symbol"],
|
|
236
|
-
theme.secondaryAccentText ?? theme.accentText,
|
|
237
|
-
);
|
|
238
|
-
pushSyntaxTokenColor(
|
|
239
|
-
tokenColors,
|
|
240
|
-
["code", "string", "markup.code"],
|
|
241
|
-
theme.diffAdded,
|
|
242
|
-
);
|
|
243
|
-
pushSyntaxTokenColor(tokenColors, "regexp", theme.diffRemoved);
|
|
244
|
-
pushSyntaxTokenColor(
|
|
245
|
-
tokenColors,
|
|
246
|
-
["attr", "attribute", "params", "property", "selector-attr"],
|
|
247
|
-
theme.accentText,
|
|
248
|
-
);
|
|
249
|
-
pushSyntaxTokenColor(
|
|
250
|
-
tokenColors,
|
|
251
|
-
[
|
|
252
|
-
"name",
|
|
253
|
-
"tag",
|
|
254
|
-
"selector-class",
|
|
255
|
-
"selector-id",
|
|
256
|
-
"selector-pseudo",
|
|
257
|
-
"selector-tag",
|
|
258
|
-
],
|
|
259
|
-
theme.accentText,
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function pushMarkdownSyntaxTokenColors(
|
|
264
|
-
tokenColors: SyntaxThemeTokenColor[],
|
|
265
|
-
theme: Theme,
|
|
266
|
-
): void {
|
|
267
|
-
pushSyntaxTokenColor(
|
|
268
|
-
tokenColors,
|
|
269
|
-
["quote", "markup.quote"],
|
|
270
|
-
theme.mutedText,
|
|
271
|
-
"italic",
|
|
272
|
-
);
|
|
273
|
-
pushSyntaxTokenColor(
|
|
274
|
-
tokenColors,
|
|
275
|
-
["section", "markup.heading"],
|
|
276
|
-
theme.accentText,
|
|
277
|
-
"bold",
|
|
278
|
-
);
|
|
279
|
-
pushSyntaxTokenColor(
|
|
280
|
-
tokenColors,
|
|
281
|
-
["bullet", "markup.list"],
|
|
282
|
-
theme.secondaryAccentText,
|
|
283
|
-
"bold",
|
|
284
|
-
);
|
|
285
|
-
pushSyntaxTokenColor(
|
|
286
|
-
tokenColors,
|
|
287
|
-
["code", "string", "markup.code"],
|
|
288
|
-
theme.diffAdded,
|
|
289
|
-
);
|
|
290
|
-
pushSyntaxTokenColor(tokenColors, "link", theme.accentText, "underline");
|
|
291
|
-
pushSyntaxTokenColor(tokenColors, "strong", undefined, "bold");
|
|
292
|
-
pushSyntaxTokenColor(tokenColors, "emphasis", undefined, "italic");
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Build the shared syntax-highlight theme registration for a UI theme variant.
|
|
297
|
-
*
|
|
298
|
-
* Markdown, read/code blocks, and shell/tool previews all flow through this
|
|
299
|
-
* helper so active-theme overrides stay consistent in one place. Variant names
|
|
300
|
-
* are included in the registration so cel-tui's internal SyntaxHighlight cache
|
|
301
|
-
* does not collapse code and shell renders onto the same custom-theme key.
|
|
302
|
-
*
|
|
303
|
-
* @param theme - Active UI theme.
|
|
304
|
-
* @param variant - Semantic highlighting variant for the rendered content.
|
|
305
|
-
* @returns A cached cel-tui syntax-highlight theme registration.
|
|
306
|
-
*/
|
|
307
|
-
export function getSyntaxHighlightTheme(
|
|
308
|
-
theme: Theme,
|
|
309
|
-
variant: SyntaxThemeVariant,
|
|
310
|
-
): SyntaxThemeRegistration {
|
|
311
|
-
const cache = syntaxThemeCache[variant];
|
|
312
|
-
const cached = cache.get(theme);
|
|
313
|
-
if (cached) {
|
|
314
|
-
return cached;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const tokenColors: SyntaxThemeTokenColor[] = [];
|
|
318
|
-
if (variant === "markdown") {
|
|
319
|
-
pushMarkdownSyntaxTokenColors(tokenColors, theme);
|
|
320
|
-
} else {
|
|
321
|
-
pushCodeSyntaxTokenColors(tokenColors, theme);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
const syntaxTheme: SyntaxThemeRegistration = {
|
|
325
|
-
name: `mini-coder-${variant}`,
|
|
326
|
-
tokenColors,
|
|
327
|
-
};
|
|
328
|
-
cache.set(theme, syntaxTheme);
|
|
329
|
-
return syntaxTheme;
|
|
330
|
-
}
|
package/src/tool-common.ts
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared helpers for built-in tool implementations.
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type {
|
|
8
|
-
ImageContent,
|
|
9
|
-
Static,
|
|
10
|
-
TextContent,
|
|
11
|
-
Tool,
|
|
12
|
-
ToolCall,
|
|
13
|
-
TSchema,
|
|
14
|
-
} from "@mariozechner/pi-ai";
|
|
15
|
-
import { validateToolArguments } from "@mariozechner/pi-ai";
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Result from executing a tool.
|
|
19
|
-
*
|
|
20
|
-
* Content blocks carry either text or image data. The agent loop maps these
|
|
21
|
-
* directly into pi-ai tool-result content.
|
|
22
|
-
*/
|
|
23
|
-
export interface ToolExecResult {
|
|
24
|
-
/** Content blocks for the tool result. */
|
|
25
|
-
content: (TextContent | ImageContent)[];
|
|
26
|
-
/** Optional structured metadata preserved on the tool-result message. */
|
|
27
|
-
details?: unknown;
|
|
28
|
-
/** Whether the execution encountered an error. */
|
|
29
|
-
isError: boolean;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Build a text-only tool result.
|
|
34
|
-
*
|
|
35
|
-
* @param text - Message text to return in the tool result.
|
|
36
|
-
* @param isError - Whether the result represents a tool error.
|
|
37
|
-
* @returns Text-only tool result content.
|
|
38
|
-
*/
|
|
39
|
-
export function textResult(text: string, isError: boolean): ToolExecResult {
|
|
40
|
-
return { content: [{ type: "text", text }], isError };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Detect which line ending a text blob uses.
|
|
45
|
-
*
|
|
46
|
-
* @param content - Text to inspect.
|
|
47
|
-
* @returns The first detected line ending, or `null` when the text is single-line.
|
|
48
|
-
*/
|
|
49
|
-
export function detectLineEnding(content: string): "\n" | "\r\n" | null {
|
|
50
|
-
if (content.includes("\r\n")) {
|
|
51
|
-
return "\r\n";
|
|
52
|
-
}
|
|
53
|
-
if (content.includes("\n")) {
|
|
54
|
-
return "\n";
|
|
55
|
-
}
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Normalize line endings to a specific style.
|
|
61
|
-
*
|
|
62
|
-
* @param content - Text to normalize.
|
|
63
|
-
* @param lineEnding - Target line ending sequence.
|
|
64
|
-
* @returns Text using only the requested line ending style.
|
|
65
|
-
*/
|
|
66
|
-
export function normalizeLineEndings(
|
|
67
|
-
content: string,
|
|
68
|
-
lineEnding: "\n" | "\r\n",
|
|
69
|
-
): string {
|
|
70
|
-
if (lineEnding === "\r\n") {
|
|
71
|
-
return content.replace(/\r?\n/g, "\r\n");
|
|
72
|
-
}
|
|
73
|
-
return content.replace(/\r\n/g, "\n");
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Validate and coerce built-in tool arguments against a typed TypeBox schema.
|
|
78
|
-
*
|
|
79
|
-
* @param tool - Built-in tool definition.
|
|
80
|
-
* @param args - Raw parsed tool-call arguments from the model.
|
|
81
|
-
* @returns Validated arguments typed from the tool schema.
|
|
82
|
-
*/
|
|
83
|
-
export function validateBuiltinToolArgs<TParameters extends TSchema>(
|
|
84
|
-
tool: Tool<TParameters>,
|
|
85
|
-
args: Record<string, unknown>,
|
|
86
|
-
): Static<TParameters> {
|
|
87
|
-
return validateToolArguments(tool, {
|
|
88
|
-
type: "toolCall",
|
|
89
|
-
id: tool.name,
|
|
90
|
-
name: tool.name,
|
|
91
|
-
arguments: args,
|
|
92
|
-
} satisfies ToolCall) as Static<TParameters>;
|
|
93
|
-
}
|
package/src/tool-delegate.ts
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* First-class delegated-subagent tool.
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { Static, Tool } from "@mariozechner/pi-ai";
|
|
8
|
-
import { Type } from "@mariozechner/pi-ai";
|
|
9
|
-
import type { ToolHandler, ToolUpdateCallback } from "./agent.ts";
|
|
10
|
-
import {
|
|
11
|
-
reserveToolDelegation,
|
|
12
|
-
type ShellDelegationContext,
|
|
13
|
-
} from "./delegation.ts";
|
|
14
|
-
import { textResult, validateBuiltinToolArgs } from "./tool-common.ts";
|
|
15
|
-
|
|
16
|
-
const delegateToolParameters = Type.Object({
|
|
17
|
-
task: Type.String({
|
|
18
|
-
description:
|
|
19
|
-
"Bounded subtask prompt for the delegated subagent. Include the specific goal, constraints, and expected deliverable.",
|
|
20
|
-
}),
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
/** Arguments for the `delegate` tool. */
|
|
24
|
-
export type DelegateArgs = Static<typeof delegateToolParameters>;
|
|
25
|
-
|
|
26
|
-
/** Structured details preserved on a persisted `delegate` tool result. */
|
|
27
|
-
export interface DelegateResultDetails {
|
|
28
|
-
/** How the delegated subagent run ended. */
|
|
29
|
-
stopReason: "stop" | "length" | "error" | "aborted";
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** Summarized output returned from one delegated subagent run. */
|
|
33
|
-
export interface DelegateRunResult {
|
|
34
|
-
/** How the delegated subagent run ended. */
|
|
35
|
-
stopReason: DelegateResultDetails["stopReason"];
|
|
36
|
-
/** Final assistant text emitted by the subagent. */
|
|
37
|
-
finalText: string;
|
|
38
|
-
/** Terminal assistant error text when the subagent failed. */
|
|
39
|
-
errorText: string | null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** pi-ai tool definition for `delegate`. */
|
|
43
|
-
export const delegateTool: Tool<typeof delegateToolParameters> = {
|
|
44
|
-
name: "delegate",
|
|
45
|
-
description:
|
|
46
|
-
"Run a bounded subtask in an isolated subagent session using the current model, prompt context, and tools. " +
|
|
47
|
-
"Use this when a focused second agent pass will help, and prefer it over shelling out to `mc -p` unless you are explicitly testing the CLI itself.",
|
|
48
|
-
parameters: delegateToolParameters,
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
/** Options for a `delegate` handler that enforces delegation safeguards. */
|
|
52
|
-
export interface CreateDelegateToolHandlerOpts {
|
|
53
|
-
/** Return the current subagent-delegation context for the active run. */
|
|
54
|
-
getDelegationContext: () => ShellDelegationContext;
|
|
55
|
-
/** Persist the updated delegation context after a launch reservation. */
|
|
56
|
-
setDelegationContext: (context: ShellDelegationContext) => void;
|
|
57
|
-
/** Execute one delegated subagent run. */
|
|
58
|
-
runSubagent: (
|
|
59
|
-
task: string,
|
|
60
|
-
context: ShellDelegationContext,
|
|
61
|
-
signal?: AbortSignal,
|
|
62
|
-
onUpdate?: ToolUpdateCallback,
|
|
63
|
-
) => Promise<DelegateRunResult>;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Format the model-visible text payload returned from a delegated subagent run.
|
|
68
|
-
*
|
|
69
|
-
* @param result - Delegated subagent result.
|
|
70
|
-
* @returns Text content suitable for the parent tool result.
|
|
71
|
-
*/
|
|
72
|
-
export function formatDelegateResultText(result: DelegateRunResult): string {
|
|
73
|
-
const lines = [`Subagent stop reason: ${result.stopReason}`];
|
|
74
|
-
|
|
75
|
-
if (result.finalText.length > 0) {
|
|
76
|
-
lines.push("", "Final answer:", result.finalText);
|
|
77
|
-
} else {
|
|
78
|
-
lines.push("", "Final answer:", "(no final text)");
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (result.errorText) {
|
|
82
|
-
lines.push("", "Terminal error:", result.errorText);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return lines.join("\n");
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Create a `delegate` tool handler that enforces delegation limits.
|
|
90
|
-
*
|
|
91
|
-
* @param opts - Delegation-context accessors plus the delegated-run executor.
|
|
92
|
-
* @returns A tool handler for first-class delegated subagent runs.
|
|
93
|
-
*/
|
|
94
|
-
export function createDelegateToolHandler(
|
|
95
|
-
opts: CreateDelegateToolHandlerOpts,
|
|
96
|
-
): ToolHandler {
|
|
97
|
-
return async (args, _cwd, signal, onUpdate) => {
|
|
98
|
-
const validatedArgs = validateBuiltinToolArgs(delegateTool, args);
|
|
99
|
-
const reservation = reserveToolDelegation(opts.getDelegationContext());
|
|
100
|
-
if (!reservation.ok) {
|
|
101
|
-
return textResult(reservation.error, true);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
opts.setDelegationContext(reservation.reservation.updatedContext);
|
|
105
|
-
const result = await opts.runSubagent(
|
|
106
|
-
validatedArgs.task,
|
|
107
|
-
reservation.reservation.childContext,
|
|
108
|
-
signal,
|
|
109
|
-
onUpdate,
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
content: [
|
|
114
|
-
{
|
|
115
|
-
type: "text",
|
|
116
|
-
text: formatDelegateResultText(result),
|
|
117
|
-
},
|
|
118
|
-
],
|
|
119
|
-
details: {
|
|
120
|
-
stopReason: result.stopReason,
|
|
121
|
-
} satisfies DelegateResultDetails,
|
|
122
|
-
isError: result.stopReason === "error" || result.stopReason === "aborted",
|
|
123
|
-
};
|
|
124
|
-
};
|
|
125
|
-
}
|