@askalf/dario 5.5.79 → 5.5.81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/proxy.js +31 -7
  2. package/package.json +1 -1
package/dist/proxy.js CHANGED
@@ -9,7 +9,7 @@ import { getAccessToken, getStatus, ignoreCcCredentials } from './oauth.js';
9
9
  import { buildHealthResponse, derivePoolStatus, probeRequested, shouldDiscloseHealthInternals, shouldRunServingProbe } from './health-response.js';
10
10
  import { getServingProbe } from './serving-probe.js';
11
11
  import { darioVersion } from './version.js';
12
- import { buildCCRequest, applyCcPromptCaching, parseEffortSuffix, reverseMapResponse, createStreamingReverseMapper, orderHeadersForOutbound, overlayTemplateHeaderValues, forwardClientCCIdentityHeaders, isMcpToolName, CC_TEMPLATE, effectiveCacheControl, withForced1hBeta } from './cc-template.js';
12
+ import { buildCCRequest, applyCcPromptCaching, isGenuineCCClient, parseEffortSuffix, reverseMapResponse, createStreamingReverseMapper, orderHeadersForOutbound, overlayTemplateHeaderValues, forwardClientCCIdentityHeaders, isMcpToolName, CC_TEMPLATE, effectiveCacheControl, withForced1hBeta } from './cc-template.js';
13
13
  import { stampCch, hasCchSeed } from './cch.js';
14
14
  import { describeTemplate, detectDrift, checkCCCompat, probeInstalledCCVersion } from './live-fingerprint.js';
15
15
  import { AccountPool, computeStickyKey, parseRateLimits, modelFamily, isInAuthCooldown, authCooldownMs, accountIneligibility, reconcilePoolAccounts, resolvePoolStrategy, utilFreshness } from './pool.js';
@@ -657,6 +657,23 @@ export function sanitizeMessages(body, preserveTags) {
657
657
  const messages = body.messages;
658
658
  if (!messages)
659
659
  return;
660
+ // A genuine Claude Code client is forwarded with its conversation untouched.
661
+ // The scrub exists to make OTHER harnesses (Aider, Cursor, OpenClaw, ...)
662
+ // look like CC by removing their orchestration wrappers; CC's own
663
+ // `<system-reminder>`, `<task-notification>`, `<env>` blocks ARE the CC
664
+ // wire shape, and stripping them made every request through dario less
665
+ // faithful than the same request sent direct. It was also the origin of a
666
+ // whole class of defects — the empty blocks and emptied turns the scrub
667
+ // leaves behind (dario#54, #744, #1033, #1092, #1117) each needed its own
668
+ // guard, and each guard patched the previous one's hole. The genuine-CC
669
+ // branch of buildCCRequest already declares "messages: untouched — the
670
+ // client is the authority on its own wire shape"; this makes that true from
671
+ // the first byte. The empty-content filters that genuine CC still needs
672
+ // (a real CC retry artifact, dario#1092) live in buildCCRequest and keep
673
+ // running. Detection is the same check the template uses: the billing
674
+ // header in system[0] and a CC opener in system[1].
675
+ if (isGenuineCCClient(body))
676
+ return;
660
677
  const patterns = orchestrationPatternsFor(preserveTags);
661
678
  // Snapshot the tail turn before scrubbing. If the scrub empties it and the
662
679
  // drop below would expose an assistant turn, we put the original content
@@ -739,16 +756,23 @@ export function sanitizeMessages(body, preserveTags) {
739
756
  // so keeping it is *more* wire-faithful, not less; for a non-CC client a
740
757
  // lone tag as the final turn is the actual prompt, and forwarding it beats
741
758
  // a hard 400. Every other position still scrubs exactly as before.
759
+ //
760
+ // This holds even when the tail was ALREADY empty before the scrub
761
+ // (dario#1117, second report). CC's stream-interruption retry appends a
762
+ // user turn with `content: []` as the final message — the shape the
763
+ // genuine-CC rewind in buildCCRequest (dario#1092) exists to recover. The
764
+ // message-level drop above ran first and removed that turn, and an
765
+ // "only restore a tail that had content" condition here let it go, so the
766
+ // template saw a request already ending on the assistant's real reply and
767
+ // upstream answered with the prefill rejection. Restoring an empty tail is
768
+ // never worse than dropping it: on the genuine-CC path #1092 rewinds the
769
+ // pair, and on the general path the upstream names the malformed turn
770
+ // accurately ("content must contain at least one block") — the #1033
771
+ // decision — instead of dario converting it into a misleading prefill 400.
742
772
  const tailWasDropped = tail !== undefined && kept[kept.length - 1] !== tail;
743
- const tailHadContent = Array.isArray(tailContentBeforeScrub)
744
- ? tailContentBeforeScrub.length > 0
745
- : typeof tailContentBeforeScrub === 'string'
746
- ? tailContentBeforeScrub !== ''
747
- : tailContentBeforeScrub != null;
748
773
  if (tail !== undefined &&
749
774
  tailWasDropped &&
750
775
  tail.role === 'user' &&
751
- tailHadContent &&
752
776
  kept.length > 0 &&
753
777
  kept[kept.length - 1].role === 'assistant') {
754
778
  tail.content = tailContentBeforeScrub;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "5.5.79",
3
+ "version": "5.5.81",
4
4
  "description": "Use your Claude Pro/Max subscription in any tool — Cursor, Cline, Aider, the Agent SDK, your scripts — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint.",
5
5
  "type": "module",
6
6
  "bin": {