@oh-my-pi/pi-coding-agent 14.7.1 → 14.7.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/package.json +7 -7
  3. package/src/config/model-equivalence.ts +1 -0
  4. package/src/config/model-registry.ts +108 -22
  5. package/src/config/settings-schema.ts +36 -1
  6. package/src/discovery/helpers.ts +4 -3
  7. package/src/edit/index.ts +1 -0
  8. package/src/eval/py/gateway-coordinator.ts +2 -3
  9. package/src/eval/py/runtime.ts +1 -0
  10. package/src/internal-urls/docs-index.generated.ts +1 -1
  11. package/src/lsp/index.ts +2 -0
  12. package/src/mcp/discoverable-tool-metadata.ts +24 -202
  13. package/src/modes/components/extensions/extension-dashboard.ts +26 -2
  14. package/src/modes/components/extensions/state-manager.ts +41 -0
  15. package/src/modes/controllers/selector-controller.ts +3 -0
  16. package/src/modes/interactive-mode.ts +26 -1
  17. package/src/prompts/tools/search-tool-bm25.md +14 -14
  18. package/src/prompts/tools/todo-write.md +1 -0
  19. package/src/sdk.ts +69 -8
  20. package/src/session/agent-session.ts +177 -1
  21. package/src/slash-commands/builtin-registry.ts +11 -0
  22. package/src/task/index.ts +2 -0
  23. package/src/tool-discovery/tool-index.ts +377 -0
  24. package/src/tools/ask.ts +2 -0
  25. package/src/tools/ast-edit.ts +2 -0
  26. package/src/tools/ast-grep.ts +2 -0
  27. package/src/tools/bash.ts +1 -0
  28. package/src/tools/browser.ts +2 -0
  29. package/src/tools/calculator.ts +2 -0
  30. package/src/tools/checkpoint.ts +4 -0
  31. package/src/tools/debug.ts +2 -0
  32. package/src/tools/eval.ts +2 -0
  33. package/src/tools/find.ts +2 -0
  34. package/src/tools/gh.ts +2 -0
  35. package/src/tools/hindsight-recall.ts +2 -0
  36. package/src/tools/hindsight-reflect.ts +2 -0
  37. package/src/tools/hindsight-retain.ts +2 -0
  38. package/src/tools/index.ts +74 -14
  39. package/src/tools/inspect-image.ts +2 -0
  40. package/src/tools/irc.ts +2 -1
  41. package/src/tools/job.ts +2 -1
  42. package/src/tools/notebook.ts +2 -0
  43. package/src/tools/read.ts +1 -0
  44. package/src/tools/recipe/index.ts +2 -0
  45. package/src/tools/render-mermaid.ts +2 -0
  46. package/src/tools/search-tool-bm25.ts +128 -42
  47. package/src/tools/search.ts +2 -0
  48. package/src/tools/ssh.ts +2 -0
  49. package/src/tools/todo-write.ts +2 -1
  50. package/src/tools/write.ts +2 -0
  51. package/src/web/search/index.ts +2 -0
  52. package/src/web/search/providers/searxng.ts +8 -0
