Commit graph

86 commits

Author SHA1 Message Date
Mario Zechner
e1e4e593c0 fix(coding-agent): persist thinking level defaults 2026-02-03 17:17:38 +01:00
warren
2613754c47 feat(coding-agent): add ExtensionAPI.getCommands() 2026-02-03 12:18:52 +01:00
Mario Zechner
030a61d88c feat: add maxDelayMs setting to cap server-requested retry delays
When a provider (e.g., Google Gemini CLI) requests a retry delay longer
than maxDelayMs (default: 60s), the request fails immediately with an
informative error instead of waiting silently for hours.

The error is then handled by agent-level auto-retry, which shows the
delay to the user and allows aborting with Escape.

- Add maxRetryDelayMs to StreamOptions (packages/ai)
- Add maxRetryDelayMs to AgentOptions (packages/agent)
- Add retry.maxDelayMs to settings (packages/coding-agent)
- Update _isRetryableError to match 'retry delay' errors

fixes #1123
2026-02-01 00:50:41 +01:00
Mario Zechner
a373dce747 fix(coding-agent): improve thinking defaults in footer 2026-01-29 00:33:45 +01:00
Mario Zechner
5ef79459dc Closes #1041, incorrect .md file name in warning messages. 2026-01-29 00:16:50 +01:00
Mario Zechner
07325c27e8 fix: use findInitialModel in SDK, default to opus-4-5 for anthropic 2026-01-25 23:59:11 +01:00
Mario Zechner
0423c2c2d5 fix: add /model instruction to no models warning 2026-01-25 23:55:40 +01:00
Mario Zechner
88f184f433 fix: point auth error messages to docs/authentication.md 2026-01-25 23:55:00 +01:00
Mario Zechner
b846a4bfcf feat(coding-agent): ResourceLoader, package management, and /reload command (#645)
- Add ResourceLoader interface and DefaultResourceLoader implementation
- Add PackageManager for npm/git extension sources with install/remove/update
- Add session.reload() and session.bindExtensions() APIs
- Add /reload command in interactive mode
- Add CLI flags: --skill, --theme, --prompt-template, --no-themes, --no-prompt-templates
- Add pi install/remove/update commands for extension management
- Refactor settings.json to use arrays for skills, prompts, themes
- Remove legacy SkillsSettings source flags and filters
- Update SDK examples and documentation for ResourceLoader pattern
- Add theme registration and loadThemeFromPath for dynamic themes
- Add getShellEnv to include bin dir in PATH for bash commands
2026-01-22 13:49:38 +01:00
Aliou Diallo
69d02b8a5f
fix(coding-agent): use dynamic paths in error messages (#887)
Error messages for missing credentials and shell config now use
getAuthPath() and getSettingsPath() instead of hardcoded ~/.pi/agent/
paths, so they correctly reflect PI_CODING_AGENT_DIR when set.
2026-01-21 23:21:10 +01:00
Mario Zechner
2b04aefa6d feat(ai): add AWS ECS/IRSA credential detection for Bedrock, fixes #848
Added support for additional AWS credential environment variables:
- AWS_CONTAINER_CREDENTIALS_RELATIVE_URI (ECS task roles)
- AWS_CONTAINER_CREDENTIALS_FULL_URI (ECS task roles)
- AWS_WEB_IDENTITY_TOKEN_FILE (IRSA for Kubernetes)

Also fixed undefined currentModel variable in OAuth error handling.
2026-01-19 16:10:10 +01:00
Dave
d6bb66a494
fix(coding-agent): prevent crash on OAuth authentication failure (#849)
Detect OAuth authentication failures (expired credentials, offline) and provide helpful error message instead of crashing with generic 'No API key found' error.

Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
2026-01-19 15:59:45 +01:00
Mario Zechner
fbb74bb29e fix(ai): filter empty error assistant messages in transformMessages
When 429/500 errors occur during tool execution, empty assistant messages
with stopReason='error' get persisted. These break the tool_use -> tool_result
chain for Claude/Gemini APIs.

Added centralized filtering in transformMessages to skip assistant messages
with empty content and no tool calls. Provider-level filters remain for
defense-in-depth.
2026-01-16 22:35:50 +01:00
Mario Zechner
7534802752 refactor: add ModelRegistry.getApiKeyForProvider() for cleaner abstraction 2026-01-13 18:12:09 +01:00
Josh Palmer
8936c5d136 fix(coding-agent): resolve api keys by provider
What:
- resolve API keys using provider argument
- add regression test for model-switch key resolution
- update coding-agent changelog
- document provider lookup in SDK

Why:
- prevent model-switch 401s from provider mismatch

Tests:
- npm run check
- npm run test -w @mariozechner/pi-coding-agent -- sdk-api-key.test.ts
2026-01-13 18:07:26 +01:00
Mario Zechner
af2d8509e6 Fix --no-skills flag not preventing skills from loading
The --no-skills flag set options.skills = [] in main.ts, but the
interactive mode UI would rediscover skills anyway because it called
loadSkills() directly instead of using the already-loaded skills.

Changes:
- Add AgentSession.skills and AgentSession.skillWarnings properties
- discoverSkills() now returns { skills, warnings } instead of Skill[]
- Interactive mode uses session.skills instead of calling loadSkills()
- Update SDK docs and examples for new return type

Fixes #577
2026-01-08 23:41:54 +01:00
Carlos Villela
c865ec1d19
fix(coding-agent): --no-skills flag not preventing skills from loading (#577)
The --no-skills flag set options.skills = [] in main.ts, but the interactive mode UI would rediscover skills anyway because it called loadSkills() directly.

Changes:
- Add AgentSession.skills and AgentSession.skillWarnings properties  
- discoverSkills() now returns { skills, warnings } instead of Skill[]
- Interactive mode uses session.skills instead of calling loadSkills()

Co-authored-by: Carlos Villela <cv@lixo.org>
2026-01-08 23:40:05 +01:00
Mario Zechner
8fda948866 fix(coding-agent): string systemPrompt now works as full replacement
When passing a string systemPrompt to createAgentSession(), it is now
used as-is without appending context files and skills. This matches the
documented behavior: 'String replaces default, function receives default
and returns final.'

Previously, string systemPrompt would have context files and skills
appended, causing duplication if they were already in the string.

fixes #543
2026-01-08 20:47:52 +01:00
Mario Zechner
e3dd4f21d1 feat(coding-agent): add tool override support via extensions
- Add setActiveTools() to ExtensionAPI for dynamic tool management
- Extensions can now override, wrap, or disable built-in tools
- Add tool-override.ts example demonstrating the pattern
- Update documentation for tool override capabilities
2026-01-08 18:52:33 +01:00
Mario Zechner
b1fb910625 refactor(coding-agent): unify tool and event handler context creation
Tools now use ExtensionRunner.createContext() instead of a separate
inline context factory. This ensures tools and event handlers share
the same context, fixing ctx.shutdown() and other context methods.

- Made ExtensionRunner.createContext() public
- Changed wrapRegisteredTools to accept ExtensionRunner instead of getContext callback
- Create ExtensionRunner when SDK custom tools are present (not just extensions)
- Removed redundant inline context factory from sdk.ts
2026-01-08 03:45:39 +01:00
Mario Zechner
cf0466d96c fix(coding-agent): make ctx.shutdown() work from extension tools
The tool execution context was created with a no-op shutdown handler.
Now it delegates to ExtensionRunner.shutdown() which uses the handler
set by the mode via initialize().
2026-01-08 03:40:09 +01:00
Kao Félix
6845c4b85e
feat(coding-agent): make ctx.shutdown() available for extensions (#542) 2026-01-08 03:30:48 +01:00
Mario Zechner
f97dcbf92f 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>
2026-01-08 03:02:08 +01:00
Mario Zechner
696e1b51d3 refactor(coding-agent): revert preloadedExtensionsResult back to preloadedExtensions
The rename was unnecessary.
2026-01-08 02:35:37 +01:00
Mario Zechner
cb3ac0ba9e refactor(coding-agent): simplify extension runtime architecture
- Replace per-extension closures with shared ExtensionRuntime
- Split context actions: ExtensionContextActions (required) + ExtensionCommandContextActions (optional)
- Rename LoadedExtension to Extension, remove setter methods
- Change runner.initialize() from options object to positional params
- Derive hasUI from uiContext presence (no separate param)
- Add warning when extensions override built-in tools
- RPC and print modes now provide full command context actions

BREAKING CHANGE: Extension system types and initialization API changed.
See CHANGELOG.md for migration details.
2026-01-07 23:50:18 +01:00
Melih Mucuk
d311978dfd Merge branch 'main' into feat/custom-thinking-budgets 2026-01-08 00:39:11 +03:00
Mario Zechner
09471ebc7d feat(coding-agent): add ctx.ui.setEditorComponent() extension API
- Add setEditorComponent() to ctx.ui for custom editor components
- Add CustomEditor base class for extensions (handles app keybindings)
- Add keybindings parameter to ctx.ui.custom() factory (breaking change)
- Add modal-editor.ts example (vim-like modes)
- Add rainbow-editor.ts example (animated text highlighting)
- Update docs: extensions.md, tui.md Pattern 7
- Clean up terminal on TUI render errors
2026-01-07 16:11:49 +01:00
Melih Mucuk
0f27eae77e feat: add thinkingBudgets option to customize token budgets 2026-01-07 15:13:26 +03:00
Austin Mudd
aea9f8439d feat(extensions): support async extension factory functions
Extensions can now use async initialization, enabling:
- Dynamic imports (e.g., loading tools from external packages)
- Async setup (config fetching, service connections)
- Lazy-loaded dependencies

Changes:
- ExtensionFactory type now returns void | Promise<void>
- loadExtensionFromFactory is now async, returns Promise<LoadedExtension>
- All factory(api) calls are now awaited

Backwards compatible: sync extensions continue to work unchanged.
2026-01-06 14:35:43 -08:00
Tudor Oancea
f755f69e0a added custom header support and example extension 2026-01-06 21:20:19 +01:00
Mario Zechner
f023af0dab Add ctx.ui.setFooter() for extensions to replace footer component
Extensions can now replace the built-in footer with a custom component:
- setFooter(factory) replaces with custom component
- setFooter(undefined) restores built-in footer

Includes example extension demonstrating context usage display.

Closes #481
2026-01-06 12:39:45 +01:00
Mario Zechner
a1d0b1c151 Merge PR #492: Add blockImages setting
- Setting controls filtering at convertToLlm layer
- Images are always stored in session, filtered dynamically based on current setting
- Toggle mid-session works: LLM sees/doesn't see images already in session
- Fixed SettingsManager.save() to handle inMemory mode for all setters

Closes #492
2026-01-06 12:00:15 +01:00
Mario Zechner
1fc2a912d4 Add blockImages setting to prevent images from being sent to LLM providers
- Setting controls filtering at convertToLlm layer (defense-in-depth)
- Images are always stored in session, filtered dynamically based on current setting
- Toggle mid-session works: LLM sees/doesn't see images already in session
- Fixed SettingsManager.save() to handle inMemory mode for all setters

Closes #492
2026-01-06 11:59:09 +01:00
Mario Zechner
edb0da9611 feat(ai,agent,coding-agent): add sessionId for provider session-based caching
- Add sessionId to StreamOptions for providers that support session-based caching
- OpenAI Codex provider uses sessionId for prompt_cache_key and routing headers
- Agent class now accepts and forwards sessionId to stream functions
- coding-agent passes session ID from SessionManager and updates on session changes
- Update ai package README with table of contents, OpenAI Codex OAuth docs, and env vars table
- Increase Codex instructions cache TTL from 15 minutes to 24 hours
- Add tests for sessionId forwarding in ai and agent packages
2026-01-06 11:08:42 +01:00
Josh
b582a6b70d
feat(coding-agent): add blockImages setting to prevent image uploads 2026-01-06 00:34:23 -06:00
Mario Zechner
3129e2ac10 docs: clarify SDK extension discovery and settings.json support 2026-01-05 18:00:32 +01:00
Aliou Diallo
042d3fa310
fix(sdk): extensions: [] now disables discovery as documented (#465) 2026-01-05 16:55:51 +01:00
Mario Zechner
79cb8f0906 Add extensions option to createAgentSession SDK
- Accept ExtensionFactory[] for inline extensions (merged with discovery)
- Mark preloadedExtensions as @internal (CLI implementation detail)
- Update sdk.md with inline extension example
- Update CHANGELOG
2026-01-05 03:38:56 +01:00
Mario Zechner
8da793b1ba Add customTools option back to createAgentSession SDK
- Accepts ToolDefinition[] directly (simplified from old { path?, tool } format)
- Tools are combined with extension-registered tools
- Updated sdk.md documentation
- Updated CHANGELOG
2026-01-05 03:34:36 +01:00
Mario Zechner
c6fc084534 Merge hooks and custom-tools into unified extensions system (#454)
Breaking changes:
- Settings: 'hooks' and 'customTools' arrays replaced with 'extensions'
- CLI: '--hook' and '--tool' flags replaced with '--extension' / '-e'
- API: HookMessage renamed to CustomMessage, role 'hookMessage' to 'custom'
- API: FileSlashCommand renamed to PromptTemplate
- API: discoverSlashCommands() renamed to discoverPromptTemplates()
- Directories: commands/ renamed to prompts/ for prompt templates

Migration:
- Session version bumped to 3 (auto-migrates v2 sessions)
- Old 'hookMessage' role entries converted to 'custom'

Structural changes:
- src/core/hooks/ and src/core/custom-tools/ merged into src/core/extensions/
- src/core/slash-commands.ts renamed to src/core/prompt-templates.ts
- examples/hooks/ and examples/custom-tools/ merged into examples/extensions/
- docs/hooks.md and docs/custom-tools.md merged into docs/extensions.md

New test coverage:
- test/extensions-runner.test.ts (10 tests)
- test/extensions-discovery.test.ts (26 tests)
- test/prompt-templates.test.ts
2026-01-05 01:43:35 +01:00
Mario Zechner
be330fdd9c Fix event bus async error handling, clear pending messages on session switch, improve SDK docs
- event-bus.ts: await async handlers to catch errors properly
- agent-session.ts: clear _pendingNextTurnMessages on newSession/switchSession/branch
- sdk.ts: make eventBus first (required) param for discoverHooks/discoverCustomTools
- docs/sdk.md: document eventBus sharing pattern for hook/tool communication
2026-01-04 22:04:50 +01:00
Nico Bailon
9c9e6822e3
feat(coding-agent): add event bus for tool/hook communication (#431)
* feat(coding-agent): add event bus for tool/hook communication

Adds pi.events API enabling custom tools and hooks to communicate via
pub/sub. Tools can emit events, hooks can listen. Shared EventBus instance
created per session in createAgentSession().

- EventBus interface with emit() and on() methods
- on() returns unsubscribe function
- Threaded through hook and tool loaders
- Documented in hooks.md and custom-tools.md

* fix(coding-agent): wrap event handlers to catch errors

* docs: note async handler error handling for event bus

* feat(coding-agent): add sendMessage to tools, nextTurn delivery mode

- Custom tools now have pi.sendMessage() for direct agent notifications
- New deliverAs: 'nextTurn' queues messages for next user prompt
- Fix: hooks and tools now share the same eventBus (was isolated before)

* fix(coding-agent): nextTurn delivery should always queue, even when streaming
2026-01-04 21:36:19 +01:00
Mario Zechner
31438fdf2a fix(tools): wrap ALL registry tools with hooks, not just active ones
wrappedToolRegistry was only containing activeToolsArray (4 tools).
Now wraps all tools from the registry so hooks can enable any tool.
2026-01-04 18:47:57 +01:00
Mario Zechner
2849623afc fix(tools): tool registry now contains ALL built-in tools
- createAllTools() populates registry with all 7 built-in tools
- --tools flag only sets initially active tools (default: read/bash/edit/write)
- Hooks can enable any tool from registry via setActiveTools()
- System prompt rebuilds with correct tool guidelines when tools change
- Document tsx module resolution workaround in README
2026-01-04 18:44:41 +01:00
Helmut Januschka
8ecb1d6c0b refactor: address PR feedback - merge setWidget, use KeyId for shortcuts
1. Merge setWidget and setWidgetComponent into single overloaded method
   - Accepts either string[] or component factory function
   - Uses single Map<string, Component> internally
   - String arrays wrapped in Container with Text components

2. Use KeyId type for registerShortcut instead of plain string
   - Import Key from @mariozechner/pi-tui
   - Update plan-mode example to use Key.shift('p')
   - Type-safe shortcut registration

3. Fix tool API docs
   - Both built-in and custom tools can be enabled/disabled
   - Removed incorrect 'custom tools always active' statement

4. Use matchesKey instead of matchShortcut (already done in rebase)
2026-01-04 18:13:30 +01:00
Helmut Januschka
4ecf3f9422 refactor(hooks): address PR feedback
- Rename getTools/setTools to getActiveTools/setActiveTools
- Add getAllTools to enumerate all configured tools
- Remove text_delta event (use turn_end/agent_end instead)
- Add shortcut conflict detection:
  - Skip shortcuts that conflict with built-in shortcuts (with warning)
  - Log warnings when hooks register same shortcut (last wins)
- Add note about prompt cache invalidation in setActiveTools
- Update plan-mode hook to use agent_end for [DONE:id] parsing
2026-01-04 18:13:29 +01:00
Helmut Januschka
c956a726ed feat(coding-agent): add hook API for CLI flags, shortcuts, and tool control
Hook API additions:
- pi.getTools() / pi.setTools(toolNames) - dynamically enable/disable tools
- pi.registerFlag(name, options) / pi.getFlag(name) - register custom CLI flags
- pi.registerShortcut(shortcut, options) - register keyboard shortcuts

Plan mode hook (examples/hooks/plan-mode.ts):
- /plan command or Shift+P shortcut to toggle
- --plan CLI flag to start in plan mode
- Read-only tools: read, bash, grep, find, ls
- Bash restricted to non-destructive commands (blocks rm, mv, git commit, etc.)
- Interactive prompt after each response: execute, stay, or refine
- Shows plan indicator in footer when active
- State persists across sessions
2026-01-04 18:13:28 +01:00
Helmut Januschka
059292ead1 WIP: Add hook API for dynamic tool control with plan-mode hook example
- Add pi.getTools() and pi.setTools(toolNames) to HookAPI
- Hooks can now enable/disable tools dynamically
- Changes take effect on next agent turn

New example hook: plan-mode.ts
- Claude Code-style read-only exploration mode
- /plan command toggles plan mode on/off
- Plan mode tools: read, bash, grep, find, ls
- Edit/write tools disabled in plan mode
- Injects context telling agent about restrictions
- After each response, prompts to execute/stay/refine
- State persists across sessions
2026-01-04 18:13:28 +01:00
Mario Zechner
e82af9da47
Merge pull request #402 from mitsuhiko/image-resize
Added automatic image resizing
2026-01-03 00:39:26 +01:00
Mario Zechner
9d8230dfc6 feat(coding-agent): expose deliverAs option in hook sendMessage() API
- pi.sendMessage(msg, options?) now accepts { triggerTurn?, deliverAs? }
- deliverAs: 'steer' (default) or 'followUp' controls delivery timing
- Update all mode handlers to pass options through
- Update file-trigger example to use new API
- Update CHANGELOG
2026-01-03 00:13:26 +01:00