agent-sh 0.15.1 → 0.15.2
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/dist/agent/agent-loop.js +11 -8
- package/dist/agent/events.d.ts +4 -0
- package/examples/extensions/ashi/package.json +1 -1
- package/examples/extensions/ashi/src/chat/tool-group.ts +3 -2
- package/examples/extensions/ashi/src/cli.ts +6 -6
- package/examples/extensions/ashi/src/dialogs.ts +16 -1
- package/examples/extensions/ashi/src/events.ts +1 -0
- package/examples/extensions/ashi/src/frontend.ts +26 -6
- package/examples/extensions/ashi/src/renderer.ts +2 -2
- package/examples/extensions/ashi/src/renderers/pi-tui/schema-mount.ts +4 -3
- package/examples/extensions/ashi/src/ui.ts +11 -0
- package/package.json +1 -1
- package/src/agent/agent-loop.ts +11 -8
- package/src/agent/events.ts +2 -0
package/dist/agent/agent-loop.js
CHANGED
|
@@ -528,14 +528,15 @@ export class AgentLoop {
|
|
|
528
528
|
// Advisable so extensions can inject fallback parsers without
|
|
529
529
|
// subclassing the protocol.
|
|
530
530
|
h.define("tool-protocol:extract-calls", (args) => this.toolProtocol.extractToolCalls(args.text, args.streamedCalls));
|
|
531
|
-
// System prompt: static identity + behavioral instructions.
|
|
532
|
-
//
|
|
533
|
-
// advise system-prompt:frontend to describe their
|
|
534
|
-
// prompt, or advise
|
|
531
|
+
// System prompt: static identity + behavioral instructions. Extensions can
|
|
532
|
+
// use registerInstruction() for a managed section, advise system-prompt:identity
|
|
533
|
+
// to replace the kernel identity, advise system-prompt:frontend to describe their
|
|
534
|
+
// surface high in the prompt, or advise system-prompt:build directly for full control.
|
|
535
|
+
h.define("system-prompt:identity", () => STATIC_IDENTITY);
|
|
535
536
|
h.define("system-prompt:build", () => {
|
|
536
537
|
// The active frontend's surface goes right after the identity; omitted if none.
|
|
537
538
|
const frontend = (this.handlers.call("system-prompt:frontend") ?? "").trim();
|
|
538
|
-
const parts = [
|
|
539
|
+
const parts = [this.handlers.call("system-prompt:identity")];
|
|
539
540
|
if (frontend)
|
|
540
541
|
parts.push(frontend);
|
|
541
542
|
parts.push(STATIC_GUIDE);
|
|
@@ -1229,8 +1230,10 @@ export class AgentLoop {
|
|
|
1229
1230
|
let reasoning = "";
|
|
1230
1231
|
const reasoningDetailsByIndex = new Map();
|
|
1231
1232
|
const pendingToolCalls = [];
|
|
1232
|
-
// Tool protocol controls what goes in the API tools param vs dynamic context
|
|
1233
|
-
|
|
1233
|
+
// Tool protocol controls what goes in the API tools param vs dynamic context.
|
|
1234
|
+
// agent:tools:visible is a filter point on the assembled list — distinct from
|
|
1235
|
+
// getTools(), which other code (e.g. tool bridges) needs unfiltered.
|
|
1236
|
+
const toolView = this.bus.emitPipe("agent:tools:visible", { tools: this.getTools() }).tools;
|
|
1234
1237
|
const apiTools = this.toolProtocol.getApiTools(toolView);
|
|
1235
1238
|
const toolPrompt = this.toolProtocol.getToolPrompt(toolView);
|
|
1236
1239
|
// Dynamic context rides on the trailing message — see
|
|
@@ -1242,7 +1245,7 @@ export class AgentLoop {
|
|
|
1242
1245
|
// Let extensions transform the message array (compact, summarize, filter, etc.)
|
|
1243
1246
|
const messages = this.handlers.call("conversation:prepare", rawMessages);
|
|
1244
1247
|
// Stream filter strips tool tags from display (inline mode only)
|
|
1245
|
-
const streamFilter = this.toolProtocol.createStreamFilter(
|
|
1248
|
+
const streamFilter = this.toolProtocol.createStreamFilter(toolView.map((t) => t.name));
|
|
1246
1249
|
const requestParams = {
|
|
1247
1250
|
messages,
|
|
1248
1251
|
tools: apiTools,
|
package/dist/agent/events.d.ts
CHANGED
|
@@ -30,6 +30,10 @@ declare module "../core/event-bus.js" {
|
|
|
30
30
|
"agent:tools": {
|
|
31
31
|
tools: ToolDefinition[];
|
|
32
32
|
};
|
|
33
|
+
/** Filter point: the assembled tool list as the model will see it, after getTools(). */
|
|
34
|
+
"agent:tools:visible": {
|
|
35
|
+
tools: ToolDefinition[];
|
|
36
|
+
};
|
|
33
37
|
"agent:instructions": {
|
|
34
38
|
instructions: Array<{
|
|
35
39
|
name: string;
|
|
@@ -44,8 +44,9 @@ export class ToolGroup {
|
|
|
44
44
|
this.repaint();
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
this.expanded
|
|
47
|
+
setExpanded(expanded: boolean): void {
|
|
48
|
+
if (this.expanded === expanded) return;
|
|
49
|
+
this.expanded = expanded;
|
|
49
50
|
this.repaint();
|
|
50
51
|
}
|
|
51
52
|
|
|
@@ -6,7 +6,7 @@ import { createCore } from "agent-sh/core";
|
|
|
6
6
|
import { loadBuiltinExtensions } from "agent-sh/extensions";
|
|
7
7
|
import { loadExtensions } from "agent-sh/extension-loader";
|
|
8
8
|
import { activateAgent } from "agent-sh/agent";
|
|
9
|
-
import { getSettings } from "agent-sh/settings";
|
|
9
|
+
import { getSettings, CONFIG_DIR } from "agent-sh/settings";
|
|
10
10
|
import { Shell } from "agent-sh/shell";
|
|
11
11
|
import { TerminalBuffer } from "agent-sh/utils/terminal-buffer";
|
|
12
12
|
import type { Terminal } from "agent-sh/shell/terminal";
|
|
@@ -37,7 +37,6 @@ import { createPiTuiRenderer } from "./renderers/pi-tui/index.js";
|
|
|
37
37
|
import type { Renderer } from "./renderer.js";
|
|
38
38
|
import { loadRendererPreference } from "./display-config.js";
|
|
39
39
|
import { applyOutputMode } from "./terminal-mode.js";
|
|
40
|
-
import * as os from "node:os";
|
|
41
40
|
import * as path from "node:path";
|
|
42
41
|
import { fileURLToPath } from "node:url";
|
|
43
42
|
|
|
@@ -150,7 +149,7 @@ async function main(): Promise<void> {
|
|
|
150
149
|
|
|
151
150
|
const cwd = process.cwd();
|
|
152
151
|
const cwdSlug = cwd.replace(/\//g, "-").replace(/^-/, "");
|
|
153
|
-
const sessionsDir = path.join(
|
|
152
|
+
const sessionsDir = path.join(CONFIG_DIR, "ashi", "history", cwdSlug, "sessions");
|
|
154
153
|
const resumeId = config.continueLast
|
|
155
154
|
? MultiSessionStore.readLastSessionId(sessionsDir, { fallbackToLatest: true })
|
|
156
155
|
: undefined;
|
|
@@ -265,9 +264,10 @@ async function main(): Promise<void> {
|
|
|
265
264
|
} else {
|
|
266
265
|
// New-session only: skip on resume so a restored transcript isn't prefixed
|
|
267
266
|
// with this. List user/installed extensions only — built-ins are always present.
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
267
|
+
const all = [...new Set(loaded)];
|
|
268
|
+
const shown = (core.bus.emitPipe("ashi:startup-extensions", { names: all }).names ?? []) as string[];
|
|
269
|
+
if (shown.length > 0) {
|
|
270
|
+
ctx.bus.emit("ui:info", { message: `extensions: ${shown.join(" · ")}` });
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
273
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { App, Renderer } from "./renderer.js";
|
|
1
|
+
import type { App, Renderer, RenderNode } from "./renderer.js";
|
|
2
2
|
import { InfoLine } from "./chat/lines.js";
|
|
3
3
|
|
|
4
4
|
export interface SelectChoice {
|
|
@@ -9,9 +9,11 @@ export interface SelectChoice {
|
|
|
9
9
|
export interface SelectOpts {
|
|
10
10
|
title?: string;
|
|
11
11
|
items: SelectChoice[];
|
|
12
|
+
body?: string[] | ((width: number) => string[]);
|
|
12
13
|
}
|
|
13
14
|
export interface ConfirmOpts {
|
|
14
15
|
title: string;
|
|
16
|
+
body?: string[] | ((width: number) => string[]);
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
export interface DialogGuard {
|
|
@@ -28,6 +30,16 @@ export function createDialogs(app: App, renderer: Renderer, guard: DialogGuard):
|
|
|
28
30
|
const select = (opts: SelectOpts): Promise<string | undefined> => {
|
|
29
31
|
if (guard.isOpen() || opts.items.length === 0) return Promise.resolve(undefined);
|
|
30
32
|
return new Promise((resolve) => {
|
|
33
|
+
let bodyNode: RenderNode | null = null;
|
|
34
|
+
if (typeof opts.body === "function") {
|
|
35
|
+
const t = renderer.text();
|
|
36
|
+
t.setRenderFn(opts.body);
|
|
37
|
+
bodyNode = t.node;
|
|
38
|
+
} else if (opts.body && opts.body.length) {
|
|
39
|
+
const t = renderer.text();
|
|
40
|
+
t.setLines(opts.body);
|
|
41
|
+
bodyNode = t.node;
|
|
42
|
+
}
|
|
31
43
|
const hint = new InfoLine(renderer, opts.title ?? "↑↓ move · enter: select · esc: cancel");
|
|
32
44
|
const picker = app.createSelectList(
|
|
33
45
|
opts.items.map((c) => ({ value: c.value, label: c.label, description: c.description })),
|
|
@@ -40,6 +52,7 @@ export function createDialogs(app: App, renderer: Renderer, guard: DialogGuard):
|
|
|
40
52
|
guard.setOpen(false);
|
|
41
53
|
app.footerSlot.removeChild(picker.node);
|
|
42
54
|
app.footerSlot.removeChild(hint.node);
|
|
55
|
+
if (bodyNode) app.footerSlot.removeChild(bodyNode);
|
|
43
56
|
app.focusInput();
|
|
44
57
|
app.requestRender();
|
|
45
58
|
resolve(result);
|
|
@@ -47,6 +60,7 @@ export function createDialogs(app: App, renderer: Renderer, guard: DialogGuard):
|
|
|
47
60
|
picker.onSelect((item) => close(item.value));
|
|
48
61
|
picker.onCancel(() => close());
|
|
49
62
|
guard.setOpen(true);
|
|
63
|
+
if (bodyNode) app.footerSlot.addChild(bodyNode);
|
|
50
64
|
app.footerSlot.addChild(hint.node);
|
|
51
65
|
app.footerSlot.addChild(picker.node);
|
|
52
66
|
app.setFocus(picker.node);
|
|
@@ -57,6 +71,7 @@ export function createDialogs(app: App, renderer: Renderer, guard: DialogGuard):
|
|
|
57
71
|
const confirm = (opts: ConfirmOpts): Promise<boolean> =>
|
|
58
72
|
select({
|
|
59
73
|
title: opts.title,
|
|
74
|
+
body: opts.body,
|
|
60
75
|
items: [
|
|
61
76
|
{ value: "yes", label: "Yes" },
|
|
62
77
|
{ value: "no", label: "No" },
|
|
@@ -36,6 +36,7 @@ import type { Capture, NestedDiff } from "./capture.js";
|
|
|
36
36
|
import { execSync } from "node:child_process";
|
|
37
37
|
import { readClipboardImage } from "./clipboard-image.js";
|
|
38
38
|
import { renderDiff, detectLanguage, highlightLine } from "agent-sh/utils/diff-renderer.js";
|
|
39
|
+
import { computeDiff } from "agent-sh/utils/diff.js";
|
|
39
40
|
import { renderBoxFrame } from "agent-sh/utils/box-frame.js";
|
|
40
41
|
|
|
41
42
|
const GROUPABLE_KINDS = new Set(["read", "search"]);
|
|
@@ -217,6 +218,17 @@ export function mountAshi(
|
|
|
217
218
|
const dialogs = createDialogs(app, renderer, modalGuard);
|
|
218
219
|
ctx.define("ui:select", (opts: SelectOpts) => dialogs.select(opts));
|
|
219
220
|
ctx.define("ui:confirm", (opts: ConfirmOpts) => dialogs.confirm(opts));
|
|
221
|
+
ctx.define(
|
|
222
|
+
"ui:diff",
|
|
223
|
+
(opts: { before?: string | null; after?: string; filePath?: string; boxed?: boolean }) => {
|
|
224
|
+
const diff = computeDiff(opts.before ?? null, opts.after ?? "");
|
|
225
|
+
return buildDiffRenderer(
|
|
226
|
+
diff as Parameters<typeof buildDiffRenderer>[0],
|
|
227
|
+
opts.filePath ?? "",
|
|
228
|
+
opts.boxed !== false,
|
|
229
|
+
);
|
|
230
|
+
},
|
|
231
|
+
);
|
|
220
232
|
ctx.define("ui:input", (opts: InputOpts) => inputPrompt.prompt(opts));
|
|
221
233
|
ctx.define("ui:editor:get-text", () => input.getText());
|
|
222
234
|
ctx.define("ui:editor:set-text", (text: string) => { input.setText(text); });
|
|
@@ -325,6 +337,14 @@ export function mountAshi(
|
|
|
325
337
|
const activeTools = new Map<string, LiveToolEntry>();
|
|
326
338
|
const groupMaxVisible = loadGroupMaxVisible();
|
|
327
339
|
|
|
340
|
+
let allExpanded = false;
|
|
341
|
+
const makeGroup = (kind: string): ToolGroup => {
|
|
342
|
+
const g = new ToolGroup(renderer, kind, groupMaxVisible);
|
|
343
|
+
g.setExpanded(allExpanded);
|
|
344
|
+
appendEntry(g.node, { t: "group", group: g });
|
|
345
|
+
return g;
|
|
346
|
+
};
|
|
347
|
+
|
|
328
348
|
let openGroup: ToolGroup | null = null;
|
|
329
349
|
const sealOpenGroup = (): void => {
|
|
330
350
|
if (openGroup) { openGroup.seal(); openGroup = null; }
|
|
@@ -464,6 +484,7 @@ export function mountAshi(
|
|
|
464
484
|
kind: args.kind,
|
|
465
485
|
rawInput: args.rawInput,
|
|
466
486
|
});
|
|
487
|
+
result.setExpanded(allExpanded);
|
|
467
488
|
return { call, result, startedAt: Date.now() };
|
|
468
489
|
};
|
|
469
490
|
|
|
@@ -579,8 +600,7 @@ export function mountAshi(
|
|
|
579
600
|
const kind = TOOL_KIND[name];
|
|
580
601
|
if (kind && GROUPABLE_KINDS.has(kind) && renderer.mountToolGroup) {
|
|
581
602
|
const mergeable = findMergeableGroup(kind);
|
|
582
|
-
const group = mergeable
|
|
583
|
-
?? (() => { const g = new ToolGroup(renderer, kind, groupMaxVisible); appendEntry(g.node, { t: "group", group: g }); return g; })();
|
|
603
|
+
const group = mergeable ?? makeGroup(kind);
|
|
584
604
|
group.addCall(id, name, detailFromArgs(tc.function.arguments));
|
|
585
605
|
if (id) toolMap.set(id, { kind: "group", group, name });
|
|
586
606
|
continue;
|
|
@@ -724,8 +744,7 @@ export function mountAshi(
|
|
|
724
744
|
if (GROUPABLE_KINDS.has(kind) && renderer.mountToolGroup) {
|
|
725
745
|
const mergeable = findMergeableGroup(kind);
|
|
726
746
|
if (!mergeable) sealOpenGroup();
|
|
727
|
-
const group = mergeable
|
|
728
|
-
?? (() => { const g = new ToolGroup(renderer, kind, groupMaxVisible); appendEntry(g.node, { t: "group", group: g }); return g; })();
|
|
747
|
+
const group = mergeable ?? makeGroup(kind);
|
|
729
748
|
group.addCall(id, lookupName, detail);
|
|
730
749
|
openGroup = group;
|
|
731
750
|
activeTools.set(id, { kind: "group", group });
|
|
@@ -1242,9 +1261,10 @@ export function mountAshi(
|
|
|
1242
1261
|
return { consume: true };
|
|
1243
1262
|
}
|
|
1244
1263
|
if (key.matches("ctrl+o")) {
|
|
1264
|
+
allExpanded = !allExpanded;
|
|
1245
1265
|
for (const e of chatEntries) {
|
|
1246
|
-
if (e.t === "group") e.group.
|
|
1247
|
-
else if (e.t === "pair") e.result.
|
|
1266
|
+
if (e.t === "group") e.group.setExpanded(allExpanded);
|
|
1267
|
+
else if (e.t === "pair") e.result.setExpanded(allExpanded);
|
|
1248
1268
|
}
|
|
1249
1269
|
app.requestRender();
|
|
1250
1270
|
return { consume: true };
|
|
@@ -133,7 +133,7 @@ export interface App {
|
|
|
133
133
|
export interface ToolCallView {
|
|
134
134
|
node: RenderNode;
|
|
135
135
|
setStatus(opts: { exitCode: number | null; elapsedMs: number; summary?: string }): void;
|
|
136
|
-
|
|
136
|
+
setExpanded?(expanded: boolean): void;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
export interface ToolResultView {
|
|
@@ -142,7 +142,7 @@ export interface ToolResultView {
|
|
|
142
142
|
/** Width-aware diff closure produced by the edit/write tool at finalize. */
|
|
143
143
|
setDiffRenderer(fn: (width: number) => string[]): void;
|
|
144
144
|
finalize(opts: { exitCode: number | null; summary?: string }): void;
|
|
145
|
-
|
|
145
|
+
setExpanded(expanded: boolean): void;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
export interface ToolGroupChild {
|
|
@@ -136,8 +136,9 @@ class SchemaResultComponent extends Container {
|
|
|
136
136
|
this.handle.dispatch("status", { ...opts, elapsedMs: 0 });
|
|
137
137
|
HANDLES.delete(this.handle.toolCallId);
|
|
138
138
|
}
|
|
139
|
-
|
|
140
|
-
this.handle.cell.env
|
|
139
|
+
setExpanded(expanded: boolean): void {
|
|
140
|
+
if (this.handle.cell.env.expanded === expanded) return;
|
|
141
|
+
this.handle.cell.env = { ...this.handle.cell.env, expanded };
|
|
141
142
|
this.repaint();
|
|
142
143
|
this.handle.cell.callView?.repaint();
|
|
143
144
|
}
|
|
@@ -198,6 +199,6 @@ export function mountResult<S>(model: RenderModel<S>, args: MountArgs, env: Moun
|
|
|
198
199
|
appendChunk: (chunk) => comp.appendChunk(chunk),
|
|
199
200
|
setDiffRenderer: (fn) => comp.setDiffRenderer(fn),
|
|
200
201
|
finalize: (opts) => comp.finalize(opts),
|
|
201
|
-
|
|
202
|
+
setExpanded: (expanded) => comp.setExpanded(expanded),
|
|
202
203
|
};
|
|
203
204
|
}
|
|
@@ -10,6 +10,13 @@ export type { StatusSegment } from "./status-footer.js";
|
|
|
10
10
|
|
|
11
11
|
export type NoticeLevel = "info" | "warn" | "error" | "success";
|
|
12
12
|
|
|
13
|
+
export interface DiffOpts {
|
|
14
|
+
before?: string | null;
|
|
15
|
+
after?: string;
|
|
16
|
+
filePath?: string;
|
|
17
|
+
boxed?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
13
20
|
export interface Contribution {
|
|
14
21
|
/** Re-pull this surface (call after the content it depends on changes). */
|
|
15
22
|
refresh(): void;
|
|
@@ -26,6 +33,7 @@ export interface Ui {
|
|
|
26
33
|
notify(message: string, level?: NoticeLevel): void;
|
|
27
34
|
select(opts: SelectOpts): Promise<string | undefined>;
|
|
28
35
|
confirm(opts: ConfirmOpts): Promise<boolean>;
|
|
36
|
+
diff(opts: DiffOpts): (width: number) => string[];
|
|
29
37
|
input(opts?: InputOpts): Promise<string | undefined>;
|
|
30
38
|
getEditorText(): string;
|
|
31
39
|
setEditorText(text: string): void;
|
|
@@ -50,6 +58,9 @@ export function createUi(ctx: ExtensionContext): Ui {
|
|
|
50
58
|
if (!has("ui:confirm")) return Promise.resolve(false);
|
|
51
59
|
return ctx.call("ui:confirm", opts) as Promise<boolean>;
|
|
52
60
|
},
|
|
61
|
+
diff(opts) {
|
|
62
|
+
return has("ui:diff") ? (ctx.call("ui:diff", opts) as (width: number) => string[]) : (() => []);
|
|
63
|
+
},
|
|
53
64
|
input(opts = {}) {
|
|
54
65
|
if (!has("ui:input")) return Promise.resolve(undefined);
|
|
55
66
|
return ctx.call("ui:input", opts) as Promise<string | undefined>;
|
package/package.json
CHANGED
package/src/agent/agent-loop.ts
CHANGED
|
@@ -623,14 +623,15 @@ export class AgentLoop implements AgentBackend {
|
|
|
623
623
|
streamedCalls: ProtocolPendingToolCall[];
|
|
624
624
|
}) => this.toolProtocol.extractToolCalls(args.text, args.streamedCalls));
|
|
625
625
|
|
|
626
|
-
// System prompt: static identity + behavioral instructions.
|
|
627
|
-
//
|
|
628
|
-
// advise system-prompt:frontend to describe their
|
|
629
|
-
// prompt, or advise
|
|
626
|
+
// System prompt: static identity + behavioral instructions. Extensions can
|
|
627
|
+
// use registerInstruction() for a managed section, advise system-prompt:identity
|
|
628
|
+
// to replace the kernel identity, advise system-prompt:frontend to describe their
|
|
629
|
+
// surface high in the prompt, or advise system-prompt:build directly for full control.
|
|
630
|
+
h.define("system-prompt:identity", () => STATIC_IDENTITY);
|
|
630
631
|
h.define("system-prompt:build", () => {
|
|
631
632
|
// The active frontend's surface goes right after the identity; omitted if none.
|
|
632
633
|
const frontend = ((this.handlers.call("system-prompt:frontend") as string) ?? "").trim();
|
|
633
|
-
const parts: string[] = [
|
|
634
|
+
const parts: string[] = [this.handlers.call("system-prompt:identity") as string];
|
|
634
635
|
if (frontend) parts.push(frontend);
|
|
635
636
|
parts.push(STATIC_GUIDE);
|
|
636
637
|
|
|
@@ -1410,8 +1411,10 @@ export class AgentLoop implements AgentBackend {
|
|
|
1410
1411
|
const reasoningDetailsByIndex = new Map<number, Record<string, unknown>>();
|
|
1411
1412
|
const pendingToolCalls: PendingToolCall[] = [];
|
|
1412
1413
|
|
|
1413
|
-
// Tool protocol controls what goes in the API tools param vs dynamic context
|
|
1414
|
-
|
|
1414
|
+
// Tool protocol controls what goes in the API tools param vs dynamic context.
|
|
1415
|
+
// agent:tools:visible is a filter point on the assembled list — distinct from
|
|
1416
|
+
// getTools(), which other code (e.g. tool bridges) needs unfiltered.
|
|
1417
|
+
const toolView = this.bus.emitPipe("agent:tools:visible", { tools: this.getTools() }).tools;
|
|
1415
1418
|
const apiTools = this.toolProtocol.getApiTools(toolView);
|
|
1416
1419
|
const toolPrompt = this.toolProtocol.getToolPrompt(toolView);
|
|
1417
1420
|
|
|
@@ -1427,7 +1430,7 @@ export class AgentLoop implements AgentBackend {
|
|
|
1427
1430
|
|
|
1428
1431
|
// Stream filter strips tool tags from display (inline mode only)
|
|
1429
1432
|
const streamFilter = this.toolProtocol.createStreamFilter(
|
|
1430
|
-
|
|
1433
|
+
toolView.map((t) => t.name),
|
|
1431
1434
|
);
|
|
1432
1435
|
|
|
1433
1436
|
const requestParams = {
|
package/src/agent/events.ts
CHANGED
|
@@ -29,6 +29,8 @@ declare module "../core/event-bus.js" {
|
|
|
29
29
|
|
|
30
30
|
"agent:info": AgentIdentity;
|
|
31
31
|
"agent:tools": { tools: ToolDefinition[] };
|
|
32
|
+
/** Filter point: the assembled tool list as the model will see it, after getTools(). */
|
|
33
|
+
"agent:tools:visible": { tools: ToolDefinition[] };
|
|
32
34
|
"agent:instructions": { instructions: Array<{ name: string; text: string }> };
|
|
33
35
|
"agent:skills": { skills: Array<{ name: string; description: string; filePath: string }> };
|
|
34
36
|
|