- Define a centralized `USER_AGENT` constant in `@oh-my-pi/pi-utils` formatted as `omp/<version>`.
- Replace hardcoded and platform-specific user agent strings across AI providers, catalog scrapers, tools, and search providers with the unified `USER_AGENT`.
- Add unit tests for update-cli binary release distribution gating.
- Expanded web search and fetching providers with robust parsing, authentication storage integration, and response validation.
- Added support for new configurations including SearXNG safesearch, Cloudflare AI Gateway endpoints, and dynamic Firecrawl base URLs.
- Implemented comprehensive test suites covering error handling, content filtering, and provider-specific response behaviors.
Decoded the extra JSON string layer returned by Z.AI MCP search and kept structured payloads out of answer text.
Added regression coverage for source extraction and plain prose preservation.
Fixes#8000
- Implemented in-house, zero-dependency utility modules in `pi-utils` covering DOM manipulation, markdown parsing, templating, browser automation helpers, and terminal buffers.
- Migrated packages across the repository to consume the new internal utilities and `omptype` schema validators instead of external dependencies.
- Removed multiple external runtime and development dependencies including Zod, Marked, LRU cache, Turndown, and Puppeteer browser packages.
Codex Responses-Lite moves web_search into additional_tools, which the hosted backend ignores. Keep the classic top-level tools contract for all dedicated Codex web searches and cover GPT-5.6 request shape.
Fixes#7666
- Introduce `@oh-my-pi/omptype` as a new ArkType-compatible schema validation package featuring a lazy JIT runtime, JSON Schema emission, and compatibility adapters.
- Replace `arktype` across workspace packages and test utilities with `@oh-my-pi/omptype`.
- Add benchmark suites, tests, and documentation for the new validation engine and adapters.
- Update workspace build, test runner, and release configurations to include the new package.
The Codex SSE `type:"error"` branch read only top-level `code`/`message`,
so backend rejections emitted under a nested `error` or `response.error`
object collapsed to `Codex error (): Unknown error`, hiding the cause
(e.g. a regional/model-snapshot rejection). `response.failed` similarly
dropped the error code.
Add a shared `extractCodexSseError` that reads top-level, nested `error`,
and `response.error` envelopes, and wire both error paths through it so
the backend code and message survive in `SearchProviderError`. The
existing `web_search_call` requirement is untouched.
Fixes#7200
DuckDuckGo does not parse after:/before: operators, so the provider relies
on the shared lenient post-filter to enforce them. But parseHtmlResults()
discarded the ISO timestamps DuckDuckGo now emits per result row, so every
source was undated and passed the date filter unconditionally.
Extract the timestamp span into publishedDate/ageSeconds so
applyQueryConstraints can honor the requested window.
Fixes#7115
Followed DuckDuckGo's returned continuation form until the requested result limit is satisfied, preserving deduplication across pages and the existing search deadline.
Added regression coverage for continuation field submission and 20-result collection.
Fixes#7116
callDuckDuckGoHtml now parses params.query once when parsedQuery is absent and uses that structured view for both q and kl. Direct searchDuckDuckGo/DuckDuckGoProvider.search calls no longer strip lang: from q while defaulting kl to us-en.
Fixes#7110
Replaced unrestricted locale component swapping with DuckDuckGo's documented kl allowlist and explicit aliases for provider-specific codes such as jp-jp, kr-kr, tw-tzh, and uk-en. Unsupported locale combinations now fall back to the existing us-en default instead of sending invalid kl values.
Expanded regression coverage for Japanese, Korean, Traditional Chinese, and unsupported region-language combinations.
Fixes#7110
callDuckDuckGoHtml hardcoded kl=us-en and never read parsedQuery.lang, so
the shared lang: directive was silently discarded — unlike the Perplexity
and SearXNG providers, which map it. Distinct locales collapsed to the same
request.
Added localeToKl mapping the parsed language-region locale onto DDG's
region-language kl code (swapping components, gb->uk alias), falling back to
us-en for language-only, malformed, or absent locales.
Fixes#7110
GPT-5.6 Responses-Lite models receive tool_choice "auto" (the forced
hosted choice is invalid under the lite shape, #5771/#5772), so the model
may answer without invoking the hosted web_search tool. The codex search
parser accepted any non-empty answer, returning a stale completion with
zero sources as a successful search.
callCodexSearch now tracks response.web_search_call.* events (and
web_search_call output items) and throws CodexNoWebSearchError when none
occurred. The candidate chain treats that error as retryable, advancing
default lite models to a non-lite model that forces web_search, and
surfaces a clear failure when the model was explicitly configured.
Fixes#6988
(cherry picked from commit a276cd0b3df1d0d041faf0a63fabcbb884e36a91)
- Implemented a structured web-search query parsing module supporting directives, tokenization, date parsing, and syntax serialization.
- Updated search providers to map query directives and date bounds to native provider parameters and filters.
- Added lenient result constraint post-filtering and configuration settings for enhanced engine routing.
- Added comprehensive unit and integration tests covering query parsing, constraint filtering, and provider-specific request mapping.
- Replaced single-provider preferences with ordered priority lists for web search and image generation.
- Added a `MultiSelectSubmenu` component supporting toggle and reordering interactions in settings.
- Implemented migration logic to convert legacy single-provider preferences into ordered priority lists.
- Updated setup wizard scenes, image generation fallback logic, and search provider chains to use priority lists.
When FIRECRAWL_API_KEY is not set, fall back to Firecrawl keyless mode
(omit Authorization header). Auto-chain still requires a credential via
isAvailable; explicit webSearch: firecrawl works keyless via
isExplicitlyAvailable returning true.
Closes https://github.com/can1357/oh-my-pi/issues/4332
- Validated the openai-codex credential origin against the registry storage that supplies the bearer, closing the OAuth-leak path when authStorage and modelRegistry diverge.
- Added a regression test covering the mismatched storage case.
Fixes#6001
- Routed Codex web search through configured Responses base URLs, API keys, and headers while preserving the official OAuth backend.
- Refused OAuth leakage to custom endpoints and stopped explicitly selected providers from silently falling back.
- Added transport, safety, and fail-closed regression coverage.
Fixes#6001
The Kimi web-search adapter posts to the Kimi Code endpoint
(api.kimi.com/coding/v1/search) but resolved and advertised Moonshot
Open Platform credentials (moonshot provider, MOONSHOT_API_KEY,
api.moonshot.ai). Those are a different credential system, so a valid
Open Platform key was rejected with 401 and the preferred provider
silently fell back to another engine.
resolveKey() and isAvailable() now use kimi-code credentials only
(explicit MOONSHOT_SEARCH_API_KEY / KIMI_SEARCH_API_KEY overrides or a
stored kimi-code login), and the missing-credential error and provider
metadata name the Kimi Code requirement.
Fixes#5762
- Routed native xAI Responses search through configured provider base URLs and headers.
- Kept endpoint credentials coupled and rejected official OAuth tokens for custom endpoints.
- Added proxy routing and credential-leak regression coverage.
Fixes#5599