@oh-my-pi/pi-coding-agent 3.14.0 → 3.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +79 -0
- package/docs/theme.md +38 -5
- package/examples/sdk/11-sessions.ts +2 -2
- package/package.json +7 -4
- package/src/cli/file-processor.ts +51 -2
- package/src/cli/plugin-cli.ts +25 -19
- package/src/cli/update-cli.ts +4 -3
- package/src/core/agent-session.ts +31 -4
- package/src/core/compaction/branch-summarization.ts +4 -32
- package/src/core/compaction/compaction.ts +6 -84
- package/src/core/compaction/utils.ts +2 -3
- package/src/core/custom-tools/types.ts +2 -0
- package/src/core/export-html/index.ts +1 -1
- package/src/core/hooks/tool-wrapper.ts +0 -1
- package/src/core/hooks/types.ts +2 -2
- package/src/core/plugins/doctor.ts +9 -1
- package/src/core/sdk.ts +2 -1
- package/src/core/session-manager.ts +518 -40
- package/src/core/settings-manager.ts +174 -0
- package/src/core/system-prompt.ts +9 -14
- package/src/core/title-generator.ts +2 -8
- package/src/core/tools/ask.ts +19 -37
- package/src/core/tools/bash.ts +2 -37
- package/src/core/tools/edit.ts +2 -9
- package/src/core/tools/exa/render.ts +52 -48
- package/src/core/tools/find.ts +10 -8
- package/src/core/tools/grep.ts +45 -17
- package/src/core/tools/ls.ts +22 -2
- package/src/core/tools/lsp/clients/biome-client.ts +207 -0
- package/src/core/tools/lsp/clients/index.ts +49 -0
- package/src/core/tools/lsp/clients/lsp-linter-client.ts +98 -0
- package/src/core/tools/lsp/config.ts +3 -0
- package/src/core/tools/lsp/index.ts +107 -55
- package/src/core/tools/lsp/render.ts +192 -79
- package/src/core/tools/lsp/types.ts +27 -0
- package/src/core/tools/lsp/utils.ts +62 -22
- package/src/core/tools/notebook.ts +9 -1
- package/src/core/tools/output.ts +37 -14
- package/src/core/tools/read.ts +349 -34
- package/src/core/tools/renderers.ts +290 -89
- package/src/core/tools/review.ts +12 -5
- package/src/core/tools/task/agents.ts +5 -5
- package/src/core/tools/task/commands.ts +3 -3
- package/src/core/tools/task/executor.ts +33 -1
- package/src/core/tools/task/index.ts +93 -6
- package/src/core/tools/task/render.ts +147 -66
- package/src/core/tools/task/types.ts +14 -9
- package/src/core/tools/web-fetch.ts +242 -103
- package/src/core/tools/web-search/index.ts +64 -20
- package/src/core/tools/web-search/providers/exa.ts +68 -172
- package/src/core/tools/web-search/render.ts +264 -74
- package/src/core/tools/write.ts +2 -8
- package/src/main.ts +10 -6
- package/src/modes/cleanup.ts +23 -0
- package/src/modes/index.ts +9 -4
- package/src/modes/interactive/components/bash-execution.ts +6 -3
- package/src/modes/interactive/components/branch-summary-message.ts +1 -1
- package/src/modes/interactive/components/compaction-summary-message.ts +1 -1
- package/src/modes/interactive/components/dynamic-border.ts +1 -1
- package/src/modes/interactive/components/extensions/extension-dashboard.ts +4 -5
- package/src/modes/interactive/components/extensions/extension-list.ts +18 -16
- package/src/modes/interactive/components/extensions/inspector-panel.ts +8 -8
- package/src/modes/interactive/components/hook-message.ts +2 -2
- package/src/modes/interactive/components/hook-selector.ts +1 -1
- package/src/modes/interactive/components/model-selector.ts +22 -9
- package/src/modes/interactive/components/oauth-selector.ts +20 -4
- package/src/modes/interactive/components/plugin-settings.ts +4 -2
- package/src/modes/interactive/components/session-selector.ts +9 -6
- package/src/modes/interactive/components/settings-defs.ts +285 -1
- package/src/modes/interactive/components/settings-selector.ts +176 -3
- package/src/modes/interactive/components/status-line/index.ts +4 -0
- package/src/modes/interactive/components/status-line/presets.ts +94 -0
- package/src/modes/interactive/components/status-line/segments.ts +350 -0
- package/src/modes/interactive/components/status-line/separators.ts +55 -0
- package/src/modes/interactive/components/status-line/types.ts +81 -0
- package/src/modes/interactive/components/status-line-segment-editor.ts +357 -0
- package/src/modes/interactive/components/status-line.ts +170 -223
- package/src/modes/interactive/components/tool-execution.ts +446 -211
- package/src/modes/interactive/components/tree-selector.ts +17 -6
- package/src/modes/interactive/components/ttsr-notification.ts +4 -4
- package/src/modes/interactive/components/welcome.ts +27 -19
- package/src/modes/interactive/interactive-mode.ts +98 -13
- package/src/modes/interactive/theme/dark.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-arctic.json +111 -0
- package/src/modes/interactive/theme/defaults/dark-catppuccin.json +106 -0
- package/src/modes/interactive/theme/defaults/dark-cyberpunk.json +109 -0
- package/src/modes/interactive/theme/defaults/dark-dracula.json +105 -0
- package/src/modes/interactive/theme/defaults/dark-forest.json +103 -0
- package/src/modes/interactive/theme/defaults/dark-github.json +112 -0
- package/src/modes/interactive/theme/defaults/dark-gruvbox.json +119 -0
- package/src/modes/interactive/theme/defaults/dark-monochrome.json +101 -0
- package/src/modes/interactive/theme/defaults/dark-monokai.json +105 -0
- package/src/modes/interactive/theme/defaults/dark-nord.json +104 -0
- package/src/modes/interactive/theme/defaults/dark-ocean.json +108 -0
- package/src/modes/interactive/theme/defaults/dark-one.json +107 -0
- package/src/modes/interactive/theme/defaults/dark-retro.json +99 -0
- package/src/modes/interactive/theme/defaults/dark-rose-pine.json +95 -0
- package/src/modes/interactive/theme/defaults/dark-solarized.json +96 -0
- package/src/modes/interactive/theme/defaults/dark-sunset.json +106 -0
- package/src/modes/interactive/theme/defaults/dark-synthwave.json +102 -0
- package/src/modes/interactive/theme/defaults/dark-tokyo-night.json +108 -0
- package/src/modes/interactive/theme/defaults/index.ts +67 -0
- package/src/modes/interactive/theme/defaults/light-arctic.json +106 -0
- package/src/modes/interactive/theme/defaults/light-catppuccin.json +105 -0
- package/src/modes/interactive/theme/defaults/light-cyberpunk.json +103 -0
- package/src/modes/interactive/theme/defaults/light-forest.json +107 -0
- package/src/modes/interactive/theme/defaults/light-github.json +114 -0
- package/src/modes/interactive/theme/defaults/light-gruvbox.json +115 -0
- package/src/modes/interactive/theme/defaults/light-monochrome.json +100 -0
- package/src/modes/interactive/theme/defaults/light-ocean.json +106 -0
- package/src/modes/interactive/theme/defaults/light-one.json +105 -0
- package/src/modes/interactive/theme/defaults/light-retro.json +105 -0
- package/src/modes/interactive/theme/defaults/light-solarized.json +101 -0
- package/src/modes/interactive/theme/defaults/light-sunset.json +106 -0
- package/src/modes/interactive/theme/defaults/light-synthwave.json +105 -0
- package/src/modes/interactive/theme/defaults/light-tokyo-night.json +118 -0
- package/src/modes/interactive/theme/light.json +3 -2
- package/src/modes/interactive/theme/theme-schema.json +120 -4
- package/src/modes/interactive/theme/theme.ts +1228 -14
- package/src/prompts/branch-summary-preamble.md +3 -0
- package/src/prompts/branch-summary.md +28 -0
- package/src/prompts/compaction-summary.md +34 -0
- package/src/prompts/compaction-turn-prefix.md +16 -0
- package/src/prompts/compaction-update-summary.md +41 -0
- package/src/prompts/init.md +30 -0
- package/src/{core/tools/task/bundled-agents → prompts}/reviewer.md +6 -0
- package/src/prompts/summarization-system.md +3 -0
- package/src/prompts/system-prompt.md +27 -0
- package/src/{core/tools/task/bundled-agents → prompts}/task.md +2 -0
- package/src/prompts/title-system.md +8 -0
- package/src/prompts/tools/ask.md +24 -0
- package/src/prompts/tools/bash.md +23 -0
- package/src/prompts/tools/edit.md +9 -0
- package/src/prompts/tools/find.md +6 -0
- package/src/prompts/tools/grep.md +12 -0
- package/src/prompts/tools/lsp.md +14 -0
- package/src/prompts/tools/output.md +23 -0
- package/src/prompts/tools/read.md +25 -0
- package/src/prompts/tools/web-fetch.md +8 -0
- package/src/prompts/tools/web-search.md +10 -0
- package/src/prompts/tools/write.md +10 -0
- package/src/commands/init.md +0 -20
- /package/src/{core/tools/task/bundled-commands → prompts}/architect-plan.md +0 -0
- /package/src/{core/tools/task/bundled-agents → prompts}/browser.md +0 -0
- /package/src/{core/tools/task/bundled-agents → prompts}/explore.md +0 -0
- /package/src/{core/tools/task/bundled-commands → prompts}/implement-with-critic.md +0 -0
- /package/src/{core/tools/task/bundled-commands → prompts}/implement.md +0 -0
- /package/src/{core/tools/task/bundled-agents → prompts}/plan.md +0 -0
|
@@ -3,6 +3,7 @@ import { dirname, join } from "node:path";
|
|
|
3
3
|
import { type Settings as SettingsItem, settingsCapability } from "../capability/settings";
|
|
4
4
|
import { getAgentDir } from "../config";
|
|
5
5
|
import { loadSync } from "../discovery";
|
|
6
|
+
import type { SymbolPreset } from "../modes/interactive/theme/theme";
|
|
6
7
|
|
|
7
8
|
export interface CompactionSettings {
|
|
8
9
|
enabled?: boolean; // default: true
|
|
@@ -68,6 +69,8 @@ export interface EditSettings {
|
|
|
68
69
|
fuzzyMatch?: boolean; // default: true (accept high-confidence fuzzy matches for whitespace/indentation)
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
export type { SymbolPreset };
|
|
73
|
+
|
|
71
74
|
export interface TtsrSettings {
|
|
72
75
|
enabled?: boolean; // default: true
|
|
73
76
|
/** What to do with partial output when TTSR triggers: "keep" shows interrupted attempt, "discard" removes it */
|
|
@@ -78,6 +81,45 @@ export interface TtsrSettings {
|
|
|
78
81
|
repeatGap?: number; // default: 10
|
|
79
82
|
}
|
|
80
83
|
|
|
84
|
+
export type StatusLineSegmentId =
|
|
85
|
+
| "pi"
|
|
86
|
+
| "model"
|
|
87
|
+
| "path"
|
|
88
|
+
| "git"
|
|
89
|
+
| "subagents"
|
|
90
|
+
| "token_in"
|
|
91
|
+
| "token_out"
|
|
92
|
+
| "token_total"
|
|
93
|
+
| "cost"
|
|
94
|
+
| "context_pct"
|
|
95
|
+
| "context_total"
|
|
96
|
+
| "time_spent"
|
|
97
|
+
| "time"
|
|
98
|
+
| "session"
|
|
99
|
+
| "hostname"
|
|
100
|
+
| "cache_read"
|
|
101
|
+
| "cache_write";
|
|
102
|
+
|
|
103
|
+
export type StatusLineSeparatorStyle = "powerline" | "powerline-thin" | "slash" | "pipe" | "block" | "none" | "ascii";
|
|
104
|
+
|
|
105
|
+
export type StatusLinePreset = "default" | "minimal" | "compact" | "full" | "nerd" | "ascii" | "custom";
|
|
106
|
+
|
|
107
|
+
export interface StatusLineSegmentOptions {
|
|
108
|
+
model?: { showThinkingLevel?: boolean };
|
|
109
|
+
path?: { abbreviate?: boolean; maxLength?: number; stripWorkPrefix?: boolean };
|
|
110
|
+
git?: { showBranch?: boolean; showStaged?: boolean; showUnstaged?: boolean; showUntracked?: boolean };
|
|
111
|
+
time?: { format?: "12h" | "24h"; showSeconds?: boolean };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface StatusLineSettings {
|
|
115
|
+
preset?: StatusLinePreset;
|
|
116
|
+
leftSegments?: StatusLineSegmentId[];
|
|
117
|
+
rightSegments?: StatusLineSegmentId[];
|
|
118
|
+
separator?: StatusLineSeparatorStyle;
|
|
119
|
+
segmentOptions?: StatusLineSegmentOptions;
|
|
120
|
+
showHookStatus?: boolean;
|
|
121
|
+
}
|
|
122
|
+
|
|
81
123
|
export interface Settings {
|
|
82
124
|
lastChangelogVersion?: string;
|
|
83
125
|
/** Model roles map: { default: "provider/modelId", small: "provider/modelId", ... } */
|
|
@@ -86,6 +128,7 @@ export interface Settings {
|
|
|
86
128
|
queueMode?: "all" | "one-at-a-time";
|
|
87
129
|
interruptMode?: "immediate" | "wait";
|
|
88
130
|
theme?: string;
|
|
131
|
+
symbolPreset?: SymbolPreset; // default: uses theme's preset or "unicode"
|
|
89
132
|
compaction?: CompactionSettings;
|
|
90
133
|
branchSummary?: BranchSummarySettings;
|
|
91
134
|
retry?: RetrySettings;
|
|
@@ -106,6 +149,7 @@ export interface Settings {
|
|
|
106
149
|
ttsr?: TtsrSettings;
|
|
107
150
|
disabledProviders?: string[]; // Discovery provider IDs that are disabled
|
|
108
151
|
disabledExtensions?: string[]; // Individual extension IDs that are disabled (e.g., "skill:commit")
|
|
152
|
+
statusLine?: StatusLineSettings; // Status line configuration
|
|
109
153
|
}
|
|
110
154
|
|
|
111
155
|
/** Deep merge settings: project/overrides take precedence, nested objects merge recursively */
|
|
@@ -298,6 +342,15 @@ export class SettingsManager {
|
|
|
298
342
|
this.save();
|
|
299
343
|
}
|
|
300
344
|
|
|
345
|
+
getSymbolPreset(): SymbolPreset | undefined {
|
|
346
|
+
return this.settings.symbolPreset;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
setSymbolPreset(preset: SymbolPreset): void {
|
|
350
|
+
this.globalSettings.symbolPreset = preset;
|
|
351
|
+
this.save();
|
|
352
|
+
}
|
|
353
|
+
|
|
301
354
|
getDefaultThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | undefined {
|
|
302
355
|
return this.settings.defaultThinkingLevel;
|
|
303
356
|
}
|
|
@@ -683,4 +736,125 @@ export class SettingsManager {
|
|
|
683
736
|
this.globalSettings.ttsr.repeatGap = gap;
|
|
684
737
|
this.save();
|
|
685
738
|
}
|
|
739
|
+
|
|
740
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
741
|
+
// Status Line Settings
|
|
742
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
743
|
+
|
|
744
|
+
getStatusLineSettings(): StatusLineSettings {
|
|
745
|
+
return this.settings.statusLine ? { ...this.settings.statusLine } : {};
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
getStatusLinePreset(): StatusLinePreset {
|
|
749
|
+
return this.settings.statusLine?.preset ?? "default";
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
setStatusLinePreset(preset: StatusLinePreset): void {
|
|
753
|
+
if (!this.globalSettings.statusLine) {
|
|
754
|
+
this.globalSettings.statusLine = {};
|
|
755
|
+
}
|
|
756
|
+
if (preset !== "custom") {
|
|
757
|
+
delete this.globalSettings.statusLine.leftSegments;
|
|
758
|
+
delete this.globalSettings.statusLine.rightSegments;
|
|
759
|
+
delete this.globalSettings.statusLine.segmentOptions;
|
|
760
|
+
}
|
|
761
|
+
this.globalSettings.statusLine.preset = preset;
|
|
762
|
+
this.save();
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
getStatusLineSeparator(): StatusLineSeparatorStyle {
|
|
766
|
+
return this.settings.statusLine?.separator ?? "powerline-thin";
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
setStatusLineSeparator(separator: StatusLineSeparatorStyle): void {
|
|
770
|
+
if (!this.globalSettings.statusLine) {
|
|
771
|
+
this.globalSettings.statusLine = {};
|
|
772
|
+
}
|
|
773
|
+
this.globalSettings.statusLine.separator = separator;
|
|
774
|
+
this.save();
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
getStatusLineLeftSegments(): StatusLineSegmentId[] {
|
|
778
|
+
return [...(this.settings.statusLine?.leftSegments ?? [])];
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
setStatusLineLeftSegments(segments: StatusLineSegmentId[]): void {
|
|
782
|
+
if (!this.globalSettings.statusLine) {
|
|
783
|
+
this.globalSettings.statusLine = {};
|
|
784
|
+
}
|
|
785
|
+
this.globalSettings.statusLine.leftSegments = segments;
|
|
786
|
+
// Setting segments explicitly implies custom preset
|
|
787
|
+
if (this.globalSettings.statusLine.preset !== "custom") {
|
|
788
|
+
this.globalSettings.statusLine.preset = "custom";
|
|
789
|
+
}
|
|
790
|
+
this.save();
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
getStatusLineRightSegments(): StatusLineSegmentId[] {
|
|
794
|
+
return [...(this.settings.statusLine?.rightSegments ?? [])];
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
setStatusLineRightSegments(segments: StatusLineSegmentId[]): void {
|
|
798
|
+
if (!this.globalSettings.statusLine) {
|
|
799
|
+
this.globalSettings.statusLine = {};
|
|
800
|
+
}
|
|
801
|
+
this.globalSettings.statusLine.rightSegments = segments;
|
|
802
|
+
// Setting segments explicitly implies custom preset
|
|
803
|
+
if (this.globalSettings.statusLine.preset !== "custom") {
|
|
804
|
+
this.globalSettings.statusLine.preset = "custom";
|
|
805
|
+
}
|
|
806
|
+
this.save();
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
getStatusLineSegmentOptions(): StatusLineSegmentOptions {
|
|
810
|
+
return { ...this.settings.statusLine?.segmentOptions };
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
setStatusLineSegmentOption<K extends keyof StatusLineSegmentOptions>(
|
|
814
|
+
segment: K,
|
|
815
|
+
option: keyof NonNullable<StatusLineSegmentOptions[K]>,
|
|
816
|
+
value: boolean | number | string,
|
|
817
|
+
): void {
|
|
818
|
+
if (!this.globalSettings.statusLine) {
|
|
819
|
+
this.globalSettings.statusLine = {};
|
|
820
|
+
}
|
|
821
|
+
if (!this.globalSettings.statusLine.segmentOptions) {
|
|
822
|
+
this.globalSettings.statusLine.segmentOptions = {};
|
|
823
|
+
}
|
|
824
|
+
if (!this.globalSettings.statusLine.segmentOptions[segment]) {
|
|
825
|
+
this.globalSettings.statusLine.segmentOptions[segment] = {} as NonNullable<StatusLineSegmentOptions[K]>;
|
|
826
|
+
}
|
|
827
|
+
(this.globalSettings.statusLine.segmentOptions[segment] as Record<string, unknown>)[option as string] = value;
|
|
828
|
+
this.save();
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
clearStatusLineSegmentOption<K extends keyof StatusLineSegmentOptions>(
|
|
832
|
+
segment: K,
|
|
833
|
+
option: keyof NonNullable<StatusLineSegmentOptions[K]>,
|
|
834
|
+
): void {
|
|
835
|
+
const segmentOptions = this.globalSettings.statusLine?.segmentOptions;
|
|
836
|
+
if (!segmentOptions || !segmentOptions[segment]) {
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
delete (segmentOptions[segment] as Record<string, unknown>)[option as string];
|
|
840
|
+
if (Object.keys(segmentOptions[segment] as Record<string, unknown>).length === 0) {
|
|
841
|
+
delete segmentOptions[segment];
|
|
842
|
+
}
|
|
843
|
+
if (Object.keys(segmentOptions).length === 0) {
|
|
844
|
+
delete this.globalSettings.statusLine?.segmentOptions;
|
|
845
|
+
}
|
|
846
|
+
this.save();
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
getStatusLineShowHookStatus(): boolean {
|
|
850
|
+
return this.settings.statusLine?.showHookStatus ?? true;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
setStatusLineShowHookStatus(show: boolean): void {
|
|
854
|
+
if (!this.globalSettings.statusLine) {
|
|
855
|
+
this.globalSettings.statusLine = {};
|
|
856
|
+
}
|
|
857
|
+
this.globalSettings.statusLine.showHookStatus = show;
|
|
858
|
+
this.save();
|
|
859
|
+
}
|
|
686
860
|
}
|
|
@@ -9,6 +9,7 @@ import type { Rule } from "../capability/rule";
|
|
|
9
9
|
import { systemPromptCapability } from "../capability/system-prompt";
|
|
10
10
|
import { getDocsPath, getExamplesPath, getReadmePath } from "../config";
|
|
11
11
|
import { type ContextFile, loadSync, type SystemPrompt as SystemPromptFile } from "../discovery/index";
|
|
12
|
+
import systemPromptTemplate from "../prompts/system-prompt.md" with { type: "text" };
|
|
12
13
|
import type { SkillsSettings } from "./settings-manager";
|
|
13
14
|
import { formatSkillsForPrompt, loadSkills, type Skill } from "./skills";
|
|
14
15
|
import type { ToolName } from "./tools/index";
|
|
@@ -390,20 +391,14 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
|
|
|
390
391
|
const guidelines = guidelinesList.map((g) => `- ${g}`).join("\n");
|
|
391
392
|
|
|
392
393
|
// Build the prompt with anti-bash rules prominently placed
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
Documentation:
|
|
402
|
-
- Main documentation: ${readmePath}
|
|
403
|
-
- Additional docs: ${docsPath}
|
|
404
|
-
- Examples: ${examplesPath} (hooks, custom tools, SDK)
|
|
405
|
-
- When asked to create: custom models/providers (README.md), hooks (docs/hooks.md, examples/hooks/), custom tools (docs/custom-tools.md, docs/tui.md, examples/custom-tools/), themes (docs/theme.md), skills (docs/skills.md)
|
|
406
|
-
- Always read the doc, examples, AND follow .md cross-references before implementing`;
|
|
394
|
+
const antiBashBlock = antiBashSection ? `\n${antiBashSection}\n` : "";
|
|
395
|
+
let prompt = systemPromptTemplate
|
|
396
|
+
.replaceAll("{{toolsList}}", toolsList)
|
|
397
|
+
.replaceAll("{{antiBashSection}}", antiBashBlock)
|
|
398
|
+
.replaceAll("{{guidelines}}", guidelines)
|
|
399
|
+
.replaceAll("{{readmePath}}", readmePath)
|
|
400
|
+
.replaceAll("{{docsPath}}", docsPath)
|
|
401
|
+
.replaceAll("{{examplesPath}}", examplesPath);
|
|
407
402
|
|
|
408
403
|
if (appendSection) {
|
|
409
404
|
prompt += appendSection;
|
|
@@ -4,18 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import type { Model } from "@oh-my-pi/pi-ai";
|
|
6
6
|
import { completeSimple } from "@oh-my-pi/pi-ai";
|
|
7
|
+
import titleSystemPrompt from "../prompts/title-system.md" with { type: "text" };
|
|
7
8
|
import { logger } from "./logger";
|
|
8
9
|
import type { ModelRegistry } from "./model-registry";
|
|
9
10
|
import { findSmolModel } from "./model-resolver";
|
|
10
11
|
|
|
11
|
-
const TITLE_SYSTEM_PROMPT =
|
|
12
|
-
|
|
13
|
-
Examples:
|
|
14
|
-
- "Fix TypeScript compilation errors"
|
|
15
|
-
- "Add user authentication"
|
|
16
|
-
- "Refactor database queries"
|
|
17
|
-
- "Debug payment webhook"
|
|
18
|
-
- "Update React components"`;
|
|
12
|
+
const TITLE_SYSTEM_PROMPT = titleSystemPrompt;
|
|
19
13
|
|
|
20
14
|
const MAX_INPUT_CHARS = 2000;
|
|
21
15
|
|
package/src/core/tools/ask.ts
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
import type { AgentTool, AgentToolContext, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
19
19
|
import { Type } from "@sinclair/typebox";
|
|
20
|
+
import { theme } from "../../modes/interactive/theme/theme";
|
|
21
|
+
import askDescription from "../../prompts/tools/ask.md" with { type: "text" };
|
|
20
22
|
|
|
21
23
|
// =============================================================================
|
|
22
24
|
// Types
|
|
@@ -53,36 +55,9 @@ export interface AskToolDetails {
|
|
|
53
55
|
// =============================================================================
|
|
54
56
|
|
|
55
57
|
const OTHER_OPTION = "Other (type your own)";
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const DESCRIPTION = `Use this tool when you need to ask the user questions during execution. This allows you to:
|
|
59
|
-
1. Gather user preferences or requirements
|
|
60
|
-
2. Clarify ambiguous instructions
|
|
61
|
-
3. Get decisions on implementation choices as you work
|
|
62
|
-
4. Offer choices to the user about what direction to take.
|
|
63
|
-
|
|
64
|
-
Usage notes:
|
|
65
|
-
- Users will always be able to select "Other" to provide custom text input
|
|
66
|
-
- Use multi: true to allow multiple answers to be selected for a question
|
|
67
|
-
- If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label
|
|
68
|
-
|
|
69
|
-
Example usage:
|
|
70
|
-
|
|
71
|
-
<example>
|
|
72
|
-
assistant: Let me ask which features you want to include.
|
|
73
|
-
assistant: Uses the ask tool:
|
|
74
|
-
{
|
|
75
|
-
"question": "Which features should I implement?",
|
|
76
|
-
"options": [
|
|
77
|
-
{"label": "Authentication"},
|
|
78
|
-
{"label": "API endpoints"},
|
|
79
|
-
{"label": "Database models"},
|
|
80
|
-
{"label": "Unit tests"},
|
|
81
|
-
{"label": "Documentation"}
|
|
82
|
-
],
|
|
83
|
-
"multi": true
|
|
58
|
+
function getDoneOptionLabel(): string {
|
|
59
|
+
return `${theme.status.success} Done selecting`;
|
|
84
60
|
}
|
|
85
|
-
</example>`;
|
|
86
61
|
|
|
87
62
|
// =============================================================================
|
|
88
63
|
// Tool Implementation
|
|
@@ -92,7 +67,7 @@ export function createAskTool(_cwd: string): AgentTool<typeof askSchema, AskTool
|
|
|
92
67
|
return {
|
|
93
68
|
name: "ask",
|
|
94
69
|
label: "Ask",
|
|
95
|
-
description:
|
|
70
|
+
description: askDescription,
|
|
96
71
|
parameters: askSchema,
|
|
97
72
|
|
|
98
73
|
async execute(
|
|
@@ -104,6 +79,7 @@ export function createAskTool(_cwd: string): AgentTool<typeof askSchema, AskTool
|
|
|
104
79
|
) {
|
|
105
80
|
const { question, options, multi = false } = params;
|
|
106
81
|
const optionLabels = options.map((o) => o.label);
|
|
82
|
+
const doneLabel = getDoneOptionLabel();
|
|
107
83
|
|
|
108
84
|
// Headless fallback - return error if no UI available
|
|
109
85
|
if (!context?.hasUI || !context.ui) {
|
|
@@ -137,12 +113,12 @@ export function createAskTool(_cwd: string): AgentTool<typeof askSchema, AskTool
|
|
|
137
113
|
|
|
138
114
|
// Add "Done" option if any selected
|
|
139
115
|
if (selected.size > 0) {
|
|
140
|
-
opts.push(
|
|
116
|
+
opts.push(doneLabel);
|
|
141
117
|
}
|
|
142
118
|
|
|
143
|
-
// Add all options with
|
|
119
|
+
// Add all options with checkbox prefix
|
|
144
120
|
for (const opt of optionLabels) {
|
|
145
|
-
const checkbox = selected.has(opt) ?
|
|
121
|
+
const checkbox = selected.has(opt) ? theme.checkbox.checked : theme.checkbox.unchecked;
|
|
146
122
|
opts.push(`${checkbox} ${opt}`);
|
|
147
123
|
}
|
|
148
124
|
|
|
@@ -152,7 +128,7 @@ export function createAskTool(_cwd: string): AgentTool<typeof askSchema, AskTool
|
|
|
152
128
|
const prefix = selected.size > 0 ? `(${selected.size} selected) ` : "";
|
|
153
129
|
const choice = await ui.select(`${prefix}${question}`, opts);
|
|
154
130
|
|
|
155
|
-
if (choice === undefined || choice ===
|
|
131
|
+
if (choice === undefined || choice === doneLabel) break;
|
|
156
132
|
|
|
157
133
|
if (choice === OTHER_OPTION) {
|
|
158
134
|
const input = await ui.input("Enter your response:");
|
|
@@ -161,9 +137,15 @@ export function createAskTool(_cwd: string): AgentTool<typeof askSchema, AskTool
|
|
|
161
137
|
}
|
|
162
138
|
|
|
163
139
|
// Toggle selection - extract the actual option name
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
140
|
+
const checkedPrefix = `${theme.checkbox.checked} `;
|
|
141
|
+
const uncheckedPrefix = `${theme.checkbox.unchecked} `;
|
|
142
|
+
let opt: string | undefined;
|
|
143
|
+
if (choice.startsWith(checkedPrefix)) {
|
|
144
|
+
opt = choice.slice(checkedPrefix.length);
|
|
145
|
+
} else if (choice.startsWith(uncheckedPrefix)) {
|
|
146
|
+
opt = choice.slice(uncheckedPrefix.length);
|
|
147
|
+
}
|
|
148
|
+
if (opt) {
|
|
167
149
|
if (selected.has(opt)) {
|
|
168
150
|
selected.delete(opt);
|
|
169
151
|
} else {
|
package/src/core/tools/bash.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import bashDescription from "../../prompts/tools/bash.md" with { type: "text" };
|
|
3
4
|
import { executeBash } from "../bash-executor";
|
|
4
5
|
import { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateTail } from "./truncate";
|
|
5
6
|
|
|
@@ -17,43 +18,7 @@ export function createBashTool(cwd: string): AgentTool<typeof bashSchema> {
|
|
|
17
18
|
return {
|
|
18
19
|
name: "bash",
|
|
19
20
|
label: "Bash",
|
|
20
|
-
description:
|
|
21
|
-
|
|
22
|
-
IMPORTANT: This tool is for terminal operations like git, npm, docker, etc. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead.
|
|
23
|
-
|
|
24
|
-
Before executing the command, please follow these steps:
|
|
25
|
-
|
|
26
|
-
1. Directory Verification:
|
|
27
|
-
- If the command will create new directories or files, first use \`ls\` to verify the parent directory exists and is the correct location
|
|
28
|
-
- For example, before running "mkdir foo/bar", first use \`ls foo\` to check that "foo" exists and is the intended parent directory
|
|
29
|
-
|
|
30
|
-
2. Command Execution:
|
|
31
|
-
- Always quote file paths that contain spaces with double quotes (e.g., cd "path with spaces/file.txt")
|
|
32
|
-
- Examples of proper quoting:
|
|
33
|
-
- cd "/Users/name/My Documents" (correct)
|
|
34
|
-
- cd /Users/name/My Documents (incorrect - will fail)
|
|
35
|
-
- python "/path/with spaces/script.py" (correct)
|
|
36
|
-
- python /path/with spaces/script.py (incorrect - will fail)
|
|
37
|
-
- After ensuring proper quoting, execute the command.
|
|
38
|
-
- Capture the output of the command.
|
|
39
|
-
|
|
40
|
-
Usage notes:
|
|
41
|
-
- The command argument is required.
|
|
42
|
-
- You can specify an optional timeout in seconds.
|
|
43
|
-
- It is very helpful if you write a clear, concise description of what this command does in 5-10 words.
|
|
44
|
-
- If the output exceeds 50KB characters, output will be truncated before being returned to you.
|
|
45
|
-
- Avoid using Bash with the \`find\`, \`grep\`, \`cat\`, \`head\`, \`tail\`, \`sed\`, \`awk\`, or \`echo\` commands, unless explicitly instructed or when these commands are truly necessary for the task. Instead, always prefer using the dedicated tools for these commands:
|
|
46
|
-
- File search: Use find (NOT find or ls)
|
|
47
|
-
- Content search: Use grep (NOT grep or rg)
|
|
48
|
-
- Read files: Use read (NOT cat/head/tail)
|
|
49
|
-
- Edit files: Use edit (NOT sed/awk)
|
|
50
|
-
- Write files: Use write (NOT echo >/cat <<EOF)
|
|
51
|
-
- Communication: Output text directly (NOT echo/printf)
|
|
52
|
-
- When issuing multiple commands:
|
|
53
|
-
- If the commands are independent and can run in parallel, make multiple bash tool calls in a single message. For example, if you need to run "git status" and "git diff", send a single message with two bash tool calls in parallel.
|
|
54
|
-
- If the commands depend on each other and must run sequentially, use a single bash call with '&&' to chain them together (e.g., \`git add . && git commit -m "message" && git push\`). For instance, if one operation must complete before another starts (like mkdir before cp, Write before Bash for git operations, or git add before git commit), run these operations sequentially instead.
|
|
55
|
-
- Use ';' only when you need to run commands sequentially but don't care if earlier commands fail
|
|
56
|
-
- DO NOT use newlines to separate commands (newlines are ok in quoted strings)`,
|
|
21
|
+
description: bashDescription,
|
|
57
22
|
parameters: bashSchema,
|
|
58
23
|
execute: async (
|
|
59
24
|
_toolCallId: string,
|
package/src/core/tools/edit.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import editDescription from "../../prompts/tools/edit.md" with { type: "text" };
|
|
3
4
|
import {
|
|
4
5
|
DEFAULT_FUZZY_THRESHOLD,
|
|
5
6
|
detectLineEnding,
|
|
@@ -43,15 +44,7 @@ export function createEditTool(cwd: string, options: EditToolOptions = {}): Agen
|
|
|
43
44
|
return {
|
|
44
45
|
name: "edit",
|
|
45
46
|
label: "Edit",
|
|
46
|
-
description:
|
|
47
|
-
|
|
48
|
-
Usage:
|
|
49
|
-
- You must use your read tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file.
|
|
50
|
-
- Fuzzy matching handles minor whitespace/indentation differences automatically - you don't need to match indentation exactly.
|
|
51
|
-
- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.
|
|
52
|
-
- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.
|
|
53
|
-
- The edit will FAIL if old_string is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use replace_all to change every instance of old_string.
|
|
54
|
-
- Use replace_all for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.`,
|
|
47
|
+
description: editDescription,
|
|
55
48
|
parameters: editSchema,
|
|
56
49
|
execute: async (
|
|
57
50
|
_toolCallId: string,
|