@oh-my-pi/pi-coding-agent 15.0.2 → 15.1.1
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/CHANGELOG.md +56 -1
- package/examples/custom-tools/README.md +11 -7
- package/examples/custom-tools/hello/index.ts +2 -2
- package/examples/extensions/README.md +19 -8
- package/examples/extensions/api-demo.ts +15 -19
- package/examples/extensions/hello.ts +5 -6
- package/examples/extensions/plan-mode.ts +1 -1
- package/examples/extensions/reload-runtime.ts +4 -3
- package/examples/extensions/with-deps/index.ts +4 -3
- package/examples/sdk/06-extensions.ts +4 -2
- package/package.json +7 -17
- package/src/autoresearch/tools/init-experiment.ts +38 -41
- package/src/autoresearch/tools/log-experiment.ts +32 -41
- package/src/autoresearch/tools/run-experiment.ts +3 -3
- package/src/autoresearch/tools/update-notes.ts +11 -11
- package/src/commit/agentic/tools/analyze-file.ts +4 -4
- package/src/commit/agentic/tools/git-file-diff.ts +4 -4
- package/src/commit/agentic/tools/git-hunk.ts +5 -5
- package/src/commit/agentic/tools/git-overview.ts +4 -4
- package/src/commit/agentic/tools/propose-changelog.ts +13 -13
- package/src/commit/agentic/tools/propose-commit.ts +6 -6
- package/src/commit/agentic/tools/recent-commits.ts +3 -3
- package/src/commit/agentic/tools/schemas.ts +28 -28
- package/src/commit/agentic/tools/split-commit.ts +22 -21
- package/src/commit/analysis/summary.ts +4 -4
- package/src/commit/changelog/generate.ts +7 -11
- package/src/commit/shared-llm.ts +22 -34
- package/src/config/config-file.ts +35 -13
- package/src/config/model-registry.ts +9 -190
- package/src/config/models-config-schema.ts +166 -0
- package/src/config/settings-schema.ts +18 -0
- package/src/edit/index.ts +2 -2
- package/src/edit/modes/apply-patch.ts +7 -6
- package/src/edit/modes/patch.ts +18 -25
- package/src/edit/modes/replace.ts +18 -20
- package/src/eval/js/shared/rewrite-imports.ts +131 -10
- package/src/eval/py/executor.ts +233 -623
- package/src/eval/py/kernel.ts +27 -2
- package/src/exa/factory.ts +5 -4
- package/src/exa/mcp-client.ts +1 -1
- package/src/exa/researcher.ts +9 -20
- package/src/exa/search.ts +26 -52
- package/src/exa/types.ts +1 -1
- package/src/exa/websets.ts +54 -53
- package/src/exec/bash-executor.ts +2 -1
- package/src/extensibility/custom-commands/loader.ts +5 -3
- package/src/extensibility/custom-commands/types.ts +4 -2
- package/src/extensibility/custom-tools/loader.ts +5 -3
- package/src/extensibility/custom-tools/types.ts +7 -6
- package/src/extensibility/custom-tools/wrapper.ts +1 -1
- package/src/extensibility/extensions/loader.ts +7 -3
- package/src/extensibility/extensions/types.ts +9 -5
- package/src/extensibility/extensions/wrapper.ts +1 -2
- package/src/extensibility/hooks/loader.ts +3 -1
- package/src/extensibility/hooks/tool-wrapper.ts +1 -1
- package/src/extensibility/hooks/types.ts +4 -2
- package/src/extensibility/plugins/legacy-pi-compat.ts +30 -0
- package/src/extensibility/shared-events.ts +1 -1
- package/src/extensibility/typebox.ts +391 -0
- package/src/goals/tools/goal-tool.ts +6 -12
- package/src/hashline/types.ts +4 -4
- package/src/hindsight/state.ts +2 -2
- package/src/index.ts +0 -2
- package/src/internal-urls/docs-index.generated.ts +7 -7
- package/src/lsp/types.ts +30 -38
- package/src/mcp/manager.ts +1 -1
- package/src/mcp/tool-bridge.ts +1 -1
- package/src/modes/components/session-observer-overlay.ts +12 -1
- package/src/modes/components/status-line/segments.ts +2 -1
- package/src/modes/controllers/command-controller.ts +27 -2
- package/src/modes/controllers/event-controller.ts +3 -4
- package/src/modes/interactive-mode.ts +1 -1
- package/src/modes/rpc/host-tools.ts +1 -1
- package/src/modes/rpc/rpc-client.ts +1 -1
- package/src/modes/rpc/rpc-types.ts +1 -1
- package/src/modes/theme/theme.ts +111 -117
- package/src/modes/types.ts +1 -1
- package/src/modes/utils/context-usage.ts +2 -2
- package/src/sdk.ts +31 -8
- package/src/session/agent-session.ts +74 -104
- package/src/session/messages.ts +16 -51
- package/src/session/session-manager.ts +22 -2
- package/src/session/streaming-output.ts +16 -6
- package/src/task/executor.ts +208 -86
- package/src/task/index.ts +15 -11
- package/src/task/render.ts +32 -5
- package/src/task/types.ts +54 -39
- package/src/tools/ask.ts +12 -12
- package/src/tools/ast-edit.ts +11 -15
- package/src/tools/ast-grep.ts +9 -10
- package/src/tools/bash.ts +9 -23
- package/src/tools/browser.ts +39 -53
- package/src/tools/calculator.ts +12 -11
- package/src/tools/checkpoint.ts +7 -7
- package/src/tools/debug.ts +40 -43
- package/src/tools/eval.ts +6 -8
- package/src/tools/find.ts +10 -13
- package/src/tools/gh.ts +71 -128
- package/src/tools/hindsight-recall.ts +4 -6
- package/src/tools/hindsight-reflect.ts +5 -5
- package/src/tools/hindsight-retain.ts +15 -17
- package/src/tools/image-gen.ts +32 -82
- package/src/tools/index.ts +4 -1
- package/src/tools/inspect-image.ts +8 -9
- package/src/tools/irc.ts +15 -27
- package/src/tools/job.ts +14 -21
- package/src/tools/read.ts +7 -8
- package/src/tools/recipe/index.ts +7 -9
- package/src/tools/render-mermaid.ts +12 -12
- package/src/tools/report-tool-issue.ts +4 -4
- package/src/tools/resolve.ts +11 -11
- package/src/tools/review.ts +14 -26
- package/src/tools/search-tool-bm25.ts +7 -9
- package/src/tools/search.ts +19 -22
- package/src/tools/ssh.ts +7 -7
- package/src/tools/todo-write.ts +26 -34
- package/src/tools/vim.ts +10 -26
- package/src/tools/write.ts +5 -5
- package/src/tools/yield.ts +100 -54
- package/src/web/search/index.ts +9 -24
- package/src/prompts/compaction/branch-summary-context.md +0 -5
- package/src/prompts/compaction/branch-summary-preamble.md +0 -2
- package/src/prompts/compaction/branch-summary.md +0 -30
- package/src/prompts/compaction/compaction-short-summary.md +0 -9
- package/src/prompts/compaction/compaction-summary-context.md +0 -5
- package/src/prompts/compaction/compaction-summary.md +0 -38
- package/src/prompts/compaction/compaction-turn-prefix.md +0 -17
- package/src/prompts/compaction/compaction-update-summary.md +0 -45
- package/src/prompts/system/auto-handoff-threshold-focus.md +0 -1
- package/src/prompts/system/file-operations.md +0 -10
- package/src/prompts/system/handoff-document.md +0 -49
- package/src/prompts/system/summarization-system.md +0 -3
- package/src/session/compaction/branch-summarization.ts +0 -324
- package/src/session/compaction/compaction.ts +0 -1420
- package/src/session/compaction/errors.ts +0 -31
- package/src/session/compaction/index.ts +0 -8
- package/src/session/compaction/pruning.ts +0 -91
- package/src/session/compaction/utils.ts +0 -184
|
@@ -8,8 +8,7 @@ import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
|
8
8
|
import type { ImageContent, Model, TextContent } from "@oh-my-pi/pi-ai";
|
|
9
9
|
import type { KeyId } from "@oh-my-pi/pi-tui";
|
|
10
10
|
import { hasFsCode, isEacces, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
11
|
-
import
|
|
12
|
-
import * as TypeBox from "@sinclair/typebox";
|
|
11
|
+
import * as Zod from "zod/v4";
|
|
13
12
|
import { type ExtensionModule, extensionModuleCapability } from "../../capability/extension-module";
|
|
14
13
|
import { loadCapability } from "../../discovery";
|
|
15
14
|
import { getExtensionNameFromPath } from "../../discovery/helpers";
|
|
@@ -19,6 +18,7 @@ import type { CustomMessage } from "../../session/messages";
|
|
|
19
18
|
import { EventBus } from "../../utils/event-bus";
|
|
20
19
|
import { installLegacyPiSpecifierShim, loadLegacyPiModule } from "../plugins/legacy-pi-compat";
|
|
21
20
|
import { getAllPluginExtensionPaths } from "../plugins/loader";
|
|
21
|
+
import * as TypeBox from "../typebox";
|
|
22
22
|
|
|
23
23
|
import { resolvePath } from "../utils";
|
|
24
24
|
import type {
|
|
@@ -119,6 +119,7 @@ export class ExtensionRuntime implements IExtensionRuntime {
|
|
|
119
119
|
class ConcreteExtensionAPI implements ExtensionAPI, IExtensionRuntime {
|
|
120
120
|
readonly logger = logger;
|
|
121
121
|
readonly typebox = TypeBox;
|
|
122
|
+
readonly zod = Zod;
|
|
122
123
|
readonly flagValues = new Map<string, boolean | string>();
|
|
123
124
|
readonly pendingProviderRegistrations: Array<{
|
|
124
125
|
name: string;
|
|
@@ -140,7 +141,10 @@ class ConcreteExtensionAPI implements ExtensionAPI, IExtensionRuntime {
|
|
|
140
141
|
this.extension.handlers.set(event, list);
|
|
141
142
|
}
|
|
142
143
|
|
|
143
|
-
registerTool<
|
|
144
|
+
registerTool<
|
|
145
|
+
TParams extends import("@oh-my-pi/pi-ai").TSchema = import("@oh-my-pi/pi-ai").TSchema,
|
|
146
|
+
TDetails = unknown,
|
|
147
|
+
>(tool: ToolDefinition<TParams, TDetails>): void {
|
|
144
148
|
this.extension.tools.set(tool.name, {
|
|
145
149
|
definition: tool,
|
|
146
150
|
extensionPath: this.extension.path,
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* - Interact with the user via UI primitives
|
|
9
9
|
*/
|
|
10
10
|
import type { AgentMessage, AgentToolResult, AgentToolUpdateCallback, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
11
|
+
import type { CompactionResult } from "@oh-my-pi/pi-agent-core/compaction";
|
|
11
12
|
import type {
|
|
12
13
|
Api,
|
|
13
14
|
AssistantMessageEvent,
|
|
@@ -17,12 +18,13 @@ import type {
|
|
|
17
18
|
Model,
|
|
18
19
|
ProviderResponseMetadata,
|
|
19
20
|
SimpleStreamOptions,
|
|
21
|
+
Static,
|
|
20
22
|
TextContent,
|
|
23
|
+
TSchema,
|
|
21
24
|
} from "@oh-my-pi/pi-ai";
|
|
22
25
|
import type { OAuthCredentials, OAuthLoginCallbacks } from "@oh-my-pi/pi-ai/utils/oauth/types";
|
|
23
26
|
import type * as piCodingAgent from "@oh-my-pi/pi-coding-agent";
|
|
24
27
|
import type { AutocompleteItem, Component, EditorTheme, KeyId, TUI } from "@oh-my-pi/pi-tui";
|
|
25
|
-
import type { Static, TSchema } from "@sinclair/typebox";
|
|
26
28
|
import type { KeybindingsManager } from "../../config/keybindings";
|
|
27
29
|
import type { ModelRegistry } from "../../config/model-registry";
|
|
28
30
|
import type { EditToolDetails } from "../../edit";
|
|
@@ -31,7 +33,6 @@ import type { BashResult } from "../../exec/bash-executor";
|
|
|
31
33
|
import type { ExecOptions, ExecResult } from "../../exec/exec";
|
|
32
34
|
import type { CustomEditor } from "../../modes/components/custom-editor";
|
|
33
35
|
import type { Theme } from "../../modes/theme/theme";
|
|
34
|
-
import type { CompactionResult } from "../../session/compaction";
|
|
35
36
|
import type { CustomMessage } from "../../session/messages";
|
|
36
37
|
import type { ReadonlySessionManager, SessionManager } from "../../session/session-manager";
|
|
37
38
|
import type {
|
|
@@ -355,7 +356,7 @@ export interface ToolDefinition<TParams extends TSchema = TSchema, TDetails = un
|
|
|
355
356
|
label: string;
|
|
356
357
|
/** Description for LLM */
|
|
357
358
|
description: string;
|
|
358
|
-
/** Parameter schema (TypeBox) */
|
|
359
|
+
/** Parameter schema (Zod, or TypeBox for legacy/extension compat). */
|
|
359
360
|
parameters: TParams;
|
|
360
361
|
/** If true, tool is excluded unless explicitly listed in --tools or agent's tools field */
|
|
361
362
|
hidden?: boolean;
|
|
@@ -833,8 +834,11 @@ export interface ExtensionAPI {
|
|
|
833
834
|
/** File logger for error/warning/debug messages */
|
|
834
835
|
logger: typeof import("@oh-my-pi/pi-utils").logger;
|
|
835
836
|
|
|
836
|
-
/** Injected
|
|
837
|
-
typebox: typeof import("
|
|
837
|
+
/** Injected zod-backed typebox shim for legacy `Type.Object(...)` parameter authoring. */
|
|
838
|
+
typebox: typeof import("../typebox");
|
|
839
|
+
|
|
840
|
+
/** Injected zod module for Zod-authored extension tools (canonical going forward). */
|
|
841
|
+
zod: typeof import("zod/v4");
|
|
838
842
|
|
|
839
843
|
/** Injected pi-coding-agent exports for accessing SDK utilities */
|
|
840
844
|
pi: typeof piCodingAgent;
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* Tool wrappers for extensions.
|
|
3
3
|
*/
|
|
4
4
|
import type { AgentTool, AgentToolContext, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
5
|
-
import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai";
|
|
6
|
-
import type { Static, TSchema } from "@sinclair/typebox";
|
|
5
|
+
import type { ImageContent, Static, TextContent, TSchema } from "@oh-my-pi/pi-ai";
|
|
7
6
|
import type { Theme } from "../../modes/theme/theme";
|
|
8
7
|
import { applyToolProxy } from "../tool-proxy";
|
|
9
8
|
import type { ExtensionRunner } from "./runner";
|
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
6
|
-
import * as
|
|
6
|
+
import * as zod from "zod/v4";
|
|
7
7
|
import { hookCapability } from "../../capability/hook";
|
|
8
8
|
import type { Hook } from "../../discovery";
|
|
9
9
|
import { loadCapability } from "../../discovery";
|
|
10
10
|
import type { HookMessage } from "../../session/messages";
|
|
11
11
|
import type { SessionManager } from "../../session/session-manager";
|
|
12
|
+
import * as typebox from "../typebox";
|
|
12
13
|
import { resolvePath } from "../utils";
|
|
13
14
|
import { execCommand } from "./runner";
|
|
14
15
|
import type { ExecOptions, HookAPI, HookFactory, HookMessageRenderer, RegisteredCommand } from "./types";
|
|
@@ -136,6 +137,7 @@ async function createHookAPI(
|
|
|
136
137
|
},
|
|
137
138
|
logger,
|
|
138
139
|
typebox,
|
|
140
|
+
zod,
|
|
139
141
|
pi: await import("@oh-my-pi/pi-coding-agent"),
|
|
140
142
|
} as HookAPI;
|
|
141
143
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Tool wrapper - wraps tools with hook callbacks for interception.
|
|
3
3
|
*/
|
|
4
4
|
import type { AgentTool, AgentToolContext, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
5
|
-
import type { Static, TSchema } from "@
|
|
5
|
+
import type { Static, TSchema } from "@oh-my-pi/pi-ai";
|
|
6
6
|
import { applyToolProxy } from "../tool-proxy";
|
|
7
7
|
import type { HookRunner } from "./runner";
|
|
8
8
|
import type { ToolCallEventResult, ToolResultEventResult } from "./types";
|
|
@@ -571,8 +571,10 @@ export interface HookAPI {
|
|
|
571
571
|
|
|
572
572
|
/** File logger for error/warning/debug messages */
|
|
573
573
|
logger: typeof import("@oh-my-pi/pi-utils").logger;
|
|
574
|
-
/** Injected
|
|
575
|
-
typebox: typeof import("
|
|
574
|
+
/** Injected zod-backed typebox shim (legacy/compat — prefer `zod`). */
|
|
575
|
+
typebox: typeof import("../typebox");
|
|
576
|
+
/** Injected zod module for Zod-authored hooks. */
|
|
577
|
+
zod: typeof import("zod/v4");
|
|
576
578
|
/** Injected pi-coding-agent exports */
|
|
577
579
|
pi: typeof import("../..");
|
|
578
580
|
}
|
|
@@ -47,6 +47,17 @@ const LEGACY_PI_FILE_PREFIX = "omp-legacy-pi-file:";
|
|
|
47
47
|
const LEGACY_PI_FILE_NAMESPACE = "omp-legacy-pi-file";
|
|
48
48
|
const resolvedSpecifierFallbacks = new Map<string, string>();
|
|
49
49
|
|
|
50
|
+
// Extensions that imported `@sinclair/typebox` directly used to resolve against a
|
|
51
|
+
// real `@sinclair/typebox` install. The runtime dep was replaced with the Zod-backed
|
|
52
|
+
// shim under `extensibility/typebox.ts`; plugins still importing the public name
|
|
53
|
+
// are redirected to that shim so existing extensions keep working without code
|
|
54
|
+
// changes. Submodules like `@sinclair/typebox/compiler` are intentionally not
|
|
55
|
+
// remapped — those expose TypeBox-only APIs the shim does not provide and plugins
|
|
56
|
+
// relying on them must vendor `@sinclair/typebox` directly.
|
|
57
|
+
const TYPEBOX_SPECIFIER = "@sinclair/typebox";
|
|
58
|
+
const TYPEBOX_SPECIFIER_FILTER = /^@sinclair\/typebox$/;
|
|
59
|
+
const TYPEBOX_SHIM_PATH = path.resolve(import.meta.dir, "../typebox.ts");
|
|
60
|
+
|
|
50
61
|
let isLegacyPiSpecifierShimInstalled = false;
|
|
51
62
|
|
|
52
63
|
function remapLegacyPiSpecifier(specifier: string): string | null {
|
|
@@ -99,6 +110,12 @@ const ANY_IMPORT_SPECIFIER_REGEX = /((?:from\s+|import\s*\(\s*)["'])([^"']+)(["'
|
|
|
99
110
|
|
|
100
111
|
/** Resolve bare imports against the extension directory before loading mirrored legacy Pi files. */
|
|
101
112
|
function isUrlLikeSpecifier(specifier: string): boolean {
|
|
113
|
+
// Windows drive-letter paths (e.g. `C:\foo` or `C:/foo`) also match the URL
|
|
114
|
+
// scheme shape `[A-Za-z][A-Za-z\d+.-]*:`. Treat them as filesystem paths so
|
|
115
|
+
// `toRewrittenImportSpecifier` converts them to `file://` URLs instead of
|
|
116
|
+
// emitting raw paths whose `\n`, `\U`, ... get eaten by TS string-literal
|
|
117
|
+
// escapes inside the mirrored extension file.
|
|
118
|
+
if (/^[a-zA-Z]:[\\/]/.test(specifier)) return false;
|
|
102
119
|
return /^[a-zA-Z][a-zA-Z\d+.-]*:/.test(specifier);
|
|
103
120
|
}
|
|
104
121
|
|
|
@@ -117,6 +134,9 @@ function rewriteBareImportsForLegacyExtension(source: string, importerPath: stri
|
|
|
117
134
|
if (shouldPreserveImportSpecifier(specifier)) {
|
|
118
135
|
return match;
|
|
119
136
|
}
|
|
137
|
+
if (specifier === TYPEBOX_SPECIFIER) {
|
|
138
|
+
return `${prefix}${toRewrittenImportSpecifier(TYPEBOX_SHIM_PATH)}${suffix}`;
|
|
139
|
+
}
|
|
120
140
|
try {
|
|
121
141
|
const resolved = Bun.resolveSync(specifier, importerDir);
|
|
122
142
|
return `${prefix}${toRewrittenImportSpecifier(resolved)}${suffix}`;
|
|
@@ -223,6 +243,10 @@ function resolveLegacyPiSpecifier(args: { path: string }): { path: string } | un
|
|
|
223
243
|
};
|
|
224
244
|
}
|
|
225
245
|
|
|
246
|
+
function resolveTypeBoxSpecifier(): { path: string } {
|
|
247
|
+
return { path: TYPEBOX_SHIM_PATH };
|
|
248
|
+
}
|
|
249
|
+
|
|
226
250
|
export function installLegacyPiSpecifierShim(): void {
|
|
227
251
|
if (isLegacyPiSpecifierShimInstalled) {
|
|
228
252
|
return;
|
|
@@ -238,6 +262,12 @@ export function installLegacyPiSpecifierShim(): void {
|
|
|
238
262
|
resolveLegacyPiSpecifier,
|
|
239
263
|
);
|
|
240
264
|
|
|
265
|
+
build.onResolve({ filter: TYPEBOX_SPECIFIER_FILTER, namespace: "file" }, resolveTypeBoxSpecifier);
|
|
266
|
+
build.onResolve(
|
|
267
|
+
{ filter: TYPEBOX_SPECIFIER_FILTER, namespace: LEGACY_PI_FILE_NAMESPACE },
|
|
268
|
+
resolveTypeBoxSpecifier,
|
|
269
|
+
);
|
|
270
|
+
|
|
241
271
|
build.onResolve({ filter: /^omp-legacy-pi-file:/, namespace: "file" }, args => ({
|
|
242
272
|
path: args.path.slice(LEGACY_PI_FILE_PREFIX.length),
|
|
243
273
|
namespace: LEGACY_PI_FILE_NAMESPACE,
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
* `types.ts` files and is documented there.
|
|
14
14
|
*/
|
|
15
15
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
16
|
+
import type { CompactionPreparation, CompactionResult } from "@oh-my-pi/pi-agent-core/compaction";
|
|
16
17
|
import type { ImageContent, TextContent, ToolResultMessage } from "@oh-my-pi/pi-ai";
|
|
17
18
|
import type { Rule } from "../capability/rule";
|
|
18
19
|
import type { Goal, GoalModeState } from "../goals/state";
|
|
19
|
-
import type { CompactionPreparation, CompactionResult } from "../session/compaction";
|
|
20
20
|
import type { BranchSummaryEntry, CompactionEntry, SessionEntry } from "../session/session-manager";
|
|
21
21
|
import type { TodoItem } from "../tools/todo-write";
|
|
22
22
|
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal `@sinclair/typebox` runtime compatibility shim, backed by Zod.
|
|
3
|
+
*
|
|
4
|
+
* Historically the coding agent injected the real `@sinclair/typebox` (~5MB
|
|
5
|
+
* dependency) into extensions, hooks, custom tools, and custom commands so
|
|
6
|
+
* they could author parameter schemas as `Type.Object({ name: Type.String() })`.
|
|
7
|
+
* Internally everything already runs through Zod (`wire.ts`, `validation.ts`);
|
|
8
|
+
* the only reason TypeBox remained was extension-author compat.
|
|
9
|
+
*
|
|
10
|
+
* This module replaces that injection with a tiny façade whose `Type` builders
|
|
11
|
+
* return Zod schemas. Output is indistinguishable from hand-written Zod inside
|
|
12
|
+
* the agent pipeline:
|
|
13
|
+
*
|
|
14
|
+
* - `isZodSchema()` keys off the Zod `_zod` marker that every schema carries.
|
|
15
|
+
* - `zodToWireSchema()` emits the same draft-7 JSON Schema providers expect
|
|
16
|
+
* from TypeBox-authored tools (defaulted fields treated as optional, etc.).
|
|
17
|
+
*
|
|
18
|
+
* The surface intentionally covers only the common TypeBox builders. Plugins
|
|
19
|
+
* that reached for niche TypeBox-only APIs (`TypeCompiler`, the global
|
|
20
|
+
* `TypeRegistry`, custom `Symbol(TypeBox.Kind)` introspection) must vendor
|
|
21
|
+
* `@sinclair/typebox` directly in their own package.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { areJsonValuesEqual } from "@oh-my-pi/pi-ai/utils/schema";
|
|
25
|
+
import {
|
|
26
|
+
type ZodArray,
|
|
27
|
+
type ZodEnum,
|
|
28
|
+
type ZodObject,
|
|
29
|
+
type ZodOptional,
|
|
30
|
+
type ZodRawShape,
|
|
31
|
+
type ZodType,
|
|
32
|
+
z,
|
|
33
|
+
} from "zod/v4";
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Type aliases — exported so `import type { Static, TSchema } from "..."`
|
|
37
|
+
// patterns keep compiling at the call site.
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
export type TSchema = ZodType;
|
|
41
|
+
export type Static<T extends ZodType> = z.infer<T>;
|
|
42
|
+
export type TAny = ZodType;
|
|
43
|
+
export type TUnknown = ZodType;
|
|
44
|
+
export type TNever = ZodType;
|
|
45
|
+
export type TNull = ZodType;
|
|
46
|
+
export type TString = z.ZodString;
|
|
47
|
+
export type TNumber = z.ZodNumber;
|
|
48
|
+
export type TInteger = z.ZodNumber;
|
|
49
|
+
export type TBoolean = z.ZodBoolean;
|
|
50
|
+
export type TLiteral<V extends string | number | boolean> = z.ZodLiteral<V>;
|
|
51
|
+
export type TArray<E extends ZodType> = ZodArray<E>;
|
|
52
|
+
export type TObject<P extends ZodRawShape = ZodRawShape> = ZodObject<P>;
|
|
53
|
+
export type TOptional<E extends ZodType> = ZodOptional<E>;
|
|
54
|
+
export type TUnion<_T extends readonly ZodType[] = readonly ZodType[]> = ZodType;
|
|
55
|
+
export type TEnum<T extends readonly (string | number)[] = readonly (string | number)[]> = ZodEnum<{
|
|
56
|
+
[K in T[number] as `${K}`]: K;
|
|
57
|
+
}>;
|
|
58
|
+
export type TRecord<_K extends ZodType, _V extends ZodType> = ZodType;
|
|
59
|
+
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Option shapes — loose subset of JSON Schema metadata + per-type constraints.
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
interface Meta {
|
|
65
|
+
title?: string;
|
|
66
|
+
description?: string;
|
|
67
|
+
default?: unknown;
|
|
68
|
+
examples?: unknown[];
|
|
69
|
+
// Real TypeBox accepts arbitrary extra JSON Schema keywords; we tolerate
|
|
70
|
+
// them silently so callers don't blow up on niche metadata.
|
|
71
|
+
[key: string]: unknown;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface StringOpts extends Meta {
|
|
75
|
+
minLength?: number;
|
|
76
|
+
maxLength?: number;
|
|
77
|
+
pattern?: string;
|
|
78
|
+
format?: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface NumberOpts extends Meta {
|
|
82
|
+
minimum?: number;
|
|
83
|
+
maximum?: number;
|
|
84
|
+
exclusiveMinimum?: number;
|
|
85
|
+
exclusiveMaximum?: number;
|
|
86
|
+
multipleOf?: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface ArrayOpts extends Meta {
|
|
90
|
+
minItems?: number;
|
|
91
|
+
maxItems?: number;
|
|
92
|
+
uniqueItems?: boolean;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
interface ObjectOpts extends Meta {
|
|
96
|
+
/**
|
|
97
|
+
* TypeBox default: extra keys are preserved. Set `false` to reject unknowns,
|
|
98
|
+
* `true` to allow any, or a schema to validate them.
|
|
99
|
+
*/
|
|
100
|
+
additionalProperties?: boolean | ZodType;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
// Helpers
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
function withMeta<T extends ZodType>(schema: T, opts: Meta | undefined): T {
|
|
108
|
+
if (!opts) return schema;
|
|
109
|
+
let out: ZodType = schema;
|
|
110
|
+
if (typeof opts.description === "string") out = out.describe(opts.description);
|
|
111
|
+
if ("default" in opts) out = out.default(opts.default as never) as unknown as ZodType;
|
|
112
|
+
|
|
113
|
+
const metadata: Record<string, unknown> = {};
|
|
114
|
+
for (const [key, value] of Object.entries(opts)) {
|
|
115
|
+
if (key === "description" || key === "default" || key === "additionalProperties") continue;
|
|
116
|
+
metadata[key] = value;
|
|
117
|
+
}
|
|
118
|
+
if (Object.keys(metadata).length > 0) out = out.meta(metadata);
|
|
119
|
+
return out as T;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// Builders
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
|
|
126
|
+
function tString(opts?: StringOpts): ZodType {
|
|
127
|
+
let s: ZodType = z.string();
|
|
128
|
+
if (opts) {
|
|
129
|
+
// Format selection swaps the base schema for a more specific Zod string
|
|
130
|
+
// validator that emits the right `format` keyword in JSON Schema.
|
|
131
|
+
switch (opts.format) {
|
|
132
|
+
case "email":
|
|
133
|
+
s = z.email();
|
|
134
|
+
break;
|
|
135
|
+
case "url":
|
|
136
|
+
case "uri":
|
|
137
|
+
s = z.url();
|
|
138
|
+
break;
|
|
139
|
+
case "uuid":
|
|
140
|
+
s = z.uuid();
|
|
141
|
+
break;
|
|
142
|
+
case "date-time":
|
|
143
|
+
s = z.iso.datetime();
|
|
144
|
+
break;
|
|
145
|
+
case "date":
|
|
146
|
+
s = z.iso.date();
|
|
147
|
+
break;
|
|
148
|
+
case "time":
|
|
149
|
+
s = z.iso.time();
|
|
150
|
+
break;
|
|
151
|
+
case "ipv4":
|
|
152
|
+
s = z.ipv4();
|
|
153
|
+
break;
|
|
154
|
+
case "ipv6":
|
|
155
|
+
s = z.ipv6();
|
|
156
|
+
break;
|
|
157
|
+
default:
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
// Length/pattern constraints live on the `_ZodString` base that every
|
|
161
|
+
// format-specific schema (ZodEmail, ZodURL, ZodISODateTime, ...) extends,
|
|
162
|
+
// so we apply them regardless of which concrete subclass `s` ended up as.
|
|
163
|
+
const sf = s as z.ZodString;
|
|
164
|
+
if (typeof opts.minLength === "number") s = sf.min(opts.minLength);
|
|
165
|
+
if (typeof opts.maxLength === "number") s = (s as z.ZodString).max(opts.maxLength);
|
|
166
|
+
if (typeof opts.pattern === "string") s = (s as z.ZodString).regex(new RegExp(opts.pattern));
|
|
167
|
+
}
|
|
168
|
+
return withMeta(s, opts);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function applyNumberConstraints(base: z.ZodNumber, opts: NumberOpts | undefined): z.ZodNumber {
|
|
172
|
+
if (!opts) return base;
|
|
173
|
+
let out = base;
|
|
174
|
+
if (typeof opts.minimum === "number") out = out.min(opts.minimum);
|
|
175
|
+
if (typeof opts.maximum === "number") out = out.max(opts.maximum);
|
|
176
|
+
if (typeof opts.exclusiveMinimum === "number") out = out.gt(opts.exclusiveMinimum);
|
|
177
|
+
if (typeof opts.exclusiveMaximum === "number") out = out.lt(opts.exclusiveMaximum);
|
|
178
|
+
if (typeof opts.multipleOf === "number") out = out.multipleOf(opts.multipleOf);
|
|
179
|
+
return out;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function tNumber(opts?: NumberOpts): ZodType {
|
|
183
|
+
return withMeta(applyNumberConstraints(z.number(), opts), opts);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function tInteger(opts?: NumberOpts): ZodType {
|
|
187
|
+
return withMeta(applyNumberConstraints(z.number().int(), opts), opts);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function tBoolean(opts?: Meta): ZodType {
|
|
191
|
+
return withMeta(z.boolean(), opts);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function tNull(opts?: Meta): ZodType {
|
|
195
|
+
return withMeta(z.null(), opts);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function tAny(opts?: Meta): ZodType {
|
|
199
|
+
return withMeta(z.any(), opts);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function tUnknown(opts?: Meta): ZodType {
|
|
203
|
+
return withMeta(z.unknown(), opts);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function tNever(opts?: Meta): ZodType {
|
|
207
|
+
return withMeta(z.never(), opts);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function tLiteral<V extends string | number | boolean>(value: V, opts?: Meta): ZodType {
|
|
211
|
+
return withMeta(z.literal(value), opts);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function tUnion<T extends readonly ZodType[]>(schemas: T, opts?: Meta): ZodType {
|
|
215
|
+
if (schemas.length === 0) return withMeta(z.never(), opts);
|
|
216
|
+
if (schemas.length === 1) return withMeta(schemas[0] as ZodType, opts);
|
|
217
|
+
return withMeta(z.union(schemas as unknown as [ZodType, ZodType, ...ZodType[]]), opts);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function tIntersect(schemas: readonly ZodType[], opts?: Meta): ZodType {
|
|
221
|
+
if (schemas.length === 0) return withMeta(z.unknown(), opts);
|
|
222
|
+
if (schemas.length === 1) return withMeta(schemas[0] as ZodType, opts);
|
|
223
|
+
let out: ZodType = schemas[0] as ZodType;
|
|
224
|
+
for (let i = 1; i < schemas.length; i++) out = z.intersection(out, schemas[i] as ZodType) as ZodType;
|
|
225
|
+
return withMeta(out, opts);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function isArrayIndexKey(key: string): boolean {
|
|
229
|
+
if (!/^(?:0|[1-9]\\d*)$/.test(key)) return false;
|
|
230
|
+
const index = Number(key);
|
|
231
|
+
return Number.isSafeInteger(index) && index >= 0;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function uniqueLiteralValues(values: readonly (string | number | boolean)[]): Array<string | number | boolean> {
|
|
235
|
+
const unique: Array<string | number | boolean> = [];
|
|
236
|
+
for (const value of values) {
|
|
237
|
+
if (!unique.some(existing => existing === value)) unique.push(value);
|
|
238
|
+
}
|
|
239
|
+
return unique;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function literalUnion(values: readonly (string | number | boolean)[], opts?: Meta): ZodType {
|
|
243
|
+
const unique = uniqueLiteralValues(values);
|
|
244
|
+
if (unique.length === 0) return withMeta(z.never(), opts);
|
|
245
|
+
if (unique.length === 1) return withMeta(z.literal(unique[0] as string | number | boolean), opts);
|
|
246
|
+
const schemas = unique.map(value => z.literal(value as string | number | boolean)) as unknown as [
|
|
247
|
+
ZodType,
|
|
248
|
+
ZodType,
|
|
249
|
+
...ZodType[],
|
|
250
|
+
];
|
|
251
|
+
return withMeta(z.union(schemas), opts);
|
|
252
|
+
}
|
|
253
|
+
function tEnum<T extends Record<string, string | number> | readonly (string | number)[]>(
|
|
254
|
+
values: T,
|
|
255
|
+
opts?: Meta,
|
|
256
|
+
): ZodType {
|
|
257
|
+
const list = Array.isArray(values)
|
|
258
|
+
? values
|
|
259
|
+
: Object.entries(values)
|
|
260
|
+
.filter(([key, value]) => !(isArrayIndexKey(key) && typeof value === "string"))
|
|
261
|
+
.map(([, value]) => value);
|
|
262
|
+
return literalUnion(list, opts);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function tArray<E extends ZodType>(item: E, opts?: ArrayOpts): ZodType {
|
|
266
|
+
let arr: ZodType = z.array(item);
|
|
267
|
+
if (opts) {
|
|
268
|
+
if (typeof opts.minItems === "number") arr = (arr as ZodArray<E>).min(opts.minItems);
|
|
269
|
+
if (typeof opts.maxItems === "number") arr = (arr as ZodArray<E>).max(opts.maxItems);
|
|
270
|
+
if (opts.uniqueItems === true) {
|
|
271
|
+
arr = arr.refine(items => {
|
|
272
|
+
if (!Array.isArray(items)) return true;
|
|
273
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
274
|
+
for (let j = i + 1; j < items.length; j += 1) {
|
|
275
|
+
if (areJsonValuesEqual(items[i], items[j])) return false;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return true;
|
|
279
|
+
}, "Expected array items to be unique");
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return withMeta(arr, opts);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function tTuple(items: readonly ZodType[], opts?: Meta): ZodType {
|
|
286
|
+
return withMeta(z.tuple(items as unknown as [ZodType, ...ZodType[]]) as unknown as ZodType, opts);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function isOptional(schema: ZodType): boolean {
|
|
290
|
+
const def = (schema as { _zod?: { def?: { type?: string } } })._zod?.def;
|
|
291
|
+
return def?.type === "optional";
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function tObject<P extends ZodRawShape>(properties: P, opts?: ObjectOpts): ZodObject<P> {
|
|
295
|
+
// `z.object` automatically derives `required` from non-optional entries,
|
|
296
|
+
// so `Type.Optional(...)` flows through unchanged (Zod treats `.optional()`
|
|
297
|
+
// and `Type.Optional`-style wrappers identically).
|
|
298
|
+
let obj = z.object(properties);
|
|
299
|
+
const ap = opts?.additionalProperties;
|
|
300
|
+
if (ap === false) {
|
|
301
|
+
obj = obj.strict() as unknown as ZodObject<P>;
|
|
302
|
+
} else if (ap === undefined || ap === true) {
|
|
303
|
+
// TypeBox preserves unknown keys by default; Zod's default is `.strip()`.
|
|
304
|
+
obj = obj.loose() as unknown as ZodObject<P>;
|
|
305
|
+
} else {
|
|
306
|
+
obj = obj.catchall(ap) as unknown as ZodObject<P>;
|
|
307
|
+
}
|
|
308
|
+
return withMeta(obj, opts);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function tRecord<V extends ZodType>(key: ZodType, value: V, opts?: Meta): ZodType {
|
|
312
|
+
return withMeta(z.record(key as never, value as never) as unknown as ZodType, opts);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function tOptional<E extends ZodType>(schema: E, _opts?: Meta): ZodOptional<E> {
|
|
316
|
+
return isOptional(schema) ? (schema as unknown as ZodOptional<E>) : (schema.optional() as ZodOptional<E>);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function tNullable<E extends ZodType>(schema: E, opts?: Meta): ZodType {
|
|
320
|
+
return withMeta(schema.nullable() as ZodType, opts);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function tReadonly<E extends ZodType>(schema: E): E {
|
|
324
|
+
// TypeBox's `Type.Readonly` is purely a marker; runtime parsing is identical.
|
|
325
|
+
return schema;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function tPartial<P extends ZodRawShape>(obj: ZodObject<P>): ZodObject<P> {
|
|
329
|
+
return obj.partial() as unknown as ZodObject<P>;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function tRequired<P extends ZodRawShape>(obj: ZodObject<P>): ZodObject<P> {
|
|
333
|
+
return obj.required() as unknown as ZodObject<P>;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function tPick<P extends ZodRawShape, K extends keyof P>(obj: ZodObject<P>, keys: readonly K[]): ZodObject<Pick<P, K>> {
|
|
337
|
+
const mask = Object.fromEntries(keys.map(k => [k as string, true]));
|
|
338
|
+
return obj.pick(mask as never) as unknown as ZodObject<Pick<P, K>>;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function tOmit<P extends ZodRawShape, K extends keyof P>(obj: ZodObject<P>, keys: readonly K[]): ZodObject<Omit<P, K>> {
|
|
342
|
+
const mask = Object.fromEntries(keys.map(k => [k as string, true]));
|
|
343
|
+
return obj.omit(mask as never) as unknown as ZodObject<Omit<P, K>>;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function tComposite(objects: readonly ZodObject<ZodRawShape>[], opts?: Meta): ZodObject<ZodRawShape> {
|
|
347
|
+
// `Type.Composite([...])` flattens every object schema into one object schema
|
|
348
|
+
// rather than producing an intersection. Mirror that via repeated `extend`.
|
|
349
|
+
if (objects.length === 0) return withMeta(z.object({}), opts) as ZodObject<ZodRawShape>;
|
|
350
|
+
let out = objects[0] as ZodObject<ZodRawShape>;
|
|
351
|
+
for (let i = 1; i < objects.length; i += 1) {
|
|
352
|
+
out = out.extend(objects[i].shape) as ZodObject<ZodRawShape>;
|
|
353
|
+
}
|
|
354
|
+
return withMeta(out, opts) as ZodObject<ZodRawShape>;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ---------------------------------------------------------------------------
|
|
358
|
+
// Public `Type` namespace
|
|
359
|
+
// ---------------------------------------------------------------------------
|
|
360
|
+
|
|
361
|
+
export const Type = {
|
|
362
|
+
String: tString,
|
|
363
|
+
Number: tNumber,
|
|
364
|
+
Integer: tInteger,
|
|
365
|
+
Boolean: tBoolean,
|
|
366
|
+
Null: tNull,
|
|
367
|
+
Any: tAny,
|
|
368
|
+
Unknown: tUnknown,
|
|
369
|
+
Never: tNever,
|
|
370
|
+
Literal: tLiteral,
|
|
371
|
+
Union: tUnion,
|
|
372
|
+
Intersect: tIntersect,
|
|
373
|
+
Enum: tEnum,
|
|
374
|
+
Array: tArray,
|
|
375
|
+
Tuple: tTuple,
|
|
376
|
+
Object: tObject,
|
|
377
|
+
Record: tRecord,
|
|
378
|
+
Optional: tOptional,
|
|
379
|
+
Nullable: tNullable,
|
|
380
|
+
Readonly: tReadonly,
|
|
381
|
+
Partial: tPartial,
|
|
382
|
+
Required: tRequired,
|
|
383
|
+
Pick: tPick,
|
|
384
|
+
Omit: tOmit,
|
|
385
|
+
Composite: tComposite,
|
|
386
|
+
} as const;
|
|
387
|
+
|
|
388
|
+
export type TypeBuilder = typeof Type;
|
|
389
|
+
|
|
390
|
+
/** Default namespace export so `import * as typebox from "./typebox"` still resolves the `Type` key. */
|
|
391
|
+
export default { Type };
|
|
@@ -2,7 +2,7 @@ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallb
|
|
|
2
2
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
3
3
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import { formatNumber, prompt } from "@oh-my-pi/pi-utils";
|
|
5
|
-
import
|
|
5
|
+
import * as z from "zod/v4";
|
|
6
6
|
import type { RenderResultOptions } from "../../extensibility/custom-tools/types";
|
|
7
7
|
import type { Theme, ThemeColor } from "../../modes/theme/theme";
|
|
8
8
|
import goalDescription from "../../prompts/tools/goal.md" with { type: "text" };
|
|
@@ -14,19 +14,13 @@ import { renderStatusLine, truncateToWidth } from "../../tui";
|
|
|
14
14
|
import { completionBudgetReport, remainingTokens } from "../runtime";
|
|
15
15
|
import type { Goal, GoalStatus, GoalToolDetails } from "../state";
|
|
16
16
|
|
|
17
|
-
const goalSchema =
|
|
18
|
-
op:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
objective: Type.Optional(Type.String({ description: "Goal objective. Required when op=create." })),
|
|
22
|
-
token_budget: Type.Optional(
|
|
23
|
-
Type.Integer({
|
|
24
|
-
description: "Optional positive token budget. Only honored when op=create.",
|
|
25
|
-
}),
|
|
26
|
-
),
|
|
17
|
+
const goalSchema = z.object({
|
|
18
|
+
op: z.union([z.literal("create"), z.literal("get"), z.literal("complete")]).describe("Goal operation."),
|
|
19
|
+
objective: z.string().describe("Goal objective. Required when op=create.").optional(),
|
|
20
|
+
token_budget: z.number().int().describe("Optional positive token budget. Only honored when op=create.").optional(),
|
|
27
21
|
});
|
|
28
22
|
|
|
29
|
-
export type GoalToolInput =
|
|
23
|
+
export type GoalToolInput = z.infer<typeof goalSchema>;
|
|
30
24
|
|
|
31
25
|
export interface GoalToolResponse {
|
|
32
26
|
goal: Goal | null;
|
package/src/hashline/types.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Type } from "@sinclair/typebox";
|
|
1
|
+
import * as z from "zod/v4";
|
|
3
2
|
import type { LspBatchRequest } from "../edit/renderer";
|
|
4
3
|
import type { WritethroughCallback, WritethroughDeferredHandle } from "../lsp";
|
|
5
4
|
import type { ToolSession } from "../tools";
|
|
@@ -26,8 +25,9 @@ export type HashlineEdit =
|
|
|
26
25
|
| { kind: "insert"; cursor: HashlineCursor; text: string; lineNum: number; index: number }
|
|
27
26
|
| { kind: "delete"; anchor: Anchor; lineNum: number; index: number; oldAssertion?: string };
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
export
|
|
28
|
+
/** `path` is accepted by the edit tool runtime; other extra keys are preserved. */
|
|
29
|
+
export const hashlineEditParamsSchema = z.object({ input: z.string(), path: z.string().optional() }).passthrough();
|
|
30
|
+
export type HashlineParams = z.infer<typeof hashlineEditParamsSchema>;
|
|
31
31
|
|
|
32
32
|
export interface HashlineStreamOptions {
|
|
33
33
|
/** First line number to use when formatting (1-indexed). */
|