* fix(typebox): migrate to v1 with extension compat
Replace AJV-based validation with TypeBox-native validation, keep legacy extension imports working (including @sinclair/typebox/compiler), and restore coercion for serialized/plain JSON schemas.
This change closes#3112.
* fix(typebox): use canonical imports and harden coercion
Switch first-party code to canonical typebox imports while retaining legacy extension aliases in the loader.
Remove obsolete runtime codegen guards, expand serialized JSON-schema coercion coverage, and update related tests and fixtures.
Fixes#3112.
---------
Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
- StreamFn type now allows returning Promise
- agent-loop awaits streamFn result
- createStreamFn takes getProxyUrl callback, reads settings on each call
- createStreamFn(proxyUrl?) returns a sync streamFn that applies proxy
- Example reads proxy settings once when creating Agent
- Matches old ProviderTransport behavior
- AgentInterface composes UserMessageWithAttachments for attachments
- Updated example to use convertToLlm instead of transport/messageTransformer
- Fixed declaration merging: target pi-agent-core, add path to example tsconfig
- Fixed typo in CustomAgentMessages key (user-with-attachment -> user-with-attachments)
- customMessageTransformer properly converts UserMessageWithAttachments to content blocks
- Removed Attachment from agent package (now in web-ui/coding-agent)
- Agent.prompt now takes (text, images?: ImageContent[])
- Removed transports from web-ui (duplicate of agent package)
- Updated coding-agent to use local message types
- Updated mom package for new agent API
Remaining: Fix AgentInterface.ts to compose UserMessageWithAttachments
Add getApiKey hook to AgentLoopConfig that resolves API keys dynamically
before each LLM call. This allows short-lived OAuth tokens (e.g. GitHub
Copilot, Anthropic OAuth) to be refreshed between turns when tool
execution takes a long time.
Previously, the API key was resolved once when ProviderTransport.run()
was called and passed as a static string to the agent loop. If the loop
ran for longer than the token lifetime (e.g. 30 minutes for Copilot),
subsequent LLM calls would fail with expired token errors.
Changes:
- Add getApiKey hook to AgentLoopConfig (packages/ai)
- Call getApiKey before each LLM call in streamAssistantResponse
- Update ProviderTransport to pass getApiKey instead of static apiKey
- Update web-ui ProviderTransport with same pattern
- Add agentLoopContinue() to pi-ai for resuming from existing context
- Add Agent.continue() method and transport.continue() interface
- Simplify AgentSession compaction to two cases: overflow (auto-retry) and threshold (no retry)
- Remove proactive mid-turn compaction abort
- Merge turn prefix summary into main summary
- Add isCompacting property to AgentSession and RPC state
- Block input during compaction in interactive mode
- Show compaction count on session resume
- Rename RPC.md to rpc.md for consistency
Related to #128
- Added totalTokens field to Usage interface in pi-ai
- Anthropic: computed as input + output + cacheRead + cacheWrite
- OpenAI/Google: uses native total_tokens/totalTokenCount
- Fixed openai-completions to compute totalTokens when reasoning tokens present
- Updated calculateContextTokens() to use totalTokens field
- Added comprehensive test covering 13 providers
fixes#130
- Move lit from dependencies to peerDependencies in web-ui to prevent multiple Lit instances being loaded
- Update mini-lit from 0.1.8/0.1.10 to 0.2.0 in root package.json and web-ui/package.json
- Install @tailwindcss/vite in web-ui/example
- Run biome formatting fixes across codebase
This resolves HMR custom element re-registration errors caused by duplicate Lit registries.
Tool results now use content blocks and can include both text and images.
All providers (Anthropic, Google, OpenAI Completions, OpenAI Responses)
correctly pass images from tool results to LLMs.
- Update ToolResultMessage type to use content blocks
- Add placeholder text for image-only tool results in Google/Anthropic
- OpenAI providers send tool result + follow-up user message with images
- Fix Anthropic JSON parsing for empty tool arguments
- Add comprehensive tests for image-only and text+image tool results
- Update README with tool result content blocks API
- Add collapsible thinking blocks with shimmer animation during streaming
- Update user messages to use orange gradient pill styling (matching sitegeist)
- Fix cost display to only show for completed messages, not while streaming
- Update tool renderers to use ChevronsUpDown/ChevronUp icons instead of rotating ChevronRight
- Export ThinkingBlock component from public API
- Add inputChanged state to track when user modifies input after save
- Remove Clear button and removeKey() method entirely
- Save button now disables after successful save until input changes
- Save button stays enabled on test failure (allows immediate retry)
- Keep input field showing stars (••••) after successful save instead of clearing
This provides clearer feedback and prevents accidental key deletion.
Adds a reload button with RefreshCw icon to HTML artifact header buttons.
Clicking the button clears logs and re-executes the HTML content, useful
for manually refreshing when developing HTML artifacts or testing changes.
Changes:
- Import Button, icon from mini-lit and RefreshCw from lucide
- Add reload button to getHeaderButtons() that clears logs and calls executeContent()
- Add "Reload HTML" i18n key in English and German translations
HTML artifacts can read other artifacts via getArtifact() and attachments.
When any artifact is created, updated, rewritten, or deleted, all HTML
artifacts now automatically reload to reflect the latest data.
Changes:
- Add reloadAllHtmlArtifacts() method to ArtifactsPanel
- Call reload after all artifact mutations (create/update/rewrite/delete)
- Make HtmlArtifact.sandboxIframeRef and executeContent() public
- Update runtime providers before re-executing HTML content
This ensures HTML artifacts always display current data from their dependencies.
Issue:
Each browser_javascript execution wrapped console methods, but captured
the current (already wrapped) console as "original". This created a chain
of wrappers that accumulated across executions:
- Execution 1: 1x console.log (wrapper1 → real console)
- Execution 2: 2x console.log (wrapper2 → wrapper1 → real console)
- Execution 3: 3x console.log (wrapper3 → wrapper2 → wrapper1 → real console)
- Execution 4: 4x console.log (and so on...)
Fix:
Store the truly original console methods in window.__originalConsole on
first wrap only. All subsequent executions use these stored original methods
instead of capturing the current console. This prevents wrapper accumulation.
Changes:
- Check if window.__originalConsole exists before wrapping
- Store original console methods with .bind() to preserve context
- Always use window.__originalConsole for local logging
- Now each execution logs exactly 1x regardless of execution count
- Add handlePaste method to detect and process pasted images
- Automatically attach pasted images as attachments
- Support multiple images in single paste
- Prevent default paste behavior for images (text paste still works normally)
- Use same loadAttachment utility as drag-and-drop for consistency
- Export UserMessageWithAttachments type from web-ui index
- Remove unused i18n import from extract-document tool
- Update models.generated.ts (model order changes from API)
This fixes type errors when sitegeist uses custom user message renderer
- Add extract_document tool for extracting text from PDF/DOCX/XLSX/PPTX from URLs
- CORS proxy support from settings for fetching documents
- Proper error messages guiding users on CORS issues and manual file attachment
- Add scroll-into-view for active artifact tabs
- Export extract_document tool from web-ui package