opencode-anthropic-fix 0.0.47 → 0.0.49
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.
- package/README.md +2 -2
- package/index.mjs +205 -75
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ The [original plugin](https://github.com/anomalyco/opencode-anthropic-auth) prov
|
|
|
42
42
|
- **Health scoring** — tracks account reliability and prefers healthy accounts
|
|
43
43
|
- **Standalone CLI** — manage accounts without opening OpenCode
|
|
44
44
|
- **Configurable strategies** — sticky, round-robin, or hybrid account selection
|
|
45
|
-
- **Claude Code signature emulation** — full HTTP header, system prompt, beta flag, and metadata mimicry derived from Claude Code's open source code
|
|
45
|
+
- **Claude Code signature emulation** — full HTTP header, system prompt, beta flag, and metadata mimicry derived from Claude Code's open source code. System prompt cache scoping follows the real CC's three-path `splitSysPromptPrefix()` architecture (boundary/global/org) with exact marker detection and scope-aware `cache_control` generation
|
|
46
46
|
- **OAuth endpoint fingerprint parity** — matches the real CLI's bundled axios 1.13.6 HTTP client signature (`Accept`, `User-Agent`, `Content-Type`) on all OAuth token endpoint calls, required since 2026-03-21 server-side enforcement
|
|
47
47
|
- **Billing header fingerprint parity** — `cc_version` suffix uses the real CLI's 3-char fingerprint hash (SHA-256 of salt + first user message chars + version), `cch` matches the Bun native client attestation placeholder, and `X-Claude-Code-Session-Id` header is sent on all requests
|
|
48
48
|
- **Adaptive thinking for Opus/Sonnet 4.6** — automatically normalizes thinking to `{type: "adaptive"}` for supported models, with `effort-2025-11-24` beta
|
|
@@ -52,7 +52,7 @@ The [original plugin](https://github.com/anomalyco/opencode-anthropic-auth) prov
|
|
|
52
52
|
- **Files API integration** — upload, list, download, and manage files via `/anthropic files` with endpoint/content-scoped `files-api-2025-04-14` beta injection
|
|
53
53
|
- **Code execution support** — available via explicit custom beta opt-in (`code-execution-2025-08-25`), not auto-enabled
|
|
54
54
|
- **Deep QA conformance** — 680+ tests across 26 test files, including 40 regression tests validating every header, body field, OAuth parameter, beta flag, system prompt block, response handling path, and telemetry schema against the [reverse-engineering doc](docs/claude-code-reverse-engineering.md)
|
|
55
|
-
- **Prompt caching with 1h TTL** — extended cache TTL on system prompt blocks, auto-disabled if API rejects; cache hit rate tracking with configurable warning threshold
|
|
55
|
+
- **Prompt caching with 1h TTL** — extended cache TTL on system prompt blocks using scope-correct `cache_control` (`'org'` for default path, `'global'` for boundary path), auto-disabled if API rejects; cache hit rate tracking with configurable warning threshold
|
|
56
56
|
- **API preconnect** — fire-and-forget HEAD request on init to pre-warm TCP+TLS connection, skipped when proxy/mTLS detected
|
|
57
57
|
- **8K default output cap** — limits `max_tokens` to 8K by default, auto-escalates to 64K after output truncation, resets after one turn
|
|
58
58
|
- **Context overflow auto-recovery** — parses structured `prompt_too_long` errors to auto-reduce `max_tokens` before falling back to message trimming
|
package/index.mjs
CHANGED
|
@@ -151,6 +151,14 @@ export async function AnthropicAuthPlugin({ client, project, directory, worktree
|
|
|
151
151
|
const getIdleRefreshWindowMs = () => config.idle_refresh.window_minutes * 60 * 1000;
|
|
152
152
|
const getIdleRefreshMinIntervalMs = () => config.idle_refresh.min_interval_minutes * 60 * 1000;
|
|
153
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Previous state of all anthropic-ratelimit-unified-* headers.
|
|
156
|
+
* Used to detect changes and emit toasts when status values transition.
|
|
157
|
+
* Keys mirror the header names (minus the "anthropic-ratelimit-unified-" prefix).
|
|
158
|
+
* @type {Record<string, string | null>}
|
|
159
|
+
*/
|
|
160
|
+
const previousUnifiedStatus = {};
|
|
161
|
+
|
|
154
162
|
// Willow Mode: detect inactivity and suggest context reset.
|
|
155
163
|
// Named after the willow tree — when idle, the session "droops" and a gentle
|
|
156
164
|
// nudge suggests starting fresh rather than accumulating stale context.
|
|
@@ -2948,6 +2956,40 @@ export async function AnthropicAuthPlugin({ client, project, directory, worktree
|
|
|
2948
2956
|
sessionMetrics.lastQuota.overageReason = overageReason;
|
|
2949
2957
|
}
|
|
2950
2958
|
|
|
2959
|
+
// Detect changes in any anthropic-ratelimit-unified-* status headers and toast
|
|
2960
|
+
if (!config.toasts?.quiet) {
|
|
2961
|
+
/** @type {Array<[string, string | null]>} header-suffix → current value */
|
|
2962
|
+
const unifiedStatusHeaders = [
|
|
2963
|
+
["status", overallStatus],
|
|
2964
|
+
["representative-claim", representativeClaim],
|
|
2965
|
+
["fallback", fallbackStatus],
|
|
2966
|
+
["fallback-percentage", fallbackPct],
|
|
2967
|
+
["overage-status", overageStatus],
|
|
2968
|
+
["overage-disabled-reason", overageReason],
|
|
2969
|
+
];
|
|
2970
|
+
// Add per-window status headers
|
|
2971
|
+
for (const win of RATE_LIMIT_WINDOWS) {
|
|
2972
|
+
unifiedStatusHeaders.push([
|
|
2973
|
+
`${win.key}-status`,
|
|
2974
|
+
response.headers.get(`anthropic-ratelimit-unified-${win.key}-status`),
|
|
2975
|
+
]);
|
|
2976
|
+
}
|
|
2977
|
+
|
|
2978
|
+
for (const [key, current] of unifiedStatusHeaders) {
|
|
2979
|
+
if (current == null) continue; // header absent — skip
|
|
2980
|
+
const prev = previousUnifiedStatus[key];
|
|
2981
|
+
if (prev !== undefined && prev !== current) {
|
|
2982
|
+
// Value changed — emit a toast
|
|
2983
|
+
const label = key.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
2984
|
+
toast(`Quota ${label}: ${prev ?? "—"} → ${current}`, "info", {
|
|
2985
|
+
debounceKey: `unified-status-${key}`,
|
|
2986
|
+
}).catch(() => {});
|
|
2987
|
+
debugLog("anthropic-ratelimit-unified status change", { key, prev, current });
|
|
2988
|
+
}
|
|
2989
|
+
previousUnifiedStatus[key] = current;
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2951
2993
|
// Back-compat: also update tokens/requests/inputTokens from the highest window
|
|
2952
2994
|
// so existing code that reads these fields still works
|
|
2953
2995
|
if (maxUtilization > 0) {
|
|
@@ -5743,6 +5785,147 @@ function getCacheControlForPolicy(cachePolicy) {
|
|
|
5743
5785
|
return { type: "ephemeral", ttl: cachePolicy.ttl };
|
|
5744
5786
|
}
|
|
5745
5787
|
|
|
5788
|
+
/**
|
|
5789
|
+
* Determine the identity string prefix, matching real CC's getCLISyspromptPrefix().
|
|
5790
|
+
* Real CC selects based on isNonInteractive + hasAppendSystemPrompt flags.
|
|
5791
|
+
* OpenCode is always interactive CLI, so DEFAULT_PREFIX is almost always correct.
|
|
5792
|
+
* We check for Agent SDK signals from the environment to match non-interactive cases.
|
|
5793
|
+
*
|
|
5794
|
+
* @returns {string}
|
|
5795
|
+
*/
|
|
5796
|
+
function getCLISyspromptPrefix() {
|
|
5797
|
+
// Agent SDK preset: when running within the Claude Agent SDK with CC preset
|
|
5798
|
+
if (isTruthyEnv(process.env.CLAUDE_AGENT_SDK_VERSION) && isTruthyEnv(process.env.CLAUDE_CODE_ENTRYPOINT)) {
|
|
5799
|
+
const entrypoint = process.env.CLAUDE_CODE_ENTRYPOINT || "";
|
|
5800
|
+
if (entrypoint === "agent-sdk" || entrypoint === "sdk") {
|
|
5801
|
+
return "You are Claude Code, Anthropic's official CLI for Claude, running within the Claude Agent SDK.";
|
|
5802
|
+
}
|
|
5803
|
+
}
|
|
5804
|
+
// Non-interactive agent without CC preset
|
|
5805
|
+
if (isTruthyEnv(process.env.CLAUDE_AGENT_SDK_VERSION) && !isTruthyEnv(process.env.CLAUDE_CODE_ENTRYPOINT)) {
|
|
5806
|
+
return "You are a Claude agent, built on Anthropic's Claude Agent SDK.";
|
|
5807
|
+
}
|
|
5808
|
+
return CLAUDE_CODE_IDENTITY_STRING;
|
|
5809
|
+
}
|
|
5810
|
+
|
|
5811
|
+
/**
|
|
5812
|
+
* Compute the cache_control object for a given cache scope and policy.
|
|
5813
|
+
* Mirrors real CC getCacheControl() (src/services/api/claude.ts:358-374).
|
|
5814
|
+
*
|
|
5815
|
+
* Real CC behavior:
|
|
5816
|
+
* - scope 'global' → {type: 'ephemeral', scope: 'global', ttl?: '1h'}
|
|
5817
|
+
* - scope 'org' → {type: 'ephemeral', ttl?: '1h'} (org is internal, NOT on wire)
|
|
5818
|
+
* - scope null → block gets NO cache_control at all (caller should omit it)
|
|
5819
|
+
*
|
|
5820
|
+
* @param {'global' | 'org' | null} cacheScope
|
|
5821
|
+
* @param {{ttl: string, ttl_supported: boolean}} cachePolicy
|
|
5822
|
+
* @returns {{type: string, ttl?: string, scope?: string} | null} null means "no cache_control"
|
|
5823
|
+
*/
|
|
5824
|
+
function getCacheControlForScope(cacheScope, cachePolicy) {
|
|
5825
|
+
if (cacheScope === null) return null; // no cache_control for this block
|
|
5826
|
+
|
|
5827
|
+
const hasTtl = cachePolicy.ttl !== "off" && cachePolicy.ttl_supported !== false;
|
|
5828
|
+
const result = { type: "ephemeral" };
|
|
5829
|
+
if (hasTtl) result.ttl = cachePolicy.ttl;
|
|
5830
|
+
// Only 'global' scope is emitted on the wire; 'org' is internal-only
|
|
5831
|
+
if (cacheScope === "global") result.scope = "global";
|
|
5832
|
+
return result;
|
|
5833
|
+
}
|
|
5834
|
+
|
|
5835
|
+
/**
|
|
5836
|
+
* Split system prompt blocks into structured blocks with cache scoping,
|
|
5837
|
+
* matching real CC splitSysPromptPrefix() (src/utils/api.ts:321-435).
|
|
5838
|
+
*
|
|
5839
|
+
* Real CC has 3 paths that produce 2 distinct wire formats:
|
|
5840
|
+
*
|
|
5841
|
+
* Path A (tool-based cache): skipGlobalCacheForSystemPrompt=true
|
|
5842
|
+
* - billing → cacheScope: null
|
|
5843
|
+
* - identity → cacheScope: 'org'
|
|
5844
|
+
* - rest (joined) → cacheScope: 'org'
|
|
5845
|
+
* Wire result: identical to Path C (org → ephemeral without scope field)
|
|
5846
|
+
*
|
|
5847
|
+
* Path B (boundary mode): shouldUseGlobalCacheScope() && boundary marker found
|
|
5848
|
+
* - billing → cacheScope: null
|
|
5849
|
+
* - identity → cacheScope: null (NO cache_control in boundary mode!)
|
|
5850
|
+
* - static blocks (before boundary, joined) → cacheScope: 'global'
|
|
5851
|
+
* - dynamic blocks (after boundary, joined) → cacheScope: null
|
|
5852
|
+
*
|
|
5853
|
+
* Path C (fallback): no global cache feature or no boundary
|
|
5854
|
+
* - billing → cacheScope: null
|
|
5855
|
+
* - identity → cacheScope: 'org'
|
|
5856
|
+
* - rest (joined) → cacheScope: 'org'
|
|
5857
|
+
*
|
|
5858
|
+
* @param {Array<{text: string}>} blocks - Already sanitized/filtered text blocks
|
|
5859
|
+
* @param {string | undefined} attributionHeader - The billing header text (or undefined)
|
|
5860
|
+
* @param {string} identityString - The identity prefix string
|
|
5861
|
+
* @param {boolean} useBoundaryMode - Whether to use Path B (global cache with boundary)
|
|
5862
|
+
* @returns {Array<{text: string, cacheScope: 'global' | 'org' | null}>}
|
|
5863
|
+
*/
|
|
5864
|
+
function splitSysPromptPrefix(blocks, attributionHeader, identityString, useBoundaryMode) {
|
|
5865
|
+
// Separate known blocks from rest, matching real CC's parsing loop
|
|
5866
|
+
const rest = [];
|
|
5867
|
+
for (const block of blocks) {
|
|
5868
|
+
if (!block.text) continue;
|
|
5869
|
+
// Skip if it's a billing header or identity string (already extracted)
|
|
5870
|
+
if (block.text.startsWith("x-anthropic-billing-header:")) continue;
|
|
5871
|
+
if (KNOWN_IDENTITY_STRINGS.has(block.text)) continue;
|
|
5872
|
+
// Skip the boundary marker itself (real CC skips it in Path A, processes it in Path B)
|
|
5873
|
+
if (block.text === SYSTEM_PROMPT_DYNAMIC_BOUNDARY) continue;
|
|
5874
|
+
rest.push(block.text);
|
|
5875
|
+
}
|
|
5876
|
+
|
|
5877
|
+
// ====================================================================
|
|
5878
|
+
// Path B: Global cache with boundary marker
|
|
5879
|
+
// Real CC (utils/api.ts:219-262): when shouldUseGlobalCacheScope() &&
|
|
5880
|
+
// boundary marker is found in the system prompt array.
|
|
5881
|
+
// ====================================================================
|
|
5882
|
+
if (useBoundaryMode) {
|
|
5883
|
+
// Find boundary marker in the ORIGINAL block array (before filtering)
|
|
5884
|
+
const boundaryIndex = blocks.findIndex((b) => b.text === SYSTEM_PROMPT_DYNAMIC_BOUNDARY);
|
|
5885
|
+
|
|
5886
|
+
if (boundaryIndex !== -1) {
|
|
5887
|
+
// Classify blocks as static (before boundary) or dynamic (after boundary)
|
|
5888
|
+
const staticBlocks = [];
|
|
5889
|
+
const dynamicBlocks = [];
|
|
5890
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
5891
|
+
const text = blocks[i].text;
|
|
5892
|
+
if (!text) continue;
|
|
5893
|
+
if (text === SYSTEM_PROMPT_DYNAMIC_BOUNDARY) continue;
|
|
5894
|
+
if (text.startsWith("x-anthropic-billing-header:")) continue;
|
|
5895
|
+
if (KNOWN_IDENTITY_STRINGS.has(text)) continue;
|
|
5896
|
+
if (i < boundaryIndex) {
|
|
5897
|
+
staticBlocks.push(text);
|
|
5898
|
+
} else {
|
|
5899
|
+
dynamicBlocks.push(text);
|
|
5900
|
+
}
|
|
5901
|
+
}
|
|
5902
|
+
|
|
5903
|
+
const result = [];
|
|
5904
|
+
if (attributionHeader) result.push({ text: attributionHeader, cacheScope: null });
|
|
5905
|
+
// Identity: cacheScope null in boundary mode (real CC behavior)
|
|
5906
|
+
result.push({ text: identityString, cacheScope: null });
|
|
5907
|
+
const staticJoined = staticBlocks.join("\n\n");
|
|
5908
|
+
if (staticJoined) result.push({ text: staticJoined, cacheScope: "global" });
|
|
5909
|
+
const dynamicJoined = dynamicBlocks.join("\n\n");
|
|
5910
|
+
if (dynamicJoined) result.push({ text: dynamicJoined, cacheScope: null });
|
|
5911
|
+
return result;
|
|
5912
|
+
}
|
|
5913
|
+
// Boundary marker not found — fall through to Path C
|
|
5914
|
+
}
|
|
5915
|
+
|
|
5916
|
+
// ====================================================================
|
|
5917
|
+
// Path C (fallback) / Path A (tool-based): no boundary or no global cache
|
|
5918
|
+
// Real CC (utils/api.ts:264-289): identity and rest get cacheScope 'org'
|
|
5919
|
+
// Path A produces identical wire output to Path C.
|
|
5920
|
+
// ====================================================================
|
|
5921
|
+
const result = [];
|
|
5922
|
+
if (attributionHeader) result.push({ text: attributionHeader, cacheScope: null });
|
|
5923
|
+
result.push({ text: identityString, cacheScope: "org" });
|
|
5924
|
+
const restJoined = rest.join("\n\n");
|
|
5925
|
+
if (restJoined) result.push({ text: restJoined, cacheScope: "org" });
|
|
5926
|
+
return result;
|
|
5927
|
+
}
|
|
5928
|
+
|
|
5746
5929
|
/**
|
|
5747
5930
|
* @param {Array<{type: string, text: string, cache_control?: {type: string}}>} system
|
|
5748
5931
|
* @param {{enabled: boolean, claudeCliVersion: string, promptCompactionMode: 'minimal' | 'off', cachePolicy?: {ttl: string, ttl_supported: boolean, boundary_marker?: boolean}}} signature
|
|
@@ -5766,91 +5949,38 @@ function buildSystemPromptBlocks(system, signature) {
|
|
|
5766
5949
|
return sanitized;
|
|
5767
5950
|
}
|
|
5768
5951
|
|
|
5769
|
-
|
|
5770
|
-
(item) => !item.text.startsWith("x-anthropic-billing-header:") && !KNOWN_IDENTITY_STRINGS.has(item.text),
|
|
5771
|
-
);
|
|
5772
|
-
|
|
5773
|
-
const blocks = [];
|
|
5952
|
+
// Build attribution header
|
|
5774
5953
|
const billingHeader = buildAnthropicBillingHeader(
|
|
5775
5954
|
signature.claudeCliVersion,
|
|
5776
5955
|
signature.firstUserMessage,
|
|
5777
5956
|
signature.provider,
|
|
5778
5957
|
);
|
|
5779
|
-
if (billingHeader) {
|
|
5780
|
-
// Billing header: no cache_control (null scope — never cached)
|
|
5781
|
-
blocks.push({ type: "text", text: billingHeader });
|
|
5782
|
-
}
|
|
5783
5958
|
|
|
5784
|
-
//
|
|
5785
|
-
|
|
5786
|
-
// system blocks must share the same TTL to avoid "1h after 5m" API rejection.
|
|
5787
|
-
const effectiveCachePolicy = signature.cachePolicy || { ttl: "1h", ttl_supported: true };
|
|
5788
|
-
const hasTtl = effectiveCachePolicy.ttl !== "off" && effectiveCachePolicy.ttl_supported !== false;
|
|
5789
|
-
|
|
5790
|
-
// CC v2.1.90 cache_control scoping (verified against bundle WQ() function):
|
|
5791
|
-
// - scope "global" is only emitted for static pre-boundary blocks
|
|
5792
|
-
// - scope "org" is internal-only, NEVER emitted on the wire
|
|
5793
|
-
// - identity block gets no cache_control in boundary mode, or {type:"ephemeral"} in fallback
|
|
5794
|
-
const baseCacheControl = hasTtl ? { type: "ephemeral", ttl: effectiveCachePolicy.ttl } : { type: "ephemeral" };
|
|
5795
|
-
const globalCacheControl = hasTtl
|
|
5796
|
-
? { type: "ephemeral", scope: "global", ttl: effectiveCachePolicy.ttl }
|
|
5797
|
-
: { type: "ephemeral", scope: "global" };
|
|
5798
|
-
|
|
5799
|
-
// Identity block: per CC v2.1.90, gets {type:"ephemeral"} with NO scope field.
|
|
5800
|
-
// In boundary mode CC assigns cacheScope:null (no cache_control at all), but
|
|
5801
|
-
// we always include it for better cache hit rates on the proxy side.
|
|
5802
|
-
blocks.push({ type: "text", text: CLAUDE_CODE_IDENTITY_STRING, cache_control: baseCacheControl });
|
|
5803
|
-
|
|
5804
|
-
// Filtered blocks: keep as-is, with optional static/dynamic boundary marker
|
|
5805
|
-
if (filtered.length > 0) {
|
|
5806
|
-
const useBoundary =
|
|
5807
|
-
signature.cachePolicy?.boundary_marker || isTruthyEnv(process.env.CLAUDE_CODE_FORCE_GLOBAL_CACHE);
|
|
5808
|
-
|
|
5809
|
-
if (useBoundary) {
|
|
5810
|
-
// Heuristic: treat first half as "static" (tool defs, instructions)
|
|
5811
|
-
// and second half as "dynamic" (env info, memory, etc.)
|
|
5812
|
-
// Find a split point: look for blocks containing environment/date/CWD info
|
|
5813
|
-
// as the boundary between static and dynamic.
|
|
5814
|
-
const splitIndex = filtered.findIndex((block) => {
|
|
5815
|
-
const text = block.text.toLowerCase();
|
|
5816
|
-
return (
|
|
5817
|
-
text.includes("working directory") ||
|
|
5818
|
-
text.includes("today's date") ||
|
|
5819
|
-
text.includes("current date") ||
|
|
5820
|
-
text.includes("environment") ||
|
|
5821
|
-
text.includes("platform:")
|
|
5822
|
-
);
|
|
5823
|
-
});
|
|
5959
|
+
// Select the identity string (matches real CC getCLISyspromptPrefix())
|
|
5960
|
+
const identityString = getCLISyspromptPrefix();
|
|
5824
5961
|
|
|
5825
|
-
|
|
5962
|
+
// Determine cache policy
|
|
5963
|
+
const effectiveCachePolicy = signature.cachePolicy || { ttl: "1h", ttl_supported: true };
|
|
5826
5964
|
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5965
|
+
// Determine if we should use boundary mode (Path B)
|
|
5966
|
+
// Real CC: shouldUseGlobalCacheScope() is a GrowthBook feature flag.
|
|
5967
|
+
// We simulate it via config: boundary_marker=true or CLAUDE_CODE_FORCE_GLOBAL_CACHE=1.
|
|
5968
|
+
const useBoundaryMode =
|
|
5969
|
+
effectiveCachePolicy.boundary_marker || isTruthyEnv(process.env.CLAUDE_CODE_FORCE_GLOBAL_CACHE);
|
|
5831
5970
|
|
|
5832
|
-
|
|
5833
|
-
|
|
5971
|
+
// Run the real CC splitSysPromptPrefix algorithm to get blocks with cacheScope
|
|
5972
|
+
const scopedBlocks = splitSysPromptPrefix(sanitized, billingHeader || undefined, identityString, useBoundaryMode);
|
|
5834
5973
|
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
const { cache_control: _cc, ...rest } = filtered[i];
|
|
5846
|
-
blocks.push(rest);
|
|
5847
|
-
}
|
|
5848
|
-
const lastFiltered = filtered[filtered.length - 1];
|
|
5849
|
-
blocks.push({ ...lastFiltered, cache_control: baseCacheControl });
|
|
5850
|
-
}
|
|
5851
|
-
}
|
|
5852
|
-
|
|
5853
|
-
return blocks;
|
|
5974
|
+
// Convert scoped blocks to wire format using getCacheControlForScope
|
|
5975
|
+
// (mirrors real CC buildSystemPromptBlocks → map + getCacheControl)
|
|
5976
|
+
return scopedBlocks.map((block) => {
|
|
5977
|
+
const cc = getCacheControlForScope(block.cacheScope, effectiveCachePolicy);
|
|
5978
|
+
return {
|
|
5979
|
+
type: "text",
|
|
5980
|
+
text: block.text,
|
|
5981
|
+
...(cc !== null && { cache_control: cc }),
|
|
5982
|
+
};
|
|
5983
|
+
});
|
|
5854
5984
|
}
|
|
5855
5985
|
|
|
5856
5986
|
/**
|