mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 13:03:42 +00:00
Merge PR #264: Add Gemini 3 preview models to google-gemini-cli provider
This commit is contained in:
commit
329b3a0a36
10 changed files with 166 additions and 38 deletions
|
|
@ -6019,9 +6019,9 @@ export const MODELS = {
|
|||
contextWindow: 32768,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"anthropic/claude-3.5-haiku": {
|
||||
id: "anthropic/claude-3.5-haiku",
|
||||
name: "Anthropic: Claude 3.5 Haiku",
|
||||
"anthropic/claude-3.5-haiku-20241022": {
|
||||
id: "anthropic/claude-3.5-haiku-20241022",
|
||||
name: "Anthropic: Claude 3.5 Haiku (2024-10-22)",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
|
|
@ -6036,9 +6036,9 @@ export const MODELS = {
|
|||
contextWindow: 200000,
|
||||
maxTokens: 8192,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"anthropic/claude-3.5-haiku-20241022": {
|
||||
id: "anthropic/claude-3.5-haiku-20241022",
|
||||
name: "Anthropic: Claude 3.5 Haiku (2024-10-22)",
|
||||
"anthropic/claude-3.5-haiku": {
|
||||
id: "anthropic/claude-3.5-haiku",
|
||||
name: "Anthropic: Claude 3.5 Haiku",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
|
|
@ -6274,23 +6274,6 @@ export const MODELS = {
|
|||
contextWindow: 128000,
|
||||
maxTokens: 16384,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"meta-llama/llama-3.1-405b-instruct": {
|
||||
id: "meta-llama/llama-3.1-405b-instruct",
|
||||
name: "Meta: Llama 3.1 405B Instruct",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 3.5,
|
||||
output: 3.5,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 130815,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"meta-llama/llama-3.1-8b-instruct": {
|
||||
id: "meta-llama/llama-3.1-8b-instruct",
|
||||
name: "Meta: Llama 3.1 8B Instruct",
|
||||
|
|
@ -6308,6 +6291,23 @@ export const MODELS = {
|
|||
contextWindow: 131072,
|
||||
maxTokens: 16384,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"meta-llama/llama-3.1-405b-instruct": {
|
||||
id: "meta-llama/llama-3.1-405b-instruct",
|
||||
name: "Meta: Llama 3.1 405B Instruct",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 3.5,
|
||||
output: 3.5,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 130815,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"meta-llama/llama-3.1-70b-instruct": {
|
||||
id: "meta-llama/llama-3.1-70b-instruct",
|
||||
name: "Meta: Llama 3.1 70B Instruct",
|
||||
|
|
|
|||
|
|
@ -23,10 +23,19 @@ import { convertMessages, convertTools, mapStopReasonString, mapToolChoice } fro
|
|||
|
||||
export interface GoogleGeminiCliOptions extends StreamOptions {
|
||||
toolChoice?: "auto" | "none" | "any";
|
||||
/**
|
||||
* Thinking/reasoning configuration.
|
||||
* - Gemini 2.x models: use `budgetTokens` to set the thinking budget
|
||||
* - Gemini 3 models (gemini-3-pro-*, gemini-3-flash-*): use `level` instead
|
||||
*
|
||||
* When using `streamSimple`, this is handled automatically based on the model.
|
||||
*/
|
||||
thinking?: {
|
||||
enabled: boolean;
|
||||
/** Thinking budget in tokens. Use for Gemini 2.x models. */
|
||||
budgetTokens?: number;
|
||||
level?: ThinkingLevel; // For Gemini 3 models
|
||||
/** Thinking level. Use for Gemini 3 models (LOW/HIGH for Pro, MINIMAL/LOW/MEDIUM/HIGH for Flash). */
|
||||
level?: ThinkingLevel;
|
||||
};
|
||||
projectId?: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@
|
|||
|
||||
### Added
|
||||
|
||||
- **Gemini 3 preview models**: Added `gemini-3-pro-preview` and `gemini-3-flash-preview` to the google-gemini-cli provider.
|
||||
- **Gemini 3 preview models**: Added `gemini-3-pro-preview` and `gemini-3-flash-preview` to the google-gemini-cli provider. ([#264](https://github.com/badlogic/pi-mono/pull/264) by [@LukeFost](https://github.com/LukeFost))
|
||||
|
||||
- **External editor support**: Press `Ctrl+G` to edit your message in an external editor. Uses `$VISUAL` or `$EDITOR` environment variable. On successful save, the message is replaced; on cancel, the original is kept. ([#266](https://github.com/badlogic/pi-mono/pull/266) by [@aliou](https://github.com/aliou))
|
||||
|
||||
- **Process suspension**: Press `Ctrl+Z` to suspend pi and return to the shell. Resume with `fg` as usual. ([#267](https://github.com/badlogic/pi-mono/pull/267) by [@aliou](https://github.com/aliou))
|
||||
|
||||
## [0.25.2] - 2025-12-21
|
||||
|
||||
|
|
|
|||
|
|
@ -226,10 +226,12 @@ The agent reads, writes, and edits files, and executes commands via bash.
|
|||
| Escape | Cancel autocomplete / abort streaming |
|
||||
| Ctrl+C | Clear editor (first) / exit (second) |
|
||||
| Ctrl+D | Exit (when editor is empty) |
|
||||
| Ctrl+Z | Suspend to background (use `fg` in shell to resume) |
|
||||
| Shift+Tab | Cycle thinking level |
|
||||
| Ctrl+P | Cycle models (scoped by `--models`) |
|
||||
| Ctrl+O | Toggle tool output expansion |
|
||||
| Ctrl+T | Toggle thinking block visibility |
|
||||
| Ctrl+G | Edit message in external editor (`$VISUAL` or `$EDITOR`) |
|
||||
|
||||
### Bash Mode
|
||||
|
||||
|
|
@ -715,7 +717,7 @@ pi [options] [@files...] [messages...]
|
|||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--provider <name>` | Provider: `anthropic`, `openai`, `google`, `mistral`, `xai`, `groq`, `cerebras`, `openrouter`, `zai`, or custom |
|
||||
| `--provider <name>` | Provider: `anthropic`, `openai`, `google`, `mistral`, `xai`, `groq`, `cerebras`, `openrouter`, `zai`, `github-copilot`, `google-gemini-cli`, `google-antigravity`, or custom |
|
||||
| `--model <id>` | Model ID |
|
||||
| `--api-key <key>` | API key (overrides environment) |
|
||||
| `--system-prompt <text\|file>` | Custom system prompt (text or file path) |
|
||||
|
|
|
|||
|
|
@ -1,4 +1,15 @@
|
|||
import { Editor, isCtrlC, isCtrlD, isCtrlO, isCtrlP, isCtrlT, isEscape, isShiftTab } from "@mariozechner/pi-tui";
|
||||
import {
|
||||
Editor,
|
||||
isCtrlC,
|
||||
isCtrlD,
|
||||
isCtrlG,
|
||||
isCtrlO,
|
||||
isCtrlP,
|
||||
isCtrlT,
|
||||
isCtrlZ,
|
||||
isEscape,
|
||||
isShiftTab,
|
||||
} from "@mariozechner/pi-tui";
|
||||
|
||||
/**
|
||||
* Custom editor that handles Escape and Ctrl+C keys for coding-agent
|
||||
|
|
@ -11,8 +22,22 @@ export class CustomEditor extends Editor {
|
|||
public onCtrlP?: () => void;
|
||||
public onCtrlO?: () => void;
|
||||
public onCtrlT?: () => void;
|
||||
public onCtrlG?: () => void;
|
||||
public onCtrlZ?: () => void;
|
||||
|
||||
handleInput(data: string): void {
|
||||
// Intercept Ctrl+G for external editor
|
||||
if (isCtrlG(data) && this.onCtrlG) {
|
||||
this.onCtrlG();
|
||||
return;
|
||||
}
|
||||
|
||||
// Intercept Ctrl+Z for suspend
|
||||
if (isCtrlZ(data) && this.onCtrlZ) {
|
||||
this.onCtrlZ();
|
||||
return;
|
||||
}
|
||||
|
||||
// Intercept Ctrl+T for thinking block visibility toggle
|
||||
if (isCtrlT(data) && this.onCtrlT) {
|
||||
this.onCtrlT();
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
import * as fs from "node:fs";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import type { AgentState, AppMessage, Attachment } from "@mariozechner/pi-agent-core";
|
||||
import type { AssistantMessage, Message } from "@mariozechner/pi-ai";
|
||||
|
|
@ -23,7 +24,7 @@ import {
|
|||
TUI,
|
||||
visibleWidth,
|
||||
} from "@mariozechner/pi-tui";
|
||||
import { exec } from "child_process";
|
||||
import { exec, spawnSync } from "child_process";
|
||||
import { APP_NAME, getDebugLogPath, getOAuthPath } from "../../config.js";
|
||||
import type { AgentSession, AgentSessionEvent } from "../../core/agent-session.js";
|
||||
import type { LoadedCustomTool, SessionEvent as ToolSessionEvent } from "../../core/custom-tools/index.js";
|
||||
|
|
@ -212,6 +213,9 @@ export class InteractiveMode {
|
|||
theme.fg("dim", "ctrl+d") +
|
||||
theme.fg("muted", " to exit (empty)") +
|
||||
"\n" +
|
||||
theme.fg("dim", "ctrl+z") +
|
||||
theme.fg("muted", " to suspend") +
|
||||
"\n" +
|
||||
theme.fg("dim", "ctrl+k") +
|
||||
theme.fg("muted", " to delete line") +
|
||||
"\n" +
|
||||
|
|
@ -575,10 +579,12 @@ export class InteractiveMode {
|
|||
|
||||
this.editor.onCtrlC = () => this.handleCtrlC();
|
||||
this.editor.onCtrlD = () => this.handleCtrlD();
|
||||
this.editor.onCtrlZ = () => this.handleCtrlZ();
|
||||
this.editor.onShiftTab = () => this.cycleThinkingLevel();
|
||||
this.editor.onCtrlP = () => this.cycleModel();
|
||||
this.editor.onCtrlO = () => this.toggleToolOutputExpansion();
|
||||
this.editor.onCtrlT = () => this.toggleThinkingBlockVisibility();
|
||||
this.editor.onCtrlG = () => this.openExternalEditor();
|
||||
|
||||
this.editor.onChange = (text: string) => {
|
||||
const wasBashMode = this.isBashMode;
|
||||
|
|
@ -1157,6 +1163,20 @@ export class InteractiveMode {
|
|||
process.exit(0);
|
||||
}
|
||||
|
||||
private handleCtrlZ(): void {
|
||||
// Set up handler to restore TUI when resumed
|
||||
process.once("SIGCONT", () => {
|
||||
this.ui.start();
|
||||
this.ui.requestRender(true);
|
||||
});
|
||||
|
||||
// Stop the TUI (restore terminal to normal mode)
|
||||
this.ui.stop();
|
||||
|
||||
// Send SIGTSTP to process group (pid=0 means all processes in group)
|
||||
process.kill(0, "SIGTSTP");
|
||||
}
|
||||
|
||||
private updateEditorBorderColor(): void {
|
||||
if (this.isBashMode) {
|
||||
this.editor.borderColor = theme.getBashModeBorderColor();
|
||||
|
|
@ -1225,6 +1245,52 @@ export class InteractiveMode {
|
|||
this.showStatus(`Thinking blocks: ${this.hideThinkingBlock ? "hidden" : "visible"}`);
|
||||
}
|
||||
|
||||
private openExternalEditor(): void {
|
||||
// Determine editor (respect $VISUAL, then $EDITOR)
|
||||
const editorCmd = process.env.VISUAL || process.env.EDITOR;
|
||||
if (!editorCmd) {
|
||||
this.showWarning("No editor configured. Set $VISUAL or $EDITOR environment variable.");
|
||||
return;
|
||||
}
|
||||
|
||||
const currentText = this.editor.getText();
|
||||
const tmpFile = path.join(os.tmpdir(), `pi-editor-${Date.now()}.pi.md`);
|
||||
|
||||
try {
|
||||
// Write current content to temp file
|
||||
fs.writeFileSync(tmpFile, currentText, "utf-8");
|
||||
|
||||
// Stop TUI to release terminal
|
||||
this.ui.stop();
|
||||
|
||||
// Split by space to support editor arguments (e.g., "code --wait")
|
||||
const [editor, ...editorArgs] = editorCmd.split(" ");
|
||||
|
||||
// Spawn editor synchronously with inherited stdio for interactive editing
|
||||
const result = spawnSync(editor, [...editorArgs, tmpFile], {
|
||||
stdio: "inherit",
|
||||
});
|
||||
|
||||
// On successful exit (status 0), replace editor content
|
||||
if (result.status === 0) {
|
||||
const newContent = fs.readFileSync(tmpFile, "utf-8").replace(/\n$/, "");
|
||||
this.editor.setText(newContent);
|
||||
}
|
||||
// On non-zero exit, keep original text (no action needed)
|
||||
} finally {
|
||||
// Clean up temp file
|
||||
try {
|
||||
fs.unlinkSync(tmpFile);
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
|
||||
// Restart TUI
|
||||
this.ui.start();
|
||||
this.ui.requestRender();
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// UI helpers
|
||||
// =========================================================================
|
||||
|
|
@ -1699,10 +1765,12 @@ export class InteractiveMode {
|
|||
| \`Escape\` | Cancel autocomplete / abort streaming |
|
||||
| \`Ctrl+C\` | Clear editor (first) / exit (second) |
|
||||
| \`Ctrl+D\` | Exit (when editor is empty) |
|
||||
| \`Ctrl+Z\` | Suspend to background |
|
||||
| \`Shift+Tab\` | Cycle thinking level |
|
||||
| \`Ctrl+P\` | Cycle models |
|
||||
| \`Ctrl+O\` | Toggle tool output expansion |
|
||||
| \`Ctrl+T\` | Toggle thinking block visibility |
|
||||
| \`Ctrl+G\` | Edit message in external editor |
|
||||
| \`/\` | Slash commands |
|
||||
| \`!\` | Run bash command |
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ export {
|
|||
isCtrlC,
|
||||
isCtrlD,
|
||||
isCtrlE,
|
||||
isCtrlG,
|
||||
isCtrlK,
|
||||
isCtrlLeft,
|
||||
isCtrlO,
|
||||
|
|
@ -41,6 +42,7 @@ export {
|
|||
isCtrlT,
|
||||
isCtrlU,
|
||||
isCtrlW,
|
||||
isCtrlZ,
|
||||
isDelete,
|
||||
isEnd,
|
||||
isEnter,
|
||||
|
|
|
|||
|
|
@ -28,12 +28,14 @@ const CODEPOINTS = {
|
|||
c: 99,
|
||||
d: 100,
|
||||
e: 101,
|
||||
g: 103,
|
||||
k: 107,
|
||||
o: 111,
|
||||
p: 112,
|
||||
t: 116,
|
||||
u: 117,
|
||||
w: 119,
|
||||
z: 122,
|
||||
|
||||
// Special keys
|
||||
escape: 27,
|
||||
|
|
@ -160,12 +162,14 @@ export const Keys = {
|
|||
CTRL_C: kittySequence(CODEPOINTS.c, MODIFIERS.ctrl),
|
||||
CTRL_D: kittySequence(CODEPOINTS.d, MODIFIERS.ctrl),
|
||||
CTRL_E: kittySequence(CODEPOINTS.e, MODIFIERS.ctrl),
|
||||
CTRL_G: kittySequence(CODEPOINTS.g, MODIFIERS.ctrl),
|
||||
CTRL_K: kittySequence(CODEPOINTS.k, MODIFIERS.ctrl),
|
||||
CTRL_O: kittySequence(CODEPOINTS.o, MODIFIERS.ctrl),
|
||||
CTRL_P: kittySequence(CODEPOINTS.p, MODIFIERS.ctrl),
|
||||
CTRL_T: kittySequence(CODEPOINTS.t, MODIFIERS.ctrl),
|
||||
CTRL_U: kittySequence(CODEPOINTS.u, MODIFIERS.ctrl),
|
||||
CTRL_W: kittySequence(CODEPOINTS.w, MODIFIERS.ctrl),
|
||||
CTRL_Z: kittySequence(CODEPOINTS.z, MODIFIERS.ctrl),
|
||||
|
||||
// Enter combinations
|
||||
SHIFT_ENTER: kittySequence(CODEPOINTS.enter, MODIFIERS.shift),
|
||||
|
|
@ -214,12 +218,14 @@ const RAW = {
|
|||
CTRL_C: "\x03",
|
||||
CTRL_D: "\x04",
|
||||
CTRL_E: "\x05",
|
||||
CTRL_G: "\x07",
|
||||
CTRL_K: "\x0b",
|
||||
CTRL_O: "\x0f",
|
||||
CTRL_P: "\x10",
|
||||
CTRL_T: "\x14",
|
||||
CTRL_U: "\x15",
|
||||
CTRL_W: "\x17",
|
||||
CTRL_Z: "\x1a",
|
||||
ALT_BACKSPACE: "\x1b\x7f",
|
||||
SHIFT_TAB: "\x1b[Z",
|
||||
} as const;
|
||||
|
|
@ -256,6 +262,14 @@ export function isCtrlE(data: string): boolean {
|
|||
return data === RAW.CTRL_E || data === Keys.CTRL_E || matchesKittySequence(data, CODEPOINTS.e, MODIFIERS.ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if input matches Ctrl+G (raw byte or Kitty protocol).
|
||||
* Ignores lock key bits.
|
||||
*/
|
||||
export function isCtrlG(data: string): boolean {
|
||||
return data === RAW.CTRL_G || data === Keys.CTRL_G || matchesKittySequence(data, CODEPOINTS.g, MODIFIERS.ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if input matches Ctrl+K (raw byte or Kitty protocol).
|
||||
* Ignores lock key bits.
|
||||
|
|
@ -311,6 +325,14 @@ export function isCtrlW(data: string): boolean {
|
|||
return data === RAW.CTRL_W || data === Keys.CTRL_W || matchesKittySequence(data, CODEPOINTS.w, MODIFIERS.ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if input matches Ctrl+Z (raw byte or Kitty protocol).
|
||||
* Ignores lock key bits.
|
||||
*/
|
||||
export function isCtrlZ(data: string): boolean {
|
||||
return data === RAW.CTRL_Z || data === Keys.CTRL_Z || matchesKittySequence(data, CODEPOINTS.z, MODIFIERS.ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if input matches Alt+Backspace (legacy or Kitty protocol).
|
||||
* Ignores lock key bits.
|
||||
|
|
|
|||
|
|
@ -118,7 +118,12 @@ export class TUI extends Container {
|
|||
this.terminal.stop();
|
||||
}
|
||||
|
||||
requestRender(): void {
|
||||
requestRender(force = false): void {
|
||||
if (force) {
|
||||
this.previousLines = [];
|
||||
this.previousWidth = 0;
|
||||
this.cursorRow = 0;
|
||||
}
|
||||
if (this.renderRequested) return;
|
||||
this.renderRequested = true;
|
||||
process.nextTick(() => {
|
||||
|
|
|
|||
|
|
@ -6,15 +6,6 @@
|
|||
},
|
||||
{
|
||||
"path": "../../moms"
|
||||
},
|
||||
{
|
||||
"path": "../../.pi/agent"
|
||||
},
|
||||
{
|
||||
"path": "../pi-skills"
|
||||
},
|
||||
{
|
||||
"path": "../sitegeist"
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue