mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-17 04:02:21 +00:00
Merge branch 'feat/custom-thinking-budgets'
feat: add thinkingBudgets setting to customize token budgets per thinking level Allows users to override default token budgets for minimal/low/medium/high thinking levels via settings.json. Useful for token-based providers. closes #529 Co-authored-by: Melih Mucuk <melih@monkeysteam.com>
This commit is contained in:
commit
f97dcbf92f
8 changed files with 126 additions and 11 deletions
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- `thinkingBudgets` option on `Agent` and `AgentOptions` to customize token budgets per thinking level ([#529](https://github.com/badlogic/pi-mono/pull/529) by [@melihmucuk](https://github.com/melihmucuk))
|
||||||
|
|
||||||
## [0.37.8] - 2026-01-07
|
## [0.37.8] - 2026-01-07
|
||||||
|
|
||||||
## [0.37.7] - 2026-01-07
|
## [0.37.7] - 2026-01-07
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import {
|
||||||
type Model,
|
type Model,
|
||||||
streamSimple,
|
streamSimple,
|
||||||
type TextContent,
|
type TextContent,
|
||||||
|
type ThinkingBudgets,
|
||||||
} from "@mariozechner/pi-ai";
|
} from "@mariozechner/pi-ai";
|
||||||
import { agentLoop, agentLoopContinue } from "./agent-loop.js";
|
import { agentLoop, agentLoopContinue } from "./agent-loop.js";
|
||||||
import type {
|
import type {
|
||||||
|
|
@ -71,6 +72,11 @@ export interface AgentOptions {
|
||||||
* Useful for expiring tokens (e.g., GitHub Copilot OAuth).
|
* Useful for expiring tokens (e.g., GitHub Copilot OAuth).
|
||||||
*/
|
*/
|
||||||
getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
|
getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom token budgets for thinking levels (token-based providers only).
|
||||||
|
*/
|
||||||
|
thinkingBudgets?: ThinkingBudgets;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Agent {
|
export class Agent {
|
||||||
|
|
@ -99,6 +105,7 @@ export class Agent {
|
||||||
public getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
|
public getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
|
||||||
private runningPrompt?: Promise<void>;
|
private runningPrompt?: Promise<void>;
|
||||||
private resolveRunningPrompt?: () => void;
|
private resolveRunningPrompt?: () => void;
|
||||||
|
private _thinkingBudgets?: ThinkingBudgets;
|
||||||
|
|
||||||
constructor(opts: AgentOptions = {}) {
|
constructor(opts: AgentOptions = {}) {
|
||||||
this._state = { ...this._state, ...opts.initialState };
|
this._state = { ...this._state, ...opts.initialState };
|
||||||
|
|
@ -109,6 +116,7 @@ export class Agent {
|
||||||
this.streamFn = opts.streamFn || streamSimple;
|
this.streamFn = opts.streamFn || streamSimple;
|
||||||
this._sessionId = opts.sessionId;
|
this._sessionId = opts.sessionId;
|
||||||
this.getApiKey = opts.getApiKey;
|
this.getApiKey = opts.getApiKey;
|
||||||
|
this._thinkingBudgets = opts.thinkingBudgets;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -126,6 +134,20 @@ export class Agent {
|
||||||
this._sessionId = value;
|
this._sessionId = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current thinking budgets.
|
||||||
|
*/
|
||||||
|
get thinkingBudgets(): ThinkingBudgets | undefined {
|
||||||
|
return this._thinkingBudgets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set custom thinking budgets for token-based providers.
|
||||||
|
*/
|
||||||
|
set thinkingBudgets(value: ThinkingBudgets | undefined) {
|
||||||
|
this._thinkingBudgets = value;
|
||||||
|
}
|
||||||
|
|
||||||
get state(): AgentState {
|
get state(): AgentState {
|
||||||
return this._state;
|
return this._state;
|
||||||
}
|
}
|
||||||
|
|
@ -310,6 +332,7 @@ export class Agent {
|
||||||
model,
|
model,
|
||||||
reasoning,
|
reasoning,
|
||||||
sessionId: this._sessionId,
|
sessionId: this._sessionId,
|
||||||
|
thinkingBudgets: this._thinkingBudgets,
|
||||||
convertToLlm: this.convertToLlm,
|
convertToLlm: this.convertToLlm,
|
||||||
transformContext: this.transformContext,
|
transformContext: this.transformContext,
|
||||||
getApiKey: this.getApiKey,
|
getApiKey: this.getApiKey,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- `thinkingBudgets` option in `SimpleStreamOptions` for customizing token budgets per thinking level on token-based providers ([#529](https://github.com/badlogic/pi-mono/pull/529) by [@melihmucuk](https://github.com/melihmucuk))
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|
||||||
- Removed OpenAI Codex model aliases (`gpt-5`, `gpt-5-mini`, `gpt-5-nano`, `codex-mini-latest`, `gpt-5-codex`, `gpt-5.1-codex`, `gpt-5.1-chat-latest`). Use canonical model IDs: `gpt-5.1`, `gpt-5.1-codex-max`, `gpt-5.1-codex-mini`, `gpt-5.2`, `gpt-5.2-codex`. ([#536](https://github.com/badlogic/pi-mono/pull/536) by [@ghoulr](https://github.com/ghoulr))
|
- Removed OpenAI Codex model aliases (`gpt-5`, `gpt-5-mini`, `gpt-5-nano`, `codex-mini-latest`, `gpt-5-codex`, `gpt-5.1-codex`, `gpt-5.1-chat-latest`). Use canonical model IDs: `gpt-5.1`, `gpt-5.1-codex-max`, `gpt-5.1-codex-mini`, `gpt-5.2`, `gpt-5.2-codex`. ([#536](https://github.com/badlogic/pi-mono/pull/536) by [@ghoulr](https://github.com/ghoulr))
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import type {
|
||||||
Model,
|
Model,
|
||||||
OptionsForApi,
|
OptionsForApi,
|
||||||
SimpleStreamOptions,
|
SimpleStreamOptions,
|
||||||
|
ThinkingBudgets,
|
||||||
ThinkingLevel,
|
ThinkingLevel,
|
||||||
} from "./types.js";
|
} from "./types.js";
|
||||||
|
|
||||||
|
|
@ -192,15 +193,17 @@ function mapOptionsForApi<TApi extends Api>(
|
||||||
|
|
||||||
// Claude requires max_tokens > thinking.budget_tokens
|
// Claude requires max_tokens > thinking.budget_tokens
|
||||||
// So we need to ensure maxTokens accounts for both thinking and output
|
// So we need to ensure maxTokens accounts for both thinking and output
|
||||||
const anthropicBudgets = {
|
const defaultBudgets: ThinkingBudgets = {
|
||||||
minimal: 1024,
|
minimal: 1024,
|
||||||
low: 2048,
|
low: 2048,
|
||||||
medium: 8192,
|
medium: 8192,
|
||||||
high: 16384,
|
high: 16384,
|
||||||
};
|
};
|
||||||
|
const budgets = { ...defaultBudgets, ...options?.thinkingBudgets };
|
||||||
|
|
||||||
const minOutputTokens = 1024;
|
const minOutputTokens = 1024;
|
||||||
let thinkingBudget = anthropicBudgets[clampReasoning(options.reasoning)!];
|
const level = clampReasoning(options.reasoning)!;
|
||||||
|
let thinkingBudget = budgets[level]!;
|
||||||
// Caller's maxTokens is the desired output; add thinking budget on top, capped at model limit
|
// Caller's maxTokens is the desired output; add thinking budget on top, capped at model limit
|
||||||
const maxTokens = Math.min((base.maxTokens || 0) + thinkingBudget, model.maxTokens);
|
const maxTokens = Math.min((base.maxTokens || 0) + thinkingBudget, model.maxTokens);
|
||||||
|
|
||||||
|
|
@ -261,7 +264,7 @@ function mapOptionsForApi<TApi extends Api>(
|
||||||
...base,
|
...base,
|
||||||
thinking: {
|
thinking: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
budgetTokens: getGoogleBudget(googleModel, effort),
|
budgetTokens: getGoogleBudget(googleModel, effort, options?.thinkingBudgets),
|
||||||
},
|
},
|
||||||
} satisfies GoogleOptions;
|
} satisfies GoogleOptions;
|
||||||
}
|
}
|
||||||
|
|
@ -287,15 +290,16 @@ function mapOptionsForApi<TApi extends Api>(
|
||||||
// Models using thinkingBudget (Gemini 2.x, Claude via Antigravity)
|
// Models using thinkingBudget (Gemini 2.x, Claude via Antigravity)
|
||||||
// Claude requires max_tokens > thinking.budget_tokens
|
// Claude requires max_tokens > thinking.budget_tokens
|
||||||
// So we need to ensure maxTokens accounts for both thinking and output
|
// So we need to ensure maxTokens accounts for both thinking and output
|
||||||
const budgets: Record<ClampedThinkingLevel, number> = {
|
const defaultBudgets: ThinkingBudgets = {
|
||||||
minimal: 1024,
|
minimal: 1024,
|
||||||
low: 2048,
|
low: 2048,
|
||||||
medium: 8192,
|
medium: 8192,
|
||||||
high: 16384,
|
high: 16384,
|
||||||
};
|
};
|
||||||
|
const budgets = { ...defaultBudgets, ...options?.thinkingBudgets };
|
||||||
|
|
||||||
const minOutputTokens = 1024;
|
const minOutputTokens = 1024;
|
||||||
let thinkingBudget = budgets[effort];
|
let thinkingBudget = budgets[effort]!;
|
||||||
// Caller's maxTokens is the desired output; add thinking budget on top, capped at model limit
|
// Caller's maxTokens is the desired output; add thinking budget on top, capped at model limit
|
||||||
const maxTokens = Math.min((base.maxTokens || 0) + thinkingBudget, model.maxTokens);
|
const maxTokens = Math.min((base.maxTokens || 0) + thinkingBudget, model.maxTokens);
|
||||||
|
|
||||||
|
|
@ -338,7 +342,7 @@ function mapOptionsForApi<TApi extends Api>(
|
||||||
...base,
|
...base,
|
||||||
thinking: {
|
thinking: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
budgetTokens: getGoogleBudget(geminiModel, effort),
|
budgetTokens: getGoogleBudget(geminiModel, effort, options?.thinkingBudgets),
|
||||||
},
|
},
|
||||||
} satisfies GoogleVertexOptions;
|
} satisfies GoogleVertexOptions;
|
||||||
}
|
}
|
||||||
|
|
@ -416,7 +420,16 @@ function getGeminiCliThinkingLevel(effort: ClampedThinkingLevel, modelId: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGoogleBudget(model: Model<"google-generative-ai">, effort: ClampedThinkingLevel): number {
|
function getGoogleBudget(
|
||||||
|
model: Model<"google-generative-ai">,
|
||||||
|
effort: ClampedThinkingLevel,
|
||||||
|
customBudgets?: ThinkingBudgets,
|
||||||
|
): number {
|
||||||
|
// Custom budgets take precedence if provided for this level
|
||||||
|
if (customBudgets?.[effort] !== undefined) {
|
||||||
|
return customBudgets[effort]!;
|
||||||
|
}
|
||||||
|
|
||||||
// See https://ai.google.dev/gemini-api/docs/thinking#set-budget
|
// See https://ai.google.dev/gemini-api/docs/thinking#set-budget
|
||||||
if (model.id.includes("2.5-pro")) {
|
if (model.id.includes("2.5-pro")) {
|
||||||
const budgets: Record<ClampedThinkingLevel, number> = {
|
const budgets: Record<ClampedThinkingLevel, number> = {
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,14 @@ export type Provider = KnownProvider | string;
|
||||||
|
|
||||||
export type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh";
|
export type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh";
|
||||||
|
|
||||||
|
/** Token budgets for each thinking level (token-based providers only) */
|
||||||
|
export interface ThinkingBudgets {
|
||||||
|
minimal?: number;
|
||||||
|
low?: number;
|
||||||
|
medium?: number;
|
||||||
|
high?: number;
|
||||||
|
}
|
||||||
|
|
||||||
// Base options all providers share
|
// Base options all providers share
|
||||||
export interface StreamOptions {
|
export interface StreamOptions {
|
||||||
temperature?: number;
|
temperature?: number;
|
||||||
|
|
@ -75,6 +83,8 @@ export interface StreamOptions {
|
||||||
// Unified options with reasoning passed to streamSimple() and completeSimple()
|
// Unified options with reasoning passed to streamSimple() and completeSimple()
|
||||||
export interface SimpleStreamOptions extends StreamOptions {
|
export interface SimpleStreamOptions extends StreamOptions {
|
||||||
reasoning?: ThinkingLevel;
|
reasoning?: ThinkingLevel;
|
||||||
|
/** Custom token budgets for thinking levels (token-based providers only) */
|
||||||
|
thinkingBudgets?: ThinkingBudgets;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic StreamFunction with typed options
|
// Generic StreamFunction with typed options
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
- SDK: `InteractiveMode`, `runPrintMode()`, `runRpcMode()` exported for building custom run modes. See `docs/sdk.md`.
|
- SDK: `InteractiveMode`, `runPrintMode()`, `runRpcMode()` exported for building custom run modes. See `docs/sdk.md`.
|
||||||
- `PI_SKIP_VERSION_CHECK` environment variable to disable new version notifications at startup ([#549](https://github.com/badlogic/pi-mono/pull/549) by [@aos](https://github.com/aos))
|
- `PI_SKIP_VERSION_CHECK` environment variable to disable new version notifications at startup ([#549](https://github.com/badlogic/pi-mono/pull/549) by [@aos](https://github.com/aos))
|
||||||
|
- `thinkingBudgets` setting to customize token budgets per thinking level for token-based providers ([#529](https://github.com/badlogic/pi-mono/pull/529) by [@melihmucuk](https://github.com/melihmucuk))
|
||||||
- Extension UI dialogs (`ctx.ui.select()`, `ctx.ui.confirm()`, `ctx.ui.input()`) now support a `timeout` option with live countdown display ([#522](https://github.com/badlogic/pi-mono/pull/522) by [@nicobailon](https://github.com/nicobailon))
|
- Extension UI dialogs (`ctx.ui.select()`, `ctx.ui.confirm()`, `ctx.ui.input()`) now support a `timeout` option with live countdown display ([#522](https://github.com/badlogic/pi-mono/pull/522) by [@nicobailon](https://github.com/nicobailon))
|
||||||
- Extensions can now provide custom editor components via `ctx.ui.setEditorComponent()`. See `examples/extensions/modal-editor.ts` and `docs/tui.md` Pattern 7.
|
- Extensions can now provide custom editor components via `ctx.ui.setEditorComponent()`. See `examples/extensions/modal-editor.ts` and `docs/tui.md` Pattern 7.
|
||||||
- Extension factories can now be async, enabling dynamic imports and lazy-loaded dependencies ([#513](https://github.com/badlogic/pi-mono/pull/513) by [@austinm911](https://github.com/austinm911))
|
- Extension factories can now be async, enabling dynamic imports and lazy-loaded dependencies ([#513](https://github.com/badlogic/pi-mono/pull/513) by [@austinm911](https://github.com/austinm911))
|
||||||
|
|
@ -135,6 +136,7 @@
|
||||||
This release unifies hooks and custom tools into a single "extensions" system and renames "slash commands" to "prompt templates". ([#454](https://github.com/badlogic/pi-mono/issues/454))
|
This release unifies hooks and custom tools into a single "extensions" system and renames "slash commands" to "prompt templates". ([#454](https://github.com/badlogic/pi-mono/issues/454))
|
||||||
|
|
||||||
**Before migrating, read:**
|
**Before migrating, read:**
|
||||||
|
|
||||||
- [docs/extensions.md](docs/extensions.md) - Full API reference
|
- [docs/extensions.md](docs/extensions.md) - Full API reference
|
||||||
- [README.md](README.md) - Extensions section with examples
|
- [README.md](README.md) - Extensions section with examples
|
||||||
- [examples/extensions/](examples/extensions/) - Working examples
|
- [examples/extensions/](examples/extensions/) - Working examples
|
||||||
|
|
@ -144,14 +146,17 @@ This release unifies hooks and custom tools into a single "extensions" system an
|
||||||
Hooks and custom tools are now unified as **extensions**. Both were TypeScript modules exporting a factory function that receives an API object. Now there's one concept, one discovery location, one CLI flag, one settings.json entry.
|
Hooks and custom tools are now unified as **extensions**. Both were TypeScript modules exporting a factory function that receives an API object. Now there's one concept, one discovery location, one CLI flag, one settings.json entry.
|
||||||
|
|
||||||
**Automatic migration:**
|
**Automatic migration:**
|
||||||
|
|
||||||
- `commands/` directories are automatically renamed to `prompts/` on startup (both `~/.pi/agent/commands/` and `.pi/commands/`)
|
- `commands/` directories are automatically renamed to `prompts/` on startup (both `~/.pi/agent/commands/` and `.pi/commands/`)
|
||||||
|
|
||||||
**Manual migration required:**
|
**Manual migration required:**
|
||||||
|
|
||||||
1. Move files from `hooks/` and `tools/` directories to `extensions/` (deprecation warnings shown on startup)
|
1. Move files from `hooks/` and `tools/` directories to `extensions/` (deprecation warnings shown on startup)
|
||||||
2. Update imports and type names in your extension code
|
2. Update imports and type names in your extension code
|
||||||
3. Update `settings.json` if you have explicit hook and custom tool paths configured
|
3. Update `settings.json` if you have explicit hook and custom tool paths configured
|
||||||
|
|
||||||
**Directory changes:**
|
**Directory changes:**
|
||||||
|
|
||||||
```
|
```
|
||||||
# Before
|
# Before
|
||||||
~/.pi/agent/hooks/*.ts → ~/.pi/agent/extensions/*.ts
|
~/.pi/agent/hooks/*.ts → ~/.pi/agent/extensions/*.ts
|
||||||
|
|
@ -161,6 +166,7 @@ Hooks and custom tools are now unified as **extensions**. Both were TypeScript m
|
||||||
```
|
```
|
||||||
|
|
||||||
**Extension discovery rules** (in `extensions/` directories):
|
**Extension discovery rules** (in `extensions/` directories):
|
||||||
|
|
||||||
1. **Direct files:** `extensions/*.ts` or `*.js` → loaded directly
|
1. **Direct files:** `extensions/*.ts` or `*.js` → loaded directly
|
||||||
2. **Subdirectory with index:** `extensions/myext/index.ts` → loaded as single extension
|
2. **Subdirectory with index:** `extensions/myext/index.ts` → loaded as single extension
|
||||||
3. **Subdirectory with package.json:** `extensions/myext/package.json` with `"pi"` field → loads declared paths
|
3. **Subdirectory with package.json:** `extensions/myext/package.json` with `"pi"` field → loads declared paths
|
||||||
|
|
@ -179,6 +185,7 @@ Hooks and custom tools are now unified as **extensions**. Both were TypeScript m
|
||||||
No recursion beyond one level. Complex packages must use the `package.json` manifest. Dependencies are resolved via jiti, and extensions can be published to and installed from npm.
|
No recursion beyond one level. Complex packages must use the `package.json` manifest. Dependencies are resolved via jiti, and extensions can be published to and installed from npm.
|
||||||
|
|
||||||
**Type renames:**
|
**Type renames:**
|
||||||
|
|
||||||
- `HookAPI` → `ExtensionAPI`
|
- `HookAPI` → `ExtensionAPI`
|
||||||
- `HookContext` → `ExtensionContext`
|
- `HookContext` → `ExtensionContext`
|
||||||
- `HookCommandContext` → `ExtensionCommandContext`
|
- `HookCommandContext` → `ExtensionCommandContext`
|
||||||
|
|
@ -191,6 +198,7 @@ No recursion beyond one level. Complex packages must use the `package.json` mani
|
||||||
- `HookMessage` → `CustomMessage`
|
- `HookMessage` → `CustomMessage`
|
||||||
|
|
||||||
**Import changes:**
|
**Import changes:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Before (hook)
|
// Before (hook)
|
||||||
import type { HookAPI, HookContext } from "@mariozechner/pi-coding-agent";
|
import type { HookAPI, HookContext } from "@mariozechner/pi-coding-agent";
|
||||||
|
|
@ -233,6 +241,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
- `ctx.sessionManager` - Read session entries, get branch history
|
- `ctx.sessionManager` - Read session entries, get branch history
|
||||||
|
|
||||||
**Settings changes:**
|
**Settings changes:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
// Before
|
// Before
|
||||||
{
|
{
|
||||||
|
|
@ -247,6 +256,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
```
|
```
|
||||||
|
|
||||||
**CLI changes:**
|
**CLI changes:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Before
|
# Before
|
||||||
pi --hook ./safety.ts --tool ./todo.ts
|
pi --hook ./safety.ts --tool ./todo.ts
|
||||||
|
|
@ -262,22 +272,26 @@ pi --extension ./safety.ts -e ./todo.ts
|
||||||
**Automatic migration:** The `commands/` directory is automatically renamed to `prompts/` on startup (if `prompts/` doesn't exist). Works for both regular directories and symlinks.
|
**Automatic migration:** The `commands/` directory is automatically renamed to `prompts/` on startup (if `prompts/` doesn't exist). Works for both regular directories and symlinks.
|
||||||
|
|
||||||
**Directory changes:**
|
**Directory changes:**
|
||||||
|
|
||||||
```
|
```
|
||||||
~/.pi/agent/commands/*.md → ~/.pi/agent/prompts/*.md
|
~/.pi/agent/commands/*.md → ~/.pi/agent/prompts/*.md
|
||||||
.pi/commands/*.md → .pi/prompts/*.md
|
.pi/commands/*.md → .pi/prompts/*.md
|
||||||
```
|
```
|
||||||
|
|
||||||
**SDK type renames:**
|
**SDK type renames:**
|
||||||
|
|
||||||
- `FileSlashCommand` → `PromptTemplate`
|
- `FileSlashCommand` → `PromptTemplate`
|
||||||
- `LoadSlashCommandsOptions` → `LoadPromptTemplatesOptions`
|
- `LoadSlashCommandsOptions` → `LoadPromptTemplatesOptions`
|
||||||
|
|
||||||
**SDK function renames:**
|
**SDK function renames:**
|
||||||
|
|
||||||
- `discoverSlashCommands()` → `discoverPromptTemplates()`
|
- `discoverSlashCommands()` → `discoverPromptTemplates()`
|
||||||
- `loadSlashCommands()` → `loadPromptTemplates()`
|
- `loadSlashCommands()` → `loadPromptTemplates()`
|
||||||
- `expandSlashCommand()` → `expandPromptTemplate()`
|
- `expandSlashCommand()` → `expandPromptTemplate()`
|
||||||
- `getCommandsDir()` → `getPromptsDir()`
|
- `getCommandsDir()` → `getPromptsDir()`
|
||||||
|
|
||||||
**SDK option renames:**
|
**SDK option renames:**
|
||||||
|
|
||||||
- `CreateAgentSessionOptions.slashCommands` → `.promptTemplates`
|
- `CreateAgentSessionOptions.slashCommands` → `.promptTemplates`
|
||||||
- `AgentSession.fileCommands` → `.promptTemplates`
|
- `AgentSession.fileCommands` → `.promptTemplates`
|
||||||
- `PromptOptions.expandSlashCommands` → `.expandPromptTemplates`
|
- `PromptOptions.expandSlashCommands` → `.expandPromptTemplates`
|
||||||
|
|
@ -285,17 +299,20 @@ pi --extension ./safety.ts -e ./todo.ts
|
||||||
### SDK Migration
|
### SDK Migration
|
||||||
|
|
||||||
**Discovery functions:**
|
**Discovery functions:**
|
||||||
|
|
||||||
- `discoverAndLoadHooks()` → `discoverAndLoadExtensions()`
|
- `discoverAndLoadHooks()` → `discoverAndLoadExtensions()`
|
||||||
- `discoverAndLoadCustomTools()` → merged into `discoverAndLoadExtensions()`
|
- `discoverAndLoadCustomTools()` → merged into `discoverAndLoadExtensions()`
|
||||||
- `loadHooks()` → `loadExtensions()`
|
- `loadHooks()` → `loadExtensions()`
|
||||||
- `loadCustomTools()` → merged into `loadExtensions()`
|
- `loadCustomTools()` → merged into `loadExtensions()`
|
||||||
|
|
||||||
**Runner and wrapper:**
|
**Runner and wrapper:**
|
||||||
|
|
||||||
- `HookRunner` → `ExtensionRunner`
|
- `HookRunner` → `ExtensionRunner`
|
||||||
- `wrapToolsWithHooks()` → `wrapToolsWithExtensions()`
|
- `wrapToolsWithHooks()` → `wrapToolsWithExtensions()`
|
||||||
- `wrapToolWithHooks()` → `wrapToolWithExtensions()`
|
- `wrapToolWithHooks()` → `wrapToolWithExtensions()`
|
||||||
|
|
||||||
**CreateAgentSessionOptions:**
|
**CreateAgentSessionOptions:**
|
||||||
|
|
||||||
- `.hooks` → removed (use `.additionalExtensionPaths` for paths)
|
- `.hooks` → removed (use `.additionalExtensionPaths` for paths)
|
||||||
- `.additionalHookPaths` → `.additionalExtensionPaths`
|
- `.additionalHookPaths` → `.additionalExtensionPaths`
|
||||||
- `.preloadedHooks` → `.preloadedExtensions`
|
- `.preloadedHooks` → `.preloadedExtensions`
|
||||||
|
|
@ -304,6 +321,7 @@ pi --extension ./safety.ts -e ./todo.ts
|
||||||
- `.slashCommands` → `.promptTemplates`
|
- `.slashCommands` → `.promptTemplates`
|
||||||
|
|
||||||
**AgentSession:**
|
**AgentSession:**
|
||||||
|
|
||||||
- `.hookRunner` → `.extensionRunner`
|
- `.hookRunner` → `.extensionRunner`
|
||||||
- `.fileCommands` → `.promptTemplates`
|
- `.fileCommands` → `.promptTemplates`
|
||||||
- `.sendHookMessage()` → `.sendCustomMessage()`
|
- `.sendHookMessage()` → `.sendCustomMessage()`
|
||||||
|
|
@ -311,6 +329,7 @@ pi --extension ./safety.ts -e ./todo.ts
|
||||||
### Session Migration
|
### Session Migration
|
||||||
|
|
||||||
**Automatic.** Session version bumped from 2 to 3. Existing sessions are migrated on first load:
|
**Automatic.** Session version bumped from 2 to 3. Existing sessions are migrated on first load:
|
||||||
|
|
||||||
- Message role `"hookMessage"` → `"custom"`
|
- Message role `"hookMessage"` → `"custom"`
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|
@ -424,7 +443,7 @@ pi --extension ./safety.ts -e ./todo.ts
|
||||||
- `steer()` and `followUp()` now expand file-based slash commands and error on hook commands (hook commands cannot be queued)
|
- `steer()` and `followUp()` now expand file-based slash commands and error on hook commands (hook commands cannot be queued)
|
||||||
- `prompt()` accepts new `streamingBehavior` option (`"steer"` or `"followUp"`) to specify queueing behavior during streaming
|
- `prompt()` accepts new `streamingBehavior` option (`"steer"` or `"followUp"`) to specify queueing behavior during streaming
|
||||||
- RPC `prompt` command now accepts optional `streamingBehavior` field
|
- RPC `prompt` command now accepts optional `streamingBehavior` field
|
||||||
([#420](https://github.com/badlogic/pi-mono/issues/420))
|
([#420](https://github.com/badlogic/pi-mono/issues/420))
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
@ -510,10 +529,12 @@ See [docs/session.md](docs/session.md) for the file format and `SessionManager`
|
||||||
The hooks API has been restructured with more granular events and better session access.
|
The hooks API has been restructured with more granular events and better session access.
|
||||||
|
|
||||||
**Type renames:**
|
**Type renames:**
|
||||||
|
|
||||||
- `HookEventContext` → `HookContext`
|
- `HookEventContext` → `HookContext`
|
||||||
- `HookCommandContext` is now a new interface extending `HookContext` with session control methods
|
- `HookCommandContext` is now a new interface extending `HookContext` with session control methods
|
||||||
|
|
||||||
**Event changes:**
|
**Event changes:**
|
||||||
|
|
||||||
- The monolithic `session` event is now split into granular events: `session_start`, `session_before_switch`, `session_switch`, `session_before_branch`, `session_branch`, `session_before_compact`, `session_compact`, `session_shutdown`
|
- The monolithic `session` event is now split into granular events: `session_start`, `session_before_switch`, `session_switch`, `session_before_branch`, `session_branch`, `session_before_compact`, `session_compact`, `session_shutdown`
|
||||||
- `session_before_switch` and `session_switch` events now include `reason: "new" | "resume"` to distinguish between `/new` and `/resume`
|
- `session_before_switch` and `session_switch` events now include `reason: "new" | "resume"` to distinguish between `/new` and `/resume`
|
||||||
- New `session_before_tree` and `session_tree` events for `/tree` navigation (hook can provide custom branch summary)
|
- New `session_before_tree` and `session_tree` events for `/tree` navigation (hook can provide custom branch summary)
|
||||||
|
|
@ -522,6 +543,7 @@ The hooks API has been restructured with more granular events and better session
|
||||||
- Session entries are no longer passed in events. Use `ctx.sessionManager.getEntries()` or `ctx.sessionManager.getBranch()` instead
|
- Session entries are no longer passed in events. Use `ctx.sessionManager.getEntries()` or `ctx.sessionManager.getBranch()` instead
|
||||||
|
|
||||||
**API changes:**
|
**API changes:**
|
||||||
|
|
||||||
- `pi.send(text, attachments?)` → `pi.sendMessage(message, triggerTurn?)` (creates `CustomMessageEntry`)
|
- `pi.send(text, attachments?)` → `pi.sendMessage(message, triggerTurn?)` (creates `CustomMessageEntry`)
|
||||||
- New `pi.appendEntry(customType, data?)` for hook state persistence (not in LLM context)
|
- New `pi.appendEntry(customType, data?)` for hook state persistence (not in LLM context)
|
||||||
- New `pi.registerCommand(name, options)` for custom slash commands (handler receives `HookCommandContext`)
|
- New `pi.registerCommand(name, options)` for custom slash commands (handler receives `HookCommandContext`)
|
||||||
|
|
@ -536,6 +558,7 @@ The hooks API has been restructured with more granular events and better session
|
||||||
- New `ctx.modelRegistry` and `ctx.model` for API key resolution
|
- New `ctx.modelRegistry` and `ctx.model` for API key resolution
|
||||||
|
|
||||||
**HookCommandContext (slash commands only):**
|
**HookCommandContext (slash commands only):**
|
||||||
|
|
||||||
- `ctx.waitForIdle()` - wait for agent to finish streaming
|
- `ctx.waitForIdle()` - wait for agent to finish streaming
|
||||||
- `ctx.newSession(options?)` - create new sessions with optional setup callback
|
- `ctx.newSession(options?)` - create new sessions with optional setup callback
|
||||||
- `ctx.branch(entryId)` - branch from a specific entry
|
- `ctx.branch(entryId)` - branch from a specific entry
|
||||||
|
|
@ -544,6 +567,7 @@ The hooks API has been restructured with more granular events and better session
|
||||||
These methods are only on `HookCommandContext` (not `HookContext`) because they can deadlock if called from event handlers that run inside the agent loop.
|
These methods are only on `HookCommandContext` (not `HookContext`) because they can deadlock if called from event handlers that run inside the agent loop.
|
||||||
|
|
||||||
**Removed:**
|
**Removed:**
|
||||||
|
|
||||||
- `hookTimeout` setting (hooks no longer have timeouts; use Ctrl+C to abort)
|
- `hookTimeout` setting (hooks no longer have timeouts; use Ctrl+C to abort)
|
||||||
- `resolveApiKey` parameter (use `ctx.modelRegistry.getApiKey(model)`)
|
- `resolveApiKey` parameter (use `ctx.modelRegistry.getApiKey(model)`)
|
||||||
|
|
||||||
|
|
@ -554,12 +578,14 @@ See [docs/hooks.md](docs/hooks.md) and [examples/hooks/](examples/hooks/) for th
|
||||||
The custom tools API has been restructured to mirror the hooks pattern with a context object.
|
The custom tools API has been restructured to mirror the hooks pattern with a context object.
|
||||||
|
|
||||||
**Type renames:**
|
**Type renames:**
|
||||||
|
|
||||||
- `CustomAgentTool` → `CustomTool`
|
- `CustomAgentTool` → `CustomTool`
|
||||||
- `ToolAPI` → `CustomToolAPI`
|
- `ToolAPI` → `CustomToolAPI`
|
||||||
- `ToolContext` → `CustomToolContext`
|
- `ToolContext` → `CustomToolContext`
|
||||||
- `ToolSessionEvent` → `CustomToolSessionEvent`
|
- `ToolSessionEvent` → `CustomToolSessionEvent`
|
||||||
|
|
||||||
**Execute signature changed:**
|
**Execute signature changed:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Before (v0.30.2)
|
// Before (v0.30.2)
|
||||||
execute(toolCallId, params, signal, onUpdate)
|
execute(toolCallId, params, signal, onUpdate)
|
||||||
|
|
@ -569,11 +595,13 @@ execute(toolCallId, params, onUpdate, ctx, signal?)
|
||||||
```
|
```
|
||||||
|
|
||||||
The new `ctx: CustomToolContext` provides `sessionManager`, `modelRegistry`, `model`, and agent state methods:
|
The new `ctx: CustomToolContext` provides `sessionManager`, `modelRegistry`, `model`, and agent state methods:
|
||||||
|
|
||||||
- `ctx.isIdle()` - check if agent is streaming
|
- `ctx.isIdle()` - check if agent is streaming
|
||||||
- `ctx.hasQueuedMessages()` - check if user has queued messages (skip interactive prompts)
|
- `ctx.hasQueuedMessages()` - check if user has queued messages (skip interactive prompts)
|
||||||
- `ctx.abort()` - abort current operation (fire-and-forget)
|
- `ctx.abort()` - abort current operation (fire-and-forget)
|
||||||
|
|
||||||
**Session event changes:**
|
**Session event changes:**
|
||||||
|
|
||||||
- `CustomToolSessionEvent` now only has `reason` and `previousSessionFile`
|
- `CustomToolSessionEvent` now only has `reason` and `previousSessionFile`
|
||||||
- Session entries are no longer in the event. Use `ctx.sessionManager.getBranch()` or `ctx.sessionManager.getEntries()` to reconstruct state
|
- Session entries are no longer in the event. Use `ctx.sessionManager.getBranch()` or `ctx.sessionManager.getEntries()` to reconstruct state
|
||||||
- Reasons: `"start" | "switch" | "branch" | "tree" | "shutdown"` (no separate `"new"` reason; `/new` triggers `"switch"`)
|
- Reasons: `"start" | "switch" | "branch" | "tree" | "shutdown"` (no separate `"new"` reason; `/new` triggers `"switch"`)
|
||||||
|
|
@ -584,6 +612,7 @@ See [docs/custom-tools.md](docs/custom-tools.md) and [examples/custom-tools/](ex
|
||||||
### SDK Migration
|
### SDK Migration
|
||||||
|
|
||||||
**Type changes:**
|
**Type changes:**
|
||||||
|
|
||||||
- `CustomAgentTool` → `CustomTool`
|
- `CustomAgentTool` → `CustomTool`
|
||||||
- `AppMessage` → `AgentMessage`
|
- `AppMessage` → `AgentMessage`
|
||||||
- `sessionFile` returns `string | undefined` (was `string | null`)
|
- `sessionFile` returns `string | undefined` (was `string | null`)
|
||||||
|
|
@ -591,6 +620,7 @@ See [docs/custom-tools.md](docs/custom-tools.md) and [examples/custom-tools/](ex
|
||||||
- `Attachment` type removed. Use `ImageContent` from `@mariozechner/pi-ai` instead. Add images directly to message content arrays.
|
- `Attachment` type removed. Use `ImageContent` from `@mariozechner/pi-ai` instead. Add images directly to message content arrays.
|
||||||
|
|
||||||
**AgentSession API:**
|
**AgentSession API:**
|
||||||
|
|
||||||
- `branch(entryIndex: number)` → `branch(entryId: string)`
|
- `branch(entryIndex: number)` → `branch(entryId: string)`
|
||||||
- `getUserMessagesForBranching()` returns `{ entryId, text }` instead of `{ entryIndex, text }`
|
- `getUserMessagesForBranching()` returns `{ entryId, text }` instead of `{ entryIndex, text }`
|
||||||
- `reset()` → `newSession(options?)` where options has optional `parentSession` for lineage tracking
|
- `reset()` → `newSession(options?)` where options has optional `parentSession` for lineage tracking
|
||||||
|
|
@ -598,9 +628,11 @@ See [docs/custom-tools.md](docs/custom-tools.md) and [examples/custom-tools/](ex
|
||||||
- New `navigateTree(targetId, options?)` for in-place tree navigation
|
- New `navigateTree(targetId, options?)` for in-place tree navigation
|
||||||
|
|
||||||
**Hook integration:**
|
**Hook integration:**
|
||||||
|
|
||||||
- New `sendHookMessage(message, triggerTurn?)` for hook message injection
|
- New `sendHookMessage(message, triggerTurn?)` for hook message injection
|
||||||
|
|
||||||
**SessionManager API:**
|
**SessionManager API:**
|
||||||
|
|
||||||
- Method renames: `saveXXX()` → `appendXXX()` (e.g., `appendMessage`, `appendCompaction`)
|
- Method renames: `saveXXX()` → `appendXXX()` (e.g., `appendMessage`, `appendCompaction`)
|
||||||
- `branchInPlace()` → `branch()`
|
- `branchInPlace()` → `branch()`
|
||||||
- `reset()` → `newSession(options?)` with optional `parentSession` for lineage tracking
|
- `reset()` → `newSession(options?)` with optional `parentSession` for lineage tracking
|
||||||
|
|
@ -618,10 +650,13 @@ See [docs/custom-tools.md](docs/custom-tools.md) and [examples/custom-tools/](ex
|
||||||
`ModelRegistry` is a new class that manages model discovery and API key resolution. It combines built-in models with custom models from `models.json` and resolves API keys via `AuthStorage`.
|
`ModelRegistry` is a new class that manages model discovery and API key resolution. It combines built-in models with custom models from `models.json` and resolves API keys via `AuthStorage`.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { discoverAuthStorage, discoverModels } from "@mariozechner/pi-coding-agent";
|
import {
|
||||||
|
discoverAuthStorage,
|
||||||
|
discoverModels,
|
||||||
|
} from "@mariozechner/pi-coding-agent";
|
||||||
|
|
||||||
const authStorage = discoverAuthStorage(); // ~/.pi/agent/auth.json
|
const authStorage = discoverAuthStorage(); // ~/.pi/agent/auth.json
|
||||||
const modelRegistry = discoverModels(authStorage); // + ~/.pi/agent/models.json
|
const modelRegistry = discoverModels(authStorage); // + ~/.pi/agent/models.json
|
||||||
|
|
||||||
// Get all models (built-in + custom)
|
// Get all models (built-in + custom)
|
||||||
const allModels = modelRegistry.getAll();
|
const allModels = modelRegistry.getAll();
|
||||||
|
|
@ -639,6 +674,7 @@ const apiKey = await modelRegistry.getApiKey(model);
|
||||||
This replaces the old `resolveApiKey` callback pattern. Hooks and custom tools access it via `ctx.modelRegistry`.
|
This replaces the old `resolveApiKey` callback pattern. Hooks and custom tools access it via `ctx.modelRegistry`.
|
||||||
|
|
||||||
**Renamed exports:**
|
**Renamed exports:**
|
||||||
|
|
||||||
- `messageTransformer` → `convertToLlm`
|
- `messageTransformer` → `convertToLlm`
|
||||||
- `SessionContext` alias `LoadedSession` removed
|
- `SessionContext` alias `LoadedSession` removed
|
||||||
|
|
||||||
|
|
@ -647,17 +683,21 @@ See [docs/sdk.md](docs/sdk.md) and [examples/sdk/](examples/sdk/) for the curren
|
||||||
### RPC Migration
|
### RPC Migration
|
||||||
|
|
||||||
**Session commands:**
|
**Session commands:**
|
||||||
|
|
||||||
- `reset` command → `new_session` command with optional `parentSession` field
|
- `reset` command → `new_session` command with optional `parentSession` field
|
||||||
|
|
||||||
**Branching commands:**
|
**Branching commands:**
|
||||||
|
|
||||||
- `branch` command: `entryIndex` → `entryId`
|
- `branch` command: `entryIndex` → `entryId`
|
||||||
- `get_branch_messages` response: `entryIndex` → `entryId`
|
- `get_branch_messages` response: `entryIndex` → `entryId`
|
||||||
|
|
||||||
**Type changes:**
|
**Type changes:**
|
||||||
|
|
||||||
- Messages are now `AgentMessage` (was `AppMessage`)
|
- Messages are now `AgentMessage` (was `AppMessage`)
|
||||||
- `prompt` command: `attachments` field replaced with `images` field using `ImageContent` format
|
- `prompt` command: `attachments` field replaced with `images` field using `ImageContent` format
|
||||||
|
|
||||||
**Compaction events:**
|
**Compaction events:**
|
||||||
|
|
||||||
- `auto_compaction_start` now includes `reason` field (`"threshold"` or `"overflow"`)
|
- `auto_compaction_start` now includes `reason` field (`"threshold"` or `"overflow"`)
|
||||||
- `auto_compaction_end` now includes `willRetry` field
|
- `auto_compaction_end` now includes `willRetry` field
|
||||||
- `compact` response includes full `CompactionResult` (`summary`, `firstKeptEntryId`, `tokensBefore`, `details`)
|
- `compact` response includes full `CompactionResult` (`summary`, `firstKeptEntryId`, `tokensBefore`, `details`)
|
||||||
|
|
@ -667,6 +707,7 @@ See [docs/rpc.md](docs/rpc.md) for the current protocol.
|
||||||
### Structured Compaction
|
### Structured Compaction
|
||||||
|
|
||||||
Compaction and branch summarization now use a structured output format:
|
Compaction and branch summarization now use a structured output format:
|
||||||
|
|
||||||
- Clear sections: Goal, Progress, Key Information, File Operations
|
- Clear sections: Goal, Progress, Key Information, File Operations
|
||||||
- File tracking: `readFiles` and `modifiedFiles` arrays in `details`, accumulated across compactions
|
- File tracking: `readFiles` and `modifiedFiles` arrays in `details`, accumulated across compactions
|
||||||
- Conversations are serialized to text before summarization to prevent the model from "continuing" them
|
- Conversations are serialized to text before summarization to prevent the model from "continuing" them
|
||||||
|
|
@ -676,6 +717,7 @@ The `before_compact` and `before_tree` hook events allow custom compaction imple
|
||||||
### Interactive Mode
|
### Interactive Mode
|
||||||
|
|
||||||
**`/tree` command:**
|
**`/tree` command:**
|
||||||
|
|
||||||
- Navigate the full session tree in-place
|
- Navigate the full session tree in-place
|
||||||
- Search by typing, page with ←/→
|
- Search by typing, page with ←/→
|
||||||
- Filter modes (Ctrl+O): default → no-tools → user-only → labeled-only → all
|
- Filter modes (Ctrl+O): default → no-tools → user-only → labeled-only → all
|
||||||
|
|
@ -683,12 +725,14 @@ The `before_compact` and `before_tree` hook events allow custom compaction imple
|
||||||
- Selecting a branch switches context and optionally injects a summary of the abandoned branch
|
- Selecting a branch switches context and optionally injects a summary of the abandoned branch
|
||||||
|
|
||||||
**Entry labels:**
|
**Entry labels:**
|
||||||
|
|
||||||
- Bookmark any entry via `/tree` → select → `l`
|
- Bookmark any entry via `/tree` → select → `l`
|
||||||
- Labels appear in tree view and persist as `LabelEntry`
|
- Labels appear in tree view and persist as `LabelEntry`
|
||||||
|
|
||||||
**Theme changes (breaking for custom themes):**
|
**Theme changes (breaking for custom themes):**
|
||||||
|
|
||||||
Custom themes must add these new color tokens or they will fail to load:
|
Custom themes must add these new color tokens or they will fail to load:
|
||||||
|
|
||||||
- `selectedBg`: background for selected/highlighted items in tree selector and other components
|
- `selectedBg`: background for selected/highlighted items in tree selector and other components
|
||||||
- `customMessageBg`: background for hook-injected messages (`CustomMessageEntry`)
|
- `customMessageBg`: background for hook-injected messages (`CustomMessageEntry`)
|
||||||
- `customMessageText`: text color for hook messages
|
- `customMessageText`: text color for hook messages
|
||||||
|
|
@ -697,6 +741,7 @@ Custom themes must add these new color tokens or they will fail to load:
|
||||||
Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) for the full color list and copy values from the built-in dark/light themes.
|
Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) for the full color list and copy values from the built-in dark/light themes.
|
||||||
|
|
||||||
**Settings:**
|
**Settings:**
|
||||||
|
|
||||||
- `enabledModels`: allowlist models in `settings.json` (same format as `--models` CLI)
|
- `enabledModels`: allowlist models in `settings.json` (same format as `--models` CLI)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
@ -794,6 +839,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
|
||||||
- **Credential storage refactored**: API keys and OAuth tokens are now stored in `~/.pi/agent/auth.json` instead of `oauth.json` and `settings.json`. Existing credentials are automatically migrated on first run. ([#296](https://github.com/badlogic/pi-mono/issues/296))
|
- **Credential storage refactored**: API keys and OAuth tokens are now stored in `~/.pi/agent/auth.json` instead of `oauth.json` and `settings.json`. Existing credentials are automatically migrated on first run. ([#296](https://github.com/badlogic/pi-mono/issues/296))
|
||||||
|
|
||||||
- **SDK API changes** ([#296](https://github.com/badlogic/pi-mono/issues/296)):
|
- **SDK API changes** ([#296](https://github.com/badlogic/pi-mono/issues/296)):
|
||||||
|
|
||||||
- Added `AuthStorage` class for credential management (API keys and OAuth tokens)
|
- Added `AuthStorage` class for credential management (API keys and OAuth tokens)
|
||||||
- Added `ModelRegistry` class for model discovery and API key resolution
|
- Added `ModelRegistry` class for model discovery and API key resolution
|
||||||
- Added `discoverAuthStorage()` and `discoverModels()` discovery functions
|
- Added `discoverAuthStorage()` and `discoverModels()` discovery functions
|
||||||
|
|
@ -832,6 +878,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- **Compaction hook improvements**: The `before_compact` session event now includes:
|
- **Compaction hook improvements**: The `before_compact` session event now includes:
|
||||||
|
|
||||||
- `previousSummary`: Summary from the last compaction (if any), so hooks can preserve accumulated context
|
- `previousSummary`: Summary from the last compaction (if any), so hooks can preserve accumulated context
|
||||||
- `messagesToKeep`: Messages that will be kept after the summary (recent turns), in addition to `messagesToSummarize`
|
- `messagesToKeep`: Messages that will be kept after the summary (recent turns), in addition to `messagesToSummarize`
|
||||||
- `resolveApiKey`: Function to resolve API keys for any model (checks settings, OAuth, env vars)
|
- `resolveApiKey`: Function to resolve API keys for any model (checks settings, OAuth, env vars)
|
||||||
|
|
@ -1094,6 +1141,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
|
||||||
- Improved system prompt documentation section with clearer pointers to specific doc files for custom models, themes, skills, hooks, custom tools, and RPC.
|
- Improved system prompt documentation section with clearer pointers to specific doc files for custom models, themes, skills, hooks, custom tools, and RPC.
|
||||||
|
|
||||||
- Cleaned up documentation:
|
- Cleaned up documentation:
|
||||||
|
|
||||||
- `theme.md`: Added missing color tokens (`thinkingXhigh`, `bashMode`)
|
- `theme.md`: Added missing color tokens (`thinkingXhigh`, `bashMode`)
|
||||||
- `skills.md`: Rewrote with better framing and examples
|
- `skills.md`: Rewrote with better framing and examples
|
||||||
- `hooks.md`: Fixed timeout/error handling docs, added import aliases section
|
- `hooks.md`: Fixed timeout/error handling docs, added import aliases section
|
||||||
|
|
|
||||||
|
|
@ -644,6 +644,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||||
: undefined,
|
: undefined,
|
||||||
steeringMode: settingsManager.getSteeringMode(),
|
steeringMode: settingsManager.getSteeringMode(),
|
||||||
followUpMode: settingsManager.getFollowUpMode(),
|
followUpMode: settingsManager.getFollowUpMode(),
|
||||||
|
thinkingBudgets: settingsManager.getThinkingBudgets(),
|
||||||
getApiKey: async () => {
|
getApiKey: async () => {
|
||||||
const currentModel = agent.state.model;
|
const currentModel = agent.state.model;
|
||||||
if (!currentModel) {
|
if (!currentModel) {
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,13 @@ export interface ImageSettings {
|
||||||
blockImages?: boolean; // default: false - when true, prevents all images from being sent to LLM providers
|
blockImages?: boolean; // default: false - when true, prevents all images from being sent to LLM providers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ThinkingBudgetsSettings {
|
||||||
|
minimal?: number;
|
||||||
|
low?: number;
|
||||||
|
medium?: number;
|
||||||
|
high?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Settings {
|
export interface Settings {
|
||||||
lastChangelogVersion?: string;
|
lastChangelogVersion?: string;
|
||||||
defaultProvider?: string;
|
defaultProvider?: string;
|
||||||
|
|
@ -59,6 +66,7 @@ export interface Settings {
|
||||||
images?: ImageSettings;
|
images?: ImageSettings;
|
||||||
enabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)
|
enabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)
|
||||||
doubleEscapeAction?: "branch" | "tree"; // Action for double-escape with empty editor (default: "tree")
|
doubleEscapeAction?: "branch" | "tree"; // Action for double-escape with empty editor (default: "tree")
|
||||||
|
thinkingBudgets?: ThinkingBudgetsSettings; // Custom token budgets for thinking levels
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Deep merge settings: project/overrides take precedence, nested objects merge recursively */
|
/** Deep merge settings: project/overrides take precedence, nested objects merge recursively */
|
||||||
|
|
@ -381,6 +389,10 @@ export class SettingsManager {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getThinkingBudgets(): ThinkingBudgetsSettings | undefined {
|
||||||
|
return this.settings.thinkingBudgets;
|
||||||
|
}
|
||||||
|
|
||||||
getShowImages(): boolean {
|
getShowImages(): boolean {
|
||||||
return this.settings.terminal?.showImages ?? true;
|
return this.settings.terminal?.showImages ?? true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue