DashScope / Aliyun Qwen (OpenAI-compatible) rejects `tools: []`
with HTTP 400 `"[] is too short - 'tools'"`. Five providers used
a truthy check (`if (context.tools)`) that treated an empty array
as "send tools", so `pi --no-tools` produced `tools: []` in the
request body. Matching the Google provider's pattern, we now
guard on `context.tools.length > 0`:
- openai-completions.ts
- openai-responses.ts
- openai-codex-responses.ts
- azure-openai-responses.ts
- anthropic.ts
The openai-completions fallback that emits `tools: []` when the
conversation has tool history (required by LiteLLM / Anthropic
proxies) is preserved via the existing `else if (hasToolHistory)`
branch.
closes#3649
Co-authored-by: 槐聚 <huaiju@zbyte-inc.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
* 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>
Bypass the Anthropic SDK streaming parser entirely. Use
client.messages.create().asResponse() and decode the SSE stream
ourselves with defensive JSON parsing that repairs invalid escape
sequences and control characters inside string literals.
- Switch from SDK .stream() to .asResponse() + pi-owned SSE decoder
- Add repairJson() / parseJsonWithRepair() to json-parse.ts
- Add anthropic-sse-parsing.test.ts regression for malformed tool deltas
- Update github-copilot-anthropic.test.ts mock to match new call path
- Update deprecated claude-3-5-haiku-20241022 refs to claude-haiku-4-5
- Remove stale non-reasoning model test
fixes#3175
* fix(ai): replace stale OpenRouter Llama 4 Maverick test model
- Switch OpenRouter Meta test model from `meta-llama/llama-4-maverick` to `meta-llama/llama-4-scout` in AI tests.
- CI failure body:
- packages/ai/test/context-overflow.test.ts(531,41): error TS2345: Argument of type "meta-llama/llama-4-maverick" is not assignable to parameter of type "...".
- packages/ai/test/total-tokens.test.ts(520,40): error TS2345: Argument of type "meta-llama/llama-4-maverick" is not assignable to parameter of type "...".
* chore(ai): add changelog entry for OpenRouter test model swap
- Add Unreleased Fixed entry for switching OpenRouter Meta test model to llama-4-scout
- Reference PR #3421 attribution
The openai-completions provider now calls .withResponse() on the
create() result to surface HTTP status/headers for the new onResponse
hook (d131fcd4). The FakeOpenAI test mock only returned an async
iterable, so 4 tests in openai-completions-tool-choice.test.ts that
actually consume the stream failed with "withResponse is not a function".
Updated the mock to return a Promise augmented with .withResponse()
resolving to { data: <async iterable>, response: { status, headers } }.
closes#3304
Mutate persisted tool-call blocks in place on function_call completion,
remove partialJson, and emit the same reference on toolcall_end.
Add regression coverage for persisted block cleanup and event identity.
fixes#3078
- Add NON_OVERFLOW_PATTERNS to explicitly exclude known non-overflow errors
- Consolidate Cerebras 400/413 no-body check into OVERFLOW_PATTERNS
- Format Bedrock errors as ${error.name}: ${error.message} for pattern matching