@oh-my-pi/pi-ai 17.2.12 → 17.2.14
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/CHANGELOG.md +25 -0
- package/dist/types/error/aws.d.ts +5 -1
- package/dist/types/providers/aws-credentials.d.ts +4 -3
- package/dist/types/providers/azure-openai-responses.d.ts +1 -0
- package/dist/types/providers/cursor/exec-modern.d.ts +1 -1
- package/dist/types/providers/cursor-pi-args.d.ts +14 -0
- package/dist/types/providers/openai-codex/request-transformer.d.ts +2 -0
- package/dist/types/providers/openai-responses.d.ts +1 -0
- package/dist/types/providers/openai-shared.d.ts +19 -1
- package/dist/types/types.d.ts +12 -0
- package/dist/types/usage/cursor.d.ts +11 -0
- package/dist/types/utils/block-symbols.d.ts +12 -0
- package/package.json +5 -5
- package/src/dialect/owned-stream.ts +3 -0
- package/src/error/aws.ts +5 -1
- package/src/providers/amazon-bedrock.ts +38 -0
- package/src/providers/aws-credentials.ts +222 -29
- package/src/providers/azure-openai-responses.ts +1 -0
- package/src/providers/cursor/exec-modern.ts +1 -0
- package/src/providers/cursor-pi-args.ts +22 -0
- package/src/providers/cursor.ts +81 -1
- package/src/providers/google-gemini-cli.ts +49 -15
- package/src/providers/google-shared.ts +7 -1
- package/src/providers/openai-codex/request-transformer.ts +47 -21
- package/src/providers/openai-codex-responses.ts +3 -3
- package/src/providers/openai-reasoning-fallback.ts +21 -8
- package/src/providers/openai-responses.ts +77 -12
- package/src/providers/openai-shared.ts +81 -1
- package/src/providers/pi-native-server.ts +1 -0
- package/src/providers/register-builtins.ts +18 -14
- package/src/registry/aws.ts +13 -6
- package/src/registry/oauth/callback-server.ts +93 -5
- package/src/stream.ts +5 -0
- package/src/types.ts +12 -0
- package/src/usage/cursor.ts +174 -42
- package/src/usage/kimi.ts +29 -5
- package/src/usage/openai-codex-reset.ts +2 -1
- package/src/usage/openai-codex.ts +2 -1
- package/src/usage/zai.ts +2 -1
- package/src/utils/aws-profile.ts +39 -1
- package/src/utils/block-symbols.ts +18 -0
- package/src/utils/leaked-thinking-stream.ts +3 -0
- package/src/utils/openrouter-headers.ts +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [17.2.14] - 2026-08-11
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added `forceReasoningOff` and `disableReasoning` options to disable reasoning in OpenAI and Azure OpenAI models
|
|
10
|
+
|
|
11
|
+
## [17.2.13] - 2026-08-11
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Standardized first-party outbound User-Agent headers on `omp/<version>` via the shared `USER_AGENT` utility.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Fixed the Amazon Bedrock and Cursor transports ignoring `StreamOptions.headers`; both built their request headers from scratch, so caller-supplied tracing or attribution headers were silently dropped while working on every other provider ([#8107](https://github.com/can1357/oh-my-pi/pull/8107) by [@svperfecta](https://github.com/svperfecta)).
|
|
20
|
+
- Fixed Antigravity Flash turns hanging after successful response headers when the endpoint never emitted an SSE event; the provider now cancels the stalled body and fails over after 60 seconds while retaining the longer allowance for Pro reasoning starts.
|
|
21
|
+
- Fixed Cursor exec-bridge bash/grep calls failing ArkType validation when the server omitted optional frame fields: synthesized and executed tool args now drop `undefined` keys (`cwd`, `case`, `skip`, `timeout`) instead of writing `optional: value || undefined`.
|
|
22
|
+
- Fixed Cursor sessions double-executing settled tools when `tools.format` is an owned dialect (e.g. `gemini`): `wrapInbandToolStream` rebuilt toolCall blocks without copying `kCursorExecResolved`, so agent-loop re-ran bash/grep/todo and appended a second result for the same call id.
|
|
23
|
+
- Fixed Codex Responses Lite requests for opaque model codenames such as Daybreak omitting the required `reasoning.context: "all_turns"` value and failing with HTTP 400.
|
|
24
|
+
- Fixed Cursor personal usage reporting for current Pro / Pro+ / Ultra `/api/usage-summary` payloads that expose `individualUsage.plan` (and optional `onDemand`) instead of the older `individualUsage.overall` bucket ([#7998](https://github.com/can1357/oh-my-pi/pull/7998) by [@dnth](https://github.com/dnth)).
|
|
25
|
+
- Allowed passive Google callers to accept empty or thinking-only `STOP` responses as successful silence instead of exhausting the provider's empty-response retry budget. ([#8223](https://github.com/can1357/oh-my-pi/issues/8223))
|
|
26
|
+
- Fixed the AWS credential resolver ignoring `role_arn` profiles: shared-config role chaining (`source_profile` recursion, `web_identity_token_file`, `credential_source`) now resolves via STS `AssumeRole`/`AssumeRoleWithWebIdentity`, honoring `role_session_name`/`duration_seconds`/`external_id`, so Bedrock is detected on EKS/IRSA and multi-account setups instead of reporting "No models available" ([#8209](https://github.com/can1357/oh-my-pi/issues/8209)).
|
|
27
|
+
- Fixed Bedrock availability being under-detected on Nitro/EKS hosts: the EC2 metadata probe now recognizes Nitro DMI markers (`board_asset_tag` instance ids, `Amazon EC2` vendor fields) in addition to the Xen `ec2` UUID prefix ([#8209](https://github.com/can1357/oh-my-pi/issues/8209)).
|
|
28
|
+
- Fixed DeepSeek Responses targets (opencode-go) rejecting a thinking-mode continuation with `400 The reasoning_text in the thinking mode must be passed back to the API` after a prewalk hand-off plus mid-run compaction: the Responses input builder re-encoded replayed assistant turns without a reasoning item, so the request enabled reasoning but shipped no `reasoning_text`. The encoder now synthesizes a `reasoning_text` reasoning item for every replayed assistant turn when the target requires reasoning replay in thinking mode (`requiresReasoningContentForAllAssistantTurns` / `requiresReasoningContentForToolCalls`), mirroring the chat-completions `reasoning_content` safety net ([#8248](https://github.com/can1357/oh-my-pi/issues/8248)).
|
|
29
|
+
|
|
5
30
|
## [17.2.12] - 2026-08-08
|
|
6
31
|
|
|
7
32
|
### Fixed
|
|
@@ -13,7 +13,11 @@ export type AwsCredentialsErrorKind =
|
|
|
13
13
|
/** STS web-identity exchange failed or returned malformed credentials. */
|
|
14
14
|
| "web-identity"
|
|
15
15
|
/** ECS/container credential endpoint failed or returned malformed credentials. */
|
|
16
|
-
| "container"
|
|
16
|
+
| "container"
|
|
17
|
+
/** Shared-config role chain is misconfigured (cycle, missing source_profile, unsupported credential_source). */
|
|
18
|
+
| "profile"
|
|
19
|
+
/** STS `AssumeRole` call failed or returned malformed credentials. */
|
|
20
|
+
| "assume-role";
|
|
17
21
|
/** A failure resolving AWS credentials for the Bedrock provider. */
|
|
18
22
|
export declare class AwsCredentialsError extends Error {
|
|
19
23
|
readonly kind: AwsCredentialsErrorKind;
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* 1. Static credentials from the environment
|
|
6
6
|
* (`AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY` [+ `AWS_SESSION_TOKEN`]).
|
|
7
7
|
* 2. Web identity (`AWS_WEB_IDENTITY_TOKEN_FILE` + `AWS_ROLE_ARN`).
|
|
8
|
-
* 3. Profile in `~/.aws/credentials` (and `~/.aws/config` for SSO):
|
|
9
|
-
* - static keys, SSO, or `
|
|
8
|
+
* 3. Profile in `~/.aws/credentials` (and `~/.aws/config` for SSO/roles):
|
|
9
|
+
* - static keys, SSO, `credential_process`, or `role_arn` role chaining
|
|
10
|
+
* (`source_profile` recursion, `web_identity_token_file`, `credential_source`).
|
|
10
11
|
* 4. ECS/container credentials from `AWS_CONTAINER_CREDENTIALS_*`.
|
|
11
12
|
* 5. EC2 IMDSv2 when metadata is enabled.
|
|
12
13
|
*
|
|
@@ -14,7 +15,7 @@
|
|
|
14
15
|
* 60 s before `Expiration` to absorb clock skew.
|
|
15
16
|
*/
|
|
16
17
|
import type { FetchImpl } from "../types.js";
|
|
17
|
-
import type
|
|
18
|
+
import { type AwsCredentials } from "./aws-sigv4.js";
|
|
18
19
|
export interface ResolvedCredentials extends AwsCredentials {
|
|
19
20
|
/** Absolute expiration timestamp in ms. `undefined` for non-expiring static creds. */
|
|
20
21
|
expiresAt?: number;
|
|
@@ -17,7 +17,7 @@ import type { ToolResultMessage } from "../../types.js";
|
|
|
17
17
|
* virtual registry. Re-exported here because this is where the frame builders
|
|
18
18
|
* and their translation are consumed together.
|
|
19
19
|
*/
|
|
20
|
-
export { piEscapeRegexLiteral, piGrepSkip, piJoinPath, piLimit, piLsPath, piReadDisplayPath, piReadPath, piReadPathHasRange, piTimeout, } from "../cursor-pi-args.js";
|
|
20
|
+
export { omitUndefinedArgs, piEscapeRegexLiteral, piGrepSkip, piJoinPath, piLimit, piLsPath, piReadDisplayPath, piReadPath, piReadPathHasRange, piTimeout, } from "../cursor-pi-args.js";
|
|
21
21
|
/** Flatten a tool result's content into the single `output` string the Pi frames carry. */
|
|
22
22
|
export declare function piOutputText(toolResult: ToolResultMessage): string;
|
|
23
23
|
/**
|
|
@@ -103,3 +103,17 @@ export declare function piLimit(limit: number | undefined): number | undefined;
|
|
|
103
103
|
* Negative values have no local meaning and fall back to the default.
|
|
104
104
|
*/
|
|
105
105
|
export declare function piTimeout(timeout: number | undefined): number | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Drop keys whose value is `undefined` so optional local-tool kwargs stay
|
|
108
|
+
* absent rather than present-as-undefined.
|
|
109
|
+
*
|
|
110
|
+
* The Cursor exec bridge historically wrote forms like
|
|
111
|
+
* `cwd: workingDirectory || undefined` and
|
|
112
|
+
* `case: caseInsensitive === true ? false : undefined`. ArkType rejects a
|
|
113
|
+
* present `undefined` on an optional field (`was undefined`) even though
|
|
114
|
+
* omitting the key is valid — which flooded Cursor sessions with bash/grep
|
|
115
|
+
* validation errors for otherwise fine frames.
|
|
116
|
+
*/
|
|
117
|
+
export declare function omitUndefinedArgs<T extends Record<string, unknown>>(args: T): {
|
|
118
|
+
[K in keyof T]?: Exclude<T[K], undefined>;
|
|
119
|
+
};
|
|
@@ -13,6 +13,8 @@ export interface ReasoningConfig {
|
|
|
13
13
|
export interface CodexRequestOptions {
|
|
14
14
|
/** User-facing effort; maps 1:1 onto the wire tier of the same name. */
|
|
15
15
|
reasoningEffort?: CodexCallerEffort | "none";
|
|
16
|
+
/** Suppress native reasoning by sending `reasoning.effort: "none"`. */
|
|
17
|
+
reasoningOff?: boolean;
|
|
16
18
|
reasoningSummary?: ReasoningConfig["summary"] | null;
|
|
17
19
|
/** Explicit `reasoning.context` override. Omitted by default; Responses Lite forces `all_turns` as required by that transport. */
|
|
18
20
|
reasoningContext?: CodexReasoningContext;
|
|
@@ -114,6 +114,7 @@ type OpenAIResponsesSamplingParams = ResponseCreateParamsStreaming & {
|
|
|
114
114
|
export declare const streamOpenAIResponses: StreamFunction<"openai-responses">;
|
|
115
115
|
export declare function buildParams(model: Model<"openai-responses">, context: Context, options: OpenAIResponsesOptions | undefined, providerSessionState: OpenAIResponsesProviderSessionState | undefined, strictToolsScope?: OpenAIStrictToolsScope, disableStrictToolsOverride?: boolean, statefulCacheBaseline?: ResponseInput): {
|
|
116
116
|
params: OpenAIResponsesSamplingParams;
|
|
117
|
+
trailingScaffoldingItems: number;
|
|
117
118
|
strictToolsApplied: boolean;
|
|
118
119
|
};
|
|
119
120
|
/**
|
|
@@ -419,6 +419,14 @@ export interface BuildResponsesInputOptions<TApi extends Api> {
|
|
|
419
419
|
repairOrphanOutputs?: boolean;
|
|
420
420
|
/** Preserve assistant message item IDs from text signatures during fallback replay. */
|
|
421
421
|
preserveAssistantMessageIds?: boolean;
|
|
422
|
+
/**
|
|
423
|
+
* Synthesize a reasoning item for every replayed assistant turn that carries
|
|
424
|
+
* content but no reasoning item. Set for DeepSeek-family Responses targets
|
|
425
|
+
* that reject a thinking-mode continuation lacking `reasoning_text`.
|
|
426
|
+
*/
|
|
427
|
+
requiresReasoningReplayForAllTurns?: boolean;
|
|
428
|
+
/** As {@link requiresReasoningReplayForAllTurns}, but only for turns that contain a tool call. */
|
|
429
|
+
requiresReasoningReplayForToolCalls?: boolean;
|
|
422
430
|
}
|
|
423
431
|
/**
|
|
424
432
|
* Escape reserved Harmony control tokens in the free-text fields of replayed
|
|
@@ -443,7 +451,7 @@ export interface BuildResponsesInputOptions<TApi extends Api> {
|
|
|
443
451
|
*/
|
|
444
452
|
export declare function escapeReplayedControlTokens(items: ResponseInput): ResponseInput;
|
|
445
453
|
export declare function buildResponsesInput<TApi extends Api>(options: BuildResponsesInputOptions<TApi>): ResponseInput;
|
|
446
|
-
export declare function convertResponsesAssistantMessage<TApi extends Api>(assistantMsg: AssistantMessage, model: Model<TApi>, msgIndex: number, knownCallIds: Set<string>, includeThinkingSignatures?: boolean, customCallIds?: Set<string>, preserveMessageIds?: boolean, supportsCustomToolCalls?: boolean, customToolWireNameMap?: ReadonlyMap<string, string>, computerCallIds?: Set<string
|
|
454
|
+
export declare function convertResponsesAssistantMessage<TApi extends Api>(assistantMsg: AssistantMessage, model: Model<TApi>, msgIndex: number, knownCallIds: Set<string>, includeThinkingSignatures?: boolean, customCallIds?: Set<string>, preserveMessageIds?: boolean, supportsCustomToolCalls?: boolean, customToolWireNameMap?: ReadonlyMap<string, string>, computerCallIds?: Set<string>, requiresReasoningReplayForAllTurns?: boolean, requiresReasoningReplayForToolCalls?: boolean): ResponseInput;
|
|
447
455
|
/** Appends one tool result while keeping consecutive outputs ahead of its synthetic image messages. */
|
|
448
456
|
export declare function appendResponsesToolResultMessages<TApi extends Api>(messages: ResponseInput, toolResult: ToolResultMessage, model: Model<TApi>, strictResponsesPairing: boolean, supportsImageDetailOriginal: boolean, knownCallIds: ReadonlySet<string>, customCallIds?: ReadonlySet<string>, supportsCustomToolCalls?: boolean, computerCallIds?: ReadonlySet<string>): void;
|
|
449
457
|
/**
|
|
@@ -497,6 +505,8 @@ export declare function appendMessageContentPart(item: ResponseOutputMessage, pa
|
|
|
497
505
|
export declare function appendMessageTextDelta(item: ResponseOutputMessage, block: TextContent, delta: string, stream: AssistantMessageEventStream, output: AssistantMessage, contentIndex: number, partType: "output_text" | "refusal"): void;
|
|
498
506
|
/** Chooses final message text while treating non-empty terminal content as authoritative. */
|
|
499
507
|
export declare function finalizeMessageText(item: ResponseOutputMessage, streamedText: string): string;
|
|
508
|
+
export declare const JUICE_EFFORT_MAP: Record<string, number>;
|
|
509
|
+
export declare function getJuiceValue(effort?: string): number;
|
|
500
510
|
export declare function accumulateToolCallArgumentsDelta(block: ResponsesToolCallBlock, delta: string, stream: AssistantMessageEventStream, output: AssistantMessage, contentIndex: number): void;
|
|
501
511
|
/**
|
|
502
512
|
* Finalize streamed function-call arguments from the authoritative `.done`
|
|
@@ -583,6 +593,14 @@ type ReasoningOptions = {
|
|
|
583
593
|
export interface ApplyResponsesCompatPolicyOptions {
|
|
584
594
|
reasoningSummary?: "auto" | "detailed" | "concise" | null;
|
|
585
595
|
mapEffort?: (effort: string) => string;
|
|
596
|
+
/**
|
|
597
|
+
* Suppress native reasoning by sending `reasoning.effort: "none"` — the only
|
|
598
|
+
* disable level the Responses API defines (`"off"` is not a wire value and
|
|
599
|
+
* 400s everywhere). Gateways that reject `none` for a given model are
|
|
600
|
+
* handled by the reasoning-effort fallback retry, which clamps to the
|
|
601
|
+
* lowest level the error reports as allowed.
|
|
602
|
+
*/
|
|
603
|
+
forceReasoningOff?: boolean;
|
|
586
604
|
}
|
|
587
605
|
export declare function applyResponsesCompatPolicy<P extends ResponseCreateParamsStreaming>(params: P, policy: OpenAICompatPolicy, options: ApplyResponsesCompatPolicyOptions | undefined): void;
|
|
588
606
|
/**
|
package/dist/types/types.d.ts
CHANGED
|
@@ -294,6 +294,11 @@ export interface StreamOptions {
|
|
|
294
294
|
* `false` so `previous_response_id` cannot explain a result.
|
|
295
295
|
*/
|
|
296
296
|
statefulResponses?: boolean;
|
|
297
|
+
/**
|
|
298
|
+
* Emit `reasoning: { effort: "none" }` for OpenAI Responses and Codex requests.
|
|
299
|
+
* Used when a caller supplies an external reasoning scratchpad; other transports ignore it.
|
|
300
|
+
*/
|
|
301
|
+
forceReasoningOff?: boolean;
|
|
297
302
|
/**
|
|
298
303
|
* Provider-scoped mutable state store for this agent session.
|
|
299
304
|
* Providers can use this to persist transport/session state between turns.
|
|
@@ -368,6 +373,13 @@ export interface StreamOptions {
|
|
|
368
373
|
* Optional retry delay hook for tests and transports that need custom scheduling.
|
|
369
374
|
*/
|
|
370
375
|
providerRetryWait?: (delayMs: number, signal?: AbortSignal) => Promise<void>;
|
|
376
|
+
/**
|
|
377
|
+
* Accept a Google `STOP` response with no visible text or tool call as a
|
|
378
|
+
* successful completion. Passive callers such as advisors use this because
|
|
379
|
+
* silence is a valid result; interactive agent turns retain empty-response
|
|
380
|
+
* retries by default. Ignored by non-Google providers.
|
|
381
|
+
*/
|
|
382
|
+
acceptEmptyResponse?: boolean;
|
|
371
383
|
/**
|
|
372
384
|
* Optional `fetch` implementation override. Providers route every HTTP
|
|
373
385
|
* request — direct calls, SDK clients, and retry helpers — through this
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import type { UsageProvider, UsageReport } from "../usage.js";
|
|
2
|
+
/**
|
|
3
|
+
* Cursor's `/api/usage-summary` has shipped two personal-bucket shapes:
|
|
4
|
+
* - Enterprise/team dashboards historically exposed `individualUsage.overall`
|
|
5
|
+
* - Current Pro / Pro+ / Ultra dashboards expose `individualUsage.plan`
|
|
6
|
+
* (plus optional `onDemand`)
|
|
7
|
+
*
|
|
8
|
+
* Prefer a *usable* overall bucket; if overall is absent/disabled/malformed,
|
|
9
|
+
* fall through to plan rails (`autoPercentUsed` / `apiPercentUsed`). Always
|
|
10
|
+
* consider on-demand afterward so a valid on-demand meter is not dropped when
|
|
11
|
+
* the included plan bucket is empty.
|
|
12
|
+
*/
|
|
2
13
|
export declare function parseCursorIndividualUsage(payload: unknown, fetchedAt?: number): UsageReport | null;
|
|
3
14
|
export declare function parseCursorUsage(payload: unknown, fetchedAt?: number): UsageReport | null;
|
|
4
15
|
export declare const cursorUsageProvider: UsageProvider;
|
|
@@ -45,6 +45,18 @@ export declare const kCursorExecResolved: unique symbol;
|
|
|
45
45
|
export type CursorExecResolvedCarrier = object & {
|
|
46
46
|
[kCursorExecResolved]?: true;
|
|
47
47
|
};
|
|
48
|
+
/** True when a toolCall block was already executed by Cursor's exec channel. */
|
|
49
|
+
export declare function isCursorExecResolved(block: CursorExecResolvedCarrier | null | undefined): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Copy {@link kCursorExecResolved} onto a cloned/projected toolCall block.
|
|
52
|
+
*
|
|
53
|
+
* Stream projectors (owned/in-band dialect, leaked-thinking heal) rebuild
|
|
54
|
+
* toolCall objects field-by-field. Dropping this marker lets `agent-loop.ts`
|
|
55
|
+
* re-execute a call Cursor already settled — duplicate toolResults and a
|
|
56
|
+
* second bash/write/delete. Partial-JSON is already copied explicitly; this
|
|
57
|
+
* marker is the other load-bearing symbol that must survive the same way.
|
|
58
|
+
*/
|
|
59
|
+
export declare function copyCursorExecResolved(target: CursorExecResolvedCarrier, source: CursorExecResolvedCarrier): void;
|
|
48
60
|
/**
|
|
49
61
|
* Marks a text block synthesized by cross-model thinking demotion in
|
|
50
62
|
* `transformMessages`. Converters that flatten adjacent text blocks into one
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-ai",
|
|
4
|
-
"version": "17.2.
|
|
4
|
+
"version": "17.2.14",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -38,10 +38,10 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@bufbuild/protobuf": "^2.12.1",
|
|
41
|
-
"@oh-my-pi/omptype": "17.2.
|
|
42
|
-
"@oh-my-pi/pi-catalog": "17.2.
|
|
43
|
-
"@oh-my-pi/pi-utils": "17.2.
|
|
44
|
-
"@oh-my-pi/pi-wire": "17.2.
|
|
41
|
+
"@oh-my-pi/omptype": "17.2.14",
|
|
42
|
+
"@oh-my-pi/pi-catalog": "17.2.14",
|
|
43
|
+
"@oh-my-pi/pi-utils": "17.2.14",
|
|
44
|
+
"@oh-my-pi/pi-wire": "17.2.14"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@bufbuild/protoc-gen-es": "^2.12.1",
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
} from "../types";
|
|
8
8
|
import {
|
|
9
9
|
clearStreamingPartialJson,
|
|
10
|
+
copyCursorExecResolved,
|
|
10
11
|
getStreamingPartialJson,
|
|
11
12
|
type StreamingPartialJsonCarrier,
|
|
12
13
|
setStreamingPartialJson,
|
|
@@ -54,6 +55,7 @@ function cloneToolCall(source: StreamingToolCall): StreamingToolCall {
|
|
|
54
55
|
};
|
|
55
56
|
const partialJson = getStreamingPartialJson(source);
|
|
56
57
|
if (partialJson !== undefined) setStreamingPartialJson(block, partialJson);
|
|
58
|
+
copyCursorExecResolved(block, source);
|
|
57
59
|
return block;
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -65,6 +67,7 @@ function syncToolCall(target: StreamingToolCall, source: StreamingToolCall): voi
|
|
|
65
67
|
const partialJson = getStreamingPartialJson(source);
|
|
66
68
|
if (partialJson === undefined) clearStreamingPartialJson(target);
|
|
67
69
|
else setStreamingPartialJson(target, partialJson);
|
|
70
|
+
copyCursorExecResolved(target, source);
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
function hasNamedNativeToolCall(source: StreamingToolCall | undefined): source is StreamingToolCall {
|
package/src/error/aws.ts
CHANGED
|
@@ -13,7 +13,11 @@ export type AwsCredentialsErrorKind =
|
|
|
13
13
|
/** STS web-identity exchange failed or returned malformed credentials. */
|
|
14
14
|
| "web-identity"
|
|
15
15
|
/** ECS/container credential endpoint failed or returned malformed credentials. */
|
|
16
|
-
| "container"
|
|
16
|
+
| "container"
|
|
17
|
+
/** Shared-config role chain is misconfigured (cycle, missing source_profile, unsupported credential_source). */
|
|
18
|
+
| "profile"
|
|
19
|
+
/** STS `AssumeRole` call failed or returned malformed credentials. */
|
|
20
|
+
| "assume-role";
|
|
17
21
|
|
|
18
22
|
/** A failure resolving AWS credentials for the Bedrock provider. */
|
|
19
23
|
export class AwsCredentialsError extends Error {
|
|
@@ -47,6 +47,19 @@ import { decodeEventStream } from "./aws-eventstream";
|
|
|
47
47
|
import { signRequest } from "./aws-sigv4";
|
|
48
48
|
import { transformMessages } from "./transform-messages";
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Headers SigV4 generates for itself. A caller cannot be allowed to supply these:
|
|
52
|
+
* `signRequest` would sign the caller's value but return its own, so the signature
|
|
53
|
+
* would not match what goes on the wire.
|
|
54
|
+
*/
|
|
55
|
+
const SIGNER_OWNED_HEADERS = new Set(["host", "x-amz-date", "x-amz-content-sha256", "x-amz-security-token"]);
|
|
56
|
+
|
|
57
|
+
/** Headers the Bedrock request sets itself; a caller copy in any casing duplicates them. */
|
|
58
|
+
// `content-length` included: the fetch layer recomputes it from the serialized
|
|
59
|
+
// body, so a caller value would be signed but not sent, and AWS rejects the
|
|
60
|
+
// mismatch.
|
|
61
|
+
const BEDROCK_RESERVED_HEADERS = new Set(["content-type", "accept", "authorization", "content-length"]);
|
|
62
|
+
|
|
50
63
|
export type BedrockThinkingDisplay = "summarized" | "omitted";
|
|
51
64
|
|
|
52
65
|
export interface BedrockOptions extends StreamOptions {
|
|
@@ -356,7 +369,32 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream"> = (
|
|
|
356
369
|
|
|
357
370
|
const bodyText = JSON.stringify(commandInput);
|
|
358
371
|
const body = new TextEncoder().encode(bodyText);
|
|
372
|
+
// Caller headers are merged BEFORE signing, so SigV4 covers them and they
|
|
373
|
+
// reach the wire. Bedrock built its header map from scratch and ignored
|
|
374
|
+
// `options.headers` entirely, so tracing/attribution headers set by a
|
|
375
|
+
// caller (or by a `before_provider_headers` extension) were silently
|
|
376
|
+
// dropped here while working on every other provider. Content-type and
|
|
377
|
+
// accept stay last: the eventstream framing is not the caller's to change.
|
|
378
|
+
//
|
|
379
|
+
// The signer's OWN headers are dropped first, and that is load-bearing:
|
|
380
|
+
// `signRequest` lets a caller value overwrite `host`/`x-amz-*` in the map
|
|
381
|
+
// it signs, but always RETURNS the generated ones, which `requestHeaders`
|
|
382
|
+
// below then puts on the wire. A caller supplying any of them would sign
|
|
383
|
+
// one set of values and send another, and Bedrock would reject every
|
|
384
|
+
// request with a signature mismatch.
|
|
385
|
+
// Lower-cased, and names the request sets itself are dropped. Keeping a
|
|
386
|
+
// caller `Content-Type` beside the fixed `content-type` leaves TWO object
|
|
387
|
+
// keys: SigV4 signs one value while fetch canonicalizes both into a single
|
|
388
|
+
// comma-joined wire header, so AWS validates different bytes than were
|
|
389
|
+
// signed and rejects the request.
|
|
390
|
+
const callerHeaders: Record<string, string> = {};
|
|
391
|
+
for (const [name, value] of Object.entries(options?.headers ?? {})) {
|
|
392
|
+
const field = name.toLowerCase();
|
|
393
|
+
if (SIGNER_OWNED_HEADERS.has(field) || BEDROCK_RESERVED_HEADERS.has(field)) continue;
|
|
394
|
+
callerHeaders[field] = value;
|
|
395
|
+
}
|
|
359
396
|
const baseHeaders: Record<string, string> = {
|
|
397
|
+
...callerHeaders,
|
|
360
398
|
"content-type": "application/json",
|
|
361
399
|
accept: "application/vnd.amazon.eventstream",
|
|
362
400
|
};
|