When downloading HTML artifacts, the generated HTML now works standalone
without requiring the extension runtime.
Changes:
- Add PrepareHtmlOptions config object to SandboxedIframe.prepareHtmlDocument()
- Add isStandalone flag to skip runtime bridge and navigation interceptor
- When isStandalone=true:
- window.sendRuntimeMessage is NOT defined
- Navigation interceptor is NOT injected
- Artifact runtime providers fall back to embedded data
- HtmlArtifact download button now uses isStandalone: true
This fixes the issue where downloaded HTML artifacts would:
- Try to call window.sendRuntimeMessage (which would fail silently)
- Try to postMessage to non-existent parent window
- Not work when opened via file:// protocol
Now downloaded artifacts work completely standalone with embedded data.
The negated approach broke browser_script which runs in page context.
browser_script injects into web pages (http://, https://) where
chrome.runtime.sendMessage doesn't work. The original whitelist
approach correctly identifies extension contexts only.
The real issue with artifacts in sandbox iframes needs a different fix.
- Changed ToolRenderer return type from TemplateResult to ToolRenderResult
- ToolRenderResult = { content: TemplateResult, isCustom: boolean }
- isCustom: true = no card wrapper, false = wrap in card
- Updated all existing tool renderers to return new format
- Updated Messages.ts to handle custom rendering
This enables tools to render without default card chrome when needed.
- Update renderHeader and renderCollapsibleHeader in renderer-registry.ts to accept `text: string | TemplateResult`
- Remove duplicated renderCollapsibleHeaderWithPill helper in artifacts-tool-renderer.ts
- Update all artifact renderer calls to use renderHeaderWithPill() inline
- Remove all separate pill rendering below headers
This allows artifact pills to be rendered inline with header text without code duplication.
- Move mini-lit from dependencies to peerDependencies
- Keep in devDependencies for development
- Prevents bundlers from including mini-lit when consuming pi-web-ui
- Consumer (sitegeist) provides mini-lit, esbuild bundles it once
- Fixes duplicate mini-lit bundling issue permanently
Storage Architecture:
- New pluggable storage system with backends (LocalStorage, ChromeStorage, IndexedDB)
- SettingsRepository for app settings (proxy config, etc.)
- ProviderKeysRepository for API key management
- AppStorage with global accessors (getAppStorage, setAppStorage, initAppStorage)
Transport Refactoring:
- Renamed DirectTransport → ProviderTransport (calls LLM providers with optional CORS proxy)
- Renamed ProxyTransport → AppTransport (uses app server with user auth)
- Updated TransportMode: "direct" → "provider", "proxy" → "app"
CORS Proxy Integration:
- ProviderTransport checks proxy.enabled/proxy.url from storage
- When enabled, modifies model baseUrl to route through proxy: {proxyUrl}/?url={originalBaseUrl}
- ProviderKeyInput test function also honors proxy settings
- Settings dialog with Proxy tab (Switch toggle, URL input, explanatory description)
Anthropic Prompt Caching:
- System prompt cached with cache_control markers (both OAuth and regular API keys)
- Last user message cached to cache conversation history
- Saves 90% on input tokens for cached content (10x cost reduction)
Settings Dialog Improvements:
- Configurable tab system with SettingsTab base class
- ApiKeysTab and ProxyTab as custom elements
- Switch toggle for proxy enable (instead of Checkbox)
- Explanatory paragraphs for each tab
- ApiKeyPromptDialog reuses ProviderKeyInput component
Removed:
- Deprecated ApiKeysDialog (replaced by ProviderKeyInput in SettingsDialog)
- Old storage-adapter and key-store (replaced by new storage architecture)
- Create Pi Reader browser extension for Chrome/Firefox
- Chrome uses Side Panel API, Firefox uses Sidebar Action API
- Supports both browsers with separate manifests and unified codebase
- Built with mini-lit components and Tailwind CSS v4
- Features model selection dialog with Ollama support
- Hot reload development server watches both browser builds
- Add useDefineForClassFields: false to fix LitElement reactivity
- Add 'aborted' as a distinct stop reason separate from 'error'
- Change AssistantMessage.error to errorMessage for clarity
- Update error event to include reason field ('error' | 'aborted')
- Map provider-specific safety/refusal reasons to 'error' stop reason
- Reorganize utility functions into utils/ directory
- Rename agent.ts to agent-loop.ts for better clarity
- Fix error handling in all providers to properly distinguish abort from error
- Added partial-json package for parsing incomplete JSON during streaming
- Tool call arguments now contain partially parsed JSON during toolcall_delta events
- Enables progressive UI updates (e.g., showing file paths before content is complete)
- Arguments are always valid objects (minimum empty {}), never undefined
- Full validation still occurs at toolcall_end when arguments are complete
- Updated all providers (Anthropic, OpenAI Completions/Responses) to use parseStreamingJson
- Added comprehensive documentation and examples in README
- Added test to verify arguments are always defined during streaming
- Switch from Zod to TypeBox for tool parameter schemas
- TypeBox schemas can be serialized/deserialized as JSON
- Use AJV for runtime validation instead of Zod's parse
- Add StringEnum helper for Google API compatibility (avoids anyOf/const patterns)
- Export Type and Static from main package for convenience
- Update all tests and documentation to reflect TypeBox usage
- Reduce default max tokens for Anthropic to 1/3 of model max
- Fix Google provider to properly handle empty tools array
- Ensure toolConfig is undefined when no tools are present
- Replace JSON Schema with Zod schemas for tool parameter definitions
- Add runtime validation for all tool calls at provider level
- Create shared validation module with detailed error formatting
- Update Agent API with comprehensive event system
- Add agent tests with calculator tool for multi-turn execution
- Add abort test to verify proper handling of aborted requests
- Update documentation with detailed event flow examples
- Rename generate.ts to stream.ts for clarity
- Add 'zai' as a KnownProvider type
- Add ZAI_API_KEY environment variable mapping
- Generate 4 zAI models (glm-4.5-air, glm-4.5v, etc.) using anthropic-messages API
- Add comprehensive test coverage for zAI provider in generate.test.ts and empty.test.ts
- Models support reasoning/thinking capabilities and tool calling
- Google provider sometimes returns duplicate or missing tool call IDs
- Added counter to ensure unique IDs for each tool call
- Check for duplicates and generate new ID when needed
- Fixes issues with multiple tool calls having the same ID
- Anthropic API requires tool call IDs to match pattern ^[a-zA-Z0-9_-]+$
- OpenAI Responses API generates IDs with pipe character (|) which breaks Anthropic
- Added sanitizeToolCallId() to replace invalid characters with underscores
- Fixes cross-provider handoffs from OpenAI Responses to Anthropic
- Added test to verify the fix works
- Replace createLLM with getModel/getModels/getProviders functions
- Rename PROVIDERS to MODELS (internal only, not exposed)
- Add streamSimple/completeSimple for unified reasoning interface
- Update README with new API examples and comprehensive documentation
- Remove model registration (models are now fixed from build time)
- Add proper TypeScript typing for provider-specific options
- Document context serialization, cross-provider handoffs, and browser usage
- Implement QueuedGenerateStream class that extends AsyncIterable with finalMessage() method
- Add new types: GenerateStream, GenerateOptions, GenerateOptionsUnified, GenerateFunction
- Create generateAnthropic function-based implementation replacing class-based approach
- Add comprehensive test suite for the new generate API
- Support streaming events with text, thinking, and tool call deltas
- Map ReasoningEffort to provider-specific options
- Include apiKey in options instead of constructor parameter
- Updated generate-models.ts to fetch these providers directly from models.dev API
- OpenRouter now only used for xAI and other third-party providers
- Fixed test model IDs to match new model names from models.dev
- Removed unused import from google.ts
- Add getApi() method to all providers to identify the API type
- Add api field to AssistantMessage to track which API generated it
- Update transformMessages to check API compatibility instead of model
- Fixes issue where OpenAI Responses API failed when switching models
- Preserves thinking blocks and signatures when staying within same API
- Required header for browser-based access to Anthropic API
- Added to both OAuth and regular API key authentication
- Ensures full browser compatibility
- Add transformMessages utility to handle cross-provider compatibility
- Convert thinking blocks to <thinking> tagged text when switching providers
- Preserve native thinking blocks when staying with same provider/model
- Add comprehensive handoff tests verifying all provider combinations
- Fix OpenAI Completions to return partial results on abort
- Update tool call ID format for Anthropic compatibility
- Document cross-provider handoff capabilities in README
- Anthropic, Google, and OpenAI Responses providers now return partial results when aborted
- Restructured streaming to accumulate content blocks incrementally
- Prevents submission of thinking/toolCall blocks from aborted completions in multi-turn conversations
- Makes UI development easier by providing partial content even when requests are interrupted
- Emit start event with model and provider info after creating stream
- Add abort signal tests for all providers
- Update README abort signal section to reflect non-throwing API
- Fix model references in README examples
- Add API changes section explaining v0.5.15+ changes
- Update Quick Start example to show content array usage
- Update Tool Calling example to filter tool calls from content blocks
- Update Streaming example to use new onEvent callback
- Fix model IDs in provider-specific examples
- Collect complete output items during streaming instead of building blocks incrementally
- Handle reasoning summary parts with proper newline separation
- Support refusal content in message outputs
- Preserve full reasoning items and message IDs for multi-turn resubmission
- Emit proper streaming events for text and thinking deltas