@oh-my-pi/pi-coding-agent 17.2.13 → 17.2.15
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 +30 -0
- package/dist/{CHANGELOG-d8xh7keh.md → CHANGELOG-fk29zh06.md} +30 -0
- package/dist/cli.js +5114 -5417
- package/dist/types/cleanse/agent.d.ts +3 -0
- package/dist/types/cleanse/checkers.d.ts +21 -1
- package/dist/types/cleanse/index.d.ts +4 -0
- package/dist/types/cleanse/parsers.d.ts +3 -1
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/cleanse-picker.d.ts +17 -0
- package/dist/types/cli/command-help.d.ts +3 -0
- package/dist/types/cli/progress-reporter.d.ts +19 -0
- package/dist/types/commands/cleanse.d.ts +11 -0
- package/dist/types/commands/compress.d.ts +37 -0
- package/dist/types/commands/launch-help.d.ts +3 -0
- package/dist/types/commands/launch.d.ts +3 -0
- package/dist/types/compress/index.d.ts +27 -0
- package/dist/types/compress/protocol.d.ts +49 -0
- package/dist/types/compress/session.d.ts +15 -0
- package/dist/types/compress/types.d.ts +54 -0
- package/dist/types/config/settings-schema.d.ts +10 -0
- package/dist/types/internal-urls/local-protocol.d.ts +8 -0
- package/dist/types/mcp/transports/header-policy.d.ts +8 -0
- package/dist/types/mcp/transports/http.d.ts +2 -0
- package/dist/types/mcp/types.d.ts +19 -0
- package/dist/types/modes/components/late-diagnostics-message.d.ts +2 -0
- package/dist/types/modes/components/todo-reminder.d.ts +2 -0
- package/dist/types/modes/components/tool-activity.d.ts +17 -0
- package/dist/types/modes/components/transcript-container.d.ts +2 -0
- package/dist/types/modes/components/ttsr-notification.d.ts +2 -0
- package/dist/types/modes/interactive-mode.d.ts +3 -1
- package/dist/types/modes/types.d.ts +3 -1
- package/dist/types/modes/utils/transcript-render-helpers.d.ts +2 -1
- package/dist/types/modes/utils/ui-helpers.d.ts +3 -1
- package/dist/types/session/agent-session-types.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +2 -0
- package/dist/types/session/session-tools.d.ts +13 -0
- package/dist/types/tools/builtin-names.d.ts +1 -2
- package/dist/types/tools/index.d.ts +1 -0
- package/dist/types/tools/think.d.ts +41 -0
- package/dist/types/utils/zip.d.ts +19 -9
- package/package.json +13 -13
- package/src/cleanse/agent.ts +67 -2
- package/src/cleanse/checkers.ts +252 -21
- package/src/cleanse/index.ts +90 -36
- package/src/cleanse/parsers.ts +243 -20
- package/src/cleanse/prompts/discovery.md +74 -0
- package/src/cli/args.ts +3 -0
- package/src/cli/cleanse-picker.ts +86 -0
- package/src/cli/command-help.ts +4 -0
- package/src/cli/flag-tables.ts +1 -0
- package/src/cli/gallery-fixtures/agentic.ts +16 -0
- package/src/{cleanse/progress.ts → cli/progress-reporter.ts} +12 -7
- package/src/cli-commands.ts +5 -0
- package/src/commands/cleanse.ts +19 -4
- package/src/commands/compress.ts +45 -0
- package/src/commands/launch-help.ts +3 -0
- package/src/commit/agentic/prompts/analyze-file.md +6 -6
- package/src/commit/agentic/prompts/session-user.md +4 -4
- package/src/compress/index.ts +318 -0
- package/src/compress/prompts/request.md +11 -0
- package/src/compress/prompts/review.md +17 -0
- package/src/compress/prompts/system.md +81 -0
- package/src/compress/protocol.ts +210 -0
- package/src/compress/session.ts +72 -0
- package/src/compress/types.ts +59 -0
- package/src/config/settings-schema.ts +11 -0
- package/src/discovery/builtin-rules/go-add-cleanup.md +8 -8
- package/src/discovery/builtin-rules/go-exp-promoted.md +8 -8
- package/src/discovery/builtin-rules/go-ioutil.md +12 -12
- package/src/discovery/builtin-rules/go-new-expr.md +8 -8
- package/src/discovery/builtin-rules/go-range-int.md +5 -5
- package/src/discovery/builtin-rules/rs-box-leak.md +7 -7
- package/src/discovery/builtin-rules/rs-future-prelude.md +4 -4
- package/src/discovery/builtin-rules/rs-parking-lot.md +6 -6
- package/src/discovery/builtin-rules/ts-no-any.md +5 -5
- package/src/discovery/builtin-rules/ts-no-deprecated-leftovers.md +8 -8
- package/src/discovery/builtin-rules/ts-no-inline-cast-access.md +13 -14
- package/src/discovery/builtin-rules/ts-no-local-is-record.md +7 -7
- package/src/discovery/builtin-rules/ts-no-test-timers.md +3 -9
- package/src/discovery/builtin-rules/ts-no-tiny-functions.md +7 -7
- package/src/discovery/builtin-rules/ts-promise-with-resolvers.md +2 -2
- package/src/discovery/builtin-rules/ts-redundant-clear-guard.md +3 -9
- package/src/discovery/builtin-rules/ts-set-map.md +2 -4
- package/src/internal-urls/local-protocol.ts +42 -0
- package/src/live/prompts/live-instructions.md +10 -10
- package/src/main.ts +4 -0
- package/src/mcp/client.ts +7 -3
- package/src/mcp/transports/header-policy.ts +28 -0
- package/src/mcp/transports/http.ts +200 -35
- package/src/mcp/types.ts +21 -0
- package/src/modes/components/chat-transcript-builder.ts +17 -5
- package/src/modes/components/late-diagnostics-message.ts +12 -1
- package/src/modes/components/todo-reminder.ts +12 -0
- package/src/modes/components/tool-activity.ts +45 -0
- package/src/modes/components/transcript-container.ts +16 -0
- package/src/modes/components/ttsr-notification.ts +12 -0
- package/src/modes/controllers/event-controller.ts +3 -6
- package/src/modes/controllers/input-controller.ts +6 -6
- package/src/modes/controllers/selector-controller.ts +8 -6
- package/src/modes/interactive-mode.ts +5 -40
- package/src/modes/print-mode.ts +13 -54
- package/src/modes/types.ts +1 -1
- package/src/modes/utils/transcript-render-helpers.ts +3 -2
- package/src/modes/utils/ui-helpers.ts +17 -7
- package/src/prompts/advisor/active-repo-watchdog.md +3 -4
- package/src/prompts/advisor/advise-tool.md +3 -3
- package/src/prompts/advisor/context-files.md +1 -1
- package/src/prompts/advisor/system.md +45 -65
- package/src/prompts/agents/designer.md +44 -44
- package/src/prompts/agents/init.md +18 -18
- package/src/prompts/agents/librarian.md +31 -31
- package/src/prompts/agents/reviewer.md +34 -39
- package/src/prompts/agents/security-reviewer.md +3 -5
- package/src/prompts/agents/task.md +11 -12
- package/src/prompts/bench.md +2 -5
- package/src/prompts/ci-green-request.md +13 -15
- package/src/prompts/dry-balance-bench.md +5 -5
- package/src/prompts/goals/goal-budget-limit.md +4 -5
- package/src/prompts/goals/goal-continuation.md +11 -11
- package/src/prompts/goals/goal-mode-active.md +7 -7
- package/src/prompts/goals/goal-todo-context.md +2 -2
- package/src/prompts/goals/guided-goal-interview.md +18 -24
- package/src/prompts/memories/read-path.md +9 -9
- package/src/prompts/memories/stage_one_system.md +9 -11
- package/src/prompts/review-custom-request.md +8 -11
- package/src/prompts/review-headless-request.md +3 -10
- package/src/prompts/security/scan-coordinator.md +6 -5
- package/src/prompts/security/validate-request.md +4 -7
- package/src/prompts/skills/user-invocation.md +2 -2
- package/src/prompts/steering/parent-irc.md +1 -1
- package/src/prompts/steering/user-interjection.md +1 -3
- package/src/prompts/system/active-repo-context.md +4 -2
- package/src/prompts/system/agent-creation-architect.md +22 -37
- package/src/prompts/system/agent-creation-user.md +3 -3
- package/src/prompts/system/auto-continue.md +1 -1
- package/src/prompts/system/auto-thinking-difficulty-local.md +5 -7
- package/src/prompts/system/auto-thinking-difficulty.md +8 -10
- package/src/prompts/system/autolearn-guidance-learn.md +2 -1
- package/src/prompts/system/autolearn-guidance.md +5 -4
- package/src/prompts/system/autolearn-nudge-autocontinue.md +3 -3
- package/src/prompts/system/background-tan-dispatch.md +3 -3
- package/src/prompts/system/btw-user.md +2 -2
- package/src/prompts/system/commit-message-system.md +8 -6
- package/src/prompts/system/eager-task.md +3 -3
- package/src/prompts/system/empty-stop-retry.md +1 -1
- package/src/prompts/system/gemini-tool-call-reminder.md +5 -5
- package/src/prompts/system/interrupted-thinking.md +3 -3
- package/src/prompts/system/irc-autoreply.md +1 -1
- package/src/prompts/system/irc-incoming.md +3 -3
- package/src/prompts/system/manual-continue.md +3 -3
- package/src/prompts/system/mcp-xdev-guidance.md +2 -2
- package/src/prompts/system/memory-consolidation-system.md +2 -2
- package/src/prompts/system/mid-run-todo-nudge.md +1 -1
- package/src/prompts/system/orchestrate-notice.md +25 -25
- package/src/prompts/system/personalities/default.md +9 -9
- package/src/prompts/system/personalities/friendly.md +11 -11
- package/src/prompts/system/personalities/pragmatic.md +8 -8
- package/src/prompts/system/plan-mode-active.md +61 -64
- package/src/prompts/system/plan-mode-approved.md +10 -11
- package/src/prompts/system/plan-mode-compact-instructions.md +11 -11
- package/src/prompts/system/plan-mode-reference.md +5 -5
- package/src/prompts/system/plan-yolo-handoff.md +2 -2
- package/src/prompts/system/prewalk-checklist.md +5 -5
- package/src/prompts/system/prewalk-continue.md +1 -1
- package/src/prompts/system/prewalk-plan.md +8 -9
- package/src/prompts/system/project-prompt.md +11 -12
- package/src/prompts/system/recap-user.md +1 -1
- package/src/prompts/system/resolve-device-reminder.md +1 -1
- package/src/prompts/system/rewind-report.md +3 -3
- package/src/prompts/system/side-channel-no-tools.md +3 -1
- package/src/prompts/system/snapcompact-context-stub.md +1 -1
- package/src/prompts/system/snapcompact-system-frames-note.md +1 -1
- package/src/prompts/system/snapcompact-system-stub.md +1 -1
- package/src/prompts/system/snapcompact-toolresult-note.md +1 -1
- package/src/prompts/system/speech-rewrite.md +11 -13
- package/src/prompts/system/subagent-async-pending.md +5 -5
- package/src/prompts/system/subagent-system-prompt.md +5 -15
- package/src/prompts/system/subagent-user-prompt.md +1 -1
- package/src/prompts/system/subagent-yield-reminder.md +12 -12
- package/src/prompts/system/system-prompt.md +110 -136
- package/src/prompts/system/tan-context-switch.md +8 -14
- package/src/prompts/system/task-label.md +3 -3
- package/src/prompts/system/thinking-loop-redirect.md +6 -6
- package/src/prompts/system/title-marker-instruction.md +2 -1
- package/src/prompts/system/title-system.md +3 -5
- package/src/prompts/system/ttsr-interrupt.md +3 -3
- package/src/prompts/system/ttsr-tool-reminder.md +1 -1
- package/src/prompts/system/ultrathink-notice.md +1 -1
- package/src/prompts/system/unexpected-stop-classifier.md +3 -3
- package/src/prompts/system/vibe-mode-active.md +15 -15
- package/src/prompts/system/web-search.md +16 -16
- package/src/prompts/system/workflow-notice.md +35 -33
- package/src/prompts/system/xdev-mount-notice.md +4 -4
- package/src/prompts/tools/apply-patch.md +22 -23
- package/src/prompts/tools/approve.md +5 -0
- package/src/prompts/tools/ask.md +10 -10
- package/src/prompts/tools/checkpoint.md +7 -7
- package/src/prompts/tools/computer.md +16 -16
- package/src/prompts/tools/github.md +12 -12
- package/src/prompts/tools/goal.md +8 -9
- package/src/prompts/tools/grep.md +5 -5
- package/src/prompts/tools/image-attachment-describe-system.md +6 -6
- package/src/prompts/tools/image-attachment-describe.md +3 -8
- package/src/prompts/tools/image-gen.md +4 -4
- package/src/prompts/tools/inspect-image-system.md +10 -10
- package/src/prompts/tools/inspect-image.md +10 -13
- package/src/prompts/tools/learn.md +4 -4
- package/src/prompts/tools/manage-skill.md +9 -6
- package/src/prompts/tools/memory-edit.md +8 -8
- package/src/prompts/tools/recall.md +4 -4
- package/src/prompts/tools/reflect.md +2 -2
- package/src/prompts/tools/replace.md +13 -11
- package/src/prompts/tools/retain.md +3 -4
- package/src/prompts/tools/rewind.md +7 -8
- package/src/prompts/tools/rewrite.md +12 -0
- package/src/prompts/tools/security-publish.md +5 -1
- package/src/prompts/tools/security-scan.md +10 -1
- package/src/prompts/tools/task-async-contract.md +7 -1
- package/src/prompts/tools/todo.md +27 -25
- package/src/prompts/tools/vibe-kill.md +2 -2
- package/src/prompts/tools/vibe-list.md +2 -2
- package/src/prompts/tools/vibe-send.md +6 -7
- package/src/prompts/tools/vibe-spawn.md +8 -6
- package/src/prompts/tools/web-search.md +5 -5
- package/src/sdk.ts +10 -1
- package/src/session/agent-session-types.ts +2 -0
- package/src/session/agent-session.ts +28 -0
- package/src/session/session-handoff.ts +21 -0
- package/src/session/session-tools.ts +47 -0
- package/src/tools/builtin-names.ts +1 -2
- package/src/tools/index.ts +10 -0
- package/src/tools/read-format.ts +8 -3
- package/src/tools/read.ts +18 -7
- package/src/tools/renderers.ts +2 -0
- package/src/tools/think.ts +84 -0
- package/src/tools/write.ts +1 -1
- package/src/utils/file-mentions.ts +8 -2
- package/src/utils/zip.ts +858 -94
- package/dist/types/cleanse/progress.d.ts +0 -14
|
@@ -21,6 +21,7 @@ import { usesCodexTaskPrompt } from "../task/prompt-policy";
|
|
|
21
21
|
import { isMCPToolName, normalizeToolNames } from "../tools/builtin-names";
|
|
22
22
|
import { computerExposureMode } from "../tools/computer/exposure";
|
|
23
23
|
import { wrapToolWithMetaNotice } from "../tools/output-meta";
|
|
24
|
+
import { supportsExternalThinking } from "../tools/think";
|
|
24
25
|
import { ToolAbortError, ToolError } from "../tools/tool-errors";
|
|
25
26
|
import { isMountableUnderXdev, listXdevTools, type XdevState, xdevDocsFor, xdevEntries } from "../tools/xdev";
|
|
26
27
|
import { type EditMode, resolveEditMode } from "../utils/edit-mode";
|
|
@@ -68,6 +69,8 @@ interface SessionToolsOptions {
|
|
|
68
69
|
toolRegistry?: Map<string, AgentTool>;
|
|
69
70
|
createVibeTools?: () => AgentTool[];
|
|
70
71
|
createComputerTool?: () => Promise<AgentTool | null>;
|
|
72
|
+
/** Creates the private `think` scratchpad tool for runtime setting changes. */
|
|
73
|
+
createThinkTool?: () => Promise<AgentTool | null>;
|
|
71
74
|
/** Creates the built-in `inspect_image` tool for session-scoped runtime enablement (see {@link SessionTools.setInspectImageMode}). */
|
|
72
75
|
createInspectImageTool?: () => Promise<AgentTool | null>;
|
|
73
76
|
builtInToolNames?: Iterable<string>;
|
|
@@ -184,6 +187,7 @@ export class SessionTools {
|
|
|
184
187
|
#toolRegistry: Map<string, AgentTool>;
|
|
185
188
|
#createVibeTools: (() => AgentTool[]) | undefined;
|
|
186
189
|
#createComputerTool: SessionToolsOptions["createComputerTool"];
|
|
190
|
+
#createThinkTool: SessionToolsOptions["createThinkTool"];
|
|
187
191
|
#createInspectImageTool: SessionToolsOptions["createInspectImageTool"];
|
|
188
192
|
#installedVibeToolNames = new Set<string>();
|
|
189
193
|
#builtInToolNames: Set<string>;
|
|
@@ -241,6 +245,7 @@ export class SessionTools {
|
|
|
241
245
|
this.#toolRegistry = options.toolRegistry ?? new Map();
|
|
242
246
|
this.#createVibeTools = options.createVibeTools;
|
|
243
247
|
this.#createComputerTool = options.createComputerTool;
|
|
248
|
+
this.#createThinkTool = options.createThinkTool;
|
|
244
249
|
this.#createInspectImageTool = options.createInspectImageTool;
|
|
245
250
|
this.#builtInToolNames = new Set(options.builtInToolNames ?? []);
|
|
246
251
|
this.#mcpManagerToolNames = new Set(options.mcpManagerToolNames ?? []);
|
|
@@ -1158,6 +1163,48 @@ export class SessionTools {
|
|
|
1158
1163
|
});
|
|
1159
1164
|
}
|
|
1160
1165
|
|
|
1166
|
+
/**
|
|
1167
|
+
* Session-scoped enable/disable for the private `think` scratchpad tool.
|
|
1168
|
+
*
|
|
1169
|
+
* Enabling constructs the tool once and refreshes the model's tool contract;
|
|
1170
|
+
* disabling removes it from the active set while preserving its registry entry.
|
|
1171
|
+
*
|
|
1172
|
+
* @returns false when enabling was requested but this session cannot build the tool.
|
|
1173
|
+
*/
|
|
1174
|
+
setThinkToolEnabled(enabled: boolean): Promise<boolean> {
|
|
1175
|
+
return this.#setThinkToolActive(enabled && supportsExternalThinking(this.#host.model()));
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
/** Reconciles the external scratchpad after the active model changes. */
|
|
1179
|
+
reconcileThinkTool(): Promise<boolean> {
|
|
1180
|
+
return this.#setThinkToolActive(
|
|
1181
|
+
this.#host.settings.get("externalThinking") && supportsExternalThinking(this.#host.model()),
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
#setThinkToolActive(enabled: boolean): Promise<boolean> {
|
|
1186
|
+
return this.runToolRegistryMutation(async () => {
|
|
1187
|
+
const active = this.getEnabledToolNames();
|
|
1188
|
+
if (!enabled) {
|
|
1189
|
+
if (active.includes("think")) {
|
|
1190
|
+
await this.#applyActiveToolsByName(active.filter(name => name !== "think"));
|
|
1191
|
+
}
|
|
1192
|
+
return true;
|
|
1193
|
+
}
|
|
1194
|
+
if (!this.#toolRegistry.has("think")) {
|
|
1195
|
+
const tool = await this.#createThinkTool?.();
|
|
1196
|
+
if (tool?.name !== "think") return false;
|
|
1197
|
+
const wrapped = this.#wrapRuntimeTool(tool);
|
|
1198
|
+
this.#toolRegistry.set(wrapped.name, wrapped);
|
|
1199
|
+
this.#builtInToolNames.add(wrapped.name);
|
|
1200
|
+
}
|
|
1201
|
+
if (!active.includes("think")) {
|
|
1202
|
+
await this.#applyActiveToolsByName([...active, "think"]);
|
|
1203
|
+
}
|
|
1204
|
+
return true;
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1161
1208
|
/** Current effective inspect_image state for `/vision status`. */
|
|
1162
1209
|
inspectImageState(): { mode: InspectImageMode; active: boolean; model: string | undefined } {
|
|
1163
1210
|
const model = this.#host.model();
|
|
@@ -32,8 +32,7 @@ export const BUILTIN_TOOL_NAMES = [
|
|
|
32
32
|
|
|
33
33
|
export type BuiltinToolName = (typeof BUILTIN_TOOL_NAMES)[number];
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
export const HIDDEN_TOOL_NAMES = ["yield", "goal"] as const;
|
|
35
|
+
export const HIDDEN_TOOL_NAMES = ["yield", "goal", "think"] as const;
|
|
37
36
|
|
|
38
37
|
export type HiddenToolName = (typeof HIDDEN_TOOL_NAMES)[number];
|
|
39
38
|
|
package/src/tools/index.ts
CHANGED
|
@@ -62,6 +62,7 @@ import { wrapToolWithMetaNotice } from "./output-meta";
|
|
|
62
62
|
import { ReadTool } from "./read";
|
|
63
63
|
import type { PlanProposalHandler } from "./resolve";
|
|
64
64
|
import { SecurityScanTool } from "./security-scan";
|
|
65
|
+
import { supportsExternalThinking, ThinkTool } from "./think";
|
|
65
66
|
import { type TodoPhase, TodoTool } from "./todo";
|
|
66
67
|
import { WriteTool } from "./write";
|
|
67
68
|
import { isMountableUnderXdev, type XdevState } from "./xdev";
|
|
@@ -102,6 +103,7 @@ export * from "./report-tool-issue";
|
|
|
102
103
|
export * from "./resolve";
|
|
103
104
|
export * from "./review";
|
|
104
105
|
export * from "./security-scan";
|
|
106
|
+
export * from "./think";
|
|
105
107
|
export * from "./todo";
|
|
106
108
|
export * from "./tts";
|
|
107
109
|
export * from "./vibe";
|
|
@@ -444,6 +446,7 @@ export const BUILTIN_TOOLS: Record<BuiltinToolName, ToolFactory> = {
|
|
|
444
446
|
};
|
|
445
447
|
|
|
446
448
|
export const HIDDEN_TOOLS: Record<HiddenToolName, ToolFactory> = {
|
|
449
|
+
think: () => new ThinkTool(),
|
|
447
450
|
yield: s => new YieldTool(s),
|
|
448
451
|
goal: s => new GoalTool(s),
|
|
449
452
|
};
|
|
@@ -464,6 +467,8 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
464
467
|
: undefined;
|
|
465
468
|
const goalEnabled = session.settings.get("goal.enabled");
|
|
466
469
|
const goalModeActive = !restrictToolNames && goalEnabled && session.getGoalModeState?.()?.enabled === true;
|
|
470
|
+
const externalThinkingActive =
|
|
471
|
+
session.settings.get("externalThinking") && supportsExternalThinking(session.getActiveModel?.());
|
|
467
472
|
if (goalModeActive && requestedTools && !requestedTools.includes("goal")) {
|
|
468
473
|
requestedTools.push("goal");
|
|
469
474
|
}
|
|
@@ -562,6 +567,9 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
562
567
|
if (session.settings.get("memory.backend") === "mnemopi" && !requestedTools.includes("memory_edit")) {
|
|
563
568
|
requestedTools.push("memory_edit");
|
|
564
569
|
}
|
|
570
|
+
if (externalThinkingActive && !requestedTools.includes("think")) {
|
|
571
|
+
requestedTools.push("think");
|
|
572
|
+
}
|
|
565
573
|
// Auto-learn tools are gated by `autolearn.enabled` but, like the memory
|
|
566
574
|
// tools above, must also be force-included into an explicit requestedTools
|
|
567
575
|
// list so a restricted top-level session whose controller/guidance is
|
|
@@ -604,6 +612,7 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
604
612
|
if (name === "inspect_image") return isInspectImageToolActive(session);
|
|
605
613
|
if (name === "web_search") return session.settings.get("web_search.enabled");
|
|
606
614
|
if (name === "security_scan") return session.settings.get("security.enabled");
|
|
615
|
+
if (name === "think") return externalThinkingActive;
|
|
607
616
|
if (name === "ask") return session.settings.get("ask.enabled");
|
|
608
617
|
if (name === "browser") return session.settings.get("browser.enabled");
|
|
609
618
|
if (name === "computer") return session.settings.get("computer.enabled");
|
|
@@ -650,6 +659,7 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
650
659
|
...Object.entries(BUILTIN_TOOLS)
|
|
651
660
|
.filter(([name]) => isToolAllowed(name))
|
|
652
661
|
.map(([name, factory]) => [name, factory] as const),
|
|
662
|
+
...(externalThinkingActive ? ([["think", HIDDEN_TOOLS.think]] as const) : []),
|
|
653
663
|
...(includeYield ? ([["yield", HIDDEN_TOOLS.yield]] as const) : []),
|
|
654
664
|
...(goalModeActive ? ([["goal", HIDDEN_TOOLS.goal]] as const) : []),
|
|
655
665
|
];
|
package/src/tools/read-format.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
formatHashlineHeader,
|
|
4
|
+
formatNumberedLine,
|
|
5
|
+
formatNumberedLines,
|
|
6
|
+
splitAddressableFileLines,
|
|
7
|
+
} from "@oh-my-pi/hashline";
|
|
3
8
|
import type { AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
4
9
|
import { canonicalSnapshotKey, getFileSnapshotStore, recordSeenLines } from "../edit/file-snapshot-store";
|
|
5
10
|
import { normalizeToLF } from "../edit/normalize";
|
|
@@ -290,7 +295,7 @@ export function buildInMemoryTextResult(
|
|
|
290
295
|
): AgentToolResult<ReadToolDetails> {
|
|
291
296
|
const displayMode = resolveFileDisplayMode(session, { raw: options.raw, immutable: options.immutable });
|
|
292
297
|
const details = options.details ?? {};
|
|
293
|
-
const allLines = text.split("\n");
|
|
298
|
+
const allLines = options.raw === true ? text.split("\n") : splitAddressableFileLines(text);
|
|
294
299
|
const totalLines = allLines.length;
|
|
295
300
|
details.totalLines = totalLines;
|
|
296
301
|
// User-requested 0-indexed range start. Lines BEFORE this are leading
|
|
@@ -487,7 +492,7 @@ export function buildInMemoryMultiRangeResult(
|
|
|
487
492
|
): AgentToolResult<ReadToolDetails> {
|
|
488
493
|
const displayMode = resolveFileDisplayMode(session, { raw: options.raw, immutable: options.immutable });
|
|
489
494
|
const details = options.details ?? {};
|
|
490
|
-
const allLines = text.split("\n");
|
|
495
|
+
const allLines = options.raw === true ? text.split("\n") : splitAddressableFileLines(text);
|
|
491
496
|
const totalLines = allLines.length;
|
|
492
497
|
details.totalLines = totalLines;
|
|
493
498
|
const shouldAddHashLines = displayMode.hashLines;
|
package/src/tools/read.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { splitAddressableFileLines } from "@oh-my-pi/hashline";
|
|
3
4
|
import { type } from "@oh-my-pi/omptype";
|
|
4
5
|
import type {
|
|
5
6
|
AgentTool,
|
|
@@ -119,12 +120,17 @@ const MAX_ARTIFACT_RAW_INLINE_BYTES = DEFAULT_MAX_BYTES;
|
|
|
119
120
|
async function readBracketContextFullLines(absolutePath: string, fileSize: number): Promise<string[] | undefined> {
|
|
120
121
|
if (fileSize > SNAPSHOT_MAX_BYTES) return undefined;
|
|
121
122
|
try {
|
|
122
|
-
return normalizeToLF(await Bun.file(absolutePath).text())
|
|
123
|
+
return splitAddressableFileLines(normalizeToLF(await Bun.file(absolutePath).text()));
|
|
123
124
|
} catch {
|
|
124
125
|
return undefined;
|
|
125
126
|
}
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
interface StreamFileLinesOptions {
|
|
130
|
+
includeTerminalNewline?: boolean;
|
|
131
|
+
stopScanAfterCollect?: boolean;
|
|
132
|
+
}
|
|
133
|
+
|
|
128
134
|
async function streamLinesFromFile(
|
|
129
135
|
filePath: string,
|
|
130
136
|
startLine: number,
|
|
@@ -132,7 +138,7 @@ async function streamLinesFromFile(
|
|
|
132
138
|
maxBytes: number,
|
|
133
139
|
selectedLineLimit: number | null,
|
|
134
140
|
signal?: AbortSignal,
|
|
135
|
-
|
|
141
|
+
options: StreamFileLinesOptions = {},
|
|
136
142
|
): Promise<{
|
|
137
143
|
lines: string[];
|
|
138
144
|
totalFileLines: number;
|
|
@@ -141,9 +147,12 @@ async function streamLinesFromFile(
|
|
|
141
147
|
firstLinePreview?: { text: string; bytes: number };
|
|
142
148
|
firstLineByteLength?: number;
|
|
143
149
|
selectedBytesTotal: number;
|
|
150
|
+
/** Whether the fully scanned source ended in a newline. */
|
|
151
|
+
hasTrailingNewline: boolean;
|
|
144
152
|
/** False when `stopScanAfterCollect` cut the scan short — `totalFileLines` is then a lower bound. */
|
|
145
153
|
reachedEof: boolean;
|
|
146
154
|
}> {
|
|
155
|
+
const { includeTerminalNewline = false, stopScanAfterCollect = false } = options;
|
|
147
156
|
const bufferChunk = Buffer.allocUnsafe(READ_CHUNK_SIZE);
|
|
148
157
|
const collectedLines: string[] = [];
|
|
149
158
|
let lineIndex = 0;
|
|
@@ -311,7 +320,7 @@ async function streamLinesFromFile(
|
|
|
311
320
|
}
|
|
312
321
|
}
|
|
313
322
|
|
|
314
|
-
if (reachedEof && (
|
|
323
|
+
if (reachedEof && (currentLineLength > 0 || !sawAnyByte || (endedWithNewline && includeTerminalNewline))) {
|
|
315
324
|
finalizeLine();
|
|
316
325
|
}
|
|
317
326
|
|
|
@@ -330,6 +339,7 @@ async function streamLinesFromFile(
|
|
|
330
339
|
firstLineByteLength,
|
|
331
340
|
selectedBytesTotal,
|
|
332
341
|
reachedEof,
|
|
342
|
+
hasTrailingNewline: reachedEof && endedWithNewline,
|
|
333
343
|
};
|
|
334
344
|
}
|
|
335
345
|
|
|
@@ -692,7 +702,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
692
702
|
maxBytesForRead,
|
|
693
703
|
maxLines,
|
|
694
704
|
signal,
|
|
695
|
-
|
|
705
|
+
{ includeTerminalNewline: rawSelector, stopScanAfterCollect: fileSize > SNAPSHOT_MAX_BYTES },
|
|
696
706
|
);
|
|
697
707
|
totalFileLines = streamResult.totalFileLines;
|
|
698
708
|
collectedLines = streamResult.lines;
|
|
@@ -1256,7 +1266,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
1256
1266
|
maxBytesForRead,
|
|
1257
1267
|
selectedLineLimit,
|
|
1258
1268
|
undefined, // plain-file read: deterministic and fast, never abort mid-read
|
|
1259
|
-
|
|
1269
|
+
{ includeTerminalNewline: rawSelector, stopScanAfterCollect: fileSize > SNAPSHOT_MAX_BYTES },
|
|
1260
1270
|
);
|
|
1261
1271
|
|
|
1262
1272
|
const {
|
|
@@ -1267,6 +1277,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
1267
1277
|
firstLinePreview,
|
|
1268
1278
|
firstLineByteLength,
|
|
1269
1279
|
reachedEof,
|
|
1280
|
+
hasTrailingNewline,
|
|
1270
1281
|
} = streamResult;
|
|
1271
1282
|
|
|
1272
1283
|
// Check if offset is out of bounds - return graceful message instead of throwing
|
|
@@ -1347,7 +1358,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
1347
1358
|
const tag = isWholeFile
|
|
1348
1359
|
? getFileSnapshotStore(this.session).record(
|
|
1349
1360
|
canonicalSnapshotKey(absolutePath),
|
|
1350
|
-
normalizeToLF(collectedLines.join("\n")),
|
|
1361
|
+
normalizeToLF(`${collectedLines.join("\n")}${hasTrailingNewline ? "\n" : ""}`),
|
|
1351
1362
|
)
|
|
1352
1363
|
: await recordFileSnapshot(this.session, absolutePath);
|
|
1353
1364
|
if (tag) {
|
|
@@ -1694,7 +1705,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
1694
1705
|
maxBytesForRead,
|
|
1695
1706
|
selectedLineLimit,
|
|
1696
1707
|
signal,
|
|
1697
|
-
artifact.size > SNAPSHOT_MAX_BYTES,
|
|
1708
|
+
{ includeTerminalNewline: rawSelector, stopScanAfterCollect: artifact.size > SNAPSHOT_MAX_BYTES },
|
|
1698
1709
|
);
|
|
1699
1710
|
const {
|
|
1700
1711
|
lines: collectedLines,
|
package/src/tools/renderers.ts
CHANGED
|
@@ -27,6 +27,7 @@ import { inspectImageToolRenderer } from "./inspect-image-renderer";
|
|
|
27
27
|
import { recallToolRenderer, reflectToolRenderer, retainToolRenderer } from "./memory-render";
|
|
28
28
|
import { readToolRenderer } from "./read";
|
|
29
29
|
import { resolveRenderer } from "./resolve";
|
|
30
|
+
import { thinkToolRenderer } from "./think";
|
|
30
31
|
import { todoToolRenderer } from "./todo";
|
|
31
32
|
import { createVibeToolRenderer } from "./vibe";
|
|
32
33
|
import { writeToolRenderer } from "./write";
|
|
@@ -115,6 +116,7 @@ export const toolRenderers: Record<string, ToolRenderer> = {
|
|
|
115
116
|
get task(): ToolRenderer {
|
|
116
117
|
return taskToolRenderer as ToolRenderer;
|
|
117
118
|
},
|
|
119
|
+
think: thinkToolRenderer as ToolRenderer,
|
|
118
120
|
todo: todoToolRenderer as ToolRenderer,
|
|
119
121
|
github: githubToolRenderer as ToolRenderer,
|
|
120
122
|
goal: goalToolRenderer as ToolRenderer,
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { type } from "@oh-my-pi/omptype";
|
|
2
|
+
import type { AgentTool, AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
3
|
+
import type { Model } from "@oh-my-pi/pi-ai";
|
|
4
|
+
import { type Component, Markdown } from "@oh-my-pi/pi-tui";
|
|
5
|
+
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
6
|
+
import { getMarkdownTheme, type Theme } from "../modes/theme/theme";
|
|
7
|
+
|
|
8
|
+
/** Whether a model transport can suppress native reasoning while private scratchpad thoughts are active. */
|
|
9
|
+
export function supportsExternalThinking(model: Model | null | undefined): boolean {
|
|
10
|
+
if (!model) return false;
|
|
11
|
+
const requiresThinking =
|
|
12
|
+
model.api === "anthropic-messages" &&
|
|
13
|
+
model.compat !== undefined &&
|
|
14
|
+
"requiresThinkingEnabled" in model.compat &&
|
|
15
|
+
model.compat.requiresThinkingEnabled === true;
|
|
16
|
+
if (model.reasoning && (requiresThinking || (model.thinking?.requiresEffort && !model.thinking.suppressWhenOff))) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
if (model.api === "google-generative-ai" || model.api === "google-gemini-cli" || model.api === "google-vertex") {
|
|
20
|
+
return !model.reasoning || model.thinking?.mode === "budget" || model.thinking?.suppressWhenOff === true;
|
|
21
|
+
}
|
|
22
|
+
return (
|
|
23
|
+
model.api === "openai-responses" ||
|
|
24
|
+
model.api === "azure-openai-responses" ||
|
|
25
|
+
model.api === "openai-codex-responses" ||
|
|
26
|
+
model.api === "anthropic-messages"
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const thinkSchema = type({
|
|
31
|
+
thoughts: type("string").describe("private scratchpad; not shown to user"),
|
|
32
|
+
"+": "reject",
|
|
33
|
+
}).describe("private scratchpad; not shown to user");
|
|
34
|
+
|
|
35
|
+
type ThinkParams = typeof thinkSchema.infer;
|
|
36
|
+
|
|
37
|
+
export type ThinkRenderArgs = {
|
|
38
|
+
thoughts?: string;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const thinkToolRenderer = {
|
|
42
|
+
inline: true,
|
|
43
|
+
renderCall(args: ThinkRenderArgs, _options: RenderResultOptions, uiTheme: Theme): Component {
|
|
44
|
+
const thoughts =
|
|
45
|
+
typeof args === "object" && args !== null && "thoughts" in args && typeof args.thoughts === "string"
|
|
46
|
+
? args.thoughts
|
|
47
|
+
: "";
|
|
48
|
+
return new Markdown(thoughts, 1, 0, getMarkdownTheme(), {
|
|
49
|
+
color: (text: string) => uiTheme.fg("thinkingText", text),
|
|
50
|
+
italic: true,
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
renderResult(): Component {
|
|
54
|
+
return undefined as unknown as Component;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
interface ThinkToolDetails {
|
|
59
|
+
recorded: true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Records private scratchpad thoughts while native model reasoning is disabled. */
|
|
63
|
+
export class ThinkTool implements AgentTool<typeof thinkSchema, ThinkToolDetails> {
|
|
64
|
+
readonly name = "think";
|
|
65
|
+
readonly approval = "read" as const;
|
|
66
|
+
readonly label = "Think";
|
|
67
|
+
readonly summary = "Record private scratchpad thoughts";
|
|
68
|
+
readonly description = "private scratchpad; not shown to user";
|
|
69
|
+
readonly parameters = thinkSchema;
|
|
70
|
+
readonly strict = true;
|
|
71
|
+
readonly intent = "omit" as const;
|
|
72
|
+
|
|
73
|
+
async execute(_toolCallId: string, _params: ThinkParams): Promise<AgentToolResult<ThinkToolDetails>> {
|
|
74
|
+
return {
|
|
75
|
+
content: [
|
|
76
|
+
{
|
|
77
|
+
type: "text",
|
|
78
|
+
text: "------",
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
details: { recorded: true },
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
package/src/tools/write.ts
CHANGED
|
@@ -659,7 +659,7 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
|
|
|
659
659
|
const entries = new Map<string, ArchiveMemberContent>();
|
|
660
660
|
if (resolvedArchivePath.exists) {
|
|
661
661
|
try {
|
|
662
|
-
const existing = await readArchiveEntries({
|
|
662
|
+
const existing = await readArchiveEntries({ path: finalPath, format });
|
|
663
663
|
for (const [entryPath, data] of existing) {
|
|
664
664
|
entries.set(entryPath, data);
|
|
665
665
|
}
|
|
@@ -7,7 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import * as fs from "node:fs/promises";
|
|
9
9
|
import path from "node:path";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
formatHashlineHeader,
|
|
12
|
+
formatNumberedLines,
|
|
13
|
+
type SnapshotStore,
|
|
14
|
+
splitAddressableFileLines,
|
|
15
|
+
} from "@oh-my-pi/hashline";
|
|
11
16
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
12
17
|
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
13
18
|
import { formatAge, formatBytes, isProbablyBinary, readImageMetadata } from "@oh-my-pi/pi-utils";
|
|
@@ -270,7 +275,8 @@ export async function generateFileMentionMessages(
|
|
|
270
275
|
const content = await Bun.file(absolutePath).text();
|
|
271
276
|
const snapshotStore = options?.useHashLines ? options.snapshotStore : undefined;
|
|
272
277
|
const normalized = snapshotStore ? normalizeToLF(content) : content;
|
|
273
|
-
|
|
278
|
+
const displayText = snapshotStore ? splitAddressableFileLines(normalized).join("\n") : normalized;
|
|
279
|
+
let { output, lineCount } = buildTextOutput(displayText);
|
|
274
280
|
if (snapshotStore) {
|
|
275
281
|
const tag = snapshotStore.record(canonicalSnapshotKey(absolutePath), normalized);
|
|
276
282
|
output = `${formatHashlineHeader(resolvedPath, tag)}\n${formatNumberedLines(output)}`;
|