diff --git a/docs/config-usage.md b/docs/config-usage.md index c6b9bd60d..561a73753 100644 --- a/docs/config-usage.md +++ b/docs/config-usage.md @@ -119,7 +119,7 @@ Supported formats: Behavior: -- Validates parsed data with AJV against a provided TypeBox schema. +- Validates parsed data against a provided Zod schema. - Caches load result until `invalidate()`. - Returns tri-state result via `tryLoad()`: - `ok` diff --git a/docs/custom-tools.md b/docs/custom-tools.md index a953920b9..46b85541b 100644 --- a/docs/custom-tools.md +++ b/docs/custom-tools.md @@ -6,7 +6,7 @@ A custom tool is a TypeScript/JavaScript module that exports a factory. The fact ## What this is (and is not) -- **Custom tool**: callable by the model during a turn (`execute` + Zod parameter schema; legacy TypeBox is still accepted and lifted to Zod at registration). +- **Custom tool**: callable by the model during a turn (`execute` + Zod parameter schema). - **Extension**: lifecycle/event framework that can register tools and intercept/modify events. - **Hook**: external pre/post command scripts. - **Skill**: static guidance/context package, not executable tool code. @@ -105,7 +105,7 @@ const factory: CustomToolFactory = (pi) => ({ export default factory; ``` -Legacy TypeBox-authored factories can still call `pi.typebox` — it's now a small Zod-backed shim (`Type.Object`, `Type.String`, etc.) baked into the host, not the real `@sinclair/typebox` package. Schemas flow through the same Zod pipeline as `pi.zod` and need no separate normalization. +Schemas are authored with Zod (`pi.zod`) and flow through the shared validation/wire pipeline. Factory return type: @@ -122,8 +122,7 @@ From `types.ts` and `loader.ts`: - `ui`: UI context (can be no-op in headless modes) - `hasUI`: `false` in non-interactive flows - `logger`: shared file logger -- `zod`: injected `zod` module (**preferred** for new tool schemas; use `pi.zod.object`, `pi.zod.string`, …) -- `typebox`: injected zod-backed `Type.*` shim (legacy extension compatibility) +- `zod`: injected `zod` module (use `pi.zod.object`, `pi.zod.string`, …) - `pi`: injected `@oh-my-pi/pi-coding-agent` exports - `pushPendingAction(action)`: register a preview action for hidden `resolve` tool (`docs/resolve-tool-runtime.md`) @@ -137,7 +136,7 @@ Loader starts with a no-op UI context and requires host code to call `setUIConte execute(toolCallId, params, onUpdate, ctx, signal); ``` -- `params` is statically typed from your Zod schema via `z.infer` (`Static` in API types). Legacy TypeBox schemas are lifted to Zod internally. +- `params` is statically typed from your Zod schema via `z.infer` (`Static` in API types). - Runtime argument validation happens before execution in the agent loop. - `onUpdate` emits partial results for UI streaming. - `ctx` includes session/model state and an `abort()` helper. diff --git a/docs/extensions.md b/docs/extensions.md index 1953a98d5..6b40ba71c 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -125,8 +125,7 @@ In interactive mode, `input` handlers run before the built-in first-message auto Also exposed: - `pi.logger` -- `pi.zod` (injected `zod` module — **preferred** for new tool schemas) -- `pi.typebox` (zod-backed `Type.*` shim — retained for legacy extension compat) +- `pi.zod` (injected `zod` module — use for tool parameter schemas) - `pi.pi` (package exports) ### Message delivery semantics diff --git a/docs/theme.md b/docs/theme.md index 98512bff5..a7129059e 100644 --- a/docs/theme.md +++ b/docs/theme.md @@ -341,6 +341,6 @@ Use this workflow: - All `colors` tokens are required for custom themes. - `export` and `symbols` are optional. -- `$schema` in theme JSON is informational; runtime validation is enforced by compiled TypeBox schema in code. +- `$schema` in theme JSON is informational; runtime validation is enforced by a Zod schema in code. - `setTheme` failure falls back to `dark`; `previewTheme` failure does not replace current theme. - File watcher reload errors or temporary missing files keep the current loaded theme until a successful reload or explicit theme switch. diff --git a/docs/tools/checkpoint.md b/docs/tools/checkpoint.md index 0dcdbe881..545e3dd4e 100644 --- a/docs/tools/checkpoint.md +++ b/docs/tools/checkpoint.md @@ -15,7 +15,7 @@ | Field | Type | Required | Description | | --- | --- | --- | --- | -| `goal` | `string` | Yes | Investigation goal. Required by the TypeBox schema and echoed in the tool result. | +| `goal` | `string` | Yes | Investigation goal. Required by the schema and echoed in the tool result. | ## Outputs The tool returns a single text result plus structured details: diff --git a/packages/agent/README.md b/packages/agent/README.md index ce3a8e160..eb089dcd4 100644 --- a/packages/agent/README.md +++ b/packages/agent/README.md @@ -279,7 +279,7 @@ const agent = new Agent({ ## Tools -Define tools using `AgentTool` with a Zod parameter schema (via `z` from `@oh-my-pi/pi-ai`). Legacy TypeBox-authored schemas are still accepted at runtime and are lifted to Zod internally. +Define tools using `AgentTool` with a Zod parameter schema (via `z` from `@oh-my-pi/pi-ai`). ```typescript import { z } from "@oh-my-pi/pi-ai"; diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 1a424198b..3cbec957b 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -5,6 +5,7 @@ - Renamed public schema utilities in `@oh-my-pi/pi-ai/utils/schema` by replacing `sanitizeSchemaForGoogle`, `sanitizeSchemaForCCA`, `prepareSchemaForCCA`, and `sanitizeSchemaForMCP` with `normalizeSchemaForGoogle`, `normalizeSchemaForCCA`, and `normalizeSchemaForMCP` - Added MCP schema normalization via `normalizeSchemaForMCP` for compatibility checks +- Removed the `StringEnum` helper from `@oh-my-pi/pi-ai/utils/schema`. Use `z.enum([...])` directly; Zod's emitted JSON Schema is already wire-compatible with Google and other providers. ### Changed diff --git a/packages/ai/README.md b/packages/ai/README.md index 333d993ec..3ada12a74 100644 --- a/packages/ai/README.md +++ b/packages/ai/README.md @@ -89,7 +89,7 @@ npm install @oh-my-pi/pi-ai ## Quick Start ```typescript -import { z, getModel, stream, complete, Context, Tool, StringEnum } from "@oh-my-pi/pi-ai"; +import { z, getModel, stream, complete, Context, Tool } from "@oh-my-pi/pi-ai"; // Fully typed with auto-complete support for both providers and models const model = getModel("openai", "gpt-4o-mini"); @@ -221,7 +221,7 @@ Tools enable LLMs to interact with external systems. This library uses **Zod** s ### Defining Tools ```typescript -import { z, Tool, StringEnum } from "@oh-my-pi/pi-ai"; +import { z, Tool } from "@oh-my-pi/pi-ai"; // Define tool parameters with Zod const weatherTool: Tool = { @@ -229,13 +229,10 @@ const weatherTool: Tool = { description: "Get current weather for a location", parameters: z.object({ location: z.string().describe("City name or coordinates"), - units: StringEnum(["celsius", "fahrenheit"], { default: "celsius" }), + units: z.enum(["celsius", "fahrenheit"]).default("celsius"), }), }; -// Note: For Google API compatibility, use the StringEnum helper instead of z.enum alone -// when you need wire-compatible { type: "string", enum: [...] } shapes. - const bookMeetingTool: Tool = { name: "book_meeting", description: "Schedule a meeting", diff --git a/packages/ai/test/stream.test.ts b/packages/ai/test/stream.test.ts index 3a8d397a1..e7c6b9655 100644 --- a/packages/ai/test/stream.test.ts +++ b/packages/ai/test/stream.test.ts @@ -6,7 +6,6 @@ import { Effort } from "@oh-my-pi/pi-ai"; import { getBundledModel } from "@oh-my-pi/pi-ai/models"; import { complete, getEnvApiKey, stream } from "@oh-my-pi/pi-ai/stream"; import type { Api, Context, ImageContent, Model, OptionsForApi, Tool, ToolResultMessage } from "@oh-my-pi/pi-ai/types"; -import { StringEnum } from "@oh-my-pi/pi-ai/utils/schema"; import { $which } from "@oh-my-pi/pi-utils"; import * as z from "zod/v4"; import { e2eApiKey, resolveApiKey } from "./oauth"; @@ -34,14 +33,12 @@ function hasBedrockCredentials(): boolean { } // Calculator tool definition (same as examples) -// Note: Using StringEnum helper because Google's API doesn't support anyOf/const patterns -// that some schema authors emit for string unions. Google requires { type: "string", enum: [...] } format. const calculatorSchema = z.object({ a: z.number().describe("First number"), b: z.number().describe("Second number"), - operation: StringEnum(["add", "subtract", "multiply", "divide"], { - description: "The operation to perform. One of 'add', 'subtract', 'multiply', 'divide'.", - }), + operation: z + .enum(["add", "subtract", "multiply", "divide"]) + .describe("The operation to perform. One of 'add', 'subtract', 'multiply', 'divide'."), }); const calculatorTool: Tool = { diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index dba4f9f41..80f2940fc 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -5,6 +5,7 @@ ### Breaking Changes - Renamed the embedded-documentation internal URL scheme from `pi://` to `omp://`. `OmpProtocolHandler` replaces `PiProtocolHandler`; update any external references accordingly. +- Removed the `StringEnum` re-export from `@oh-my-pi/pi-coding-agent`. Custom tools and extensions should use `z.enum([...])` directly via the injected `pi.zod`. ## [15.1.2] - 2026-05-15 ### Fixed diff --git a/packages/coding-agent/examples/custom-tools/README.md b/packages/coding-agent/examples/custom-tools/README.md index 0c88fb304..e0e0e12c3 100644 --- a/packages/coding-agent/examples/custom-tools/README.md +++ b/packages/coding-agent/examples/custom-tools/README.md @@ -47,7 +47,6 @@ See [docs/custom-tools.md](../../docs/custom-tools.md) for full documentation. **Factory pattern:** ```typescript -import { StringEnum } from "@oh-my-pi/pi-ai"; import { Text } from "@oh-my-pi/pi-tui"; import type { CustomToolFactory } from "@oh-my-pi/pi-coding-agent"; @@ -56,7 +55,7 @@ const factory: CustomToolFactory = (pi) => ({ label: "My Tool", description: "Tool description for LLM", parameters: pi.zod.object({ - action: StringEnum(["list", "add"] as const), + action: pi.zod.enum(["list", "add"]), }), // Called on session start/switch/branch/clear @@ -76,9 +75,6 @@ const factory: CustomToolFactory = (pi) => ({ export default factory; ``` - -**Legacy:** `parameters: pi.typebox.Type.Object({ ... })` still works; the injected `typebox` is a small Zod-backed shim, and schemas flow through the same Zod pipeline as `pi.zod` schemas. - **Custom rendering:** ```typescript @@ -97,17 +93,12 @@ renderResult(result, { expanded, isPartial }, theme) { }, ``` -**Use `StringEnum` for discriminated string tool args** (required for Google API compatibility): +**Use `z.enum` for discriminated string tool args:** ```typescript -import { StringEnum } from "@oh-my-pi/pi-ai"; - const { z } = pi.zod; -// Good — Google-safe enum wiring parameters: z.object({ - action: StringEnum(["list", "add"] as const), + action: z.enum(["list", "add"]), }); - -// Avoid raw union-of-literals patterns that don't degrade well for strict JSON Schema providers ``` diff --git a/packages/coding-agent/examples/extensions/README.md b/packages/coding-agent/examples/extensions/README.md index 747d33c9d..f0624d9e0 100644 --- a/packages/coding-agent/examples/extensions/README.md +++ b/packages/coding-agent/examples/extensions/README.md @@ -108,29 +108,16 @@ export default function (pi: ExtensionAPI) { }); } ``` - -**Legacy TypeBox-style schemas** (`pi.typebox`) remain available for older extensions and are backed by a tiny Zod-shim — prefer `pi.zod` directly for new code. - -```typescript -const { Type } = pi.typebox; -parameters: Type.Object({ name: Type.String() }); -``` - ## Key Patterns -**Use `StringEnum` for discriminated string tool args** (required for Google API compatibility): +**Use `z.enum` for discriminated string tool args:** ```typescript -import { StringEnum } from "@oh-my-pi/pi-ai"; - const { z } = pi.zod; -// Good — Google-safe enum wiring parameters: z.object({ - action: StringEnum(["list", "add"] as const), + action: z.enum(["list", "add"]), }); - -// Avoid raw union-of-literals patterns that don't degrade well for strict JSON Schema providers ``` **State persistence via details:** diff --git a/packages/coding-agent/examples/extensions/api-demo.ts b/packages/coding-agent/examples/extensions/api-demo.ts index 9883e6c59..aaf12084d 100644 --- a/packages/coding-agent/examples/extensions/api-demo.ts +++ b/packages/coding-agent/examples/extensions/api-demo.ts @@ -10,9 +10,6 @@ import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent"; export default function (pi: ExtensionAPI) { const { z } = pi.zod; - // Access shared schema helpers from package exports (e.g. StringEnum for Google-safe enums) - const { StringEnum } = pi.pi; - // Access the logger for debugging pi.logger.debug("API demo extension loaded"); @@ -22,10 +19,7 @@ export default function (pi: ExtensionAPI) { description: "Demonstrates ExtensionAPI capabilities: logger, zod, and pi module access", parameters: z.object({ message: z.string().describe("Test message"), - logLevel: StringEnum(["error", "warn", "debug"], { - description: "Log level to use", - default: "debug", - }), + logLevel: z.enum(["error", "warn", "debug"]).default("debug").describe("Log level to use"), }), async execute(_toolCallId, params, _onUpdate, ctx, _signal) { diff --git a/packages/coding-agent/src/autoresearch/tools/init-experiment.ts b/packages/coding-agent/src/autoresearch/tools/init-experiment.ts index c1db6854c..55065d04d 100644 --- a/packages/coding-agent/src/autoresearch/tools/init-experiment.ts +++ b/packages/coding-agent/src/autoresearch/tools/init-experiment.ts @@ -17,42 +17,20 @@ export const DEFAULT_HARNESS_COMMAND = `bash ${HARNESS_FILENAME}`; const HARNESS_COMMIT_TITLE = "autoresearch: harness setup"; const initExperimentSchema = z.object({ - name: z.string().describe("Human-readable experiment name."), - goal: z.string().describe("Free-form description of what this session optimizes.").optional(), - primary_metric: z - .string() - .describe( - "Primary metric name shown in the dashboard. Match the `METRIC =` lines printed by the benchmark.", - ), - metric_unit: z.string().describe("Unit for the primary metric (e.g. ms, µs, mb). Empty when unitless.").optional(), + name: z.string().describe("experiment name"), + goal: z.string().describe("session goal").optional(), + primary_metric: z.string().describe("primary metric name"), + metric_unit: z.string().describe("metric unit (e.g. ms, µs, mb)").optional(), direction: z .enum(["lower", "higher"] as const) - .describe("Whether lower or higher values are better. Defaults to lower.") - .optional(), - secondary_metrics: z - .array(z.string()) - .describe("Names of secondary metrics tracked alongside the primary metric.") - .optional(), - scope_paths: z - .array(z.string()) - .describe( - "Files or directories the agent expects to modify. Used post-hoc to flag scope deviations on log_experiment; never used to block edits.", - ) - .optional(), - off_limits: z - .array(z.string()) - .describe( - "Paths the agent SHOULD NOT modify. Used post-hoc to flag scope deviations on log_experiment; never used to block edits.", - ) - .optional(), - constraints: z.array(z.string()).describe("Free-form constraints (e.g. 'no api break').").optional(), - max_iterations: z.number().describe("Soft cap on iterations per segment. Optional.").optional(), - new_segment: z - .boolean() - .describe( - "When true, bump to a new segment even when an active session exists. New baselines and best-metric reset.", - ) + .describe("better direction (default lower)") .optional(), + secondary_metrics: z.array(z.string()).describe("secondary metric names").optional(), + scope_paths: z.array(z.string()).describe("expected-to-modify paths").optional(), + off_limits: z.array(z.string()).describe("off-limits paths").optional(), + constraints: z.array(z.string()).describe("free-form constraints").optional(), + max_iterations: z.number().describe("soft iteration cap per segment").optional(), + new_segment: z.boolean().describe("bump to a new segment in existing session").optional(), }); interface InitExperimentDetails { diff --git a/packages/coding-agent/src/autoresearch/tools/log-experiment.ts b/packages/coding-agent/src/autoresearch/tools/log-experiment.ts index bb6ea635b..e0514bd43 100644 --- a/packages/coding-agent/src/autoresearch/tools/log-experiment.ts +++ b/packages/coding-agent/src/autoresearch/tools/log-experiment.ts @@ -37,35 +37,21 @@ import type { const EXPERIMENT_TOOL_NAMES = ["init_experiment", "run_experiment", "log_experiment", "update_notes"]; const logExperimentSchema = z.object({ - metric: z - .number() - .describe("Primary metric value for this run. May differ from the parsed value; deviation is recorded."), - status: z.enum(["keep", "discard", "crash", "checks_failed"] as const).describe("Outcome for this run."), - description: z.string().describe("Short description of the experiment."), - metrics: z.record(z.string(), z.number()).describe("Secondary metrics for this run.").optional(), - asi: z - .object({}) - .passthrough() - .describe("Free-form structured metadata captured for this run (hypothesis, learnings, etc.).") - .optional(), - commit: z - .string() - .describe("Override the commit hash recorded for this run. Defaults to the current HEAD.") - .optional(), - justification: z - .string() - .describe( - "Required when the run modifies paths outside scope or inside off-limits and you still want it kept. Free-form explanation.", - ) - .optional(), + metric: z.number().describe("primary metric value"), + status: z.enum(["keep", "discard", "crash", "checks_failed"] as const).describe("run outcome"), + description: z.string().describe("short run description"), + metrics: z.record(z.string(), z.number()).describe("secondary metrics").optional(), + asi: z.object({}).passthrough().describe("free-form structured metadata").optional(), + commit: z.string().describe("override recorded commit hash").optional(), + justification: z.string().describe("required when keeping a scope-deviating run").optional(), flag_runs: z .array( z.object({ - run_id: z.number().describe("Run id (#) of a previously logged run to flag as suspect."), - reason: z.string().describe("Why this earlier run is suspect (e.g. reward-hacked, broken metric)."), + run_id: z.number().describe("run id to flag"), + reason: z.string().describe("why this run is suspect"), }), ) - .describe("Mark earlier runs as flagged. Flagged runs are excluded from baseline and best-metric math.") + .describe("flag earlier runs as suspect") .optional(), }); diff --git a/packages/coding-agent/src/autoresearch/tools/run-experiment.ts b/packages/coding-agent/src/autoresearch/tools/run-experiment.ts index 59d06d69e..34a6f08c4 100644 --- a/packages/coding-agent/src/autoresearch/tools/run-experiment.ts +++ b/packages/coding-agent/src/autoresearch/tools/run-experiment.ts @@ -27,7 +27,7 @@ import type { AutoresearchToolFactoryOptions, RunDetails, RunExperimentProgressD import { DEFAULT_HARNESS_COMMAND } from "./init-experiment"; const runExperimentSchema = z.object({ - timeout_seconds: z.number().describe("Timeout in seconds. Defaults to 600.").optional(), + timeout_seconds: z.number().describe("timeout in seconds (default 600)").optional(), }); interface ProcessExecutionResult { diff --git a/packages/coding-agent/src/autoresearch/tools/update-notes.ts b/packages/coding-agent/src/autoresearch/tools/update-notes.ts index d5b378a96..90118040c 100644 --- a/packages/coding-agent/src/autoresearch/tools/update-notes.ts +++ b/packages/coding-agent/src/autoresearch/tools/update-notes.ts @@ -9,15 +9,8 @@ import { openAutoresearchStorageIfExists } from "../storage"; import type { AutoresearchToolFactoryOptions } from "../types"; const updateNotesSchema = z.object({ - body: z - .string() - .describe("Replacement markdown body for the active autoresearch session's notes (your durable playbook)."), - append_idea: z - .string() - .describe( - "When set, append this string as a new bullet under an Ideas section instead of replacing the body. `body` is ignored.", - ) - .optional(), + body: z.string().describe("replacement notes body"), + append_idea: z.string().describe("append as bullet under Ideas instead of replacing body").optional(), }); interface UpdateNotesDetails { diff --git a/packages/coding-agent/src/commit/agentic/tools/analyze-file.ts b/packages/coding-agent/src/commit/agentic/tools/analyze-file.ts index 38c0055b0..78f0e7b2b 100644 --- a/packages/coding-agent/src/commit/agentic/tools/analyze-file.ts +++ b/packages/coding-agent/src/commit/agentic/tools/analyze-file.ts @@ -13,8 +13,8 @@ import type { ToolSession } from "../../../tools"; import { getFilePriority } from "./git-file-diff"; const analyzeFileSchema = z.object({ - files: z.array(z.string().describe("File path")).min(1), - goal: z.string().describe("Optional analysis focus").optional(), + files: z.array(z.string().describe("file path")).min(1), + goal: z.string().describe("analysis focus").optional(), }); const analyzeFileOutputSchema = { diff --git a/packages/coding-agent/src/commit/agentic/tools/git-file-diff.ts b/packages/coding-agent/src/commit/agentic/tools/git-file-diff.ts index 345413e70..bba265821 100644 --- a/packages/coding-agent/src/commit/agentic/tools/git-file-diff.ts +++ b/packages/coding-agent/src/commit/agentic/tools/git-file-diff.ts @@ -132,8 +132,8 @@ function processDiffs(files: string[], diffs: Map): { result: st } const gitFileDiffSchema = z.object({ - files: z.array(z.string().describe("Files to diff")).min(1).max(10), - staged: z.boolean().describe("Use staged changes (default: true)").optional(), + files: z.array(z.string().describe("file to diff")).min(1).max(10), + staged: z.boolean().describe("use staged changes (default true)").optional(), }); export function createGitFileDiffTool(cwd: string, state: CommitAgentState): CustomTool { diff --git a/packages/coding-agent/src/commit/agentic/tools/git-hunk.ts b/packages/coding-agent/src/commit/agentic/tools/git-hunk.ts index 37cd1272b..1f0044e7b 100644 --- a/packages/coding-agent/src/commit/agentic/tools/git-hunk.ts +++ b/packages/coding-agent/src/commit/agentic/tools/git-hunk.ts @@ -4,9 +4,9 @@ import type { CustomTool } from "../../../extensibility/custom-tools/types"; import * as git from "../../../utils/git"; const gitHunkSchema = z.object({ - file: z.string().describe("File path"), - hunks: z.array(z.number().describe("1-based hunk indices")).min(1).optional(), - staged: z.boolean().describe("Use staged changes (default: true)").optional(), + file: z.string().describe("file path"), + hunks: z.array(z.number().describe("1-based hunk index")).min(1).optional(), + staged: z.boolean().describe("use staged changes (default true)").optional(), }); function selectHunks(fileHunks: FileHunks, requested?: number[]): DiffHunk[] { diff --git a/packages/coding-agent/src/commit/agentic/tools/git-overview.ts b/packages/coding-agent/src/commit/agentic/tools/git-overview.ts index 3e66f52c1..b8b22faaf 100644 --- a/packages/coding-agent/src/commit/agentic/tools/git-overview.ts +++ b/packages/coding-agent/src/commit/agentic/tools/git-overview.ts @@ -43,8 +43,8 @@ function filterExcludedFiles(files: string[]): { filtered: string[]; excluded: s } const gitOverviewSchema = z.object({ - staged: z.boolean().describe("Use staged changes (default: true)").optional(), - include_untracked: z.boolean().describe("Include untracked files when staged=false").optional(), + staged: z.boolean().describe("use staged changes (default true)").optional(), + include_untracked: z.boolean().describe("include untracked when unstaged").optional(), }); export function createGitOverviewTool(cwd: string, state: CommitAgentState): CustomTool { diff --git a/packages/coding-agent/src/commit/agentic/tools/propose-changelog.ts b/packages/coding-agent/src/commit/agentic/tools/propose-changelog.ts index 8d28fff6b..a81be11c6 100644 --- a/packages/coding-agent/src/commit/agentic/tools/propose-changelog.ts +++ b/packages/coding-agent/src/commit/agentic/tools/propose-changelog.ts @@ -12,9 +12,7 @@ const changelogEntryProperties = CHANGELOG_CATEGORIES.reduce; diff --git a/packages/coding-agent/src/edit/modes/patch.ts b/packages/coding-agent/src/edit/modes/patch.ts index f935f652a..1b6f9a9a4 100644 --- a/packages/coding-agent/src/edit/modes/patch.ts +++ b/packages/coding-agent/src/edit/modes/patch.ts @@ -1578,16 +1578,16 @@ export async function computePatchDiff( export const patchEditEntrySchema = z .object({ - op: z.enum(["create", "delete", "update"]).optional().describe("Operation (default: update)"), - rename: z.string().describe("New path for move").optional(), - diff: z.string().describe("Diff hunks (update) or full content (create)").optional(), + op: z.enum(["create", "delete", "update"]).optional().describe("operation (default update)"), + rename: z.string().describe("new path for move").optional(), + diff: z.string().describe("diff hunks or full content for create").optional(), }) .strict(); export const patchEditSchema = z .object({ - path: z.string().describe("file path for edits"), - edits: z.array(patchEditEntrySchema).min(1).describe("Patch operations"), + path: z.string().describe("file path"), + edits: z.array(patchEditEntrySchema).min(1).describe("patch operations"), }) .strict(); diff --git a/packages/coding-agent/src/edit/modes/replace.ts b/packages/coding-agent/src/edit/modes/replace.ts index 00f8229b0..be3fde872 100644 --- a/packages/coding-agent/src/edit/modes/replace.ts +++ b/packages/coding-agent/src/edit/modes/replace.ts @@ -978,16 +978,16 @@ export function findContextLine( export const replaceEditEntrySchema = z .object({ - old_text: z.string().describe("Text to find (fuzzy whitespace matching enabled)"), - new_text: z.string().describe("Replacement text"), - all: z.boolean().describe("Replace all occurrences (default: unique match required)").optional(), + old_text: z.string().describe("text to find"), + new_text: z.string().describe("replacement text"), + all: z.boolean().describe("replace all occurrences").optional(), }) .strict(); export const replaceEditSchema = z .object({ - path: z.string().describe("file path for edits"), - edits: z.array(replaceEditEntrySchema).min(1).describe("Replacements"), + path: z.string().describe("file path"), + edits: z.array(replaceEditEntrySchema).min(1).describe("replacements"), }) .strict(); diff --git a/packages/coding-agent/src/exa/researcher.ts b/packages/coding-agent/src/exa/researcher.ts index 64173249b..29bec943a 100644 --- a/packages/coding-agent/src/exa/researcher.ts +++ b/packages/coding-agent/src/exa/researcher.ts @@ -14,9 +14,9 @@ const researcherStartTool = createExaTool( "Start Deep Research", "Start an asynchronous deep research task using Exa's researcher. Returns a task_id for polling completion.", z.object({ - query: z.string().describe("Research query to investigate"), - depth: z.number().int().min(1).max(5).describe("Research depth (1-5, default: 3)").optional(), - breadth: z.number().int().min(1).max(5).describe("Research breadth (1-5, default: 3)").optional(), + query: z.string().describe("research query"), + depth: z.number().int().min(1).max(5).describe("research depth (1-5)").optional(), + breadth: z.number().int().min(1).max(5).describe("research breadth (1-5)").optional(), }), "deep_researcher_start", { formatResponse: false }, @@ -27,7 +27,7 @@ const researcherPollTool = createExaTool( "Poll Research Status", "Poll the status of an asynchronous research task. Returns status (pending|running|completed|failed) and result if completed.", z.object({ - task_id: z.string().describe("Task ID returned from exa_researcher_start"), + task_id: z.string().describe("task id"), }), "deep_researcher_check", { formatResponse: false }, diff --git a/packages/coding-agent/src/exa/search.ts b/packages/coding-agent/src/exa/search.ts index 73990fa15..b8ad803e0 100644 --- a/packages/coding-agent/src/exa/search.ts +++ b/packages/coding-agent/src/exa/search.ts @@ -30,28 +30,16 @@ Parameters: - num_results: Maximum number of results to return (default: 10, max: 100)`, z.object({ - query: z.string().describe("Search query"), - type: z - .enum(["keyword", "neural", "auto"]) - .describe("Search type - neural (semantic), keyword (exact), or auto") - .optional(), - include_domains: z.array(z.string()).describe("Only include results from these domains").optional(), - exclude_domains: z.array(z.string()).describe("Exclude results from these domains").optional(), - start_published_date: z - .string() - .describe("Filter results published after this date (ISO 8601 format)") - .optional(), - end_published_date: z.string().describe("Filter results published before this date (ISO 8601 format)").optional(), - use_autoprompt: z.boolean().describe("Let Exa optimize your query automatically (default: true)").optional(), - text: z.boolean().describe("Include page text content in results (costs more, default: false)").optional(), - highlights: z.boolean().describe("Include highlighted relevant snippets (default: false)").optional(), - num_results: z - .number() - .int() - .min(1) - .max(100) - .describe("Maximum number of results to return (default: 10, max: 100)") - .optional(), + query: z.string().describe("search query"), + type: z.enum(["keyword", "neural", "auto"]).describe("search type").optional(), + include_domains: z.array(z.string()).describe("include domains").optional(), + exclude_domains: z.array(z.string()).describe("exclude domains").optional(), + start_published_date: z.string().describe("published after (iso 8601)").optional(), + end_published_date: z.string().describe("published before (iso 8601)").optional(), + use_autoprompt: z.boolean().describe("autoprompt").optional(), + text: z.boolean().describe("include page text").optional(), + highlights: z.boolean().describe("include highlights").optional(), + num_results: z.number().int().min(1).max(100).describe("max results (1-100)").optional(), }), "web_search_exa", ); diff --git a/packages/coding-agent/src/exa/websets.ts b/packages/coding-agent/src/exa/websets.ts index 84c356be5..7b62ad52e 100644 --- a/packages/coding-agent/src/exa/websets.ts +++ b/packages/coding-agent/src/exa/websets.ts @@ -53,8 +53,8 @@ const websetCreateTool = createWebsetTool( "Create Webset", "Create a new webset collection for organizing web content.", z.object({ - name: z.string().describe("Name of the webset"), - description: z.string().describe("Optional description").optional(), + name: z.string().describe("webset name"), + description: z.string().describe("description").optional(), }), "create_webset", ); @@ -72,7 +72,7 @@ const websetGetTool = createWebsetTool( "Get Webset", "Get details of a specific webset by ID.", z.object({ - id: z.string().describe("Webset ID"), + id: z.string().describe("webset id"), }), "get_webset", ); @@ -82,9 +82,9 @@ const websetUpdateTool = createWebsetTool( "Update Webset", "Update a webset's name or description.", z.object({ - id: z.string().describe("Webset ID"), - name: z.string().describe("New name").optional(), - description: z.string().describe("New description").optional(), + id: z.string().describe("webset id"), + name: z.string().describe("new name").optional(), + description: z.string().describe("new description").optional(), }), "update_webset", ); @@ -94,7 +94,7 @@ const websetDeleteTool = createWebsetTool( "Delete Webset", "Delete a webset and all its contents.", z.object({ - id: z.string().describe("Webset ID"), + id: z.string().describe("webset id"), }), "delete_webset", ); @@ -105,9 +105,9 @@ const websetItemsListTool = createWebsetTool( "List Webset Items", "List items in a webset with optional pagination.", z.object({ - webset_id: z.string().describe("Webset ID"), - limit: z.number().describe("Number of items to return").optional(), - offset: z.number().describe("Pagination offset").optional(), + webset_id: z.string().describe("webset id"), + limit: z.number().describe("max items").optional(), + offset: z.number().describe("offset").optional(), }), "list_webset_items", ); @@ -117,8 +117,8 @@ const websetItemGetTool = createWebsetTool( "Get Webset Item", "Get a specific item from a webset.", z.object({ - webset_id: z.string().describe("Webset ID"), - item_id: z.string().describe("Item ID"), + webset_id: z.string().describe("webset id"), + item_id: z.string().describe("item id"), }), "get_item", ); @@ -129,8 +129,8 @@ const websetSearchCreateTool = createWebsetTool( "Create Webset Search", "Create a new search within a webset.", z.object({ - webset_id: z.string().describe("Webset ID"), - query: z.string().describe("Search query"), + webset_id: z.string().describe("webset id"), + query: z.string().describe("search query"), }), "create_search", ); @@ -140,8 +140,8 @@ const websetSearchGetTool = createWebsetTool( "Get Webset Search", "Get the status and results of a webset search.", z.object({ - webset_id: z.string().describe("Webset ID"), - search_id: z.string().describe("Search ID"), + webset_id: z.string().describe("webset id"), + search_id: z.string().describe("search id"), }), "get_search", ); @@ -151,8 +151,8 @@ const websetSearchCancelTool = createWebsetTool( "Cancel Webset Search", "Cancel a running webset search.", z.object({ - webset_id: z.string().describe("Webset ID"), - search_id: z.string().describe("Search ID"), + webset_id: z.string().describe("webset id"), + search_id: z.string().describe("search id"), }), "cancel_search", ); @@ -163,9 +163,9 @@ const websetEnrichmentCreateTool = createWebsetTool( "Create Enrichment", "Create a new enrichment task for a webset.", z.object({ - webset_id: z.string().describe("Webset ID"), - name: z.string().describe("Enrichment name"), - prompt: z.string().describe("Enrichment prompt"), + webset_id: z.string().describe("webset id"), + name: z.string().describe("enrichment name"), + prompt: z.string().describe("enrichment prompt"), }), "create_enrichment", ); @@ -175,8 +175,8 @@ const websetEnrichmentGetTool = createWebsetTool( "Get Enrichment", "Get the status and results of an enrichment task.", z.object({ - webset_id: z.string().describe("Webset ID"), - enrichment_id: z.string().describe("Enrichment ID"), + webset_id: z.string().describe("webset id"), + enrichment_id: z.string().describe("enrichment id"), }), "get_enrichment", ); @@ -186,10 +186,10 @@ const websetEnrichmentUpdateTool = createWebsetTool( "Update Enrichment", "Update an enrichment's name or prompt.", z.object({ - webset_id: z.string().describe("Webset ID"), - enrichment_id: z.string().describe("Enrichment ID"), - name: z.string().describe("New name").optional(), - prompt: z.string().describe("New prompt").optional(), + webset_id: z.string().describe("webset id"), + enrichment_id: z.string().describe("enrichment id"), + name: z.string().describe("new name").optional(), + prompt: z.string().describe("new prompt").optional(), }), "update_enrichment", ); @@ -199,8 +199,8 @@ const websetEnrichmentDeleteTool = createWebsetTool( "Delete Enrichment", "Delete an enrichment task.", z.object({ - webset_id: z.string().describe("Webset ID"), - enrichment_id: z.string().describe("Enrichment ID"), + webset_id: z.string().describe("webset id"), + enrichment_id: z.string().describe("enrichment id"), }), "delete_enrichment", ); @@ -210,8 +210,8 @@ const websetEnrichmentCancelTool = createWebsetTool( "Cancel Enrichment", "Cancel a running enrichment task.", z.object({ - webset_id: z.string().describe("Webset ID"), - enrichment_id: z.string().describe("Enrichment ID"), + webset_id: z.string().describe("webset id"), + enrichment_id: z.string().describe("enrichment id"), }), "cancel_enrichment", ); @@ -222,8 +222,8 @@ const websetMonitorCreateTool = createWebsetTool( "Create Monitor", "Create a monitoring task for a webset with optional webhook notifications.", z.object({ - webset_id: z.string().describe("Webset ID"), - webhook_url: z.string().describe("Webhook URL for notifications").optional(), + webset_id: z.string().describe("webset id"), + webhook_url: z.string().describe("webhook url").optional(), }), "create_monitor", ); diff --git a/packages/coding-agent/src/goals/tools/goal-tool.ts b/packages/coding-agent/src/goals/tools/goal-tool.ts index f562ac7e7..c634fde23 100644 --- a/packages/coding-agent/src/goals/tools/goal-tool.ts +++ b/packages/coding-agent/src/goals/tools/goal-tool.ts @@ -15,9 +15,9 @@ import { completionBudgetReport, remainingTokens } from "../runtime"; import type { Goal, GoalStatus, GoalToolDetails } from "../state"; const goalSchema = z.object({ - op: z.union([z.literal("create"), z.literal("get"), z.literal("complete")]).describe("Goal operation."), - objective: z.string().describe("Goal objective. Required when op=create.").optional(), - token_budget: z.number().int().describe("Optional positive token budget. Only honored when op=create.").optional(), + op: z.enum(["create", "get", "complete"]).describe("goal operation"), + objective: z.string().describe("goal objective").optional(), + token_budget: z.number().int().describe("token budget").optional(), }); export type GoalToolInput = z.infer; diff --git a/packages/coding-agent/src/index.ts b/packages/coding-agent/src/index.ts index 350d392d7..ace3d23ce 100644 --- a/packages/coding-agent/src/index.ts +++ b/packages/coding-agent/src/index.ts @@ -2,9 +2,6 @@ import { HookEditorComponent, HookInputComponent, HookSelectorComponent } from " // Core session management -// TypeBox helper for string enums (convenience for custom tools) -// Re-export from pi-ai which uses the correct enum-based schema format -export { StringEnum } from "@oh-my-pi/pi-ai"; // Re-export TUI components for custom tool rendering export { Container, Markdown, Spacer, Text } from "@oh-my-pi/pi-tui"; // Logging diff --git a/packages/coding-agent/src/lsp/types.ts b/packages/coding-agent/src/lsp/types.ts index 876ec5a09..96b6a1f6d 100644 --- a/packages/coding-agent/src/lsp/types.ts +++ b/packages/coding-agent/src/lsp/types.ts @@ -22,17 +22,14 @@ export const lspSchema = z.object({ "capabilities", "request", ]), - file: z.string().describe("File path or source path for rename_file").optional(), - line: z.number().describe("Line number (1-indexed)").optional(), - symbol: z.string().describe("Symbol/substring to locate on the line").optional(), - query: z.string().describe("Search query, code-action selector, or LSP method name for action=request").optional(), - new_name: z.string().describe("New name for rename, or destination path for rename_file").optional(), - apply: z.boolean().describe("Apply edits (default: true for rename/rename_file)").optional(), - timeout: z.number().describe("Request timeout in seconds").optional(), - payload: z - .string() - .describe("JSON-encoded params for action=request. When omitted, params are auto-built from file/line/symbol.") - .optional(), + file: z.string().describe("file path or source path for rename_file").optional(), + line: z.number().describe("line number (1-indexed)").optional(), + symbol: z.string().describe("symbol substring on the line").optional(), + query: z.string().describe("search query or code-action selector").optional(), + new_name: z.string().describe("new symbol name or destination path").optional(), + apply: z.boolean().describe("apply edits").optional(), + timeout: z.number().describe("request timeout in seconds").optional(), + payload: z.string().describe("json-encoded request params").optional(), }); export type LspParams = z.infer; diff --git a/packages/coding-agent/src/prompts/tools/resolve.md b/packages/coding-agent/src/prompts/tools/resolve.md index bff34d67c..e195178a9 100644 --- a/packages/coding-agent/src/prompts/tools/resolve.md +++ b/packages/coding-agent/src/prompts/tools/resolve.md @@ -2,7 +2,7 @@ Resolves a pending action by either applying or discarding it. - `action` is required: - `"apply"` persists / submits the pending action. - `"discard"` rejects the pending action. -- `reason` is required and must briefly explain why you chose to apply or discard. +- `reason` is required: one short complete sentence explaining why, starting with a capital letter and ending with a period. - `extra` (optional) is free-form metadata passed to the resolving tool. Schema depends on context: Valid whenever a pending action exists — either a preview-style staging (e.g. `ast_edit`) or a long-lived approval gate. diff --git a/packages/coding-agent/src/session/agent-storage.ts b/packages/coding-agent/src/session/agent-storage.ts index 7af2dac44..3def35979 100644 --- a/packages/coding-agent/src/session/agent-storage.ts +++ b/packages/coding-agent/src/session/agent-storage.ts @@ -1,7 +1,12 @@ import { Database, type Statement } from "bun:sqlite"; import * as fs from "node:fs"; import * as path from "node:path"; -import { type AuthCredential, AuthCredentialStore, type StoredAuthCredential } from "@oh-my-pi/pi-ai"; +import { + type AuthCredential, + type AuthCredentialStore, + SqliteAuthCredentialStore, + type StoredAuthCredential, +} from "@oh-my-pi/pi-ai"; import { getAgentDbPath, isRecord, logger } from "@oh-my-pi/pi-utils"; import type { RawSettings as Settings } from "../config/settings"; @@ -57,7 +62,7 @@ export class AgentStorage { this.#hardenPermissions(dbPath); // Create AuthCredentialStore with our open database - this.#authStore = new AuthCredentialStore(this.#db); + this.#authStore = new SqliteAuthCredentialStore(this.#db); this.#listSettingsStmt = this.#db.prepare("SELECT key, value FROM settings"); this.#upsertModelUsageStmt = this.#db.prepare( diff --git a/packages/coding-agent/src/session/auth-storage.ts b/packages/coding-agent/src/session/auth-storage.ts index a150eefcb..49d670eae 100644 --- a/packages/coding-agent/src/session/auth-storage.ts +++ b/packages/coding-agent/src/session/auth-storage.ts @@ -14,4 +14,4 @@ export type { SerializedAuthStorage, StoredAuthCredential, } from "@oh-my-pi/pi-ai"; -export { AuthStorage } from "@oh-my-pi/pi-ai"; +export { AuthStorage, SqliteAuthCredentialStore } from "@oh-my-pi/pi-ai"; diff --git a/packages/coding-agent/src/task/types.ts b/packages/coding-agent/src/task/types.ts index 1516b829f..776144249 100644 --- a/packages/coding-agent/src/task/types.ts +++ b/packages/coding-agent/src/task/types.ts @@ -57,18 +57,13 @@ export interface SubagentLifecyclePayload { index: number; } -const assignmentDescriptionForContextEnabled = - "Complete per-task instructions the subagent executes. Must follow the Target/Change/Edge Cases/Acceptance structure. Only include per-task deltas — shared background belongs in `context`."; -const assignmentDescriptionForContextDisabled = - "Complete per-task instructions the subagent executes. Must follow the Target/Change/Edge Cases/Acceptance structure, and include any background that would otherwise live in `context` since shared context is disabled in this mode."; +const assignmentDescription = "per-task instructions; self-contained"; -const createTaskItemSchema = (contextEnabled: boolean) => +const createTaskItemSchema = (_contextEnabled: boolean) => z.object({ - id: z.string().max(48).describe("CamelCase identifier, max 48 chars"), - description: z.string().describe("Short one-liner for UI display only — not seen by the subagent"), - assignment: z - .string() - .describe(contextEnabled ? assignmentDescriptionForContextEnabled : assignmentDescriptionForContextDisabled), + id: z.string().max(48).describe("camelcase identifier"), + description: z.string().describe("ui label, not seen by subagent"), + assignment: z.string().describe(assignmentDescription), }); /** Single task item for parallel execution (default shape with context enabled). */ @@ -80,44 +75,24 @@ const createTaskSchema = (options: { isolationEnabled: boolean; simpleMode: Task const itemSchema = createTaskItemSchema(contextEnabled); let schema = z.object({ - agent: z.string().describe("Agent type for all tasks in this batch"), - tasks: z - .array(itemSchema) - .describe( - contextEnabled - ? "Tasks to execute in parallel. Each must be small-scoped (3-5 files max) and self-contained given context + assignment." - : "Tasks to execute in parallel. Each must be small-scoped (3-5 files max) and fully self-contained inside assignment because shared context is disabled.", - ), + agent: z.string().describe("agent type"), + tasks: z.array(itemSchema).describe("tasks to execute in parallel"), }); - if (contextEnabled) { schema = schema.extend({ - context: z - .string() - .optional() - .describe( - "Shared background prepended to every task's assignment. Put goal, non-goals, constraints, conventions, reference paths, API contracts, and global acceptance commands here once — instead of duplicating across assignments.", - ), + context: z.string().optional().describe("shared background prepended to each assignment"), }); } if (customSchemaEnabled) { schema = schema.extend({ - schema: z - .string() - .optional() - .describe( - "JSON-encoded JTD schema defining expected response structure. Output format belongs here — never in context or assignment.", - ), + schema: z.string().optional().describe("jtd schema for expected response shape"), }); } if (options.isolationEnabled) { schema = schema.extend({ - isolated: z - .boolean() - .optional() - .describe("Run in isolated environment; returns patches. Use when tasks edit overlapping files."), + isolated: z.boolean().optional().describe("run in isolated env; returns patches"), }); } diff --git a/packages/coding-agent/src/tools/browser.ts b/packages/coding-agent/src/tools/browser.ts index 8f2e2128b..d42a763f9 100644 --- a/packages/coding-agent/src/tools/browser.ts +++ b/packages/coding-agent/src/tools/browser.ts @@ -18,19 +18,16 @@ export type { Observation, ObservationEntry } from "./browser/tab-protocol"; const DEFAULT_TAB_NAME = "main"; const appSchema = z.object({ - path: z.string().describe("absolute path to a binary to spawn (single-instance reuse)").optional(), - cdp_url: z.string().describe("existing CDP endpoint to connect to (e.g. http://127.0.0.1:9222)").optional(), - args: z.array(z.string()).describe("extra CLI args when spawning").optional(), - target: z.string().describe("substring matched against url+title to pick a BrowserWindow").optional(), + path: z.string().describe("binary path to spawn").optional(), + cdp_url: z.string().describe("existing cdp endpoint").optional(), + args: z.array(z.string()).describe("extra cli args").optional(), + target: z.string().describe("substring to pick a window").optional(), }); const browserSchema = z.object({ - action: z.enum(["open", "close", "run"] as const).describe("tab/browser operation"), - name: z - .string() - .describe("tab id; default 'main'. Multiple tabs can coexist; reusable across run() calls and subagents.") - .optional(), - url: z.string().describe("open: navigate after acquiring tab").optional(), + action: z.enum(["open", "close", "run"] as const).describe("operation"), + name: z.string().describe("tab id (default 'main')").optional(), + url: z.string().describe("url to open").optional(), app: appSchema.optional(), viewport: z .object({ @@ -41,21 +38,16 @@ const browserSchema = z.object({ .optional(), wait_until: z .enum(["load", "domcontentloaded", "networkidle0", "networkidle2"] as const) - .describe("navigation wait condition for url") + .describe("navigation wait condition") .optional(), dialogs: z .enum(["accept", "dismiss"] as const) - .describe("open: auto-handle alert/confirm/beforeunload dialogs (default: leave for caller to handle)") - .optional(), - code: z - .string() - .describe( - "run: JS body executed with `page`, `browser`, `tab`, `display`, `assert`, `wait` in scope. Treated as the body of an async function. Use `display(value)` to attach text/JSON/images; the function's return value is JSON-serialized as a final block.", - ) + .describe("auto-handle dialogs") .optional(), + code: z.string().describe("js body to run in tab").optional(), timeout: z.number().default(30).describe("timeout in seconds").optional(), - all: z.boolean().describe("close: close every tab").optional(), - kill: z.boolean().describe("close: also kill spawned-app browsers (default: leave running)").optional(), + all: z.boolean().describe("close every tab").optional(), + kill: z.boolean().describe("also kill spawned-app browsers").optional(), }); /** Input schema for the browser tool. */ diff --git a/packages/coding-agent/src/tools/gh.ts b/packages/coding-agent/src/tools/gh.ts index 02567fd5c..8b60ef247 100644 --- a/packages/coding-agent/src/tools/gh.ts +++ b/packages/coding-agent/src/tools/gh.ts @@ -213,58 +213,34 @@ const githubSchema = z "run_watch", ] as const) .describe("github operation"), - repo: z.string().describe("owner/repo (any op)").optional(), - branch: z.string().describe("branch (repo_view, pr_push local branch, run_watch)").optional(), + repo: z.string().describe("owner/repo").optional(), + branch: z.string().describe("branch").optional(), pr: z .union([z.string(), z.array(z.string())]) - .describe( - "pr number, url, or branch (pr_checkout); pass an array to batch-process multiple pull requests in one call", - ) - .optional(), - force: z.boolean().describe("reset existing local branch (pr_checkout)").optional(), - forceWithLease: z.boolean().describe("force-with-lease push (pr_push)").optional(), - title: z.string().describe("PR title (pr_create)").optional(), - body: z.string().describe("PR body markdown (pr_create); mutually exclusive with fill").optional(), - base: z.string().describe("PR base branch (pr_create); defaults to repo default branch").optional(), - head: z.string().describe("PR head branch (pr_create); defaults to current branch").optional(), - draft: z.boolean().describe("open PR as draft (pr_create)").optional(), - fill: z - .boolean() - .describe("auto-fill PR title/body from commits (pr_create); mutually exclusive with title/body") - .optional(), - reviewer: z.array(z.string()).describe("reviewers to request (pr_create); accepts users or org/team").optional(), - assignee: z.array(z.string()).describe("assignees (pr_create); use @me for the authenticated user").optional(), - label: z.array(z.string()).describe("labels to apply (pr_create)").optional(), - query: z - .string() - .describe("search query (search_issues, search_prs, search_code, search_commits, search_repos)") - .optional(), - since: z - .string() - .describe( - "lower-bound date for search_issues/search_prs/search_commits/search_repos. Accepts a relative duration (`` with unit `m`/`h`/`d`/`w`/`mo`/`y`, e.g. `3d`, `12h`, `2w`) or an ISO date (`YYYY-MM-DD`) / datetime. Translated to a `created:>=…` (or `committer-date:`/`pushed:`) qualifier; not supported by search_code.", - ) - .optional(), - until: z - .string() - .describe( - "upper-bound date in the same format as `since`. With both, builds a `field:since..until` range qualifier.", - ) + .describe("pr number, url, or branch") .optional(), + force: z.boolean().describe("reset existing local branch").optional(), + forceWithLease: z.boolean().describe("force-with-lease push").optional(), + title: z.string().describe("pr title").optional(), + body: z.string().describe("pr body markdown").optional(), + base: z.string().describe("pr base branch").optional(), + head: z.string().describe("pr head branch").optional(), + draft: z.boolean().describe("open pr as draft").optional(), + fill: z.boolean().describe("auto-fill pr title/body from commits").optional(), + reviewer: z.array(z.string()).describe("reviewers").optional(), + assignee: z.array(z.string()).describe("assignees").optional(), + label: z.array(z.string()).describe("labels").optional(), + query: z.string().describe("search query").optional(), + since: z.string().describe("lower-bound date filter").optional(), + until: z.string().describe("upper-bound date filter").optional(), dateField: z .enum(["created", "updated"] as const) - .describe( - "date field used by `since`/`until`. issues/prs: `created` (default) or `updated`. repos: `created` (default) or `updated` (mapped to GitHub's `pushed:`). commits: ignored — always uses `committer-date`.", - ) + .describe("date field") .default("created") .optional(), - limit: z - .number() - .default(10) - .describe("max results (search_issues, search_prs, search_code, search_commits, search_repos)") - .optional(), - run: z.string().describe("actions run id or url (run_watch)").optional(), - tail: z.number().default(15).describe("log lines per failed job (run_watch)").optional(), + limit: z.number().default(10).describe("max results").optional(), + run: z.string().describe("actions run id or url").optional(), + tail: z.number().default(15).describe("log lines per failed job").optional(), }) .strict(); diff --git a/packages/coding-agent/src/tools/hindsight-recall.ts b/packages/coding-agent/src/tools/hindsight-recall.ts index 856dd1f03..67d18df1b 100644 --- a/packages/coding-agent/src/tools/hindsight-recall.ts +++ b/packages/coding-agent/src/tools/hindsight-recall.ts @@ -6,7 +6,7 @@ import recallDescription from "../prompts/tools/recall.md" with { type: "text" } import type { ToolSession } from "."; const hindsightRecallSchema = z.object({ - query: z.string().describe("Natural language search query. Be specific about what you need to know."), + query: z.string().describe("natural language search query"), }); export type HindsightRecallParams = z.infer; diff --git a/packages/coding-agent/src/tools/hindsight-reflect.ts b/packages/coding-agent/src/tools/hindsight-reflect.ts index ba4b99f04..d46e6e02b 100644 --- a/packages/coding-agent/src/tools/hindsight-reflect.ts +++ b/packages/coding-agent/src/tools/hindsight-reflect.ts @@ -6,8 +6,8 @@ import reflectDescription from "../prompts/tools/reflect.md" with { type: "text" import type { ToolSession } from "."; const hindsightReflectSchema = z.object({ - query: z.string().describe("The question to answer using long-term memory."), - context: z.string().describe("Optional additional context to guide the reflection.").optional(), + query: z.string().describe("question to answer"), + context: z.string().describe("optional context").optional(), }); export type HindsightReflectParams = z.infer; diff --git a/packages/coding-agent/src/tools/hindsight-retain.ts b/packages/coding-agent/src/tools/hindsight-retain.ts index 088a85edb..e8dc37d50 100644 --- a/packages/coding-agent/src/tools/hindsight-retain.ts +++ b/packages/coding-agent/src/tools/hindsight-retain.ts @@ -7,16 +7,12 @@ const hindsightRetainSchema = z.object({ items: z .array( z.object({ - content: z - .string() - .describe("The information to remember. Be specific and self-contained — include who, what, when, why."), - context: z.string().describe("Optional context describing where this information came from.").optional(), + content: z.string().describe("information to remember"), + context: z.string().describe("source context").optional(), }), ) .min(1) - .describe( - "One or more memories to retain. Batch related facts in a single call rather than calling retain repeatedly — they are deduplicated and consolidated together.", - ), + .describe("memories to retain"), }); export type HindsightRetainParams = z.infer; diff --git a/packages/coding-agent/src/tools/irc.ts b/packages/coding-agent/src/tools/irc.ts index 30d4a1bc9..b1f169ba6 100644 --- a/packages/coding-agent/src/tools/irc.ts +++ b/packages/coding-agent/src/tools/irc.ts @@ -26,18 +26,10 @@ import type { AgentRef, AgentRegistry } from "../registry/agent-registry"; import type { ToolSession } from "."; const ircSchema = z.object({ - op: z - .union([ - z.literal("send").describe("Send a message to one peer or to all peers"), - z.literal("list").describe("List currently visible peers"), - ]) - .describe("IRC operation"), - to: z.string().optional().describe('Recipient agent id (e.g. "0-Main", "0-AuthLoader") or "all" to broadcast'), - message: z.string().optional().describe("Message body to deliver"), - awaitReply: z - .boolean() - .optional() - .describe("Wait for the recipient's prose reply (default: true for DM, false for broadcast)"), + op: z.enum(["send", "list"]).describe("irc operation"), + to: z.string().optional().describe('recipient agent id or "all"'), + message: z.string().optional().describe("message body"), + awaitReply: z.boolean().optional().describe("wait for prose reply"), }); type IrcParams = z.infer; diff --git a/packages/coding-agent/src/tools/job.ts b/packages/coding-agent/src/tools/job.ts index 9782b8684..a4f811688 100644 --- a/packages/coding-agent/src/tools/job.ts +++ b/packages/coding-agent/src/tools/job.ts @@ -23,17 +23,9 @@ import { import { ToolError } from "./tool-errors"; const jobSchema = z.object({ - poll: z - .array(z.string()) - .optional() - .describe("background job ids to wait for; omit (with no `cancel`) to wait on all running jobs"), - cancel: z.array(z.string()).optional().describe("background job ids to cancel"), - list: z - .boolean() - .optional() - .describe( - "Return an immediate snapshot of every job spawned by this agent (running + completed within retention). Read-only \u2014 cannot be combined with `poll` or `cancel`.", - ), + poll: z.array(z.string()).optional().describe("job ids to wait for"), + cancel: z.array(z.string()).optional().describe("job ids to cancel"), + list: z.boolean().optional().describe("snapshot all jobs"), }); type JobParams = z.infer; diff --git a/packages/coding-agent/src/tools/resolve.ts b/packages/coding-agent/src/tools/resolve.ts index f48b9f0c0..a2e6c4423 100644 --- a/packages/coding-agent/src/tools/resolve.ts +++ b/packages/coding-agent/src/tools/resolve.ts @@ -12,14 +12,9 @@ import { replaceTabs } from "./render-utils"; import { ToolError } from "./tool-errors"; const resolveSchema = z.object({ - action: z.union([z.literal("apply"), z.literal("discard")]), + action: z.enum(["apply", "discard"]), reason: z.string().describe("reason for action"), - extra: z - .record(z.string(), z.unknown()) - .optional() - .describe( - 'Free-form metadata interpreted by the resolving tool (e.g. plan-mode approval requires `{ title: "" }`).', - ), + extra: z.record(z.string(), z.unknown()).optional().describe("free-form metadata"), }); type ResolveParams = z.infer; diff --git a/packages/coding-agent/src/tools/todo-write.ts b/packages/coding-agent/src/tools/todo-write.ts index c909519d8..ba9f8e56c 100644 --- a/packages/coding-agent/src/tools/todo-write.ts +++ b/packages/coding-agent/src/tools/todo-write.ts @@ -49,31 +49,24 @@ const TodoOp = z .describe("operation to apply"); const InitListEntry = z.object({ - phase: z.string().describe("phase name (short noun phrase)"), - items: z - .array(z.string().describe("task content (5-10 words)")) - .min(1) - .describe("tasks for this phase, in execution order; all start as pending"), + phase: z.string().describe("phase name"), + items: z.array(z.string().describe("task content")).min(1).describe("tasks for this phase"), }); const TodoOpEntry = z.object({ op: TodoOp, - list: z.array(InitListEntry).optional().describe("phased task list for op=init"), - task: z.string().optional().describe("task content for start/done/rm/drop/note"), - phase: z.string().optional().describe("phase name for done/rm/drop/append"), - items: z - .array(z.string().describe("task content (5-10 words)")) - .min(1) - .optional() - .describe("tasks to append to `phase` for op=append"), - text: z.string().optional().describe("note text for op=note (appended with newline)"), + list: z.array(InitListEntry).optional().describe("phased task list (init)"), + task: z.string().optional().describe("task content"), + phase: z.string().optional().describe("phase name"), + items: z.array(z.string().describe("task content")).min(1).optional().describe("tasks to append"), + text: z.string().optional().describe("note text"), }); const todoWriteSchema = z .object({ ops: z.array(TodoOpEntry).min(1).describe("ordered todo operations"), }) - .describe("Apply ordered todo operations"); + .describe("apply ordered todo operations"); type TodoWriteParams = z.infer; type TodoOpEntryValue = TodoWriteParams["ops"][number]; diff --git a/packages/coding-agent/src/web/search/index.ts b/packages/coding-agent/src/web/search/index.ts index 47b74cd1e..58f6147d2 100644 --- a/packages/coding-agent/src/web/search/index.ts +++ b/packages/coding-agent/src/web/search/index.ts @@ -21,12 +21,12 @@ import { SearchProviderError } from "./types"; /** Web search tool parameters schema */ export const webSearchSchema = z.object({ - query: z.string().describe("Search query"), - recency: z.enum(["day", "week", "month", "year"]).describe("Recency filter (Brave, Perplexity)").optional(), - limit: z.number().describe("Max results to return").optional(), - max_tokens: z.number().describe("Maximum output tokens").optional(), - temperature: z.number().describe("Sampling temperature").optional(), - num_search_results: z.number().describe("Number of search results to retrieve").optional(), + query: z.string().describe("search query"), + recency: z.enum(["day", "week", "month", "year"]).describe("recency filter").optional(), + limit: z.number().describe("max results").optional(), + max_tokens: z.number().describe("max output tokens").optional(), + temperature: z.number().describe("sampling temperature").optional(), + num_search_results: z.number().describe("number of search results").optional(), }); export type SearchToolParams = z.infer;