
































@@ -160,34 +160,28 @@ function makeAppInferenceProfileDescriptor(modelId: string): never {
160160} as never;
161161}
162162163-/**
164- * Call wrapStreamFn and then invoke the returned stream function, capturing
165- * the payload via the onPayload hook that streamWithPayloadPatch installs.
166- */
167163async function callWrappedStream(
168164provider: RegisteredProviderPlugin,
169165modelId: string,
170166modelDescriptor: never,
171167config?: OpenClawConfig,
168+extraParams?: Record<string, unknown>,
169+payload: Record<string, unknown> = {},
172170): Promise<Record<string, unknown>> {
173171const wrapped = provider.wrapStreamFn?.({
174172provider: "amazon-bedrock",
175173 modelId,
176174 config,
177175streamFn: spyStreamFn,
176+ ...(extraParams ? { extraParams } : {}),
178177} as never);
179178180-// The wrapped stream returns the options object (from spyStreamFn).
181-// For guardrail-wrapped streams, streamWithPayloadPatch intercepts onPayload,
182-// so we need to invoke onPayload on the returned options to trigger the patch.
183179const result = wrapped?.(modelDescriptor, { messages: [] } as never, {}) as unknown as Record<
184180string,
185181unknown
186182>;
187183188-// If onPayload was installed by streamWithPayloadPatch, call it to apply the patch.
189184if (typeof result?.onPayload === "function") {
190-const payload: Record<string, unknown> = {};
191185await (result.onPayload as (p: Record<string, unknown>, model: unknown) => Promise<unknown>)(
192186payload,
193187modelDescriptor,
@@ -719,6 +713,89 @@ describe("amazon-bedrock provider plugin", () => {
719713});
720714});
721715716+describe("service tier", () => {
717+const CONVERSE_MODEL_DESCRIPTOR = {
718+api: "bedrock-converse-stream",
719+provider: "amazon-bedrock",
720+id: NON_ANTHROPIC_MODEL,
721+} as never;
722+723+it("injects serviceTier for valid camelCase value ('flex')", async () => {
724+const provider = await registerWithConfig(undefined);
725+const result = await callWrappedStream(
726+provider,
727+NON_ANTHROPIC_MODEL,
728+CONVERSE_MODEL_DESCRIPTOR,
729+runtimePluginConfig(undefined),
730+{ serviceTier: "flex" },
731+);
732+expect(result._capturedPayload).toMatchObject({ serviceTier: { type: "flex" } });
733+});
734+735+it("injects serviceTier for valid snake_case value ('priority')", async () => {
736+const provider = await registerWithConfig(undefined);
737+const result = await callWrappedStream(
738+provider,
739+NON_ANTHROPIC_MODEL,
740+CONVERSE_MODEL_DESCRIPTOR,
741+runtimePluginConfig(undefined),
742+{ service_tier: "priority" },
743+);
744+expect(result._capturedPayload).toMatchObject({ serviceTier: { type: "priority" } });
745+});
746+747+it("injects serviceTier for all valid tier names", async () => {
748+const provider = await registerWithConfig(undefined);
749+for (const tier of ["flex", "priority", "default", "reserved"] as const) {
750+const result = await callWrappedStream(
751+provider,
752+NON_ANTHROPIC_MODEL,
753+CONVERSE_MODEL_DESCRIPTOR,
754+runtimePluginConfig(undefined),
755+{ serviceTier: tier },
756+);
757+expect(result._capturedPayload).toMatchObject({ serviceTier: { type: tier } });
758+}
759+});
760+761+it("does not inject serviceTier when value is invalid", async () => {
762+const provider = await registerWithConfig(undefined);
763+const result = await callWrappedStream(
764+provider,
765+NON_ANTHROPIC_MODEL,
766+CONVERSE_MODEL_DESCRIPTOR,
767+runtimePluginConfig(undefined),
768+{ serviceTier: "not-a-tier" },
769+);
770+expect(result).not.toHaveProperty("_capturedPayload");
771+});
772+773+it("does not overwrite caller-provided serviceTier in payload", async () => {
774+const provider = await registerWithConfig(undefined);
775+const result = await callWrappedStream(
776+provider,
777+NON_ANTHROPIC_MODEL,
778+CONVERSE_MODEL_DESCRIPTOR,
779+runtimePluginConfig(undefined),
780+{ serviceTier: "flex" },
781+{ serviceTier: { type: "priority" } },
782+);
783+expect(result._capturedPayload).toMatchObject({ serviceTier: { type: "priority" } });
784+});
785+786+it("skips injection for non-converse API models", async () => {
787+const provider = await registerWithConfig(undefined);
788+const result = await callWrappedStream(
789+provider,
790+NON_ANTHROPIC_MODEL,
791+{ api: "openai-completions", provider: "amazon-bedrock", id: NON_ANTHROPIC_MODEL } as never,
792+runtimePluginConfig(undefined),
793+{ serviceTier: "flex" },
794+);
795+expect(result).not.toHaveProperty("_capturedPayload");
796+});
797+});
798+722799describe("application inference profile cache point injection", () => {
723800/**
724801 * Invoke wrapStreamFn with a payload containing system/messages, then
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。