@oh-my-pi/pi-coding-agent 3.20.0 → 3.21.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 +78 -8
- package/docs/custom-tools.md +3 -3
- package/docs/extensions.md +226 -220
- package/docs/hooks.md +2 -2
- package/docs/sdk.md +3 -3
- package/examples/custom-tools/README.md +2 -2
- package/examples/custom-tools/subagent/index.ts +1 -1
- package/examples/extensions/README.md +76 -74
- package/examples/extensions/todo.ts +2 -5
- package/examples/hooks/custom-compaction.ts +1 -1
- package/examples/hooks/handoff.ts +1 -1
- package/examples/hooks/qna.ts +1 -1
- package/examples/sdk/02-custom-model.ts +1 -1
- package/examples/sdk/12-full-control.ts +1 -1
- package/examples/sdk/README.md +1 -1
- package/package.json +5 -5
- package/src/cli/file-processor.ts +1 -1
- package/src/cli/list-models.ts +1 -1
- package/src/core/agent-session.ts +13 -2
- package/src/core/auth-storage.ts +1 -1
- package/src/core/compaction/branch-summarization.ts +2 -2
- package/src/core/compaction/compaction.ts +2 -2
- package/src/core/compaction/utils.ts +1 -1
- package/src/core/custom-tools/types.ts +1 -1
- package/src/core/extensions/runner.ts +1 -1
- package/src/core/extensions/types.ts +1 -1
- package/src/core/extensions/wrapper.ts +1 -1
- package/src/core/hooks/runner.ts +2 -2
- package/src/core/hooks/types.ts +1 -1
- package/src/core/messages.ts +1 -1
- package/src/core/model-registry.ts +1 -1
- package/src/core/model-resolver.ts +1 -1
- package/src/core/sdk.ts +33 -4
- package/src/core/session-manager.ts +11 -22
- package/src/core/settings-manager.ts +66 -1
- package/src/core/slash-commands.ts +12 -5
- package/src/core/system-prompt.ts +27 -3
- package/src/core/title-generator.ts +2 -2
- package/src/core/tools/ask.ts +88 -1
- package/src/core/tools/bash-interceptor.ts +7 -0
- package/src/core/tools/bash.ts +106 -0
- package/src/core/tools/edit-diff.ts +73 -24
- package/src/core/tools/edit.ts +214 -20
- package/src/core/tools/find.ts +162 -1
- package/src/core/tools/gemini-image.ts +279 -56
- package/src/core/tools/git.ts +4 -0
- package/src/core/tools/grep.ts +191 -0
- package/src/core/tools/index.ts +3 -6
- package/src/core/tools/ls.ts +142 -2
- package/src/core/tools/lsp/render.ts +34 -14
- package/src/core/tools/notebook.ts +110 -0
- package/src/core/tools/output.ts +179 -7
- package/src/core/tools/read.ts +122 -9
- package/src/core/tools/render-utils.ts +241 -0
- package/src/core/tools/renderers.ts +40 -828
- package/src/core/tools/review.ts +26 -7
- package/src/core/tools/rulebook.ts +3 -1
- package/src/core/tools/task/index.ts +18 -3
- package/src/core/tools/task/render.ts +7 -2
- package/src/core/tools/task/types.ts +1 -1
- package/src/core/tools/truncate.ts +27 -1
- package/src/core/tools/web-fetch.ts +23 -15
- package/src/core/tools/web-search/index.ts +130 -45
- package/src/core/tools/web-search/providers/anthropic.ts +7 -2
- package/src/core/tools/web-search/providers/exa.ts +2 -1
- package/src/core/tools/web-search/providers/perplexity.ts +6 -1
- package/src/core/tools/web-search/render.ts +5 -0
- package/src/core/tools/web-search/types.ts +13 -0
- package/src/core/tools/write.ts +90 -0
- package/src/core/voice.ts +1 -1
- package/src/lib/worktree/constants.ts +6 -6
- package/src/main.ts +1 -1
- package/src/modes/interactive/components/assistant-message.ts +1 -1
- package/src/modes/interactive/components/custom-message.ts +1 -1
- package/src/modes/interactive/components/extensions/inspector-panel.ts +25 -22
- package/src/modes/interactive/components/extensions/state-manager.ts +12 -0
- package/src/modes/interactive/components/footer.ts +1 -1
- package/src/modes/interactive/components/hook-message.ts +1 -1
- package/src/modes/interactive/components/model-selector.ts +1 -1
- package/src/modes/interactive/components/oauth-selector.ts +1 -1
- package/src/modes/interactive/components/settings-defs.ts +49 -0
- package/src/modes/interactive/components/status-line.ts +1 -1
- package/src/modes/interactive/components/tool-execution.ts +93 -538
- package/src/modes/interactive/interactive-mode.ts +19 -7
- package/src/modes/print-mode.ts +1 -1
- package/src/modes/rpc/rpc-client.ts +1 -1
- package/src/modes/rpc/rpc-types.ts +1 -1
- package/src/prompts/system-prompt.md +4 -0
- package/src/prompts/tools/gemini-image.md +5 -1
- package/src/prompts/tools/output.md +4 -0
- package/src/prompts/tools/web-fetch.md +1 -0
- package/src/prompts/tools/web-search.md +2 -0
- package/src/utils/image-convert.ts +8 -2
- package/src/utils/image-magick.ts +247 -0
- package/src/utils/image-resize.ts +53 -13
package/src/core/tools/write.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import type { Component } from "@oh-my-pi/pi-tui";
|
|
3
|
+
import { Text } from "@oh-my-pi/pi-tui";
|
|
2
4
|
import { Type } from "@sinclair/typebox";
|
|
5
|
+
import { getLanguageFromPath, highlightCode, type Theme } from "../../modes/interactive/theme/theme";
|
|
3
6
|
import writeDescription from "../../prompts/tools/write.md" with { type: "text" };
|
|
7
|
+
import type { RenderResultOptions } from "../custom-tools/types";
|
|
4
8
|
import { type FileDiagnosticsResult, type WritethroughCallback, writethroughNoop } from "./lsp/index";
|
|
5
9
|
import { resolveToCwd } from "./path-utils";
|
|
10
|
+
import { formatDiagnostics, replaceTabs, shortenPath } from "./render-utils";
|
|
6
11
|
|
|
7
12
|
const writeSchema = Type.Object({
|
|
8
13
|
path: Type.String({ description: "Path to the file to write (relative or absolute)" }),
|
|
@@ -61,3 +66,88 @@ export function createWriteTool(
|
|
|
61
66
|
|
|
62
67
|
/** Default write tool using process.cwd() - for backwards compatibility */
|
|
63
68
|
export const writeTool = createWriteTool(process.cwd());
|
|
69
|
+
|
|
70
|
+
// =============================================================================
|
|
71
|
+
// TUI Renderer
|
|
72
|
+
// =============================================================================
|
|
73
|
+
|
|
74
|
+
interface WriteRenderArgs {
|
|
75
|
+
path?: string;
|
|
76
|
+
file_path?: string;
|
|
77
|
+
content?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function countLines(text: string): number {
|
|
81
|
+
if (!text) return 0;
|
|
82
|
+
return text.split("\n").length;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function formatMetadataLine(lineCount: number | null, language: string | undefined, uiTheme: Theme): string {
|
|
86
|
+
const icon = uiTheme.getLangIcon(language);
|
|
87
|
+
if (lineCount !== null) {
|
|
88
|
+
return uiTheme.fg("dim", `${icon} ${lineCount} lines`);
|
|
89
|
+
}
|
|
90
|
+
return uiTheme.fg("dim", `${icon}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const writeToolRenderer = {
|
|
94
|
+
renderCall(args: WriteRenderArgs, uiTheme: Theme): Component {
|
|
95
|
+
const rawPath = args.file_path || args.path || "";
|
|
96
|
+
const filePath = shortenPath(rawPath);
|
|
97
|
+
const pathDisplay = filePath ? uiTheme.fg("accent", filePath) : uiTheme.fg("toolOutput", uiTheme.format.ellipsis);
|
|
98
|
+
const text = `${uiTheme.fg("toolTitle", uiTheme.bold("Write"))} ${pathDisplay}`;
|
|
99
|
+
return new Text(text, 0, 0);
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
renderResult(
|
|
103
|
+
result: { content: Array<{ type: string; text?: string }>; details?: WriteToolDetails },
|
|
104
|
+
{ expanded }: RenderResultOptions,
|
|
105
|
+
uiTheme: Theme,
|
|
106
|
+
args?: WriteRenderArgs,
|
|
107
|
+
): Component {
|
|
108
|
+
const rawPath = args?.file_path || args?.path || "";
|
|
109
|
+
const fileContent = args?.content || "";
|
|
110
|
+
const lang = getLanguageFromPath(rawPath);
|
|
111
|
+
const contentLines = fileContent
|
|
112
|
+
? lang
|
|
113
|
+
? highlightCode(replaceTabs(fileContent), lang)
|
|
114
|
+
: fileContent.split("\n")
|
|
115
|
+
: [];
|
|
116
|
+
const totalLines = contentLines.length;
|
|
117
|
+
const outputLines: string[] = [];
|
|
118
|
+
|
|
119
|
+
outputLines.push(formatMetadataLine(countLines(fileContent), lang ?? "text", uiTheme));
|
|
120
|
+
|
|
121
|
+
if (fileContent) {
|
|
122
|
+
const maxLines = expanded ? contentLines.length : 10;
|
|
123
|
+
const displayLines = contentLines.slice(0, maxLines);
|
|
124
|
+
const remaining = contentLines.length - maxLines;
|
|
125
|
+
|
|
126
|
+
outputLines.push(
|
|
127
|
+
"",
|
|
128
|
+
...displayLines.map((line: string) =>
|
|
129
|
+
lang ? replaceTabs(line) : uiTheme.fg("toolOutput", replaceTabs(line)),
|
|
130
|
+
),
|
|
131
|
+
);
|
|
132
|
+
if (remaining > 0) {
|
|
133
|
+
outputLines.push(
|
|
134
|
+
uiTheme.fg(
|
|
135
|
+
"toolOutput",
|
|
136
|
+
`${uiTheme.format.ellipsis} (${remaining} more lines, ${totalLines} total) ${uiTheme.format.bracketLeft}Ctrl+O to expand${uiTheme.format.bracketRight}`,
|
|
137
|
+
),
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Show LSP diagnostics if available
|
|
143
|
+
if (result.details?.diagnostics) {
|
|
144
|
+
outputLines.push(
|
|
145
|
+
formatDiagnostics(result.details.diagnostics, expanded, uiTheme, (fp) =>
|
|
146
|
+
uiTheme.getLangIcon(getLanguageFromPath(fp)),
|
|
147
|
+
),
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return new Text(outputLines.join("\n"), 0, 0);
|
|
152
|
+
},
|
|
153
|
+
};
|
package/src/core/voice.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { unlinkSync } from "node:fs";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { completeSimple, type Model } from "@
|
|
4
|
+
import { completeSimple, type Model } from "@mariozechner/pi-ai";
|
|
5
5
|
import voiceSummaryPrompt from "../prompts/voice-summary.md" with { type: "text" };
|
|
6
6
|
import { logger } from "./logger";
|
|
7
7
|
import type { ModelRegistry } from "./model-registry";
|
|
@@ -3,12 +3,12 @@ import * as os from "node:os";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
|
|
5
5
|
function getWorktreeBase(): string {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
try {
|
|
7
|
+
accessSync("/work", constants.W_OK);
|
|
8
|
+
return "/work/.tree";
|
|
9
|
+
} catch {
|
|
10
|
+
return path.join(os.tmpdir(), ".tree");
|
|
11
|
+
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export const WORKTREE_BASE = getWorktreeBase();
|
package/src/main.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* createAgentSession() options. The SDK does the heavy lifting.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { type ImageContent, supportsXhigh } from "@
|
|
8
|
+
import { type ImageContent, supportsXhigh } from "@mariozechner/pi-ai";
|
|
9
9
|
import chalk from "chalk";
|
|
10
10
|
import { type Args, parseArgs, printHelp } from "./cli/args";
|
|
11
11
|
import { processFileArguments } from "./cli/file-processor";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TextContent } from "@
|
|
1
|
+
import type { TextContent } from "@mariozechner/pi-ai";
|
|
2
2
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
3
3
|
import { Box, Container, Markdown, Spacer, Text } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import type { MessageRenderer } from "../../../core/extensions/types";
|
|
@@ -68,7 +68,7 @@ export class InspectorPanel implements Component {
|
|
|
68
68
|
|
|
69
69
|
switch (ext.kind) {
|
|
70
70
|
case "context-file":
|
|
71
|
-
content = this.renderFilePreview(ext.
|
|
71
|
+
content = this.renderFilePreview(ext.raw, width);
|
|
72
72
|
break;
|
|
73
73
|
case "tool":
|
|
74
74
|
content = this.renderToolArgs(ext.raw, width);
|
|
@@ -91,37 +91,40 @@ export class InspectorPanel implements Component {
|
|
|
91
91
|
return lines;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
private renderFilePreview(
|
|
94
|
+
private renderFilePreview(raw: unknown, width: number): string[] {
|
|
95
95
|
const lines: string[] = [];
|
|
96
96
|
lines.push(theme.fg("muted", "Preview:"));
|
|
97
97
|
lines.push(theme.fg("dim", theme.boxSharp.horizontal.repeat(Math.min(width - 2, 40))));
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
} catch (err) {
|
|
118
|
-
lines.push(theme.fg("error", `Failed to read file: ${err instanceof Error ? err.message : String(err)}`));
|
|
99
|
+
const content = this.getContextFileContent(raw);
|
|
100
|
+
if (!content) {
|
|
101
|
+
lines.push(theme.fg("dim", " (no content)"));
|
|
102
|
+
lines.push("");
|
|
103
|
+
return lines;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const fileLines = content.split("\n");
|
|
107
|
+
for (const line of fileLines.slice(0, 20)) {
|
|
108
|
+
const highlighted = this.highlightMarkdown(line);
|
|
109
|
+
lines.push(truncateToWidth(highlighted, width - 2));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (fileLines.length > 20) {
|
|
113
|
+
lines.push(theme.fg("dim", "(truncated at line 20)"));
|
|
119
114
|
}
|
|
120
115
|
|
|
121
116
|
lines.push("");
|
|
122
117
|
return lines;
|
|
123
118
|
}
|
|
124
119
|
|
|
120
|
+
private getContextFileContent(raw: unknown): string | null {
|
|
121
|
+
if (raw && typeof raw === "object" && "content" in raw) {
|
|
122
|
+
const content = (raw as { content?: unknown }).content;
|
|
123
|
+
return typeof content === "string" ? content : null;
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
125
128
|
private highlightMarkdown(line: string): string {
|
|
126
129
|
// Basic markdown syntax highlighting
|
|
127
130
|
let highlighted = line;
|
|
@@ -10,6 +10,7 @@ import type { MCPServer } from "../../../../capability/mcp";
|
|
|
10
10
|
import type { Prompt } from "../../../../capability/prompt";
|
|
11
11
|
import type { Rule } from "../../../../capability/rule";
|
|
12
12
|
import type { Skill } from "../../../../capability/skill";
|
|
13
|
+
import type { SlashCommand } from "../../../../capability/slash-command";
|
|
13
14
|
import type { CustomTool } from "../../../../capability/tool";
|
|
14
15
|
import type { SourceMeta } from "../../../../capability/types";
|
|
15
16
|
import {
|
|
@@ -192,6 +193,17 @@ export function loadAllExtensions(cwd?: string, disabledIds?: string[]): Extensi
|
|
|
192
193
|
// Capability may not be registered
|
|
193
194
|
}
|
|
194
195
|
|
|
196
|
+
// Load slash commands
|
|
197
|
+
try {
|
|
198
|
+
const commands = loadSync<SlashCommand>("slash-commands", loadOpts);
|
|
199
|
+
addItems(commands.all, "slash-command", {
|
|
200
|
+
getDescription: () => undefined,
|
|
201
|
+
getTrigger: (c) => `/${c.name}`,
|
|
202
|
+
});
|
|
203
|
+
} catch {
|
|
204
|
+
// Capability may not be registered
|
|
205
|
+
}
|
|
206
|
+
|
|
195
207
|
// Load hooks
|
|
196
208
|
try {
|
|
197
209
|
const hooks = loadSync<Hook>("hooks", loadOpts);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, type FSWatcher, readFileSync, watch } from "node:fs";
|
|
2
|
-
import type { AssistantMessage } from "@
|
|
2
|
+
import type { AssistantMessage } from "@mariozechner/pi-ai";
|
|
3
3
|
import { type Component, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import { dirname, join } from "path";
|
|
5
5
|
import type { AgentSession } from "../../../core/agent-session";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TextContent } from "@
|
|
1
|
+
import type { TextContent } from "@mariozechner/pi-ai";
|
|
2
2
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
3
3
|
import { Box, Container, Markdown, Spacer, Text } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import type { HookMessageRenderer } from "../../../core/hooks/types";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getOAuthProviders, type OAuthProviderInfo } from "@
|
|
1
|
+
import { getOAuthProviders, type OAuthProviderInfo } from "@mariozechner/pi-ai";
|
|
2
2
|
import { Container, isArrowDown, isArrowUp, isCtrlC, isEnter, isEscape, Spacer, TruncatedText } from "@oh-my-pi/pi-tui";
|
|
3
3
|
import type { AuthStorage } from "../../../core/auth-storage";
|
|
4
4
|
import { theme } from "../theme/theme";
|
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
12
12
|
import { getCapabilities } from "@oh-my-pi/pi-tui";
|
|
13
13
|
import type {
|
|
14
|
+
ImageProviderOption,
|
|
14
15
|
NotificationMethod,
|
|
15
16
|
SettingsManager,
|
|
16
17
|
StatusLinePreset,
|
|
17
18
|
StatusLineSeparatorStyle,
|
|
18
19
|
SymbolPreset,
|
|
20
|
+
WebSearchProviderOption,
|
|
19
21
|
} from "../../../core/settings-manager";
|
|
20
22
|
import { getPreset } from "./status-line/presets";
|
|
21
23
|
|
|
@@ -86,6 +88,15 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
86
88
|
get: (sm) => sm.getCompactionEnabled(),
|
|
87
89
|
set: (sm, v) => sm.setCompactionEnabled(v), // Also handled in session
|
|
88
90
|
},
|
|
91
|
+
{
|
|
92
|
+
id: "branchSummaries",
|
|
93
|
+
tab: "config",
|
|
94
|
+
type: "boolean",
|
|
95
|
+
label: "Branch summaries",
|
|
96
|
+
description: "Prompt to summarize when leaving a branch",
|
|
97
|
+
get: (sm) => sm.getBranchSummaryEnabled(),
|
|
98
|
+
set: (sm, v) => sm.setBranchSummaryEnabled(v),
|
|
99
|
+
},
|
|
89
100
|
{
|
|
90
101
|
id: "showImages",
|
|
91
102
|
tab: "config",
|
|
@@ -191,6 +202,15 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
191
202
|
get: (sm) => sm.getBashInterceptorEnabled(),
|
|
192
203
|
set: (sm, v) => sm.setBashInterceptorEnabled(v),
|
|
193
204
|
},
|
|
205
|
+
{
|
|
206
|
+
id: "gitTool",
|
|
207
|
+
tab: "config",
|
|
208
|
+
type: "boolean",
|
|
209
|
+
label: "Git tool",
|
|
210
|
+
description: "Enable structured Git tool",
|
|
211
|
+
get: (sm) => sm.getGitToolEnabled(),
|
|
212
|
+
set: (sm, v) => sm.setGitToolEnabled(v),
|
|
213
|
+
},
|
|
194
214
|
{
|
|
195
215
|
id: "mcpProjectConfig",
|
|
196
216
|
tab: "config",
|
|
@@ -277,6 +297,35 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
277
297
|
{ value: "ascii", label: "ASCII", description: "ASCII-only characters (maximum compatibility)" },
|
|
278
298
|
],
|
|
279
299
|
},
|
|
300
|
+
{
|
|
301
|
+
id: "webSearchProvider",
|
|
302
|
+
tab: "config",
|
|
303
|
+
type: "submenu",
|
|
304
|
+
label: "Web search provider",
|
|
305
|
+
description: "Provider for web search tool",
|
|
306
|
+
get: (sm) => sm.getWebSearchProvider(),
|
|
307
|
+
set: (sm, v) => sm.setWebSearchProvider(v as WebSearchProviderOption),
|
|
308
|
+
getOptions: () => [
|
|
309
|
+
{ value: "auto", label: "Auto", description: "Priority: Exa > Perplexity > Anthropic" },
|
|
310
|
+
{ value: "exa", label: "Exa", description: "Use Exa (requires EXA_API_KEY)" },
|
|
311
|
+
{ value: "perplexity", label: "Perplexity", description: "Use Perplexity (requires PERPLEXITY_API_KEY)" },
|
|
312
|
+
{ value: "anthropic", label: "Anthropic", description: "Use Anthropic web search" },
|
|
313
|
+
],
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
id: "imageProvider",
|
|
317
|
+
tab: "config",
|
|
318
|
+
type: "submenu",
|
|
319
|
+
label: "Image provider",
|
|
320
|
+
description: "Provider for image generation tool",
|
|
321
|
+
get: (sm) => sm.getImageProvider(),
|
|
322
|
+
set: (sm, v) => sm.setImageProvider(v as ImageProviderOption),
|
|
323
|
+
getOptions: () => [
|
|
324
|
+
{ value: "auto", label: "Auto", description: "Priority: OpenRouter > Gemini" },
|
|
325
|
+
{ value: "gemini", label: "Gemini", description: "Use Gemini API directly (requires GEMINI_API_KEY)" },
|
|
326
|
+
{ value: "openrouter", label: "OpenRouter", description: "Use OpenRouter (requires OPENROUTER_API_KEY)" },
|
|
327
|
+
],
|
|
328
|
+
},
|
|
280
329
|
|
|
281
330
|
// LSP tab
|
|
282
331
|
{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AssistantMessage } from "@
|
|
1
|
+
import type { AssistantMessage } from "@mariozechner/pi-ai";
|
|
2
2
|
import { type Component, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
|
3
3
|
import { type FSWatcher, watch } from "fs";
|
|
4
4
|
import { dirname, join } from "path";
|