@xiaoso/dsh-tool-plus 0.1.0-beta.2 → 0.1.0-beta.4
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.en.md +122 -0
- package/README.md +3 -2
- package/THIRD_PARTY_NOTICES.md +4 -35
- package/lib/abort-B7izMMna.mjs +51 -0
- package/lib/abort-D1_Z5Ut5.mjs +51 -0
- package/lib/abort-dIkZBV7Q.mjs +51 -0
- package/lib/amazon-bedrock-B0nxT06F.mjs +917 -0
- package/lib/amazon-bedrock-D-shAr1X.mjs +917 -0
- package/lib/amazon-bedrock-WQhvjHYu.mjs +917 -0
- package/lib/anthropic-BWsZFzU8.mjs +262 -0
- package/lib/anthropic-CJCauvYz.mjs +3115 -0
- package/lib/anthropic-CMT1Qj1t.mjs +3115 -0
- package/lib/anthropic-CZghe_9U.mjs +3115 -0
- package/lib/anthropic-sCMH7JID.mjs +262 -0
- package/lib/anthropic-tTntD8BD.mjs +262 -0
- package/lib/api-key-login-BzqNdM2y.mjs +157 -0
- package/lib/api-key-login-CWVwvHT1.mjs +157 -0
- package/lib/api-key-login-CpzSezsi.mjs +157 -0
- package/lib/aws-credentials-8Mgn5MAy.mjs +867 -0
- package/lib/aws-credentials-CXryMobh.mjs +867 -0
- package/lib/aws-credentials-ChG79ey-.mjs +867 -0
- package/lib/azure-openai-responses-CNkHiLUh.mjs +274 -0
- package/lib/azure-openai-responses-Cgmc-rbL.mjs +274 -0
- package/lib/azure-openai-responses-DuukbD0F.mjs +274 -0
- package/lib/bun-shim.mjs +252 -12
- package/lib/bundled-references-CSuBco5p.mjs +55 -0
- package/lib/bundled-references-Cavaffah.mjs +55 -0
- package/lib/bundled-references-sLN0YdXU.mjs +55 -0
- package/lib/callback-server-BEFNf-jf.mjs +398 -0
- package/lib/callback-server-CQ5Jo8F-.mjs +398 -0
- package/lib/callback-server-DDSrZ6l_.mjs +398 -0
- package/lib/client.js +111 -41
- package/lib/cursor-B3zg7EHj.mjs +273 -0
- package/lib/cursor-B6TUEmgP.mjs +135 -0
- package/lib/cursor-BIQfBC6V.mjs +135 -0
- package/lib/cursor-D8gvtTL3.mjs +135 -0
- package/lib/cursor-DNk6eXDd.mjs +5470 -0
- package/lib/cursor-DkSX2h3H.mjs +5441 -0
- package/lib/cursor-MjSm74IJ.mjs +273 -0
- package/lib/cursor-aJrXeYCb.mjs +273 -0
- package/lib/cursor-mJQwUKXK.mjs +5441 -0
- package/lib/device-code-DBo3B5nh.mjs +51 -0
- package/lib/device-code-DIb0FU-H.mjs +51 -0
- package/lib/device-code-OI_tQcmc.mjs +51 -0
- package/lib/devin-BHZZyMhO.mjs +95 -0
- package/lib/devin-BK7DHeca.mjs +114 -0
- package/lib/devin-CfMp3cXS.mjs +95 -0
- package/lib/devin-CldyPD8K.mjs +95 -0
- package/lib/devin-CzRpTUOA.mjs +114 -0
- package/lib/devin-D9zR5B_R.mjs +542 -0
- package/lib/devin-DXOeNyU7.mjs +542 -0
- package/lib/devin-Q1yem3lp.mjs +114 -0
- package/lib/devin-vNZTNUON.mjs +542 -0
- package/lib/error-B3bevhrs.mjs +1449 -0
- package/lib/error-Dd8DIqs-.mjs +1449 -0
- package/lib/error-yCSG0mGC.mjs +1449 -0
- package/lib/event-stream-BDPi64mK.mjs +151 -0
- package/lib/event-stream-BbFZJy-z.mjs +151 -0
- package/lib/event-stream-loUa0s1T.mjs +151 -0
- package/lib/fs-promises-shim-Bx0fpxuk.mjs +57 -0
- package/lib/github-copilot-4GaMtQmg.mjs +208 -0
- package/lib/github-copilot-B1yiyVRh.mjs +104 -0
- package/lib/github-copilot-B2HGSIJK.mjs +104 -0
- package/lib/github-copilot-BWT3eAOF.mjs +208 -0
- package/lib/github-copilot-CYkjeTi3.mjs +208 -0
- package/lib/github-copilot-jscUZ8Hf.mjs +104 -0
- package/lib/gitlab-duo-CM7Ref1H.mjs +155 -0
- package/lib/gitlab-duo-akICyfeD.mjs +155 -0
- package/lib/gitlab-duo-gubO4FNw.mjs +155 -0
- package/lib/gitlab-duo-workflow-BGAF6JDw.mjs +91 -0
- package/lib/gitlab-duo-workflow-CSEgYk3N.mjs +91 -0
- package/lib/gitlab-duo-workflow-D78tdn8E.mjs +91 -0
- package/lib/google-BS4T25Pn.mjs +30 -0
- package/lib/google-TFe-7-of.mjs +30 -0
- package/lib/google-antigravity-DGmwC2KV.mjs +198 -0
- package/lib/google-antigravity-DNYhgTpA.mjs +198 -0
- package/lib/google-antigravity-Dlkdhahq.mjs +198 -0
- package/lib/google-auth-B6gjsZvg.mjs +232 -0
- package/lib/google-auth-De7_s3eo.mjs +232 -0
- package/lib/google-auth-DhqpOYrX.mjs +232 -0
- package/lib/google-gemini-cli-BG_LRdIV.mjs +850 -0
- package/lib/google-gemini-cli-CWu8HvXW.mjs +211 -0
- package/lib/google-gemini-cli-Cb97bzQc.mjs +850 -0
- package/lib/google-gemini-cli-Cqds_Q5T.mjs +850 -0
- package/lib/google-gemini-cli-Dsztq0N5.mjs +211 -0
- package/lib/google-gemini-cli-zJhiOcND.mjs +211 -0
- package/lib/google-oauth-shared-CuEHaDDj.mjs +147 -0
- package/lib/google-oauth-shared-CwNWYdmR.mjs +147 -0
- package/lib/google-oauth-shared-yqlyqPPC.mjs +147 -0
- package/lib/google-shared-CgKmmdO3.mjs +760 -0
- package/lib/google-shared-Dr-VG-ap.mjs +760 -0
- package/lib/google-shared-DzhCb9b0.mjs +760 -0
- package/lib/google-vertex-BDN2tLaD.mjs +99 -0
- package/lib/google-vertex-DopVOQOG.mjs +99 -0
- package/lib/google-vertex-kscbkyRb.mjs +99 -0
- package/lib/google-zyDOG9x7.mjs +30 -0
- package/lib/identity-Da1GPU9a.mjs +219 -0
- package/lib/identity-DnB63pS7.mjs +219 -0
- package/lib/identity-xRP7_eSR.mjs +219 -0
- package/lib/idle-iterator-Baoyn3Hp.mjs +366 -0
- package/lib/idle-iterator-C6XbWcuB.mjs +366 -0
- package/lib/idle-iterator-DUjKQEGT.mjs +366 -0
- package/lib/index.mjs +4608 -3935
- package/lib/kimi--wUOWER5.mjs +236 -0
- package/lib/kimi-DMVI-zrZ.mjs +236 -0
- package/lib/kimi-Dh0pv3WZ.mjs +236 -0
- package/lib/markit-BL3cH47U.mjs +1417 -0
- package/lib/markit-BNiNY6SE.mjs +1417 -0
- package/lib/markit-M0jhziqU.mjs +1417 -0
- package/lib/minimax-code-BK-3eBbz.mjs +53 -0
- package/lib/minimax-code-DCbuA6Yk.mjs +53 -0
- package/lib/minimax-code-Uq8Qu9LW.mjs +53 -0
- package/lib/models-CfT4coYT.mjs +104660 -0
- package/lib/models-D_XnT6ay.mjs +104660 -0
- package/lib/models-SGASygJ3.mjs +104660 -0
- package/lib/ollama-BQMGPxtV.mjs +589 -0
- package/lib/ollama-DPzBmq89.mjs +589 -0
- package/lib/ollama-DoBz5SFm.mjs +589 -0
- package/lib/openai-codex-Bi-4S4PX.mjs +255 -0
- package/lib/openai-codex-CQL_kvYL.mjs +255 -0
- package/lib/openai-codex-Ch8CkT3p.mjs +255 -0
- package/lib/openai-codex-responses-CvxL_FMF.mjs +3144 -0
- package/lib/openai-codex-responses-Cz-2qpC7.mjs +3144 -0
- package/lib/openai-codex-responses-pejZgdZo.mjs +3144 -0
- package/lib/openai-completions-CF8IyNtP.mjs +1360 -0
- package/lib/openai-completions-DIf361kF.mjs +1360 -0
- package/lib/openai-completions-i8doczAk.mjs +1360 -0
- package/lib/openai-reasoning-fallback-DGVVLgd1.mjs +286 -0
- package/lib/openai-reasoning-fallback-Nj6yB2rY.mjs +286 -0
- package/lib/openai-reasoning-fallback-OdJREP1o.mjs +286 -0
- package/lib/openai-responses-BqXJInHX.mjs +867 -0
- package/lib/openai-responses-DTkBiiy-.mjs +867 -0
- package/lib/openai-responses-Db_a-U4-.mjs +867 -0
- package/lib/opencode-DaJjcUbf.mjs +38 -0
- package/lib/opencode-DhMolSoB.mjs +38 -0
- package/lib/opencode-Rq_Q2vAO.mjs +38 -0
- package/lib/perplexity-9b-RQ0mV.mjs +194 -0
- package/lib/perplexity-C4iLVMUj.mjs +194 -0
- package/lib/perplexity-Uu7Jzg5b.mjs +194 -0
- package/lib/proxy-DDqrmjjC.mjs +190 -0
- package/lib/proxy-ZtUcl6r5.mjs +190 -0
- package/lib/proxy-pM_NIv-H.mjs +190 -0
- package/lib/request-debug-HJMoJncL.mjs +183 -0
- package/lib/sanitize-text-CfcXzw5X.mjs +33 -0
- package/lib/scrapers-BkFfcPHj.mjs +9198 -0
- package/lib/scrapers-CL-WgdU1.mjs +9198 -0
- package/lib/scrapers-CVptboMs.mjs +9198 -0
- package/lib/scrapers-CipyKyCH.mjs +9198 -0
- package/lib/scrapers-DGfrYhtw.mjs +9198 -0
- package/lib/scrapers-DSUPYoUF.mjs +9198 -0
- package/lib/scrapers-DZ2GXmp7.mjs +9198 -0
- package/lib/scrapers-nhQAvc8d.mjs +9198 -0
- package/lib/shell-snapshot-fn-env.sh +67 -43
- package/lib/src-BgpusnsB.mjs +5076 -0
- package/lib/src-DTid0g4K.mjs +5001 -0
- package/lib/src-lDmkSRbm.mjs +5006 -0
- package/lib/stream-BlldLkVq.mjs +10236 -0
- package/lib/stream-CRtexYLe.mjs +10236 -0
- package/lib/stream-C_RAoxJC.mjs +10236 -0
- package/lib/stream-markup-healing-2toHXWXM.mjs +491 -0
- package/lib/stream-markup-healing-DMsxBx1L.mjs +491 -0
- package/lib/stream-markup-healing-KMkiAA00.mjs +491 -0
- package/lib/turndown-DN7ByzEI.mjs +667 -0
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/config/fields.d.ts +1 -1
- package/lib/types/config/settings.d.ts +25 -3
- package/lib/types/config/truncate.d.ts +9 -5
- package/lib/types/tools/bash/background.d.ts +1 -1
- package/lib/types/tools/bash/bash-executor.d.ts +4 -0
- package/lib/types/tools/bash/bash-interceptor.d.ts +10 -8
- package/lib/types/tools/bash/cd-workdir.d.ts +35 -0
- package/lib/types/tools/bash/non-interactive-env.d.ts +2 -0
- package/lib/types/tools/bash/render.d.ts +4 -3
- package/lib/types/tools/bash/sanitize-text.d.ts +5 -0
- package/lib/types/tools/bash/shell-snapshot.d.ts +4 -1
- package/lib/types/tools/bash/shell-tokenize.d.ts +60 -0
- package/lib/types/tools/bash/streaming-output.d.ts +12 -212
- package/lib/types/tools/bash/which.d.ts +20 -0
- package/lib/types/tools/bash/windows-shell.d.ts +31 -0
- package/lib/types/tools/edit/adapter/index.d.ts +25 -3
- package/lib/types/tools/edit/adapter/tools/auto-generated-guard.d.ts +7 -17
- package/lib/types/tools/glob/adapter/index.d.ts +27 -1
- package/lib/types/tools/grep/adapter/index.d.ts +29 -1
- package/lib/types/tools/omp/edit/dispatch.d.ts +43 -0
- package/lib/types/tools/omp/edit/hashline/noop-loop-guard.d.ts +3 -1
- package/lib/types/tools/omp/sdk.d.ts +6 -0
- package/lib/types/tools/omp/tools/auto-generated-guard.d.ts +20 -0
- package/lib/types/tools/omp/tools/fetch.d.ts +2 -0
- package/lib/types/tools/omp/tools/read.d.ts +2 -8
- package/lib/types/tools/omp/tools/write.d.ts +4 -4
- package/lib/types/tools/omp/utils/image-loading.d.ts +10 -36
- package/lib/types/tools/read/adapter/index.d.ts +4 -1
- package/lib/types/tools/read-image/index.d.ts +4 -0
- package/lib/types/tools/shared/auto-generated-guard.dsh.d.ts +16 -4
- package/lib/types/tools/shared/bun-shim.d.ts +39 -3
- package/lib/types/tools/shared/fs-promises-shim.d.ts +3 -1
- package/lib/types/tools/shared/image-bridge.d.ts +98 -0
- package/lib/types/tools/shared/omp-prompt.d.ts +17 -9
- package/lib/types/tools/shared/session-state.d.ts +9 -3
- package/lib/utils-2Wq2eATG.mjs +8119 -0
- package/lib/utils-BnX8O3vi.mjs +12303 -0
- package/lib/utils-Bw139LTz.mjs +8119 -0
- package/lib/utils-CE8N8P4Q.mjs +12315 -0
- package/lib/utils-CZw4tVZQ.mjs +12315 -0
- package/lib/utils-C_MrQ_0z.mjs +12301 -0
- package/lib/utils-CiGN7OHR.mjs +12315 -0
- package/lib/utils-Cp76gCyk.mjs +8119 -0
- package/lib/utils-D0GRDgAr.mjs +12315 -0
- package/lib/utils-D0Z1fyoO.mjs +12299 -0
- package/lib/utils-D2YknRk4.mjs +51 -0
- package/lib/utils-DppGHXQB.mjs +51 -0
- package/lib/utils-DzXZDfYc.mjs +51 -0
- package/lib/utils-W8WdSBpX.mjs +12315 -0
- package/lib/vision-guard-01qSwFpf.mjs +92 -0
- package/lib/vision-guard-BDD4OrKo.mjs +92 -0
- package/lib/vision-guard-DzZGaOga.mjs +92 -0
- package/lib/wafer-CgtPHerf.mjs +17 -0
- package/lib/wafer-DRU0EjZX.mjs +17 -0
- package/lib/wafer-cBtrn6q9.mjs +17 -0
- package/lib/xai-oauth-Buk8XVvM.mjs +446 -0
- package/lib/xai-oauth-CMal8l1O.mjs +446 -0
- package/lib/xai-oauth-DPHDXKD7.mjs +446 -0
- package/lib/xiaomi-CZgwvX2G.mjs +157 -0
- package/lib/xiaomi-D2qT5cAC.mjs +157 -0
- package/lib/xiaomi-Dd87KSg5.mjs +157 -0
- package/lib/zai-7DWMkEqM.mjs +203 -0
- package/lib/zai-C59YnomG.mjs +203 -0
- package/lib/zai-CFeOt-53.mjs +203 -0
- package/lib/zip-Cg9ANN_U.mjs +1316 -0
- package/lib/zip-D36ZKsP8.mjs +1316 -0
- package/lib/zip-D6QXpvaJ.mjs +1316 -0
- package/package.json +14 -10
- package/presets/package.json +1 -1
- package/presets/tool-plus-ptc/preset.yml +1 -1
- package/presets/tool-plus-standard/preset.yml +1 -1
|
@@ -0,0 +1,917 @@
|
|
|
1
|
+
import { installBunShim as __installBunShim } from "./bun-shim.mjs";
|
|
2
|
+
__installBunShim();
|
|
3
|
+
import { I as $flag, _ as parseStreamingJsonThrottled, g as parseStreamingJson } from "./src-lDmkSRbm.mjs";
|
|
4
|
+
import { G as fetchWithRetry, I as BedrockApiError, U as EventStreamFrameError, l as finalize, r as ValidationError, v as AbortError } from "./error-yCSG0mGC.mjs";
|
|
5
|
+
import { C as kStreamingPartialJson, S as kStreamingLastParseLen, a as normalizeSystemPrompts, h as clearStreamingPartialJson, k as toolWireSchema, m as transformMessages, o as normalizeToolCallId, s as resolveCacheRetention, w as renderDemotedThinking, y as kStreamingBlockIndex } from "./utils-Bw139LTz.mjs";
|
|
6
|
+
import { i as resolveAwsBearerToken, n as resolveAwsCredentials, r as signRequest, s as resolveAwsAmbientRegion, t as invalidateAwsCredentialCache } from "./aws-credentials-ChG79ey-.mjs";
|
|
7
|
+
import { o as mapEffortToAnthropicAdaptiveEffort, s as requireSupportedEffort, t as calculateCost } from "./models-D_XnT6ay.mjs";
|
|
8
|
+
import { t as AssistantMessageEventStream } from "./event-stream-loUa0s1T.mjs";
|
|
9
|
+
import { i as getStreamFirstEventTimeoutMs, t as armPreResponseTimeout } from "./idle-iterator-Baoyn3Hp.mjs";
|
|
10
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/providers/aws-eventstream.ts
|
|
11
|
+
/**
|
|
12
|
+
* `application/vnd.amazon.eventstream` decoder.
|
|
13
|
+
*
|
|
14
|
+
* Wire format (all integers big-endian):
|
|
15
|
+
*
|
|
16
|
+
* [total length u32]
|
|
17
|
+
* [headers length u32]
|
|
18
|
+
* [prelude CRC32 u32] <- CRC over the first 8 bytes
|
|
19
|
+
* [headers headers_length]
|
|
20
|
+
* [payload total_length - headers_length - 16]
|
|
21
|
+
* [message CRC32 u32] <- CRC over the entire message minus the trailing 4 bytes
|
|
22
|
+
*
|
|
23
|
+
* Headers: a sequence of `[name_len u8][name utf8][value_type u8][value …]`.
|
|
24
|
+
* We only need the typed values Bedrock emits (boolean true/false, byte, short,
|
|
25
|
+
* integer, long, byte-array, string, timestamp, uuid). All are surfaced as
|
|
26
|
+
* strings for ease of consumption — Bedrock only sets string-valued headers in
|
|
27
|
+
* practice (`:event-type`, `:message-type`, `:content-type`, `:exception-type`).
|
|
28
|
+
*/
|
|
29
|
+
const PRELUDE_LEN = 8;
|
|
30
|
+
const MESSAGE_CRC_LEN = 4;
|
|
31
|
+
const HEADER_BLOCK_OFFSET = 12;
|
|
32
|
+
const MIN_MESSAGE_LEN = 16;
|
|
33
|
+
/** CRC32 (IEEE / zlib polynomial 0xEDB88320), matches `@aws-crypto/crc32`. */
|
|
34
|
+
function crc32(bytes) {
|
|
35
|
+
return Bun.hash.crc32(bytes) >>> 0;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Decode a single, fully buffered eventstream message. Throws if the framing is
|
|
39
|
+
* malformed or either CRC mismatches. Used by both `decodeEventStream` (the
|
|
40
|
+
* streaming entry point) and the unit tests, which exercise it with hand-built
|
|
41
|
+
* frames.
|
|
42
|
+
*/
|
|
43
|
+
function decodeMessage(frame) {
|
|
44
|
+
if (frame.length < MIN_MESSAGE_LEN) throw new EventStreamFrameError("frame too short");
|
|
45
|
+
const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
|
|
46
|
+
const total = view.getUint32(0, false);
|
|
47
|
+
if (total !== frame.length) throw new EventStreamFrameError(`framed length ${total} != buffer ${frame.length}`);
|
|
48
|
+
const headersLen = view.getUint32(4, false);
|
|
49
|
+
const preludeCrc = view.getUint32(8, false);
|
|
50
|
+
if (crc32(frame.subarray(0, PRELUDE_LEN)) !== preludeCrc) throw new EventStreamFrameError("prelude CRC mismatch");
|
|
51
|
+
const msgCrc = view.getUint32(total - MESSAGE_CRC_LEN, false);
|
|
52
|
+
if (crc32(frame.subarray(0, total - MESSAGE_CRC_LEN)) !== msgCrc) throw new EventStreamFrameError("message CRC mismatch");
|
|
53
|
+
const headersBytes = frame.subarray(HEADER_BLOCK_OFFSET, HEADER_BLOCK_OFFSET + headersLen);
|
|
54
|
+
const payload = frame.subarray(HEADER_BLOCK_OFFSET + headersLen, total - MESSAGE_CRC_LEN);
|
|
55
|
+
return {
|
|
56
|
+
headers: parseHeaders(headersBytes),
|
|
57
|
+
payload
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function parseHeaders(buf) {
|
|
61
|
+
const out = {};
|
|
62
|
+
const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
63
|
+
const decoder = new TextDecoder();
|
|
64
|
+
let p = 0;
|
|
65
|
+
while (p < buf.length) {
|
|
66
|
+
const nameLen = view.getUint8(p);
|
|
67
|
+
p += 1;
|
|
68
|
+
const name = decoder.decode(buf.subarray(p, p + nameLen));
|
|
69
|
+
p += nameLen;
|
|
70
|
+
const type = view.getUint8(p);
|
|
71
|
+
p += 1;
|
|
72
|
+
switch (type) {
|
|
73
|
+
case 0:
|
|
74
|
+
out[name] = "true";
|
|
75
|
+
break;
|
|
76
|
+
case 1:
|
|
77
|
+
out[name] = "false";
|
|
78
|
+
break;
|
|
79
|
+
case 2:
|
|
80
|
+
out[name] = String(view.getInt8(p));
|
|
81
|
+
p += 1;
|
|
82
|
+
break;
|
|
83
|
+
case 3:
|
|
84
|
+
out[name] = String(view.getInt16(p, false));
|
|
85
|
+
p += 2;
|
|
86
|
+
break;
|
|
87
|
+
case 4:
|
|
88
|
+
out[name] = String(view.getInt32(p, false));
|
|
89
|
+
p += 4;
|
|
90
|
+
break;
|
|
91
|
+
case 5:
|
|
92
|
+
out[name] = bigIntFromBytes(buf.subarray(p, p + 8)).toString();
|
|
93
|
+
p += 8;
|
|
94
|
+
break;
|
|
95
|
+
case 6: {
|
|
96
|
+
const len = view.getUint16(p, false);
|
|
97
|
+
p += 2;
|
|
98
|
+
out[name] = Buffer.from(buf.buffer, buf.byteOffset + p, len).toString("base64");
|
|
99
|
+
p += len;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case 7: {
|
|
103
|
+
const len = view.getUint16(p, false);
|
|
104
|
+
p += 2;
|
|
105
|
+
out[name] = decoder.decode(buf.subarray(p, p + len));
|
|
106
|
+
p += len;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case 8:
|
|
110
|
+
out[name] = new Date(Number(bigIntFromBytes(buf.subarray(p, p + 8)))).toISOString();
|
|
111
|
+
p += 8;
|
|
112
|
+
break;
|
|
113
|
+
case 9: {
|
|
114
|
+
const u = buf.subarray(p, p + 16);
|
|
115
|
+
const hex = [];
|
|
116
|
+
for (let i = 0; i < 16; i++) hex.push(u[i].toString(16).padStart(2, "0"));
|
|
117
|
+
out[name] = `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10, 16).join("")}`;
|
|
118
|
+
p += 16;
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
default: throw new EventStreamFrameError(`unknown header value type ${type}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
function bigIntFromBytes(b) {
|
|
127
|
+
let v = 0n;
|
|
128
|
+
for (let i = 0; i < b.length; i++) v = v << 8n | BigInt(b[i]);
|
|
129
|
+
if (b.length === 8 && b[0] & 128) v -= 1n << 64n;
|
|
130
|
+
return v;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Async generator that consumes a `ReadableStream<Uint8Array>` (e.g. a fetch
|
|
134
|
+
* response body) and yields fully-framed messages. Handles arbitrary chunk
|
|
135
|
+
* boundaries: messages may span multiple chunks, and a single chunk may carry
|
|
136
|
+
* many messages.
|
|
137
|
+
*/
|
|
138
|
+
async function* decodeEventStream(source) {
|
|
139
|
+
const reader = source.getReader();
|
|
140
|
+
let buf = /* @__PURE__ */ new Uint8Array(0);
|
|
141
|
+
let completed = false;
|
|
142
|
+
try {
|
|
143
|
+
while (true) {
|
|
144
|
+
const { value, done } = await reader.read();
|
|
145
|
+
if (value && value.length > 0) buf = buf.length === 0 ? value : Buffer.concat([buf, value]);
|
|
146
|
+
let offset = 0;
|
|
147
|
+
while (buf.length - offset >= 4) {
|
|
148
|
+
const total = new DataView(buf.buffer, buf.byteOffset + offset, buf.length - offset).getUint32(0, false);
|
|
149
|
+
if (total < MIN_MESSAGE_LEN) throw new EventStreamFrameError(`total length ${total} below minimum`);
|
|
150
|
+
if (buf.length - offset < total) break;
|
|
151
|
+
yield decodeMessage(buf.subarray(offset, offset + total));
|
|
152
|
+
offset += total;
|
|
153
|
+
}
|
|
154
|
+
if (offset > 0) buf = buf.slice(offset);
|
|
155
|
+
if (done) break;
|
|
156
|
+
}
|
|
157
|
+
if (buf.length > 0) throw new EventStreamFrameError("truncated message at end of stream");
|
|
158
|
+
completed = true;
|
|
159
|
+
} finally {
|
|
160
|
+
if (!completed) await reader.cancel().catch(() => {});
|
|
161
|
+
reader.releaseLock();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//#endregion
|
|
165
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/providers/amazon-bedrock.ts
|
|
166
|
+
/**
|
|
167
|
+
* Headers SigV4 generates for itself. A caller cannot be allowed to supply these:
|
|
168
|
+
* `signRequest` would sign the caller's value but return its own, so the signature
|
|
169
|
+
* would not match what goes on the wire.
|
|
170
|
+
*/
|
|
171
|
+
const SIGNER_OWNED_HEADERS = /* @__PURE__ */ new Set([
|
|
172
|
+
"host",
|
|
173
|
+
"x-amz-date",
|
|
174
|
+
"x-amz-content-sha256",
|
|
175
|
+
"x-amz-security-token"
|
|
176
|
+
]);
|
|
177
|
+
/** Headers the Bedrock request sets itself; a caller copy in any casing duplicates them. */
|
|
178
|
+
const BEDROCK_RESERVED_HEADERS = /* @__PURE__ */ new Set([
|
|
179
|
+
"content-type",
|
|
180
|
+
"accept",
|
|
181
|
+
"authorization",
|
|
182
|
+
"content-length"
|
|
183
|
+
]);
|
|
184
|
+
function resolveBearerToken(options) {
|
|
185
|
+
return resolveAwsBearerToken(options.apiKey, options.bearerToken);
|
|
186
|
+
}
|
|
187
|
+
function inferRegionFromBedrockArn(modelId) {
|
|
188
|
+
const parts = modelId.split(":", 6);
|
|
189
|
+
if (parts[0] !== "arn" || parts[2] !== "bedrock") return void 0;
|
|
190
|
+
return parts[3] || void 0;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Default AWS region for each Bedrock cross-region inference-profile geo prefix.
|
|
194
|
+
* A geo-prefixed profile (e.g. `eu.anthropic.claude-…`) is only servable from
|
|
195
|
+
* regions in its own geo, so routing one to `us-east-1` yields HTTP 400 "The
|
|
196
|
+
* provided model identifier is invalid." `global.` profiles are anchored in the
|
|
197
|
+
* us regions and intentionally absent here (they resolve fine via `us-east-1`).
|
|
198
|
+
*/
|
|
199
|
+
const INFERENCE_PROFILE_GEO_DEFAULT_REGION = {
|
|
200
|
+
us: "us-east-1",
|
|
201
|
+
"us-gov": "us-gov-west-1",
|
|
202
|
+
eu: "eu-west-1",
|
|
203
|
+
apac: "ap-southeast-1",
|
|
204
|
+
au: "ap-southeast-2",
|
|
205
|
+
jp: "ap-northeast-1"
|
|
206
|
+
};
|
|
207
|
+
/** Geo prefix of a cross-region inference-profile id, e.g. `eu.anthropic.…` → `eu`. */
|
|
208
|
+
function inferenceProfileGeo(modelId) {
|
|
209
|
+
const dot = modelId.indexOf(".");
|
|
210
|
+
if (dot <= 0) return void 0;
|
|
211
|
+
const prefix = modelId.slice(0, dot);
|
|
212
|
+
return prefix in INFERENCE_PROFILE_GEO_DEFAULT_REGION ? prefix : void 0;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Whether a concrete AWS region can serve a given inference-profile geo. The
|
|
216
|
+
* `ap-` regions overlap across `apac`/`au`/`jp` profiles, so the Australia and
|
|
217
|
+
* Japan geos pin their specific source regions rather than matching all `ap-*`.
|
|
218
|
+
*/
|
|
219
|
+
function regionServesGeo(region, geo) {
|
|
220
|
+
switch (geo) {
|
|
221
|
+
case "us-gov": return region.startsWith("us-gov-");
|
|
222
|
+
case "us": return region.startsWith("us-") && !region.startsWith("us-gov-");
|
|
223
|
+
case "eu": return region.startsWith("eu-");
|
|
224
|
+
case "apac": return region.startsWith("ap-");
|
|
225
|
+
case "au": return region === "ap-southeast-2" || region === "ap-southeast-4";
|
|
226
|
+
case "jp": return region === "ap-northeast-1" || region === "ap-northeast-3";
|
|
227
|
+
default: return false;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Resolve the Bedrock runtime region for a request. An explicit per-request
|
|
232
|
+
* region and an ARN-embedded region win outright. Otherwise, for a geo-prefixed
|
|
233
|
+
* cross-region inference profile (`us.`/`eu.`/`apac.`/`au.`/`jp.`/`us-gov.`), an
|
|
234
|
+
* ambient region (`AWS_REGION` / `AWS_DEFAULT_REGION`) is honored only when it
|
|
235
|
+
* can serve the profile's geo; a mismatched or absent ambient region is
|
|
236
|
+
* corrected to the geo default so an `eu.`/`apac.` profile never POSTs to a `us`
|
|
237
|
+
* endpoint (and vice versa). `global.` profiles have no geo entry, so the
|
|
238
|
+
* ambient region (or `us-east-1`) is used unchanged.
|
|
239
|
+
*/
|
|
240
|
+
function resolveBedrockRegion(modelId, options) {
|
|
241
|
+
const explicit = options.region || inferRegionFromBedrockArn(modelId);
|
|
242
|
+
if (explicit) return explicit;
|
|
243
|
+
const ambient = resolveAwsAmbientRegion(options.profile);
|
|
244
|
+
const geo = inferenceProfileGeo(modelId);
|
|
245
|
+
if (geo) {
|
|
246
|
+
if (ambient && regionServesGeo(ambient, geo)) return ambient;
|
|
247
|
+
return INFERENCE_PROFILE_GEO_DEFAULT_REGION[geo];
|
|
248
|
+
}
|
|
249
|
+
return ambient || "us-east-1";
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Bedrock validates that requests carrying any `toolUse`/`toolResult` history
|
|
253
|
+
* include a `toolConfig`. For no-tool ephemeral turns (`/btw`, IRC auto-replies)
|
|
254
|
+
* we have nothing real to send, so we inject this placeholder. Its presence is
|
|
255
|
+
* tracked by a per-request flag — never the wire name — so callers who happen
|
|
256
|
+
* to register a real tool literally called `__no_tools__` are not affected.
|
|
257
|
+
*/
|
|
258
|
+
const NO_TOOLS_SENTINEL_NAME = "__no_tools__";
|
|
259
|
+
const NO_TOOLS_SENTINEL = { toolSpec: {
|
|
260
|
+
name: NO_TOOLS_SENTINEL_NAME,
|
|
261
|
+
description: "Placeholder required by Bedrock validation. Do not call; answer with text.",
|
|
262
|
+
inputSchema: { json: {
|
|
263
|
+
type: "object",
|
|
264
|
+
properties: {}
|
|
265
|
+
} }
|
|
266
|
+
} };
|
|
267
|
+
const streamBedrock = (model, context, options) => {
|
|
268
|
+
const stream = new AssistantMessageEventStream();
|
|
269
|
+
(async () => {
|
|
270
|
+
const startTime = performance.now();
|
|
271
|
+
let firstTokenTime;
|
|
272
|
+
const output = {
|
|
273
|
+
role: "assistant",
|
|
274
|
+
content: [],
|
|
275
|
+
api: "bedrock-converse-stream",
|
|
276
|
+
provider: model.provider,
|
|
277
|
+
model: model.id,
|
|
278
|
+
usage: {
|
|
279
|
+
input: 0,
|
|
280
|
+
output: 0,
|
|
281
|
+
cacheRead: 0,
|
|
282
|
+
cacheWrite: 0,
|
|
283
|
+
totalTokens: 0,
|
|
284
|
+
cost: {
|
|
285
|
+
input: 0,
|
|
286
|
+
output: 0,
|
|
287
|
+
cacheRead: 0,
|
|
288
|
+
cacheWrite: 0,
|
|
289
|
+
total: 0
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
stopReason: "stop",
|
|
293
|
+
timestamp: Date.now()
|
|
294
|
+
};
|
|
295
|
+
const blocks = output.content;
|
|
296
|
+
let rawRequestDump;
|
|
297
|
+
const region = resolveBedrockRegion(model.id, options);
|
|
298
|
+
try {
|
|
299
|
+
const promptCachePolicy = resolvePromptCachePolicy(model, resolveCacheRetention(options.cacheRetention));
|
|
300
|
+
const convertedMessages = convertMessages(context, model, promptCachePolicy);
|
|
301
|
+
const toolPlan = planToolConfig(context.tools, options.toolChoice, convertedMessages);
|
|
302
|
+
const toolConfig = toolPlan.toolConfig;
|
|
303
|
+
const sentinelInjected = toolPlan.sentinelInjected;
|
|
304
|
+
let additionalModelRequestFields = buildAdditionalModelRequestFields(model, options);
|
|
305
|
+
if (toolConfig?.toolChoice && additionalModelRequestFields) {
|
|
306
|
+
const tc = toolConfig.toolChoice;
|
|
307
|
+
if (tc.any || tc.tool) additionalModelRequestFields = void 0;
|
|
308
|
+
}
|
|
309
|
+
const commandInput = {
|
|
310
|
+
messages: convertedMessages,
|
|
311
|
+
system: buildSystemPrompt(context.systemPrompt, promptCachePolicy),
|
|
312
|
+
inferenceConfig: {
|
|
313
|
+
maxTokens: options.maxTokens,
|
|
314
|
+
temperature: options.temperature,
|
|
315
|
+
topP: options.topP
|
|
316
|
+
},
|
|
317
|
+
toolConfig,
|
|
318
|
+
additionalModelRequestFields
|
|
319
|
+
};
|
|
320
|
+
options?.onPayload?.(commandInput, model);
|
|
321
|
+
const host = `bedrock-runtime.${region}.amazonaws.com`;
|
|
322
|
+
const url = `https://${host}/model/${encodeURIComponent(model.id)}/converse-stream`;
|
|
323
|
+
const urlPath = `/model/${encodeURIComponent(model.id)}/converse-stream`;
|
|
324
|
+
rawRequestDump = {
|
|
325
|
+
provider: model.provider,
|
|
326
|
+
api: output.api,
|
|
327
|
+
model: model.id,
|
|
328
|
+
method: "POST",
|
|
329
|
+
url,
|
|
330
|
+
body: commandInput
|
|
331
|
+
};
|
|
332
|
+
const bodyText = JSON.stringify(commandInput);
|
|
333
|
+
const body = new TextEncoder().encode(bodyText);
|
|
334
|
+
const callerHeaders = {};
|
|
335
|
+
for (const [name, value] of Object.entries(options?.headers ?? {})) {
|
|
336
|
+
const field = name.toLowerCase();
|
|
337
|
+
if (SIGNER_OWNED_HEADERS.has(field) || BEDROCK_RESERVED_HEADERS.has(field)) continue;
|
|
338
|
+
callerHeaders[field] = value;
|
|
339
|
+
}
|
|
340
|
+
const baseHeaders = {
|
|
341
|
+
...callerHeaders,
|
|
342
|
+
"content-type": "application/json",
|
|
343
|
+
accept: "application/vnd.amazon.eventstream"
|
|
344
|
+
};
|
|
345
|
+
const bearerToken = resolveBearerToken(options);
|
|
346
|
+
let requestHeaders;
|
|
347
|
+
if (bearerToken) requestHeaders = {
|
|
348
|
+
...baseHeaders,
|
|
349
|
+
Authorization: `Bearer ${bearerToken}`
|
|
350
|
+
};
|
|
351
|
+
else {
|
|
352
|
+
let credentials;
|
|
353
|
+
if ($flag("AWS_BEDROCK_SKIP_AUTH")) credentials = {
|
|
354
|
+
accessKeyId: "dummy-access-key",
|
|
355
|
+
secretAccessKey: "dummy-secret-key"
|
|
356
|
+
};
|
|
357
|
+
else credentials = await resolveAwsCredentials({
|
|
358
|
+
profile: options.profile,
|
|
359
|
+
region,
|
|
360
|
+
signal: options.signal,
|
|
361
|
+
fetch: options.fetch
|
|
362
|
+
});
|
|
363
|
+
const signed = await signRequest({
|
|
364
|
+
method: "POST",
|
|
365
|
+
host,
|
|
366
|
+
path: urlPath,
|
|
367
|
+
body,
|
|
368
|
+
region,
|
|
369
|
+
service: "bedrock",
|
|
370
|
+
credentials,
|
|
371
|
+
headers: baseHeaders
|
|
372
|
+
});
|
|
373
|
+
requestHeaders = {
|
|
374
|
+
...baseHeaders,
|
|
375
|
+
...signed
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
const firstEventTimeoutMs = options.streamFirstEventTimeoutMs ?? getStreamFirstEventTimeoutMs();
|
|
379
|
+
const watchdog = armPreResponseTimeout(options.signal, firstEventTimeoutMs);
|
|
380
|
+
let response;
|
|
381
|
+
try {
|
|
382
|
+
response = await fetchWithRetry(url, {
|
|
383
|
+
method: "POST",
|
|
384
|
+
headers: requestHeaders,
|
|
385
|
+
body,
|
|
386
|
+
signal: watchdog.signal,
|
|
387
|
+
fetch: options.fetch,
|
|
388
|
+
timeout: false
|
|
389
|
+
});
|
|
390
|
+
} finally {
|
|
391
|
+
watchdog.clear();
|
|
392
|
+
}
|
|
393
|
+
if (!response.ok) {
|
|
394
|
+
if (!bearerToken && (response.status === 401 || response.status === 403)) invalidateAwsCredentialCache({
|
|
395
|
+
profile: options.profile,
|
|
396
|
+
region
|
|
397
|
+
});
|
|
398
|
+
const errBody = await response.text().catch(() => "");
|
|
399
|
+
throw new BedrockApiError(`Bedrock HTTP ${response.status}: ${errBody.slice(0, 1e3)}`, response.status, { headers: response.headers });
|
|
400
|
+
}
|
|
401
|
+
if (!response.body) throw new BedrockApiError("Bedrock response has no body", response.status);
|
|
402
|
+
for await (const message of decodeEventStream(response.body)) {
|
|
403
|
+
const messageType = message.headers[":message-type"];
|
|
404
|
+
const eventType = message.headers[":event-type"];
|
|
405
|
+
if (messageType === "exception") {
|
|
406
|
+
const exceptionType = message.headers[":exception-type"] || "Exception";
|
|
407
|
+
const text = `${exceptionType}: ${safeParsePayload(message.payload)?.message || new TextDecoder().decode(message.payload)}`;
|
|
408
|
+
throw new BedrockApiError(text, 400, { code: exceptionType });
|
|
409
|
+
}
|
|
410
|
+
if (messageType === "error") {
|
|
411
|
+
const code = message.headers[":error-code"] || "UnknownError";
|
|
412
|
+
const errorMessage = message.headers[":error-message"] || new TextDecoder().decode(message.payload);
|
|
413
|
+
throw new BedrockApiError(`${code}: ${errorMessage}`, 400, { code });
|
|
414
|
+
}
|
|
415
|
+
if (messageType !== "event") continue;
|
|
416
|
+
const payload = safeParsePayload(message.payload);
|
|
417
|
+
if (!payload) continue;
|
|
418
|
+
switch (eventType) {
|
|
419
|
+
case "messageStart":
|
|
420
|
+
if (payload.role !== "assistant") throw new BedrockApiError("Unexpected assistant message start but got user message start instead", 0);
|
|
421
|
+
stream.push({
|
|
422
|
+
type: "start",
|
|
423
|
+
partial: output
|
|
424
|
+
});
|
|
425
|
+
break;
|
|
426
|
+
case "contentBlockStart":
|
|
427
|
+
if (!firstTokenTime) firstTokenTime = performance.now();
|
|
428
|
+
handleContentBlockStart(payload, blocks, output, stream, sentinelInjected);
|
|
429
|
+
break;
|
|
430
|
+
case "contentBlockDelta":
|
|
431
|
+
if (!firstTokenTime) firstTokenTime = performance.now();
|
|
432
|
+
handleContentBlockDelta(payload, blocks, output, stream);
|
|
433
|
+
break;
|
|
434
|
+
case "contentBlockStop":
|
|
435
|
+
handleContentBlockStop(payload, blocks, output, stream);
|
|
436
|
+
break;
|
|
437
|
+
case "messageStop": {
|
|
438
|
+
const ev = payload;
|
|
439
|
+
output.stopReason = sentinelInjected && ev.stopReason === "tool_use" ? "stop" : mapStopReason(ev.stopReason);
|
|
440
|
+
if (output.stopReason === "error") output.errorMessage = `Generation failed with stop reason: ${ev.stopReason ?? "unknown"}`;
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
case "metadata": handleMetadata(payload, model, output);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
if (options.signal?.aborted) throw new AbortError();
|
|
447
|
+
if (output.stopReason === "error" || output.stopReason === "aborted") throw new BedrockApiError(output.errorMessage ?? "An unknown error occurred", 0);
|
|
448
|
+
output.duration = performance.now() - startTime;
|
|
449
|
+
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
450
|
+
stream.push({
|
|
451
|
+
type: "done",
|
|
452
|
+
reason: output.stopReason,
|
|
453
|
+
message: output
|
|
454
|
+
});
|
|
455
|
+
stream.end();
|
|
456
|
+
} catch (error) {
|
|
457
|
+
for (const block of output.content) if (block.type === "toolCall") clearStreamingPartialJson(block);
|
|
458
|
+
let baseMessage;
|
|
459
|
+
try {
|
|
460
|
+
baseMessage = error instanceof Error ? error.message : JSON.stringify(error) ?? String(error);
|
|
461
|
+
} catch {
|
|
462
|
+
baseMessage = String(error);
|
|
463
|
+
}
|
|
464
|
+
let diagnostics = "";
|
|
465
|
+
if (baseMessage.includes("signature") || baseMessage.includes("thinking")) {
|
|
466
|
+
const thinkingBlocks = context.messages.filter((m) => m.role === "assistant").flatMap((m, mi) => m.content.filter((b) => b.type === "thinking").map((b, bi) => ({
|
|
467
|
+
msg: mi,
|
|
468
|
+
block: bi,
|
|
469
|
+
stop: m.stopReason,
|
|
470
|
+
sigLen: b.thinkingSignature?.length ?? -1,
|
|
471
|
+
thinkLen: b.thinking.length
|
|
472
|
+
})));
|
|
473
|
+
if (thinkingBlocks.length > 0) diagnostics = `\n[thinking-diag] ${JSON.stringify(thinkingBlocks)}`;
|
|
474
|
+
}
|
|
475
|
+
const result = await finalize(error, {
|
|
476
|
+
api: model.api,
|
|
477
|
+
signal: options.signal,
|
|
478
|
+
rawRequestDump
|
|
479
|
+
});
|
|
480
|
+
output.stopReason = result.stopReason;
|
|
481
|
+
output.errorStatus = result.status;
|
|
482
|
+
output.errorId = result.id;
|
|
483
|
+
output.errorMessage = result.message + diagnostics;
|
|
484
|
+
output.duration = performance.now() - startTime;
|
|
485
|
+
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
486
|
+
stream.push({
|
|
487
|
+
type: "error",
|
|
488
|
+
reason: output.stopReason,
|
|
489
|
+
error: output
|
|
490
|
+
});
|
|
491
|
+
stream.end();
|
|
492
|
+
}
|
|
493
|
+
})();
|
|
494
|
+
return stream;
|
|
495
|
+
};
|
|
496
|
+
function safeParsePayload(payload) {
|
|
497
|
+
if (payload.length === 0) return {};
|
|
498
|
+
try {
|
|
499
|
+
return JSON.parse(new TextDecoder().decode(payload));
|
|
500
|
+
} catch {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
function handleContentBlockStart(event, blocks, output, stream, sentinelInjected) {
|
|
505
|
+
const index = event.contentBlockIndex;
|
|
506
|
+
const start = event.start;
|
|
507
|
+
if (sentinelInjected && start?.toolUse?.name === NO_TOOLS_SENTINEL_NAME) return;
|
|
508
|
+
if (start?.toolUse) {
|
|
509
|
+
const block = {
|
|
510
|
+
type: "toolCall",
|
|
511
|
+
id: normalizeToolCallId(start.toolUse.toolUseId || ""),
|
|
512
|
+
name: start.toolUse.name || "",
|
|
513
|
+
arguments: {},
|
|
514
|
+
[kStreamingPartialJson]: "",
|
|
515
|
+
[kStreamingBlockIndex]: index
|
|
516
|
+
};
|
|
517
|
+
output.content.push(block);
|
|
518
|
+
stream.push({
|
|
519
|
+
type: "toolcall_start",
|
|
520
|
+
contentIndex: blocks.length - 1,
|
|
521
|
+
partial: output
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function handleContentBlockDelta(event, blocks, output, stream) {
|
|
526
|
+
const contentBlockIndex = event.contentBlockIndex;
|
|
527
|
+
const delta = event.delta;
|
|
528
|
+
let index = blocks.findIndex((b) => b[kStreamingBlockIndex] === contentBlockIndex);
|
|
529
|
+
let block = blocks[index];
|
|
530
|
+
if (delta?.text !== void 0) {
|
|
531
|
+
if (!block) {
|
|
532
|
+
const newBlock = {
|
|
533
|
+
type: "text",
|
|
534
|
+
text: "",
|
|
535
|
+
[kStreamingBlockIndex]: contentBlockIndex
|
|
536
|
+
};
|
|
537
|
+
output.content.push(newBlock);
|
|
538
|
+
index = blocks.length - 1;
|
|
539
|
+
block = blocks[index];
|
|
540
|
+
stream.push({
|
|
541
|
+
type: "text_start",
|
|
542
|
+
contentIndex: index,
|
|
543
|
+
partial: output
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
if (block.type === "text") {
|
|
547
|
+
block.text += delta.text;
|
|
548
|
+
stream.push({
|
|
549
|
+
type: "text_delta",
|
|
550
|
+
contentIndex: index,
|
|
551
|
+
delta: delta.text,
|
|
552
|
+
partial: output
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
} else if (delta?.toolUse && block?.type === "toolCall") {
|
|
556
|
+
block[kStreamingPartialJson] = (block[kStreamingPartialJson] || "") + (delta.toolUse.input || "");
|
|
557
|
+
const throttled = parseStreamingJsonThrottled(block[kStreamingPartialJson], block[kStreamingLastParseLen] ?? 0);
|
|
558
|
+
if (throttled) {
|
|
559
|
+
block.arguments = throttled.value;
|
|
560
|
+
block[kStreamingLastParseLen] = throttled.parsedLen;
|
|
561
|
+
}
|
|
562
|
+
stream.push({
|
|
563
|
+
type: "toolcall_delta",
|
|
564
|
+
contentIndex: index,
|
|
565
|
+
delta: delta.toolUse.input || "",
|
|
566
|
+
partial: output
|
|
567
|
+
});
|
|
568
|
+
} else if (delta?.reasoningContent) {
|
|
569
|
+
let thinkingBlock = block;
|
|
570
|
+
let thinkingIndex = index;
|
|
571
|
+
if (!thinkingBlock) {
|
|
572
|
+
const newBlock = {
|
|
573
|
+
type: "thinking",
|
|
574
|
+
thinking: "",
|
|
575
|
+
thinkingSignature: "",
|
|
576
|
+
[kStreamingBlockIndex]: contentBlockIndex
|
|
577
|
+
};
|
|
578
|
+
output.content.push(newBlock);
|
|
579
|
+
thinkingIndex = blocks.length - 1;
|
|
580
|
+
thinkingBlock = blocks[thinkingIndex];
|
|
581
|
+
stream.push({
|
|
582
|
+
type: "thinking_start",
|
|
583
|
+
contentIndex: thinkingIndex,
|
|
584
|
+
partial: output
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
if (thinkingBlock?.type === "thinking") {
|
|
588
|
+
if (delta.reasoningContent.text) {
|
|
589
|
+
thinkingBlock.thinking += delta.reasoningContent.text;
|
|
590
|
+
stream.push({
|
|
591
|
+
type: "thinking_delta",
|
|
592
|
+
contentIndex: thinkingIndex,
|
|
593
|
+
delta: delta.reasoningContent.text,
|
|
594
|
+
partial: output
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
if (delta.reasoningContent.signature) thinkingBlock.thinkingSignature = (thinkingBlock.thinkingSignature || "") + delta.reasoningContent.signature;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
function handleMetadata(event, model, output) {
|
|
602
|
+
if (event.usage) {
|
|
603
|
+
output.usage.input = event.usage.inputTokens || 0;
|
|
604
|
+
output.usage.output = event.usage.outputTokens || 0;
|
|
605
|
+
output.usage.cacheRead = event.usage.cacheReadInputTokens || 0;
|
|
606
|
+
output.usage.cacheWrite = event.usage.cacheWriteInputTokens || 0;
|
|
607
|
+
output.usage.totalTokens = event.usage.totalTokens || output.usage.input + output.usage.output;
|
|
608
|
+
calculateCost(model, output.usage);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
function handleContentBlockStop(event, blocks, output, stream) {
|
|
612
|
+
const index = blocks.findIndex((b) => b[kStreamingBlockIndex] === event.contentBlockIndex);
|
|
613
|
+
const block = blocks[index];
|
|
614
|
+
if (!block) return;
|
|
615
|
+
switch (block.type) {
|
|
616
|
+
case "text":
|
|
617
|
+
stream.push({
|
|
618
|
+
type: "text_end",
|
|
619
|
+
contentIndex: index,
|
|
620
|
+
content: block.text,
|
|
621
|
+
partial: output
|
|
622
|
+
});
|
|
623
|
+
break;
|
|
624
|
+
case "thinking":
|
|
625
|
+
stream.push({
|
|
626
|
+
type: "thinking_end",
|
|
627
|
+
contentIndex: index,
|
|
628
|
+
content: block.thinking,
|
|
629
|
+
partial: output
|
|
630
|
+
});
|
|
631
|
+
break;
|
|
632
|
+
case "toolCall":
|
|
633
|
+
block.arguments = parseStreamingJson(block[kStreamingPartialJson]);
|
|
634
|
+
clearStreamingPartialJson(block);
|
|
635
|
+
stream.push({
|
|
636
|
+
type: "toolcall_end",
|
|
637
|
+
contentIndex: index,
|
|
638
|
+
toolCall: block,
|
|
639
|
+
partial: output
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Resolve Bedrock's explicit-cache request policy from the catalog's
|
|
645
|
+
* materialized provider contract. Bedrock enforces each model's minimum
|
|
646
|
+
* prefix-token requirement, so this boundary intentionally does not locally
|
|
647
|
+
* count tokens. The emitter prioritizes the final user boundary, then the
|
|
648
|
+
* system boundary, without exceeding the configured checkpoint maximum.
|
|
649
|
+
*
|
|
650
|
+
* `AWS_BEDROCK_FORCE_CACHE` remains an escape hatch for opaque application
|
|
651
|
+
* inference profiles, defaulting those otherwise-unknown models to the
|
|
652
|
+
* existing two-checkpoint layout without inventing 1h retention.
|
|
653
|
+
*/
|
|
654
|
+
function resolvePromptCachePolicy(model, cacheRetention) {
|
|
655
|
+
if (cacheRetention === "none" || model.compat.promptCacheMode === "automatic") return { remainingCheckpoints: 0 };
|
|
656
|
+
const forced = $flag("AWS_BEDROCK_FORCE_CACHE");
|
|
657
|
+
const explicit = model.compat.promptCacheMode === "explicit";
|
|
658
|
+
if (!explicit && !forced) return { remainingCheckpoints: 0 };
|
|
659
|
+
const configuredMaximum = explicit ? model.compat.promptCacheMaximumCheckpoints : 2;
|
|
660
|
+
if (configuredMaximum <= 0) return { remainingCheckpoints: 0 };
|
|
661
|
+
return {
|
|
662
|
+
remainingCheckpoints: Math.min(configuredMaximum, 2),
|
|
663
|
+
...cacheRetention === "long" && model.compat.supportsLongPromptCacheRetention ? { ttl: "1h" } : {}
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
function takeCachePoint(policy) {
|
|
667
|
+
if (policy.remainingCheckpoints <= 0) return void 0;
|
|
668
|
+
policy.remainingCheckpoints--;
|
|
669
|
+
return { cachePoint: {
|
|
670
|
+
type: "default",
|
|
671
|
+
...policy.ttl ? { ttl: policy.ttl } : {}
|
|
672
|
+
} };
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Check if the model supports thinking signatures in reasoningContent.
|
|
676
|
+
* Only Anthropic Claude models support the signature field.
|
|
677
|
+
* Other models (Nova, Titan, Mistral, Llama, etc.) reject it with:
|
|
678
|
+
* "This model doesn't support the reasoningContent.reasoningText.signature field"
|
|
679
|
+
*/
|
|
680
|
+
function supportsThinkingSignature(model) {
|
|
681
|
+
const id = model.id.toLowerCase();
|
|
682
|
+
return id.includes("anthropic.claude") || id.includes("anthropic/claude");
|
|
683
|
+
}
|
|
684
|
+
function buildSystemPrompt(systemPrompt, promptCachePolicy) {
|
|
685
|
+
const prompts = normalizeSystemPrompts(systemPrompt);
|
|
686
|
+
if (prompts.length === 0) return void 0;
|
|
687
|
+
const blocks = prompts.map((prompt) => ({ text: prompt }));
|
|
688
|
+
const cachePoint = takeCachePoint(promptCachePolicy);
|
|
689
|
+
if (cachePoint) blocks.push(cachePoint);
|
|
690
|
+
return blocks;
|
|
691
|
+
}
|
|
692
|
+
function convertMessages(context, model, promptCachePolicy) {
|
|
693
|
+
const result = [];
|
|
694
|
+
const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);
|
|
695
|
+
for (let i = 0; i < transformedMessages.length; i++) {
|
|
696
|
+
const m = transformedMessages[i];
|
|
697
|
+
switch (m.role) {
|
|
698
|
+
case "developer":
|
|
699
|
+
case "user":
|
|
700
|
+
if (typeof m.content === "string") {
|
|
701
|
+
if (!m.content || m.content.trim() === "") continue;
|
|
702
|
+
result.push({
|
|
703
|
+
role: "user",
|
|
704
|
+
content: [{ text: m.content.toWellFormed() }]
|
|
705
|
+
});
|
|
706
|
+
} else {
|
|
707
|
+
const contentBlocks = [];
|
|
708
|
+
for (const c of m.content) switch (c.type) {
|
|
709
|
+
case "text": {
|
|
710
|
+
const text = c.text.toWellFormed();
|
|
711
|
+
if (text.trim().length === 0) continue;
|
|
712
|
+
contentBlocks.push({ text });
|
|
713
|
+
break;
|
|
714
|
+
}
|
|
715
|
+
case "image":
|
|
716
|
+
contentBlocks.push({ image: createImageBlock(c.mimeType, c.data) });
|
|
717
|
+
break;
|
|
718
|
+
default: throw new ValidationError("Unknown user content type");
|
|
719
|
+
}
|
|
720
|
+
if (contentBlocks.length === 0) continue;
|
|
721
|
+
result.push({
|
|
722
|
+
role: "user",
|
|
723
|
+
content: contentBlocks
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
break;
|
|
727
|
+
case "assistant": {
|
|
728
|
+
if (m.content.length === 0) continue;
|
|
729
|
+
const contentBlocks = [];
|
|
730
|
+
for (const c of m.content) switch (c.type) {
|
|
731
|
+
case "text":
|
|
732
|
+
if (c.text.trim().length === 0) continue;
|
|
733
|
+
contentBlocks.push({ text: c.text.toWellFormed() });
|
|
734
|
+
break;
|
|
735
|
+
case "toolCall":
|
|
736
|
+
contentBlocks.push({ toolUse: {
|
|
737
|
+
toolUseId: normalizeToolCallId(c.id),
|
|
738
|
+
name: c.name,
|
|
739
|
+
input: c.arguments
|
|
740
|
+
} });
|
|
741
|
+
break;
|
|
742
|
+
case "thinking":
|
|
743
|
+
if (c.thinking.trim().length === 0) continue;
|
|
744
|
+
if (c.thinkingSignature) contentBlocks.push({ reasoningContent: { reasoningText: {
|
|
745
|
+
text: c.thinking.toWellFormed(),
|
|
746
|
+
signature: c.thinkingSignature
|
|
747
|
+
} } });
|
|
748
|
+
else if (!supportsThinkingSignature(model)) contentBlocks.push({ reasoningContent: { reasoningText: { text: c.thinking.toWellFormed() } } });
|
|
749
|
+
else contentBlocks.push({ text: renderDemotedThinking(model.id, c.thinking) });
|
|
750
|
+
break;
|
|
751
|
+
default: throw new ValidationError("Unknown assistant content type");
|
|
752
|
+
}
|
|
753
|
+
if (contentBlocks.length === 0) continue;
|
|
754
|
+
result.push({
|
|
755
|
+
role: "assistant",
|
|
756
|
+
content: contentBlocks
|
|
757
|
+
});
|
|
758
|
+
break;
|
|
759
|
+
}
|
|
760
|
+
case "toolResult": {
|
|
761
|
+
const toolResults = [];
|
|
762
|
+
toolResults.push({ toolResult: {
|
|
763
|
+
toolUseId: normalizeToolCallId(m.toolCallId),
|
|
764
|
+
content: m.content.map((c) => c.type === "image" ? { image: createImageBlock(c.mimeType, c.data) } : { text: c.text.toWellFormed() }),
|
|
765
|
+
status: m.isError ? "error" : "success"
|
|
766
|
+
} });
|
|
767
|
+
let j = i + 1;
|
|
768
|
+
while (j < transformedMessages.length && transformedMessages[j].role === "toolResult") {
|
|
769
|
+
const nextMsg = transformedMessages[j];
|
|
770
|
+
toolResults.push({ toolResult: {
|
|
771
|
+
toolUseId: normalizeToolCallId(nextMsg.toolCallId),
|
|
772
|
+
content: nextMsg.content.map((c) => c.type === "image" ? { image: createImageBlock(c.mimeType, c.data) } : { text: c.text.toWellFormed() }),
|
|
773
|
+
status: nextMsg.isError ? "error" : "success"
|
|
774
|
+
} });
|
|
775
|
+
j++;
|
|
776
|
+
}
|
|
777
|
+
i = j - 1;
|
|
778
|
+
result.push({
|
|
779
|
+
role: "user",
|
|
780
|
+
content: toolResults
|
|
781
|
+
});
|
|
782
|
+
break;
|
|
783
|
+
}
|
|
784
|
+
default: throw new ValidationError("Unknown message role");
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
if (result.length > 0) {
|
|
788
|
+
const lastMessage = result[result.length - 1];
|
|
789
|
+
if (lastMessage.role === "user" && lastMessage.content) {
|
|
790
|
+
const cachePoint = takeCachePoint(promptCachePolicy);
|
|
791
|
+
if (cachePoint) lastMessage.content.push(cachePoint);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
return result;
|
|
795
|
+
}
|
|
796
|
+
function messagesHaveToolBlocks(messages) {
|
|
797
|
+
for (const message of messages) for (const block of message.content) if ("toolUse" in block || "toolResult" in block) return true;
|
|
798
|
+
return false;
|
|
799
|
+
}
|
|
800
|
+
function convertToolSpec(tool) {
|
|
801
|
+
return { toolSpec: {
|
|
802
|
+
name: tool.name,
|
|
803
|
+
description: tool.description || "",
|
|
804
|
+
inputSchema: { json: toolWireSchema(tool) }
|
|
805
|
+
} };
|
|
806
|
+
}
|
|
807
|
+
function planToolConfig(tools, toolChoice, messages) {
|
|
808
|
+
const activeTools = tools ?? [];
|
|
809
|
+
const hasTools = activeTools.length > 0;
|
|
810
|
+
const historyHasToolBlocks = messagesHaveToolBlocks(messages);
|
|
811
|
+
if (toolChoice === "none") {
|
|
812
|
+
if (!historyHasToolBlocks) return {
|
|
813
|
+
toolConfig: void 0,
|
|
814
|
+
sentinelInjected: false
|
|
815
|
+
};
|
|
816
|
+
if (!hasTools) return {
|
|
817
|
+
toolConfig: {
|
|
818
|
+
tools: [NO_TOOLS_SENTINEL],
|
|
819
|
+
toolChoice: { auto: {} }
|
|
820
|
+
},
|
|
821
|
+
sentinelInjected: true
|
|
822
|
+
};
|
|
823
|
+
return {
|
|
824
|
+
toolConfig: { tools: activeTools.map(convertToolSpec) },
|
|
825
|
+
sentinelInjected: false
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
if (!hasTools) return {
|
|
829
|
+
toolConfig: void 0,
|
|
830
|
+
sentinelInjected: false
|
|
831
|
+
};
|
|
832
|
+
const bedrockTools = activeTools.map(convertToolSpec);
|
|
833
|
+
let bedrockToolChoice;
|
|
834
|
+
switch (toolChoice) {
|
|
835
|
+
case "auto":
|
|
836
|
+
bedrockToolChoice = { auto: {} };
|
|
837
|
+
break;
|
|
838
|
+
case "any":
|
|
839
|
+
bedrockToolChoice = { any: {} };
|
|
840
|
+
break;
|
|
841
|
+
default: if (toolChoice?.type === "tool") bedrockToolChoice = { tool: { name: toolChoice.name } };
|
|
842
|
+
}
|
|
843
|
+
return {
|
|
844
|
+
toolConfig: {
|
|
845
|
+
tools: bedrockTools,
|
|
846
|
+
toolChoice: bedrockToolChoice
|
|
847
|
+
},
|
|
848
|
+
sentinelInjected: false
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
function mapStopReason(reason) {
|
|
852
|
+
switch (reason) {
|
|
853
|
+
case "end_turn":
|
|
854
|
+
case "stop_sequence": return "stop";
|
|
855
|
+
case "max_tokens":
|
|
856
|
+
case "model_context_window_exceeded": return "length";
|
|
857
|
+
case "tool_use": return "toolUse";
|
|
858
|
+
default: return "error";
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
function buildAdditionalModelRequestFields(model, options) {
|
|
862
|
+
const reasoning = options.reasoning;
|
|
863
|
+
if (!reasoning || !model.reasoning) return void 0;
|
|
864
|
+
if (model.thinking?.mode === "anthropic-adaptive") {
|
|
865
|
+
const effort = mapEffortToAnthropicAdaptiveEffort(model, reasoning);
|
|
866
|
+
const adaptive = { type: "adaptive" };
|
|
867
|
+
if (model.thinking?.supportsDisplay) adaptive.display = options.thinkingDisplay ?? "summarized";
|
|
868
|
+
return {
|
|
869
|
+
thinking: adaptive,
|
|
870
|
+
output_config: { effort }
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
const level = requireSupportedEffort(model, reasoning);
|
|
874
|
+
const result = { thinking: {
|
|
875
|
+
type: "enabled",
|
|
876
|
+
budget_tokens: options.thinkingBudgets?.[level] ?? {
|
|
877
|
+
minimal: 1024,
|
|
878
|
+
low: 2048,
|
|
879
|
+
medium: 8192,
|
|
880
|
+
high: 16384,
|
|
881
|
+
xhigh: 32768,
|
|
882
|
+
max: 32768
|
|
883
|
+
}[level],
|
|
884
|
+
display: options.thinkingDisplay ?? "summarized"
|
|
885
|
+
} };
|
|
886
|
+
if (options.interleavedThinking) result.anthropic_beta = ["interleaved-thinking-2025-05-14"];
|
|
887
|
+
return result;
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Bedrock's wire format expects the image as `{ source: { bytes: <base64-string> }, format }`.
|
|
891
|
+
* The caller already passes base64-encoded data, so no decode/re-encode round-trip is needed.
|
|
892
|
+
*/
|
|
893
|
+
function createImageBlock(mimeType, data) {
|
|
894
|
+
let format;
|
|
895
|
+
switch (mimeType) {
|
|
896
|
+
case "image/jpeg":
|
|
897
|
+
case "image/jpg":
|
|
898
|
+
format = "jpeg";
|
|
899
|
+
break;
|
|
900
|
+
case "image/png":
|
|
901
|
+
format = "png";
|
|
902
|
+
break;
|
|
903
|
+
case "image/gif":
|
|
904
|
+
format = "gif";
|
|
905
|
+
break;
|
|
906
|
+
case "image/webp":
|
|
907
|
+
format = "webp";
|
|
908
|
+
break;
|
|
909
|
+
default: throw new ValidationError(`Unknown image type: ${mimeType}`);
|
|
910
|
+
}
|
|
911
|
+
return {
|
|
912
|
+
source: { bytes: data },
|
|
913
|
+
format
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
//#endregion
|
|
917
|
+
export { streamBedrock };
|