@falkenslab/agent-kit 0.28.0 → 0.29.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/dist/chat/chatController.d.ts +5 -2
- package/dist/chat/chatController.js +4 -2
- package/dist/core/agentSpec.d.ts +2 -2
- package/dist/core/extensions.d.ts +2 -0
- package/dist/core/externalExtensions.d.ts +10 -3
- package/dist/core/externalExtensions.js +9 -1
- package/dist/core/hooks/guidedGate.d.ts +7 -3
- package/dist/core/hooks/guidedGate.js +13 -6
- package/dist/core/session.js +1 -1
- package/dist/core/toolLabels.d.ts +21 -0
- package/dist/core/toolLabels.js +17 -0
- package/dist/extensions/awareness/index.js +3 -1
- package/dist/extensions/knowledge/index.js +3 -1
- package/dist/extensions/memory/index.js +3 -1
- package/dist/extensions/sources/index.js +3 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/tui/ink/runChatInk.js +3 -1
- package/package.json +1 -1
- package/schemas/agent-kit-metadata.schema.json +11 -1
|
@@ -7,7 +7,7 @@ import { type AgentEvent, type AgentRun, type SessionUsage } from "../core/runne
|
|
|
7
7
|
import { type RunFolder } from "../core/runs.js";
|
|
8
8
|
import { type ExtensionsStatus, type ModeControl } from "../core/session.js";
|
|
9
9
|
import { type Todo } from "../core/todos.js";
|
|
10
|
-
import { type ToolLabels } from "../core/toolLabels.js";
|
|
10
|
+
import { type ToolLabels, type ToolResult } from "../core/toolLabels.js";
|
|
11
11
|
import type { ToolPhrase } from "../core/messages/index.js";
|
|
12
12
|
import type { SignIn } from "../core/liveExtensions.js";
|
|
13
13
|
import { type ExtensionOptionState, type ExtensionScope } from "../core/externalExtensions.js";
|
|
@@ -42,6 +42,8 @@ export interface ChatSettings {
|
|
|
42
42
|
/** Tool call labels and folded-group phrases on top of the kit's and the extensions'. */
|
|
43
43
|
formatAction?: (toolName: string, input: unknown) => string;
|
|
44
44
|
toolPhrase?: (toolName: string) => ToolPhrase | undefined;
|
|
45
|
+
/** The line under a tool call for its result, before the labels' own (`ToolLabel.result`, #79): a string replaces it, `null` hides it, `undefined` leaves it to them. */
|
|
46
|
+
formatResult?: (toolName: string, result: ToolResult) => string | null | undefined;
|
|
45
47
|
/** Runs the agent: the SDK's (`runQuery()`) by default; another for tests, or a host of its own. */
|
|
46
48
|
runQuery?: (prompt: AsyncIterable<SDKUserMessage>, options: Options) => AgentRun;
|
|
47
49
|
/** The SDK's prompt suggestions (on by default). */
|
|
@@ -223,9 +225,10 @@ export declare function createChatController(options: Options | SessionOpener, s
|
|
|
223
225
|
subscribe(listener: (state: ChatState) => void): () => void;
|
|
224
226
|
/** Calls `listener` with every event, in order; returns how to stop. */
|
|
225
227
|
onEvent(listener: (event: ChatEvent) => void): () => void;
|
|
226
|
-
/** Tool call labels and
|
|
228
|
+
/** Tool call labels, phrases and result lines with the extensions' (for a view that renders events itself). */
|
|
227
229
|
formatAction: (toolName: string, toolInput: unknown) => string;
|
|
228
230
|
toolPhrase: (toolName: string) => ToolPhrase | undefined;
|
|
231
|
+
formatResult: (toolName: string, result: ToolResult) => string | null | undefined;
|
|
229
232
|
/** The folder the session works in. */
|
|
230
233
|
cwd: () => string;
|
|
231
234
|
/** Draws the run's earlier conversation, then sends the initial prompt (for a new run). */
|
|
@@ -7,7 +7,7 @@ import { runQuery } from "../core/runner.js";
|
|
|
7
7
|
import { createRunFolder, listRuns, readConversation, readRunSession } from "../core/runs.js";
|
|
8
8
|
import { createInputQueue, togglePlanMode } from "../core/session.js";
|
|
9
9
|
import { hasOpenTodos, parseTodos, TODO_TOOL } from "../core/todos.js";
|
|
10
|
-
import { withToolLabels, withToolPhrases } from "../core/toolLabels.js";
|
|
10
|
+
import { withToolLabels, withToolPhrases, withToolResults } from "../core/toolLabels.js";
|
|
11
11
|
import { createConsoleRenderer } from "../tui/consoleRenderer.js";
|
|
12
12
|
import { chatExtensionsCommand } from "./extensions.js";
|
|
13
13
|
import { trustWorkspace } from "../core/workspaceTrust.js";
|
|
@@ -39,6 +39,7 @@ export async function createChatController(options, settings = {}) {
|
|
|
39
39
|
const modeControl = () => current.modeControl ?? settings.modeControl;
|
|
40
40
|
const formatAction = withToolLabels(() => current.toolLabels ?? settings.toolLabels, settings.formatAction);
|
|
41
41
|
const toolPhrase = withToolPhrases(() => current.toolLabels ?? settings.toolLabels, settings.toolPhrase);
|
|
42
|
+
const formatResult = withToolResults(() => current.toolLabels ?? settings.toolLabels, settings.formatResult);
|
|
42
43
|
// State and listeners.
|
|
43
44
|
const stateListeners = new Set();
|
|
44
45
|
const eventListeners = new Set();
|
|
@@ -425,9 +426,10 @@ export async function createChatController(options, settings = {}) {
|
|
|
425
426
|
eventListeners.add(listener);
|
|
426
427
|
return () => eventListeners.delete(listener);
|
|
427
428
|
},
|
|
428
|
-
/** Tool call labels and
|
|
429
|
+
/** Tool call labels, phrases and result lines with the extensions' (for a view that renders events itself). */
|
|
429
430
|
formatAction,
|
|
430
431
|
toolPhrase,
|
|
432
|
+
formatResult,
|
|
431
433
|
/** The folder the session works in. */
|
|
432
434
|
cwd: () => current.options.cwd ?? process.cwd(),
|
|
433
435
|
/** Draws the run's earlier conversation, then sends the initial prompt (for a new run). */
|
package/dist/core/agentSpec.d.ts
CHANGED
|
@@ -219,8 +219,8 @@ export interface ExtensionGateSpec {
|
|
|
219
219
|
/** `false` turns the gate off: extensions' tools run without asking, as the model decides. */
|
|
220
220
|
enabled?: boolean;
|
|
221
221
|
/**
|
|
222
|
-
* Tools that always ask, even inside a batch the person approved
|
|
223
|
-
* extension and short tool name (`{ canva: ["create-design"] }`): added to its manifest's `confirmTools`.
|
|
222
|
+
* Tools that always ask, on every call and even inside a batch the person approved (never
|
|
223
|
+
* offered "this session" or "always"), by extension and short tool name (`{ canva: ["create-design"] }`): added to its manifest's `confirmTools`.
|
|
224
224
|
*/
|
|
225
225
|
confirmTools?: Record<string, string[]>;
|
|
226
226
|
/** In autonomous mode, where no one can be asked: `"deny"` (the default) blocks those tools, `"allow"` runs them. */
|
|
@@ -71,6 +71,8 @@ export interface ExtensionContribution {
|
|
|
71
71
|
confirmTools?: string[];
|
|
72
72
|
/** Its MCP servers whose tools that always ask guided mode learns from their `destructiveHint`: an installed extension whose manifest lists no `confirmTools`. */
|
|
73
73
|
confirmHintServers?: string[];
|
|
74
|
+
/** Its MCP tools whose server asks the person itself (MCP elicitation), by full name: guided mode doesn't ask too (#77). */
|
|
75
|
+
serverConfirmTools?: string[];
|
|
74
76
|
/**
|
|
75
77
|
* Its MCP servers that are remote (#61), by session name: the SDK fixes their URL and headers
|
|
76
78
|
* when the session opens, so a changed option takes opening it again, and they may need the
|
|
@@ -58,6 +58,8 @@ export declare function remoteHosts(manifest: Pick<ExternalManifest, "servers">)
|
|
|
58
58
|
export interface ExternalToolLabel {
|
|
59
59
|
label: string;
|
|
60
60
|
phrase?: ToolPhrase;
|
|
61
|
+
/** The line under the call when it succeeded, instead of its result's first line, written for the model (#79). */
|
|
62
|
+
result?: string;
|
|
61
63
|
}
|
|
62
64
|
/** Who made an extension, as Claude Code's `plugin.json` has it. */
|
|
63
65
|
export interface ExtensionAuthor {
|
|
@@ -102,11 +104,16 @@ export interface ExternalManifest {
|
|
|
102
104
|
*/
|
|
103
105
|
readOnlyTools?: string[];
|
|
104
106
|
/**
|
|
105
|
-
* Its tools that always ask the person in guided mode (short names),
|
|
106
|
-
* approved,
|
|
107
|
-
* Without the key, its servers' `destructiveHint` says which.
|
|
107
|
+
* Its tools that always ask the person in guided mode (short names), on every call and even
|
|
108
|
+
* inside a batch they approved, never offering "this session" or "always" (#76, #78): what
|
|
109
|
+
* creates, edits or publishes in their account. Without the key, its servers' `destructiveHint` says which.
|
|
108
110
|
*/
|
|
109
111
|
confirmTools?: string[];
|
|
112
|
+
/**
|
|
113
|
+
* Its tools whose server asks the person itself before acting, through MCP elicitation (short
|
|
114
|
+
* names, #77): guided mode doesn't ask too while the person can be asked, so it's one question.
|
|
115
|
+
*/
|
|
116
|
+
serverConfirmTools?: string[];
|
|
110
117
|
/** Its tools' chat labels, by short name (of any of its servers) and language (English when the kit's isn't there). */
|
|
111
118
|
labels: Record<string, Partial<Record<Language, ExternalToolLabel>>>;
|
|
112
119
|
/** What it says about itself in a session, for the agent to tell the person (`SessionFacts`). */
|
|
@@ -141,6 +141,7 @@ export async function readExternalManifest(dir) {
|
|
|
141
141
|
servers: await pluginServers(dir, raw),
|
|
142
142
|
...(Array.isArray(kit.readOnlyTools) ? { readOnlyTools: kit.readOnlyTools.filter((tool) => typeof tool === "string") } : {}),
|
|
143
143
|
...(Array.isArray(kit.confirmTools) ? { confirmTools: kit.confirmTools.filter((tool) => typeof tool === "string") } : {}),
|
|
144
|
+
...(Array.isArray(kit.serverConfirmTools) ? { serverConfirmTools: kit.serverConfirmTools.filter((tool) => typeof tool === "string") } : {}),
|
|
144
145
|
labels: kit.labels ?? {},
|
|
145
146
|
...(kit.help ? { help: kit.help } : {}),
|
|
146
147
|
userConfig: parseUserConfig(raw.userConfig),
|
|
@@ -367,7 +368,12 @@ function manifestToolLabels(manifest, sessionServers) {
|
|
|
367
368
|
const texts = byLanguage[language] ?? byLanguage.en;
|
|
368
369
|
if (!texts)
|
|
369
370
|
return [];
|
|
370
|
-
const label = {
|
|
371
|
+
const label = {
|
|
372
|
+
label: (input) => fill(texts.label, input),
|
|
373
|
+
...(texts.phrase ? { phrase: texts.phrase } : {}),
|
|
374
|
+
// In the person's language when it succeeded; a failure keeps its own line (#79).
|
|
375
|
+
...(texts.result ? { result: (result) => (result.isError ? undefined : texts.result) } : {}),
|
|
376
|
+
};
|
|
371
377
|
return sessionServers.map((server) => [`mcp__${server}__${tool}`, label]);
|
|
372
378
|
}));
|
|
373
379
|
}
|
|
@@ -429,6 +435,8 @@ function externalExtension(installed, manifest, cache, unavailable = []) {
|
|
|
429
435
|
...(manifest.confirmTools
|
|
430
436
|
? { confirmTools: Object.keys(servers).flatMap((server) => manifest.confirmTools.map((tool) => `mcp__${server}__${tool}`)) }
|
|
431
437
|
: { confirmHintServers: Object.keys(servers) }),
|
|
438
|
+
// And those whose server asks the person itself (#77).
|
|
439
|
+
...(manifest.serverConfirmTools ? { serverConfirmTools: Object.keys(servers).flatMap((server) => manifest.serverConfirmTools.map((tool) => `mcp__${server}__${tool}`)) } : {}),
|
|
432
440
|
toolLabels: manifestToolLabels(manifest, Object.keys(servers)),
|
|
433
441
|
...(remote.length ? { remoteServers: remote } : {}),
|
|
434
442
|
...(manifest.help ? { helpLines: [manifest.help] } : {}),
|
|
@@ -10,12 +10,14 @@ export interface GuardedExtension {
|
|
|
10
10
|
servers: readonly string[];
|
|
11
11
|
/** Its tools that always ask (full names): its manifest's `confirmTools` and the agent's own list. */
|
|
12
12
|
confirmTools: readonly string[];
|
|
13
|
+
/** Its tools whose server asks the person itself (full names, the manifest's `serverConfirmTools`, #77). */
|
|
14
|
+
serverConfirmTools?: readonly string[];
|
|
13
15
|
}
|
|
14
16
|
/** One answer the gate gave, for the transcript: what was asked, and what the person (or the mode) said. */
|
|
15
17
|
export interface GuidedDecision {
|
|
16
18
|
extension: string;
|
|
17
19
|
tool: string;
|
|
18
|
-
answer: "yes" | "session" | "always" | "no" | "never" | "kept-never" | "autonomous-deny";
|
|
20
|
+
answer: "yes" | "session" | "always" | "no" | "never" | "kept-never" | "autonomous-deny" | "server-asks";
|
|
19
21
|
}
|
|
20
22
|
/** The guided gate: its `PreToolUse` hook, and what ends or starts an approved batch. */
|
|
21
23
|
export interface GuidedGate {
|
|
@@ -37,8 +39,10 @@ export interface GuidedGate {
|
|
|
37
39
|
* this session, always (kept in the extension's lock), no, never (kept too). Right after
|
|
38
40
|
* `request_human_approval` is approved, calls go on until the person's next message (a batch),
|
|
39
41
|
* except those that always ask: the agent's or the manifest's `confirmTools`, else the server's
|
|
40
|
-
* `destructiveHint`,
|
|
41
|
-
* runs without asking.
|
|
42
|
+
* `destructiveHint`, asked on every call, so they're offered only yes, no and never (#78). An extension whose lock says `off`
|
|
43
|
+
* runs without asking. A tool whose server asks the person itself (`serverConfirmTools`, #77)
|
|
44
|
+
* isn't asked about too in guided mode, where that question reaches the person: one question,
|
|
45
|
+
* the server's. Approving gives no decision of its own, so the other gates still judge.
|
|
42
46
|
*/
|
|
43
47
|
export declare function createGuidedGate(options: {
|
|
44
48
|
runDir: string;
|
|
@@ -15,8 +15,10 @@ const APPROVAL_TOOL = "mcp__approvals__request_human_approval";
|
|
|
15
15
|
* this session, always (kept in the extension's lock), no, never (kept too). Right after
|
|
16
16
|
* `request_human_approval` is approved, calls go on until the person's next message (a batch),
|
|
17
17
|
* except those that always ask: the agent's or the manifest's `confirmTools`, else the server's
|
|
18
|
-
* `destructiveHint`,
|
|
19
|
-
* runs without asking.
|
|
18
|
+
* `destructiveHint`, asked on every call, so they're offered only yes, no and never (#78). An extension whose lock says `off`
|
|
19
|
+
* runs without asking. A tool whose server asks the person itself (`serverConfirmTools`, #77)
|
|
20
|
+
* isn't asked about too in guided mode, where that question reaches the person: one question,
|
|
21
|
+
* the server's. Approving gives no decision of its own, so the other gates still judge.
|
|
20
22
|
*/
|
|
21
23
|
export function createGuidedGate(options) {
|
|
22
24
|
const thisSession = new Set();
|
|
@@ -47,10 +49,14 @@ export function createGuidedGate(options) {
|
|
|
47
49
|
await record("kept-never");
|
|
48
50
|
return deny(pre, `The person never lets ${extension.name} run ${tool} (they said so before). Don't call it again: do the task another way, or tell them it needs it.`);
|
|
49
51
|
}
|
|
50
|
-
|
|
51
|
-
if (
|
|
52
|
+
// Its server asks the person itself, and in guided mode its question reaches them (#77).
|
|
53
|
+
if (mode === "guided" && extension.serverConfirmTools?.includes(full)) {
|
|
54
|
+
await record("server-asks");
|
|
52
55
|
return {};
|
|
53
|
-
|
|
56
|
+
}
|
|
57
|
+
const alwaysAsks = extension.confirmTools.includes(full) || (await options.isDestructive(full));
|
|
58
|
+
// A tool that always asks is asked on every call (#78): no kept "always", no "this session".
|
|
59
|
+
if (!alwaysAsks && (kept === "always" || thisSession.has(full)))
|
|
54
60
|
return {};
|
|
55
61
|
if (mode === "autonomous") {
|
|
56
62
|
if (options.autonomous === "allow")
|
|
@@ -61,7 +67,8 @@ export function createGuidedGate(options) {
|
|
|
61
67
|
if (batch && !alwaysAsks)
|
|
62
68
|
return {};
|
|
63
69
|
const answers = t().confirmAnswers;
|
|
64
|
-
|
|
70
|
+
// For one that always asks, only what covers this call, or makes it stricter (#78).
|
|
71
|
+
const choices = alwaysAsks ? [answers.yes, answers.no, answers.never] : [answers.yes, answers.session, answers.always, answers.no, answers.never];
|
|
65
72
|
const label = options.labels?.()[full]?.label((pre.tool_input ?? {}));
|
|
66
73
|
const answer = await askForChoice(options.runDir, {
|
|
67
74
|
title: t().guidedTitle(extension.name),
|
package/dist/core/session.js
CHANGED
|
@@ -195,7 +195,7 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
|
|
|
195
195
|
return [];
|
|
196
196
|
const servers = Object.keys(added[index]?.mcpServers ?? {});
|
|
197
197
|
const own = (gateSpec.confirmTools?.[extension.name] ?? []).flatMap((tool) => servers.map((server) => `mcp__${server}__${tool}`));
|
|
198
|
-
return [{ name: extension.name, scopeDir: installed.scopeDir, servers, confirmTools: [...(added[index]?.confirmTools ?? []), ...own] }];
|
|
198
|
+
return [{ name: extension.name, scopeDir: installed.scopeDir, servers, confirmTools: [...(added[index]?.confirmTools ?? []), ...own], serverConfirmTools: added[index]?.serverConfirmTools ?? [] }];
|
|
199
199
|
});
|
|
200
200
|
const neverTools = (await Promise.all(guardedExtensions.map(async (extension) => {
|
|
201
201
|
const confirm = (await readLock(extension.scopeDir).catch(() => ({})))[extension.name]?.confirm;
|
|
@@ -22,7 +22,23 @@ export interface ToolLabel {
|
|
|
22
22
|
label(input: Record<string, unknown>): string;
|
|
23
23
|
/** How it counts in a folded group's summary, `[one, many]` with `{n}`: `["read {n} page", "read {n} pages"]`. */
|
|
24
24
|
phrase?: ToolPhrase;
|
|
25
|
+
/**
|
|
26
|
+
* The line under it for its result, in the kit's language (#79): a string replaces the result's
|
|
27
|
+
* first line (written for the model, in English), `null` hides it, `undefined` keeps it. The
|
|
28
|
+
* model's result is never changed.
|
|
29
|
+
*/
|
|
30
|
+
result?(result: ToolResult): string | null | undefined;
|
|
25
31
|
}
|
|
32
|
+
/** A tool call's result, as the chat shows it. */
|
|
33
|
+
export interface ToolResult {
|
|
34
|
+
isError: boolean;
|
|
35
|
+
text: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Labels whose result line is hidden when the call succeeded (#79): for tools whose label already
|
|
39
|
+
* says what happened, so the person doesn't read the model's English under it. A failure still shows.
|
|
40
|
+
*/
|
|
41
|
+
export declare function quietResults(labels: ToolLabels): ToolLabels;
|
|
26
42
|
/** Tools' labels by full name (`mcp__<server>__<tool>`): what the extensions of a session bring. */
|
|
27
43
|
export type ToolLabels = Readonly<Record<string, ToolLabel>>;
|
|
28
44
|
/**
|
|
@@ -33,6 +49,11 @@ export type ToolLabels = Readonly<Record<string, ToolLabel>>;
|
|
|
33
49
|
export declare function withToolLabels(labels: () => ToolLabels | undefined, formatAction?: (toolName: string, toolInput: unknown) => string): (toolName: string, toolInput: unknown) => string;
|
|
34
50
|
/** A `toolPhrase` that counts the tools in `labels()` with their phrase, and any other with `toolPhrase`. */
|
|
35
51
|
export declare function withToolPhrases(labels: () => ToolLabels | undefined, toolPhrase?: (toolName: string) => ToolPhrase | undefined): (toolName: string) => ToolPhrase | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* A result formatter (the Ink chat's `formatResult`) that asks `formatResult` first, then the
|
|
54
|
+
* tools' labels (`ToolLabel.result`, #79): `undefined` from both keeps the result's first line.
|
|
55
|
+
*/
|
|
56
|
+
export declare function withToolResults(labels: () => ToolLabels | undefined, formatResult?: (toolName: string, result: ToolResult) => string | null | undefined): (toolName: string, result: ToolResult) => string | null | undefined;
|
|
36
57
|
/** An agent's labels for its own tools: the tool's short name and input, to a label, or `undefined` for the kit's default. */
|
|
37
58
|
export type ToolDescriber = (shortName: string, input: Record<string, unknown>) => string | undefined;
|
|
38
59
|
/**
|
package/dist/core/toolLabels.js
CHANGED
|
@@ -71,6 +71,13 @@ function describeCore(shortName, input) {
|
|
|
71
71
|
return undefined;
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Labels whose result line is hidden when the call succeeded (#79): for tools whose label already
|
|
76
|
+
* says what happened, so the person doesn't read the model's English under it. A failure still shows.
|
|
77
|
+
*/
|
|
78
|
+
export function quietResults(labels) {
|
|
79
|
+
return Object.fromEntries(Object.entries(labels).map(([tool, label]) => [tool, { ...label, result: (result) => (result.isError ? undefined : null) }]));
|
|
80
|
+
}
|
|
74
81
|
/**
|
|
75
82
|
* A `formatAction` that shows the tools in `labels()` with their label, and any other with
|
|
76
83
|
* `formatAction` (the kit's by default). `labels` is read on every call, so it can follow the
|
|
@@ -88,6 +95,16 @@ export function withToolLabels(labels, formatAction = createFriendlyToolLabel())
|
|
|
88
95
|
export function withToolPhrases(labels, toolPhrase) {
|
|
89
96
|
return (toolName) => labels()?.[toolName]?.phrase ?? toolPhrase?.(toolName);
|
|
90
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* A result formatter (the Ink chat's `formatResult`) that asks `formatResult` first, then the
|
|
100
|
+
* tools' labels (`ToolLabel.result`, #79): `undefined` from both keeps the result's first line.
|
|
101
|
+
*/
|
|
102
|
+
export function withToolResults(labels, formatResult) {
|
|
103
|
+
return (toolName, result) => {
|
|
104
|
+
const own = formatResult?.(toolName, result);
|
|
105
|
+
return own !== undefined ? own : labels()?.[toolName]?.result?.(result);
|
|
106
|
+
};
|
|
107
|
+
}
|
|
91
108
|
/**
|
|
92
109
|
* Builds a `friendlyToolLabel(toolName, toolInput)` — `describe` lets the host agent
|
|
93
110
|
* layer its own domain-specific cases (e.g. Playwright's browser_* tools) on top of this
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { quietResults } from "../../core/toolLabels.js";
|
|
3
4
|
import { agentKitVersion } from "../../core/version.js";
|
|
4
5
|
import { awarenessToolLabels } from "./labels.js";
|
|
5
6
|
import { createAwarenessServer } from "./tools.js";
|
|
@@ -44,7 +45,8 @@ export function awareness(options = {}) {
|
|
|
44
45
|
mcpServers: { awareness: createAwarenessServer(session, options.guide, catalog ? [createCatalogTool(config, session)] : []) },
|
|
45
46
|
promptSection: identityPromptSection(spec.identity, { catalog }),
|
|
46
47
|
readOnlyTools: ["mcp__awareness__about_me", ...(catalog ? ["mcp__awareness__extensions_catalog"] : [])],
|
|
47
|
-
|
|
48
|
+
// Their labels already say what happened: no English result line under them (#79).
|
|
49
|
+
toolLabels: quietResults(awarenessToolLabels()),
|
|
48
50
|
};
|
|
49
51
|
},
|
|
50
52
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { quietResults } from "../../core/toolLabels.js";
|
|
1
2
|
import { folderOf } from "../../core/extensions.js";
|
|
2
3
|
import { createFileKnowledgeStore } from "./fileKnowledgeStore.js";
|
|
3
4
|
import { knowledgeToolLabels } from "./labels.js";
|
|
@@ -27,7 +28,8 @@ export function knowledge(options) {
|
|
|
27
28
|
toolOnlyDirs: [{ dir: knowledgeDir, instead: "the knowledge_* tools" }],
|
|
28
29
|
readOnlyTools: ["mcp__knowledge__knowledge_index", "mcp__knowledge__knowledge_search", "mcp__knowledge__knowledge_read", "mcp__knowledge__knowledge_check"],
|
|
29
30
|
selfAskingTools: ["mcp__knowledge__knowledge_retire"],
|
|
30
|
-
|
|
31
|
+
// Their labels already say what happened: no English result line under them (#79).
|
|
32
|
+
toolLabels: quietResults(knowledgeToolLabels()),
|
|
31
33
|
helpLines: [
|
|
32
34
|
"You keep a knowledge base (your memory across sessions). Its commands: `/knowledge:ingest` (learn the new or changed files of the sources folder), `/knowledge:query <question>` (answer from it), `/knowledge:lint` (check it and fix what's mechanical).",
|
|
33
35
|
],
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { quietResults } from "../../core/toolLabels.js";
|
|
3
4
|
import { folderOf } from "../../core/extensions.js";
|
|
4
5
|
import { readConversation } from "../../core/runs.js";
|
|
5
6
|
import { memoryToolLabels } from "./labels.js";
|
|
@@ -49,7 +50,8 @@ export function memory(options) {
|
|
|
49
50
|
toolOnlyDirs: [{ dir: memoryDir, instead: "its tools: recall, remember, forget" }],
|
|
50
51
|
readOnlyTools: ["mcp__memory__recall"],
|
|
51
52
|
hooks: { UserPromptSubmit: [{ hooks: [hear] }] },
|
|
52
|
-
|
|
53
|
+
// Their labels already say what happened: no English result line under them (#79).
|
|
54
|
+
toolLabels: quietResults(memoryToolLabels()),
|
|
53
55
|
helpLines: [
|
|
54
56
|
"You keep a memory of the person across all their projects (how they like things done, who they are): `/memory:list` shows it, `/memory:forget <entry>` forgets an entry. Only what they tell you goes in it.",
|
|
55
57
|
],
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { quietResults } from "../../core/toolLabels.js";
|
|
3
4
|
import { folderOf } from "../../core/extensions.js";
|
|
4
5
|
import { sourcesToolLabels } from "./labels.js";
|
|
5
6
|
import { addSource } from "./sources.js";
|
|
@@ -29,7 +30,8 @@ export function sources(options) {
|
|
|
29
30
|
readOnlyDirs: [sourcesDir],
|
|
30
31
|
readOnlyTools: ["mcp__sourceFiles__list_sources", "mcp__sourceFiles__extract_text"],
|
|
31
32
|
selfAskingTools: ["mcp__sourceFiles__request_file", "mcp__sourceFiles__retire_source"],
|
|
32
|
-
|
|
33
|
+
// Their labels already say what happened: no English result line under them (#79).
|
|
34
|
+
toolLabels: quietResults(sourcesToolLabels()),
|
|
33
35
|
// For the host (a page's "add to the chest"): a file the person gave, with the same rules
|
|
34
36
|
// as the tools (never overwriting, a duplicate recognized) and the person as its origin.
|
|
35
37
|
api: {
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { allowAnyMcpTool } from "./core/mcpPermissions.js";
|
|
|
5
5
|
export { createPromptLoader } from "./core/promptTemplate.js";
|
|
6
6
|
export { resolveClaudeAuth, type ClaudeAuthConfig } from "./core/claudeAuth.js";
|
|
7
7
|
export { ensureClaudeAuth } from "./tui/claudeAuth.js";
|
|
8
|
-
export { createFriendlyToolLabel, truncate, truncatePath, withToolLabels, withToolPhrases, type ToolDescriber, type ToolLabel, type ToolLabels, } from "./core/toolLabels.js";
|
|
8
|
+
export { createFriendlyToolLabel, truncate, truncatePath, withToolLabels, withToolPhrases, withToolResults, quietResults, type ToolResult, type ToolDescriber, type ToolLabel, type ToolLabels, } from "./core/toolLabels.js";
|
|
9
9
|
export type { Mode, BaseSessionConfig, AgentSpec, AgentIdentity, PlanModeSpec, ExtensionGateSpec } from "./core/agentSpec.js";
|
|
10
10
|
export { buildSessionOptions, createInputQueue, createDeferred, createModeControl, togglePlanMode, type ModeControl, type ExtensionsStatus } from "./core/session.js";
|
|
11
11
|
export { runQuery, type AgentEvent, type AgentRun, type SessionUsage, type ContextUsage } from "./core/runner.js";
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ export { allowAnyMcpTool } from "./core/mcpPermissions.js";
|
|
|
7
7
|
export { createPromptLoader } from "./core/promptTemplate.js";
|
|
8
8
|
export { resolveClaudeAuth } from "./core/claudeAuth.js";
|
|
9
9
|
export { ensureClaudeAuth } from "./tui/claudeAuth.js";
|
|
10
|
-
export { createFriendlyToolLabel, truncate, truncatePath, withToolLabels, withToolPhrases, } from "./core/toolLabels.js";
|
|
10
|
+
export { createFriendlyToolLabel, truncate, truncatePath, withToolLabels, withToolPhrases, withToolResults, quietResults, } from "./core/toolLabels.js";
|
|
11
11
|
export { buildSessionOptions, createInputQueue, createDeferred, createModeControl, togglePlanMode } from "./core/session.js";
|
|
12
12
|
export { runQuery } from "./core/runner.js";
|
|
13
13
|
export { knowledgePluginRoot, knowledgePromptSection } from "./extensions/knowledge/prompt.js";
|
|
@@ -198,6 +198,7 @@ export async function runChatInk(options, tuiOptions = {}) {
|
|
|
198
198
|
toolLabels: tuiOptions.toolLabels,
|
|
199
199
|
formatAction: tuiOptions.formatAction,
|
|
200
200
|
toolPhrase: tuiOptions.toolPhrase,
|
|
201
|
+
formatResult: tuiOptions.formatResult,
|
|
201
202
|
...(tuiOptions.openBrowser !== undefined ? { openBrowser: tuiOptions.openBrowser } : {}),
|
|
202
203
|
promptSuggestions: tuiOptions.promptSuggestions ?? true,
|
|
203
204
|
// The /resume list in place of the prompt.
|
|
@@ -221,7 +222,8 @@ export async function runChatInk(options, tuiOptions = {}) {
|
|
|
221
222
|
formatAction: controller.formatAction,
|
|
222
223
|
toolPhrase: controller.toolPhrase,
|
|
223
224
|
toolDetail: tuiOptions.toolDetail,
|
|
224
|
-
|
|
225
|
+
// The agent's, then the labels' (#79).
|
|
226
|
+
formatResult: controller.formatResult,
|
|
225
227
|
agentLabel: tuiOptions.agentLabel,
|
|
226
228
|
width: () => liveWidth(stdout.columns),
|
|
227
229
|
});
|
package/package.json
CHANGED
|
@@ -35,7 +35,12 @@
|
|
|
35
35
|
"items": { "type": "string", "minLength": 1 }
|
|
36
36
|
},
|
|
37
37
|
"confirmTools": {
|
|
38
|
-
"description": "Its tools that always ask the person in guided mode (short names), even inside a batch they approved,
|
|
38
|
+
"description": "Its tools that always ask the person in guided mode (short names), on every call, even inside a batch they approved, never offered \"this session\" or \"always\": what creates, edits or publishes in their account. Without it, its servers' destructiveHint says which.",
|
|
39
|
+
"type": "array",
|
|
40
|
+
"items": { "type": "string", "minLength": 1 }
|
|
41
|
+
},
|
|
42
|
+
"serverConfirmTools": {
|
|
43
|
+
"description": "Its tools whose server asks the person itself before acting, through MCP elicitation (short names): guided mode doesn't ask too while the person can be asked, so it's one question, the server's. Plan mode still stops them; autonomous mode still denies them unless the agent allows them.",
|
|
39
44
|
"type": "array",
|
|
40
45
|
"items": { "type": "string", "minLength": 1 }
|
|
41
46
|
},
|
|
@@ -57,6 +62,11 @@
|
|
|
57
62
|
"prefixItems": [{ "type": "string" }, { "type": "string" }],
|
|
58
63
|
"minItems": 2,
|
|
59
64
|
"maxItems": 2
|
|
65
|
+
},
|
|
66
|
+
"result": {
|
|
67
|
+
"description": "The line under the call when it succeeded, in this language, instead of the result's first line (written for the model, in English). A failure still shows its own.",
|
|
68
|
+
"type": "string",
|
|
69
|
+
"minLength": 1
|
|
60
70
|
}
|
|
61
71
|
}
|
|
62
72
|
}
|