mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-22 00:00:27 +00:00
fix(coding-agent): make resolveCliModel sync, update docs and changelog
This commit is contained in:
parent
56342258e1
commit
4793f7c92d
7 changed files with 35 additions and 22 deletions
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
- Fixed context usage percentage in footer showing stale pre-compaction values. After compaction the footer now shows `?/200k` until the next LLM response provides accurate usage ([#1382](https://github.com/badlogic/pi-mono/pull/1382) by [@ferologics](https://github.com/ferologics))
|
- Fixed context usage percentage in footer showing stale pre-compaction values. After compaction the footer now shows `?/200k` until the next LLM response provides accurate usage ([#1382](https://github.com/badlogic/pi-mono/pull/1382) by [@ferologics](https://github.com/ferologics))
|
||||||
- Fixed `_checkCompaction()` using the first compaction entry instead of the latest, which could cause incorrect overflow detection with multiple compactions ([#1382](https://github.com/badlogic/pi-mono/pull/1382) by [@ferologics](https://github.com/ferologics))
|
- Fixed `_checkCompaction()` using the first compaction entry instead of the latest, which could cause incorrect overflow detection with multiple compactions ([#1382](https://github.com/badlogic/pi-mono/pull/1382) by [@ferologics](https://github.com/ferologics))
|
||||||
|
- `--model` now works without `--provider`, supports `provider/id` syntax, fuzzy matching, and `:<thinking>` suffix (e.g., `--model sonnet:high`, `--model openai/gpt-4o`) ([#1350](https://github.com/badlogic/pi-mono/pull/1350) by [@mitsuhiko](https://github.com/mitsuhiko))
|
||||||
|
|
||||||
## [0.52.9] - 2026-02-08
|
## [0.52.9] - 2026-02-08
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -452,7 +452,7 @@ pi config # Enable/disable package resources
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
|--------|-------------|
|
|--------|-------------|
|
||||||
| `--provider <name>` | Provider (anthropic, openai, google, etc.) |
|
| `--provider <name>` | Provider (anthropic, openai, google, etc.) |
|
||||||
| `--model <id>` | Model ID |
|
| `--model <pattern>` | Model pattern or ID (supports `provider/id` and optional `:<thinking>`) |
|
||||||
| `--api-key <key>` | API key (overrides env vars) |
|
| `--api-key <key>` | API key (overrides env vars) |
|
||||||
| `--thinking <level>` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh` |
|
| `--thinking <level>` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh` |
|
||||||
| `--models <patterns>` | Comma-separated patterns for Ctrl+P cycling |
|
| `--models <patterns>` | Comma-separated patterns for Ctrl+P cycling |
|
||||||
|
|
@ -524,6 +524,12 @@ pi -p "Summarize this codebase"
|
||||||
# Different model
|
# Different model
|
||||||
pi --provider openai --model gpt-4o "Help me refactor"
|
pi --provider openai --model gpt-4o "Help me refactor"
|
||||||
|
|
||||||
|
# Model with provider prefix (no --provider needed)
|
||||||
|
pi --model openai/gpt-4o "Help me refactor"
|
||||||
|
|
||||||
|
# Model with thinking level shorthand
|
||||||
|
pi --model sonnet:high "Solve this complex problem"
|
||||||
|
|
||||||
# Limit model cycling
|
# Limit model cycling
|
||||||
pi --models "claude-*,gpt-4o"
|
pi --models "claude-*,gpt-4o"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ pi --mode rpc [options]
|
||||||
|
|
||||||
Common options:
|
Common options:
|
||||||
- `--provider <name>`: Set the LLM provider (anthropic, openai, google, etc.)
|
- `--provider <name>`: Set the LLM provider (anthropic, openai, google, etc.)
|
||||||
- `--model <id>`: Set the model ID
|
- `--model <pattern>`: Model pattern or ID (supports `provider/id` and optional `:<thinking>`)
|
||||||
- `--no-session`: Disable session persistence
|
- `--no-session`: Disable session persistence
|
||||||
- `--session-dir <path>`: Custom session storage directory
|
- `--session-dir <path>`: Custom session storage directory
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,12 @@ ${chalk.bold("Examples:")}
|
||||||
# Use different model
|
# Use different model
|
||||||
${APP_NAME} --provider openai --model gpt-4o-mini "Help me refactor this code"
|
${APP_NAME} --provider openai --model gpt-4o-mini "Help me refactor this code"
|
||||||
|
|
||||||
|
# Use model with provider prefix (no --provider needed)
|
||||||
|
${APP_NAME} --model openai/gpt-4o "Help me refactor this code"
|
||||||
|
|
||||||
|
# Use model with thinking level shorthand
|
||||||
|
${APP_NAME} --model sonnet:high "Solve this complex problem"
|
||||||
|
|
||||||
# Limit model cycling to specific models
|
# Limit model cycling to specific models
|
||||||
${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o
|
${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -274,11 +274,11 @@ export interface ResolveCliModelResult {
|
||||||
* Note: This does not apply the thinking level by itself, but it may *parse* and
|
* Note: This does not apply the thinking level by itself, but it may *parse* and
|
||||||
* return a thinking level from "<pattern>:<thinking>" so the caller can apply it.
|
* return a thinking level from "<pattern>:<thinking>" so the caller can apply it.
|
||||||
*/
|
*/
|
||||||
export async function resolveCliModel(options: {
|
export function resolveCliModel(options: {
|
||||||
cliProvider?: string;
|
cliProvider?: string;
|
||||||
cliModel?: string;
|
cliModel?: string;
|
||||||
modelRegistry: ModelRegistry;
|
modelRegistry: ModelRegistry;
|
||||||
}): Promise<ResolveCliModelResult> {
|
}): ResolveCliModelResult {
|
||||||
const { cliProvider, cliModel, modelRegistry } = options;
|
const { cliProvider, cliModel, modelRegistry } = options;
|
||||||
|
|
||||||
if (!cliModel) {
|
if (!cliModel) {
|
||||||
|
|
|
||||||
|
|
@ -403,13 +403,13 @@ async function createSessionManager(parsed: Args, cwd: string): Promise<SessionM
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildSessionOptions(
|
function buildSessionOptions(
|
||||||
parsed: Args,
|
parsed: Args,
|
||||||
scopedModels: ScopedModel[],
|
scopedModels: ScopedModel[],
|
||||||
sessionManager: SessionManager | undefined,
|
sessionManager: SessionManager | undefined,
|
||||||
modelRegistry: ModelRegistry,
|
modelRegistry: ModelRegistry,
|
||||||
settingsManager: SettingsManager,
|
settingsManager: SettingsManager,
|
||||||
): Promise<{ options: CreateAgentSessionOptions; cliThinkingFromModel: boolean }> {
|
): { options: CreateAgentSessionOptions; cliThinkingFromModel: boolean } {
|
||||||
const options: CreateAgentSessionOptions = {};
|
const options: CreateAgentSessionOptions = {};
|
||||||
let cliThinkingFromModel = false;
|
let cliThinkingFromModel = false;
|
||||||
|
|
||||||
|
|
@ -421,7 +421,7 @@ async function buildSessionOptions(
|
||||||
// - supports --provider <name> --model <pattern>
|
// - supports --provider <name> --model <pattern>
|
||||||
// - supports --model <provider>/<pattern>
|
// - supports --model <provider>/<pattern>
|
||||||
if (parsed.model) {
|
if (parsed.model) {
|
||||||
const resolved = await resolveCliModel({
|
const resolved = resolveCliModel({
|
||||||
cliProvider: parsed.provider,
|
cliProvider: parsed.provider,
|
||||||
cliModel: parsed.model,
|
cliModel: parsed.model,
|
||||||
modelRegistry,
|
modelRegistry,
|
||||||
|
|
@ -670,7 +670,7 @@ export async function main(args: string[]) {
|
||||||
sessionManager = SessionManager.open(selectedPath);
|
sessionManager = SessionManager.open(selectedPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { options: sessionOptions, cliThinkingFromModel } = await buildSessionOptions(
|
const { options: sessionOptions, cliThinkingFromModel } = buildSessionOptions(
|
||||||
parsed,
|
parsed,
|
||||||
scopedModels,
|
scopedModels,
|
||||||
sessionManager,
|
sessionManager,
|
||||||
|
|
|
||||||
|
|
@ -207,12 +207,12 @@ describe("parseModelPattern", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("resolveCliModel", () => {
|
describe("resolveCliModel", () => {
|
||||||
test("resolves --model provider/id without --provider", async () => {
|
test("resolves --model provider/id without --provider", () => {
|
||||||
const registry = {
|
const registry = {
|
||||||
getAll: () => allModels,
|
getAll: () => allModels,
|
||||||
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
||||||
|
|
||||||
const result = await resolveCliModel({
|
const result = resolveCliModel({
|
||||||
cliModel: "openai/gpt-4o",
|
cliModel: "openai/gpt-4o",
|
||||||
modelRegistry: registry,
|
modelRegistry: registry,
|
||||||
});
|
});
|
||||||
|
|
@ -222,12 +222,12 @@ describe("resolveCliModel", () => {
|
||||||
expect(result.model?.id).toBe("gpt-4o");
|
expect(result.model?.id).toBe("gpt-4o");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("resolves fuzzy patterns within an explicit provider", async () => {
|
test("resolves fuzzy patterns within an explicit provider", () => {
|
||||||
const registry = {
|
const registry = {
|
||||||
getAll: () => allModels,
|
getAll: () => allModels,
|
||||||
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
||||||
|
|
||||||
const result = await resolveCliModel({
|
const result = resolveCliModel({
|
||||||
cliProvider: "openai",
|
cliProvider: "openai",
|
||||||
cliModel: "4o",
|
cliModel: "4o",
|
||||||
modelRegistry: registry,
|
modelRegistry: registry,
|
||||||
|
|
@ -238,12 +238,12 @@ describe("resolveCliModel", () => {
|
||||||
expect(result.model?.id).toBe("gpt-4o");
|
expect(result.model?.id).toBe("gpt-4o");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("supports --model <pattern>:<thinking> (without explicit --thinking)", async () => {
|
test("supports --model <pattern>:<thinking> (without explicit --thinking)", () => {
|
||||||
const registry = {
|
const registry = {
|
||||||
getAll: () => allModels,
|
getAll: () => allModels,
|
||||||
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
||||||
|
|
||||||
const result = await resolveCliModel({
|
const result = resolveCliModel({
|
||||||
cliModel: "sonnet:high",
|
cliModel: "sonnet:high",
|
||||||
modelRegistry: registry,
|
modelRegistry: registry,
|
||||||
});
|
});
|
||||||
|
|
@ -253,12 +253,12 @@ describe("resolveCliModel", () => {
|
||||||
expect(result.thinkingLevel).toBe("high");
|
expect(result.thinkingLevel).toBe("high");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("prefers exact model id match over provider inference (OpenRouter-style ids)", async () => {
|
test("prefers exact model id match over provider inference (OpenRouter-style ids)", () => {
|
||||||
const registry = {
|
const registry = {
|
||||||
getAll: () => allModels,
|
getAll: () => allModels,
|
||||||
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
||||||
|
|
||||||
const result = await resolveCliModel({
|
const result = resolveCliModel({
|
||||||
cliModel: "openai/gpt-4o:extended",
|
cliModel: "openai/gpt-4o:extended",
|
||||||
modelRegistry: registry,
|
modelRegistry: registry,
|
||||||
});
|
});
|
||||||
|
|
@ -268,12 +268,12 @@ describe("resolveCliModel", () => {
|
||||||
expect(result.model?.id).toBe("openai/gpt-4o:extended");
|
expect(result.model?.id).toBe("openai/gpt-4o:extended");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("does not strip invalid :suffix as thinking level in --model (fail fast)", async () => {
|
test("does not strip invalid :suffix as thinking level in --model (fail fast)", () => {
|
||||||
const registry = {
|
const registry = {
|
||||||
getAll: () => allModels,
|
getAll: () => allModels,
|
||||||
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
||||||
|
|
||||||
const result = await resolveCliModel({
|
const result = resolveCliModel({
|
||||||
cliProvider: "openai",
|
cliProvider: "openai",
|
||||||
cliModel: "gpt-4o:extended",
|
cliModel: "gpt-4o:extended",
|
||||||
modelRegistry: registry,
|
modelRegistry: registry,
|
||||||
|
|
@ -283,12 +283,12 @@ describe("resolveCliModel", () => {
|
||||||
expect(result.error).toContain("not found");
|
expect(result.error).toContain("not found");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("returns a clear error when there are no models", async () => {
|
test("returns a clear error when there are no models", () => {
|
||||||
const registry = {
|
const registry = {
|
||||||
getAll: () => [],
|
getAll: () => [],
|
||||||
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
||||||
|
|
||||||
const result = await resolveCliModel({
|
const result = resolveCliModel({
|
||||||
cliProvider: "openai",
|
cliProvider: "openai",
|
||||||
cliModel: "gpt-4o",
|
cliModel: "gpt-4o",
|
||||||
modelRegistry: registry,
|
modelRegistry: registry,
|
||||||
|
|
@ -298,12 +298,12 @@ describe("resolveCliModel", () => {
|
||||||
expect(result.error).toContain("No models available");
|
expect(result.error).toContain("No models available");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("resolves provider-prefixed fuzzy patterns (openrouter/qwen -> openrouter model)", async () => {
|
test("resolves provider-prefixed fuzzy patterns (openrouter/qwen -> openrouter model)", () => {
|
||||||
const registry = {
|
const registry = {
|
||||||
getAll: () => allModels,
|
getAll: () => allModels,
|
||||||
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"];
|
||||||
|
|
||||||
const result = await resolveCliModel({
|
const result = resolveCliModel({
|
||||||
cliModel: "openrouter/qwen",
|
cliModel: "openrouter/qwen",
|
||||||
modelRegistry: registry,
|
modelRegistry: registry,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue