Fix agentic-traffic reliability and enable provider prompt caching - #91
Merged
Merged
Conversation
Measured on ITSMBench + terminal-bench via a pi-agent harness; each fix
addresses a defect observed in production-like agent loops:
- openai-router: never serve a clean empty completion. Upstream 429-retry
exhaustion surfaced as a contentless 200 with finish_reason=stop, which
agent clients read as "task complete" and terminated mid-task (observed
killing 6/7 benchmark episodes). Abort the SSE stream instead so clients
retry.
- databricks (Azure Responses): forward reasoning effort (was silently
dropped — thinking requests never reached the model), fix
max_output_tokens (read from max_completion_tokens for gpt-5.x), and
surface cache_read_input_tokens through both response conversions so
telemetry records provider cache hits (was always null).
- Prefix stability for provider prompt caching (measured 0-3% -> 92-95%
cache hit rate, ~5x real cost cut on agent loops):
* deterministic tool-call fallback IDs (were Date.now()+random — history
re-randomized every turn)
* one constant system prompt per conversation (continuations previously
swapped in a generic prompt, which also silently discarded the client
agent's instructions after turn 1)
* uniform system-reminder stripping on every turn
* content-hash tee IDs in the tool-result compressor (were timestamped —
new bytes in old messages each turn)
* fixed compression threshold (routed tier flaps between turns; COMPLEX
keeps compression deterministic and lightly lossy)
* prompt_cache_key on Azure gpt-5.x requests (session id or first-user-
message hash)
- config: TOOL_RESULT_COMPRESSION_ENABLED env knob (was hardcoded)
- nodemon.json: ignore self-written data/db files (restart-storm fix)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ions - zai (anthropic-format endpoint): force buffered mode. With stream:true the endpoint returns Anthropic SSE, but the downstream transformer parses OpenAI SSE — every chunk was unreadable and clients received empty completions on all streamed turns (terminal-bench: 0/13 episodes survived; 32% pass rate after this fix, verifying the mechanism). - openai-router: mirror the streaming empty-completion guard on the non-streaming path — return a retryable 502 instead of a clean empty 200 that agent clients read as "task complete". - docs: add ITSMBench results writeup (methodology, full-89 + subset scores, per-family and assertion-level analysis, reproduction). Known issue (not fixed here): the provider fallback ladder keeps the original tier's model name when switching providers (observed: fallback to azure-openai requesting model "kimi-k3" → 404). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
veerareddyvishal144
force-pushed
the
fix/agentic-reliability-prompt-cache
branch
from
August 18, 2026 20:53
74d38d4 to
6b40190
Compare
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The classifier leg is live and can time out under load, sending identical text down different fallback paths — the same turn scored differently between the router and the pin-drift checker (observed 63 vs 77 under suite-wide Ollama contention; session-fingerprint drift-consistency test failed intermittently in the full suite). First resolution wins for the process lifetime. Lexical fallback is not memoized so a degraded score isn't locked in past service recovery. Calls with scoring-altering opts (custom centroids/embedFn, risk, prior turns) bypass the memo. Fixes the flaky drift-consistency failure; 1257/1257 passing across back-to-back full-suite runs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
veerareddyvishal144
pushed a commit
that referenced
this pull request
Aug 18, 2026
The "Web Tools Test Suite" check has been failing on every PR/push that touches its trigger paths (including src/config/index.js, which this branch's Baidu changes touch) since commit b32e988 deleted src/tools/web.js, src/tools/web-client.js, and test/web-tools.test.js without removing the standalone workflow that ran that test file — this predates and is unrelated to the Baidu provider work, confirmed failing on main itself and on PR #90/#91 too (`gh run list --workflow web-tools-tests.yml`). - Remove .github/workflows/web-tools-tests.yml (nothing left to test) - Remove the same two stale file refs (test/web-tools.test.js, test/code-mode.test.js — deleted in the same commit) from ci.yml's "Tests" job. These didn't fail there since node --test silently skips a missing file when given alongside other real ones in one invocation, but a passing check that silently means "0 tests ran for this file" is a gap worth closing, not a reference worth keeping. - Update workflows/README.md: drop the Web Tools Tests section, renumber remaining sections, drop the dead badge/example command. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
veerareddyvishal144
added a commit
that referenced
this pull request
Aug 18, 2026
* Add Baidu Qianfan (ERNIE) as a supported model provider Wires up "baidu" end-to-end alongside openai/openrouter/moonshot/zai, modeled on invokeMoonshot since Qianfan's v2 endpoint is OpenAI-compatible: - src/config/index.js: BAIDU_API_KEY/BAIDU_ENDPOINT/BAIDU_MODEL parsing, config.baidu block, SUPPORTED_MODEL_PROVIDERS entry, hot-reload sync - src/clients/databricks.js: new invokeBaidu (request conversion via openrouter-utils, response converted to Anthropic shape locally), registered in PROVIDER_INVOKERS - src/orchestrator/index.js: destination-url, tool-schema, and response-conversion branches for "baidu" - src/routing/model-tiers.js: baidu case in _getProviderModel - src/api/providers-handler.js, src/api/openai-router.js: discovery listing - bin/lynkr-init.js: onboarding wizard entry + PROVIDER_ORDER + baseline env - .env.example, documentation/providers.md: new provider docs/section - test/baidu-model-mapping.test.js: model mapping, tool conversion, auth, response conversion (mirrors moonshot-model-mapping.test.js) - test/dispatch-registry.test.js, test/init.test.js: anti-drift guard lists - package.json: wire new test file into test:unit Not yet done, flagged in code/docs: sampling-param quirks and the exact ERNIE model roster are best-effort from public docs, not probed against a live key; "baidu" is not yet in DEFAULT_OPENAI_SSE_PROVIDERS (streaming is buffered-only until SSE shape is confirmed); not added to REASONING_CONTENT_PROVIDERS (unconfirmed whether ERNIE reasoning models emit reasoning_content). All 1267 existing unit tests plus the new baidu suite pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * docs(README): add Z.ai, Moonshot, and Baidu Qianfan to provider table Follow-up to 57959c0. Only these three rows + the cloud-provider count are touched — README already had unrelated pending edits (OAuth/wrap-mode policy note) in the working tree that are intentionally left unstaged, they're not part of this branch's scope. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * ci: remove dead web-tools-tests workflow and stale test refs The "Web Tools Test Suite" check has been failing on every PR/push that touches its trigger paths (including src/config/index.js, which this branch's Baidu changes touch) since commit b32e988 deleted src/tools/web.js, src/tools/web-client.js, and test/web-tools.test.js without removing the standalone workflow that ran that test file — this predates and is unrelated to the Baidu provider work, confirmed failing on main itself and on PR #90/#91 too (`gh run list --workflow web-tools-tests.yml`). - Remove .github/workflows/web-tools-tests.yml (nothing left to test) - Remove the same two stale file refs (test/web-tools.test.js, test/code-mode.test.js — deleted in the same commit) from ci.yml's "Tests" job. These didn't fail there since node --test silently skips a missing file when given alongside other real ones in one invocation, but a passing check that silently means "0 tests ran for this file" is a gap worth closing, not a reference worth keeping. - Update workflows/README.md: drop the Web Tools Tests section, renumber remaining sections, drop the dead badge/example command. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: vishal veerareddy <vishalveera.reddy@servicenow.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Agent loops through Lynkr were silently degraded in four ways, all observed and measured on ITSMBench / terminal-bench harnesses (pi agent, Azure gpt-5.6-sol):
finish_reason: stop; agent clients read that as "done" and stopped. Killed 6/7 benchmark episodes in one run.reasoning_effortwas dropped on the Azure Responses path; thinking requests silently ran at minimum effort.max_output_tokenswas also unset for gpt-5.x (read from the wrong key).Date.now()+random), the system-prompt swap, conditional reminder-stripping, timestamped tee IDs in tool-result compression, tier-flapping compression thresholds — so prefixes never matched and every token billed at full price.Fix
openai-router: guard that aborts the SSE stream (client retries) instead of serving a clean empty completion.databricks: forwardreasoning.effort; fixmax_output_tokens; surfacecache_read_input_tokensthrough both response conversions into telemetry; addprompt_cache_key(session id or first-user-message hash) on gpt-5.x requests.config: newTOOL_RESULT_COMPRESSION_ENABLEDenv knob (was hardcoded).nodemon.json: ignore self-written data/db files (dev restart storms).Measured results
Behavior changes for review
Known issue (follow-up, not addressed here)
Terminal-bench A/B shows Lynkr still costs significant quality on long compute-heavy coding tasks (direct 17/22 vs through-Lynkr 8/21), dominated by agent timeouts from per-turn latency (buffered non-streaming upstream calls). Fix is true streaming passthrough — proposed as a follow-up issue.
🤖 Generated with Claude Code