@@ -0,0 +1,377 @@
1
+ import type { AgentTool } from "@oh-my-pi/pi-agent-core";
2
+
3
+ // ─── Generic Tool Discovery Types ────────────────────────────────────────────
4
+
5
+ export type DiscoverableToolSource = "builtin" | "mcp" | "extension" | "custom";
6
+
7
+ export interface DiscoverableTool {
8
+ name: string;
9
+ label: string;
10
+ /** Short BM25 corpus entry; falls back to description first 200 chars */
11
+ summary: string;
12
+ source: DiscoverableToolSource;
13
+ /** MCP only */
14
+ serverName?: string;
15
+ /** MCP only */
16
+ mcpToolName?: string;
17
+ schemaKeys: string[];
18
+ }
19
+
20
+ export interface DiscoverableToolServerSummary {
21
+ name: string;
22
+ toolCount: number;
23
+ }
24
+
25
+ export interface DiscoverableToolSummary {
26
+ servers: DiscoverableToolServerSummary[];
27
+ toolCount: number;
28
+ }
29
+
30
+ export interface DiscoverableToolSearchDocument {
31
+ tool: DiscoverableTool;
32
+ termFrequencies: Map<string, number>;
33
+ length: number;
34
+ }
35
+
36
+ export interface DiscoverableToolSearchIndex {
37
+ documents: DiscoverableToolSearchDocument[];
38
+ averageLength: number;
39
+ documentFrequencies: Map<string, number>;
40
+ }
41
+
42
+ export interface DiscoverableToolSearchResult {
43
+ tool: DiscoverableTool;
44
+ score: number;
45
+ }
46
+
47
+ // ─── Legacy MCP-typed aliases (back-compat) ──────────────────────────────────
48
+
49
+ /** @deprecated Use DiscoverableTool with source === "mcp" */
50
+ export type DiscoverableMCPTool = Pick<
51
+ DiscoverableTool,
52
+ "name" | "label" | "schemaKeys" | "serverName" | "mcpToolName"
53
+ > & { description: string };
54
+
55
+ /** @deprecated Use DiscoverableToolServerSummary */
56
+ export type DiscoverableMCPToolServerSummary = DiscoverableToolServerSummary;
57
+
58
+ /** @deprecated Use DiscoverableToolSummary */
59
+ export type DiscoverableMCPToolSummary = DiscoverableToolSummary;
60
+
61
+ /** Tool object stored on legacy MCP index documents. Carries both legacy `description` and the
62
+ * generic `summary`/`source` so the legacy index is structurally assignable to
63
+ * DiscoverableToolSearchIndex (search functions read termFrequencies, not the tool fields). */
64
+ export type DiscoverableMCPSearchTool = DiscoverableTool & { description: string };
65
+
66
+ /** @deprecated Use DiscoverableToolSearchDocument */
67
+ export interface DiscoverableMCPSearchDocument {
68
+ tool: DiscoverableMCPSearchTool;
69
+ termFrequencies: Map<string, number>;
70
+ length: number;
71
+ }
72
+
73
+ /** @deprecated Use DiscoverableToolSearchIndex.
74
+ * Documents on this index expose `tool.description` (legacy MCP shape) while still being
75
+ * searchable via `searchDiscoverableTools`. */
76
+ export interface DiscoverableMCPSearchIndex {
77
+ documents: DiscoverableMCPSearchDocument[];
78
+ averageLength: number;
79
+ documentFrequencies: Map<string, number>;
80
+ }
81
+
82
+ /** @deprecated Use DiscoverableToolSearchResult */
83
+ export interface DiscoverableMCPSearchResult {
84
+ tool: DiscoverableMCPSearchTool;
85
+ score: number;
86
+ }
87
+
88
+ // ─── BM25 Constants ───────────────────────────────────────────────────────────
89
+
90
+ const BM25_K1 = 1.2;
91
+ const BM25_B = 0.75;
92
+ const FIELD_WEIGHTS = {
93
+ name: 6,
94
+ label: 4,
95
+ serverName: 2,
96
+ mcpToolName: 4,
97
+ summary: 2,
98
+ schemaKey: 1,
99
+ } as const;
100
+
101
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
102
+
103
+ export function isMCPToolName(name: string): boolean {
104
+ return name.startsWith("mcp__");
105
+ }
106
+
107
+ function getSchemaPropertyKeys(parameters: unknown): string[] {
108
+ if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) return [];
109
+ const properties = (parameters as { properties?: unknown }).properties;
110
+ if (!properties || typeof properties !== "object" || Array.isArray(properties)) return [];
111
+ return Object.keys(properties as Record<string, unknown>).sort();
112
+ }
113
+
114
+ function tokenize(value: string): string[] {
115
+ return value
116
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
117
+ .replace(/[^a-zA-Z0-9]+/g, " ")
118
+ .toLowerCase()
119
+ .trim()
120
+ .split(/\s+/)
121
+ .filter(token => token.length > 0);
122
+ }
123
+
124
+ function addWeightedTokens(termFrequencies: Map<string, number>, value: string | undefined, weight: number): void {
125
+ if (!value) return;
126
+ for (const token of tokenize(value)) {
127
+ termFrequencies.set(token, (termFrequencies.get(token) ?? 0) + weight);
128
+ }
129
+ }
130
+
131
+ function buildSearchDocument(tool: DiscoverableTool): DiscoverableToolSearchDocument {
132
+ const termFrequencies = new Map<string, number>();
133
+ addWeightedTokens(termFrequencies, tool.name, FIELD_WEIGHTS.name);
134
+ addWeightedTokens(termFrequencies, tool.label, FIELD_WEIGHTS.label);
135
+ addWeightedTokens(termFrequencies, tool.serverName, FIELD_WEIGHTS.serverName);
136
+ addWeightedTokens(termFrequencies, tool.mcpToolName, FIELD_WEIGHTS.mcpToolName);
137
+ addWeightedTokens(termFrequencies, tool.summary, FIELD_WEIGHTS.summary);
138
+ for (const schemaKey of tool.schemaKeys) {
139
+ addWeightedTokens(termFrequencies, schemaKey, FIELD_WEIGHTS.schemaKey);
140
+ }
141
+ const length = Array.from(termFrequencies.values()).reduce((sum, value) => sum + value, 0);
142
+ return { tool, termFrequencies, length };
143
+ }
144
+
145
+ // ─── Generic Tool Discovery Functions ────────────────────────────────────────
146
+
147
+ /**
148
+ * Convert a raw AgentTool into a DiscoverableTool generic descriptor.
149
+ * source: "mcp" if name starts with "mcp__", else "builtin" (caller may override).
150
+ */
151
+ export function getDiscoverableTool(
152
+ tool: AgentTool,
153
+ overrides?: { source?: DiscoverableToolSource; summary?: string },
154
+ ): DiscoverableTool | null {
155
+ const toolRecord = tool as AgentTool & {
156
+ label?: string;
157
+ description?: string;
158
+ mcpServerName?: string;
159
+ summary?: string;
160
+ mcpToolName?: string;
161
+ parameters?: unknown;
162
+ };
163
+ const source: DiscoverableToolSource = overrides?.source ?? (isMCPToolName(tool.name) ? "mcp" : "builtin");
164
+ const rawSummary =
165
+ typeof overrides?.summary === "string"
166
+ ? overrides.summary
167
+ : typeof toolRecord.summary === "string"
168
+ ? toolRecord.summary
169
+ : undefined;
170
+ const rawDescription = typeof toolRecord.description === "string" ? toolRecord.description : "";
171
+ const summary = rawSummary ?? rawDescription.slice(0, 200);
172
+ return {
173
+ name: tool.name,
174
+ label: typeof toolRecord.label === "string" ? toolRecord.label : tool.name,
175
+ summary,
176
+ source,
177
+ serverName: typeof toolRecord.mcpServerName === "string" ? toolRecord.mcpServerName : undefined,
178
+ mcpToolName: typeof toolRecord.mcpToolName === "string" ? toolRecord.mcpToolName : undefined,
179
+ schemaKeys: getSchemaPropertyKeys(toolRecord.parameters),
180
+ };
181
+ }
182
+
183
+ /** Collect all DiscoverableTools from a tool iterable. Skips tools that return null. */
184
+ export function collectDiscoverableTools(
185
+ tools: Iterable<AgentTool>,
186
+ options?: { source?: DiscoverableToolSource; summaryMap?: Map<string, string> },
187
+ ): DiscoverableTool[] {
188
+ const discoverable: DiscoverableTool[] = [];
189
+ for (const tool of tools) {
190
+ const summary = options?.summaryMap?.get(tool.name);
191
+ const meta = getDiscoverableTool(tool, { source: options?.source, summary });
192
+ if (meta) {
193
+ discoverable.push(meta);
194
+ }
195
+ }
196
+ return discoverable;
197
+ }
198
+
199
+ /** Filter discoverable tools by source */
200
+ export function filterBySource(tools: DiscoverableTool[], source: DiscoverableToolSource): DiscoverableTool[] {
201
+ return tools.filter(t => t.source === source);
202
+ }
203
+
204
+ export function formatDiscoverableToolServerSummary(server: DiscoverableToolServerSummary): string {
205
+ const toolLabel = server.toolCount === 1 ? "tool" : "tools";
206
+ return `${server.name} (${server.toolCount} ${toolLabel})`;
207
+ }
208
+
209
+ export function selectDiscoverableToolNamesByServer(
210
+ tools: Iterable<DiscoverableTool>,
211
+ serverNames: ReadonlySet<string>,
212
+ ): string[] {
213
+ if (serverNames.size === 0) return [];
214
+ return Array.from(tools)
215
+ .filter(tool => tool.serverName !== undefined && serverNames.has(tool.serverName))
216
+ .map(tool => tool.name);
217
+ }
218
+
219
+ export function summarizeDiscoverableTools(tools: DiscoverableTool[]): DiscoverableToolSummary {
220
+ const serverToolCounts = new Map<string, number>();
221
+ for (const tool of tools) {
222
+ if (!tool.serverName) continue;
223
+ serverToolCounts.set(tool.serverName, (serverToolCounts.get(tool.serverName) ?? 0) + 1);
224
+ }
225
+ const servers = Array.from(serverToolCounts.entries())
226
+ .sort(([left], [right]) => left.localeCompare(right))
227
+ .map(([name, toolCount]) => ({ name, toolCount }));
228
+ return {
229
+ servers,
230
+ toolCount: tools.length,
231
+ };
232
+ }
233
+
234
+ export function buildDiscoverableToolSearchIndex(tools: Iterable<DiscoverableTool>): DiscoverableToolSearchIndex {
235
+ const documents = Array.from(tools, buildSearchDocument);
236
+ const averageLength = documents.reduce((sum, document) => sum + document.length, 0) / documents.length || 1;
237
+ const documentFrequencies = new Map<string, number>();
238
+ for (const document of documents) {
239
+ for (const token of new Set(document.termFrequencies.keys())) {
240
+ documentFrequencies.set(token, (documentFrequencies.get(token) ?? 0) + 1);
241
+ }
242
+ }
243
+ return {
244
+ documents,
245
+ averageLength,
246
+ documentFrequencies,
247
+ };
248
+ }
249
+
250
+ export function searchDiscoverableTools(
251
+ index: DiscoverableToolSearchIndex,
252
+ query: string,
253
+ limit: number,
254
+ ): DiscoverableToolSearchResult[] {
255
+ const queryTokens = tokenize(query);
256
+ if (queryTokens.length === 0) {
257
+ throw new Error("Query must contain at least one letter or number.");
258
+ }
259
+ if (index.documents.length === 0) {
260
+ return [];
261
+ }
262
+
263
+ const queryTermCounts = new Map<string, number>();
264
+ for (const token of queryTokens) {
265
+ queryTermCounts.set(token, (queryTermCounts.get(token) ?? 0) + 1);
266
+ }
267
+
268
+ return index.documents
269
+ .map(document => {
270
+ let score = 0;
271
+ for (const [token, queryTermCount] of queryTermCounts) {
272
+ const termFrequency = document.termFrequencies.get(token) ?? 0;
273
+ if (termFrequency === 0) continue;
274
+ const documentFrequency = index.documentFrequencies.get(token) ?? 0;
275
+ const idf = Math.log(1 + (index.documents.length - documentFrequency + 0.5) / (documentFrequency + 0.5));
276
+ const normalization = BM25_K1 * (1 - BM25_B + BM25_B * (document.length / index.averageLength));
277
+ score += queryTermCount * idf * ((termFrequency * (BM25_K1 + 1)) / (termFrequency + normalization));
278
+ }
279
+ return { tool: document.tool, score };
280
+ })
281
+ .filter(result => result.score > 0)
282
+ .sort((left, right) => right.score - left.score || left.tool.name.localeCompare(right.tool.name))
283
+ .slice(0, limit);
284
+ }
285
+
286
+ // ─── Legacy MCP-specific shims (back-compat wrappers) ────────────────────────
287
+
288
+ /** @deprecated Use getDiscoverableTool */
289
+ export function getDiscoverableMCPTool(tool: AgentTool): DiscoverableMCPTool | null {
290
+ if (!isMCPToolName(tool.name)) return null;
291
+ const toolRecord = tool as AgentTool & {
292
+ label?: string;
293
+ description?: string;
294
+ mcpServerName?: string;
295
+ mcpToolName?: string;
296
+ parameters?: unknown;
297
+ };
298
+ return {
299
+ name: tool.name,
300
+ label: typeof toolRecord.label === "string" ? toolRecord.label : tool.name,
301
+ description: typeof toolRecord.description === "string" ? toolRecord.description : "",
302
+ serverName: typeof toolRecord.mcpServerName === "string" ? toolRecord.mcpServerName : undefined,
303
+ mcpToolName: typeof toolRecord.mcpToolName === "string" ? toolRecord.mcpToolName : undefined,
304
+ schemaKeys: getSchemaPropertyKeys(toolRecord.parameters),
305
+ };
306
+ }
307
+
308
+ /** @deprecated Use collectDiscoverableTools with source filter */
309
+ export function collectDiscoverableMCPTools(tools: Iterable<AgentTool>): DiscoverableMCPTool[] {
310
+ const discoverable: DiscoverableMCPTool[] = [];
311
+ for (const tool of tools) {
312
+ const metadata = getDiscoverableMCPTool(tool);
313
+ if (metadata) {
314
+ discoverable.push(metadata);
315
+ }
316
+ }
317
+ return discoverable;
318
+ }
319
+
320
+ /** @deprecated Use selectDiscoverableToolNamesByServer */
321
+ export function selectDiscoverableMCPToolNamesByServer(
322
+ tools: Iterable<DiscoverableMCPTool>,
323
+ serverNames: ReadonlySet<string>,
324
+ ): string[] {
325
+ if (serverNames.size === 0) return [];
326
+ return Array.from(tools)
327
+ .filter(tool => tool.serverName !== undefined && serverNames.has(tool.serverName))
328
+ .map(tool => tool.name);
329
+ }
330
+
331
+ /** @deprecated Use summarizeDiscoverableTools */
332
+ export function summarizeDiscoverableMCPTools(tools: DiscoverableMCPTool[]): DiscoverableMCPToolSummary {
333
+ const serverToolCounts = new Map<string, number>();
334
+ for (const tool of tools) {
335
+ if (!tool.serverName) continue;
336
+ serverToolCounts.set(tool.serverName, (serverToolCounts.get(tool.serverName) ?? 0) + 1);
337
+ }
338
+ const servers = Array.from(serverToolCounts.entries())
339
+ .sort(([left], [right]) => left.localeCompare(right))
340
+ .map(([name, toolCount]) => ({ name, toolCount }));
341
+ return {
342
+ servers,
343
+ toolCount: tools.length,
344
+ };
345
+ }
346
+
347
+ /** @deprecated Use buildDiscoverableToolSearchIndex.
348
+ * Builds an index whose documents preserve the legacy `description` field on each tool while
349
+ * also carrying the generic `summary` (set from `description`) so the index remains usable
350
+ * with `searchDiscoverableTools`. */
351
+ export function buildDiscoverableMCPSearchIndex(tools: Iterable<DiscoverableMCPTool>): DiscoverableMCPSearchIndex {
352
+ const adapted: DiscoverableMCPSearchTool[] = Array.from(tools).map(t => ({
353
+ name: t.name,
354
+ label: t.label,
355
+ description: t.description,
356
+ summary: t.description,
357
+ source: "mcp" as DiscoverableToolSource,
358
+ serverName: t.serverName,
359
+ mcpToolName: t.mcpToolName,
360
+ schemaKeys: t.schemaKeys,
361
+ }));
362
+ const generic = buildDiscoverableToolSearchIndex(adapted);
363
+ // Documents reference `adapted` tools (with `description`), so the cast is sound.
364
+ return generic as unknown as DiscoverableMCPSearchIndex;
365
+ }
366
+
367
+ /** @deprecated Use searchDiscoverableTools */
368
+ export function searchDiscoverableMCPTools(
369
+ index: DiscoverableMCPSearchIndex | DiscoverableToolSearchIndex,
370
+ query: string,
371
+ limit: number,
372
+ ): DiscoverableMCPSearchResult[] {
373
+ return searchDiscoverableTools(index as DiscoverableToolSearchIndex, query, limit) as DiscoverableMCPSearchResult[];
374
+ }
375
+
376
+ /** @deprecated Use formatDiscoverableToolServerSummary */
377
+ export const formatDiscoverableMCPToolServerSummary = formatDiscoverableToolServerSummary;
package/src/tools/ask.ts CHANGED
@@ -379,9 +379,11 @@ type AskParams = AskToolInput;
379
379
  export class AskTool implements AgentTool<typeof askSchema, AskToolDetails> {
380
380
  readonly name = "ask";
381
381
  readonly label = "Ask";
382
+ readonly summary = "Ask the user a clarifying question";
382
383
  readonly description: string;
383
384
  readonly parameters = askSchema;
384
385
  readonly strict = true;
386
+ readonly loadMode = "discoverable";
385
387
 
386
388
  constructor(private readonly session: ToolSession) {
387
389
  this.description = prompt.render(askDescription);
@@ -167,10 +167,12 @@ export interface AstEditToolDetails {
167
167
  export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolDetails> {
168
168
  readonly name = "ast_edit";
169
169
  readonly label = "AST Edit";
170
+ readonly summary = "Perform AST-aware code edits (structural refactoring)";
170
171
  readonly description: string;
171
172
  readonly parameters = astEditSchema;
172
173
  readonly strict = true;
173
174
  readonly deferrable = true;
175
+ readonly loadMode = "discoverable";
174
176
  constructor(private readonly session: ToolSession) {
175
177
  this.description = prompt.render(astEditDescription);
176
178
  }
@@ -122,9 +122,11 @@ export interface AstGrepToolDetails {
122
122
  export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolDetails> {
123
123
  readonly name = "ast_grep";
124
124
  readonly label = "AST Grep";
125
+ readonly summary = "Search code with AST patterns (structural grep)";
125
126
  readonly description: string;
126
127
  readonly parameters = astGrepSchema;
127
128
  readonly strict = true;
129
+ readonly loadMode = "discoverable";
128
130
 
129
131
  constructor(private readonly session: ToolSession) {
130
132
  this.description = prompt.render(astGrepDescription);
package/src/tools/bash.ts CHANGED
@@ -236,6 +236,7 @@ function formatTimeoutClampNotice(requestedTimeoutSec: number, effectiveTimeoutS
236
236
  export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
237
237
  readonly name = "bash";
238
238
  readonly label = "Bash";
239
+ readonly loadMode = "essential";
239
240
  readonly description: string;
240
241
  readonly parameters: BashToolSchema;
241
242
  readonly concurrency = "exclusive";
@@ -110,6 +110,8 @@ function resolveBrowserKind(params: BrowserParams, session: ToolSession): Browse
110
110
  export class BrowserTool implements AgentTool<typeof browserSchema, BrowserToolDetails> {
111
111
  readonly name = "browser";
112
112
  readonly label = "Browser";
113
+ readonly loadMode = "discoverable";
114
+ readonly summary = "Control a headless browser to navigate and interact with web pages";
113
115
  readonly parameters = browserSchema;
114
116
  readonly strict = true;
115
117
 
@@ -396,6 +396,8 @@ type CalculatorParams = Static<typeof calculatorSchema>;
396
396
  export class CalculatorTool implements AgentTool<typeof calculatorSchema, CalculatorToolDetails> {
397
397
  readonly name = "calc";
398
398
  readonly label = "Calc";
399
+ readonly summary = "Evaluate a mathematical expression";
400
+ readonly loadMode = "discoverable";
399
401
  readonly description: string;
400
402
  readonly parameters = calculatorSchema;
401
403
  readonly strict = true;
@@ -49,9 +49,11 @@ function isTopLevelSession(session: ToolSession): boolean {
49
49
  export class CheckpointTool implements AgentTool<typeof checkpointSchema, CheckpointToolDetails> {
50
50
  readonly name = "checkpoint";
51
51
  readonly label = "Checkpoint";
52
+ readonly summary = "Create a git-based checkpoint to save and restore session state";
52
53
  readonly description: string;
53
54
  readonly parameters = checkpointSchema;
54
55
  readonly strict = true;
56
+ readonly loadMode = "discoverable";
55
57
  readonly intent = (args: Partial<CheckpointParams>) => (args.goal ? `checkpointing: ${args.goal}` : "checkpointing");
56
58
 
57
59
  constructor(private readonly session: ToolSession) {
@@ -92,9 +94,11 @@ export class CheckpointTool implements AgentTool<typeof checkpointSchema, Checkp
92
94
  export class RewindTool implements AgentTool<typeof rewindSchema, RewindToolDetails> {
93
95
  readonly name = "rewind";
94
96
  readonly label = "Rewind";
97
+ readonly summary = "Rewind to a previously created checkpoint";
95
98
  readonly description: string;
96
99
  readonly parameters = rewindSchema;
97
100
  readonly strict = true;
101
+ readonly loadMode = "discoverable";
98
102
  readonly intent = (): string => "rewinding";
99
103
 
100
104
  constructor(private readonly session: ToolSession) {
@@ -597,10 +597,12 @@ export const debugToolRenderer = {
597
597
  export class DebugTool implements AgentTool<typeof debugSchema, DebugToolDetails> {
598
598
  readonly name = "debug";
599
599
  readonly label = "Debug";
600
+ readonly summary = "Debug a running process with DAP (debugger adapter protocol)";
600
601
  readonly description: string;
601
602
  readonly parameters = debugSchema;
602
603
  readonly strict = true;
603
604
  readonly concurrency = "exclusive";
605
+ readonly loadMode = "discoverable";
604
606
 
605
607
  constructor(private readonly session: ToolSession) {
606
608
  this.description = prompt.render(debugDescription);
package/src/tools/eval.ts CHANGED
@@ -207,6 +207,8 @@ async function resolveBackend(
207
207
 
208
208
  export class EvalTool implements AgentTool<typeof evalSchema> {
209
209
  readonly name = "eval";
210
+ readonly summary = "Execute Python or JavaScript code in an in-process eval backend";
211
+ readonly loadMode = "discoverable";
210
212
  readonly label = "Eval";
211
213
  get description(): string {
212
214
  if (!this.session) return getEvalToolDescription();
package/src/tools/find.ts CHANGED
@@ -88,6 +88,8 @@ export interface FindToolOptions {
88
88
 
89
89
  export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
90
90
  readonly name = "find";
91
+ readonly summary = "Find files and directories matching a glob pattern";
92
+ readonly loadMode = "discoverable";
91
93
  readonly label = "Find";
92
94
  readonly description: string;
93
95
  readonly parameters = findSchema;
package/src/tools/gh.ts CHANGED
@@ -2087,6 +2087,8 @@ function buildTextResult(
2087
2087
 
2088
2088
  export class GithubTool implements AgentTool<typeof githubSchema, GhToolDetails> {
2089
2089
  readonly name = "github";
2090
+ readonly summary = "Interact with GitHub issues, pull requests, and repositories";
2091
+ readonly loadMode = "discoverable";
2090
2092
  readonly label = "GitHub";
2091
2093
  readonly description = prompt.render(githubDescription);
2092
2094
  readonly parameters = githubSchema;
@@ -19,6 +19,8 @@ export class HindsightRecallTool implements AgentTool<typeof hindsightRecallSche
19
19
  readonly description = recallDescription;
20
20
  readonly parameters = hindsightRecallSchema;
21
21
  readonly strict = true;
22
+ readonly loadMode = "discoverable";
23
+ readonly summary = "Search hindsight memory for relevant prior context";
22
24
 
23
25
  constructor(private readonly session: ToolSession) {}
24
26
 
@@ -18,6 +18,8 @@ export class HindsightReflectTool implements AgentTool<typeof hindsightReflectSc
18
18
  readonly description = reflectDescription;
19
19
  readonly parameters = hindsightReflectSchema;
20
20
  readonly strict = true;
21
+ readonly loadMode = "discoverable";
22
+ readonly summary = "Reflect on recent work and write hindsight memory";
21
23
 
22
24
  constructor(private readonly session: ToolSession) {}
23
25
 
@@ -28,6 +28,8 @@ export class HindsightRetainTool implements AgentTool<typeof hindsightRetainSche
28
28
  readonly description = retainDescription;
29
29
  readonly parameters = hindsightRetainSchema;
30
30
  readonly strict = true;
31
+ readonly loadMode = "discoverable";
32
+ readonly summary = "Store important facts in hindsight memory";
31
33
 
32
34
  constructor(private readonly session: ToolSession) {}
33
35