@mupt-ai/dari-gateway 0.2.0 → 0.3.0
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 +8 -4
- package/dist/bun.d.ts +2 -0
- package/dist/bun.js +4 -0
- package/dist/context/eval_catalog.d.ts +3 -0
- package/dist/context/eval_catalog.js +7 -0
- package/dist/context/interaction_fingerprint.d.ts +27 -0
- package/dist/context/interaction_fingerprint.js +519 -0
- package/dist/context/interaction_fingerprint_format.d.ts +42 -0
- package/dist/context/interaction_fingerprint_format.js +113 -0
- package/dist/context/interaction_lease_depth.d.ts +2 -0
- package/dist/context/interaction_lease_depth.js +110 -0
- package/dist/context/lease_history.d.ts +7 -0
- package/dist/context/lease_history.js +158 -0
- package/dist/context/pricing.d.ts +4 -0
- package/dist/context/pricing.js +27 -0
- package/dist/context/provider_prompt_accounting.d.ts +14 -0
- package/dist/context/provider_prompt_accounting.js +187 -0
- package/dist/context/routing_context.d.ts +40 -0
- package/dist/context/routing_context.js +211 -0
- package/dist/http/auth.d.ts +2 -0
- package/dist/http/auth.js +35 -0
- package/dist/http/errors.d.ts +19 -0
- package/dist/http/errors.js +89 -0
- package/dist/http/handler.d.ts +12 -0
- package/dist/http/handler.js +88 -0
- package/dist/http/http2_server.d.ts +6 -0
- package/dist/http/http2_server.js +103 -0
- package/dist/http/serve.d.ts +20 -0
- package/dist/http/serve.js +78 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +9 -0
- package/dist/ingress/anthropic_messages.d.ts +3 -0
- package/dist/ingress/anthropic_messages.js +122 -0
- package/dist/ingress/anthropic_models.d.ts +1 -0
- package/dist/ingress/anthropic_models.js +23 -0
- package/dist/ingress/chat_completions.d.ts +2 -0
- package/dist/ingress/chat_completions.js +44 -0
- package/dist/ingress/claude_code/request_context.d.ts +2 -0
- package/dist/ingress/claude_code/request_context.js +31 -0
- package/dist/ingress/codex.d.ts +3 -0
- package/dist/ingress/codex.js +69 -0
- package/dist/ingress/codex_models.d.ts +2 -0
- package/dist/ingress/codex_models.js +89 -0
- package/dist/ingress/json.d.ts +1 -0
- package/dist/ingress/json.js +95 -0
- package/dist/ingress/models.d.ts +1 -0
- package/dist/ingress/models.js +65 -0
- package/dist/ingress/muse_code.d.ts +2 -0
- package/dist/ingress/muse_code.js +8 -0
- package/dist/ingress/muse_models.d.ts +9 -0
- package/dist/ingress/muse_models.js +32 -0
- package/dist/interaction/capabilities.d.ts +3 -0
- package/dist/interaction/capabilities.js +24 -0
- package/dist/interaction/image.d.ts +4 -0
- package/dist/interaction/image.js +13 -0
- package/dist/interaction/portable_reasoning_state.d.ts +4 -0
- package/dist/interaction/portable_reasoning_state.js +18 -0
- package/dist/interaction/provider_continuation_state.d.ts +6 -0
- package/dist/interaction/provider_continuation_state.js +27 -0
- package/dist/interaction/tool_identity.d.ts +10 -0
- package/dist/interaction/tool_identity.js +41 -0
- package/dist/interaction/types.d.ts +204 -0
- package/dist/interaction/types.js +5 -0
- package/dist/models/catalog.d.ts +35 -0
- package/dist/models/catalog.js +232 -0
- package/dist/models/context_limits.d.ts +2 -0
- package/dist/models/context_limits.js +7 -0
- package/dist/models/execution_provider.d.ts +9 -0
- package/dist/models/execution_provider.js +17 -0
- package/dist/models/gateways.d.ts +11 -0
- package/dist/models/gateways.js +45 -0
- package/dist/models/ids.d.ts +1 -0
- package/dist/models/ids.js +15 -0
- package/dist/models/provider_defaults.d.ts +4 -0
- package/dist/models/provider_defaults.js +44 -0
- package/dist/models/runtime_overrides.d.ts +7 -0
- package/dist/models/runtime_overrides.js +226 -0
- package/dist/models/subscriptions.d.ts +8 -0
- package/dist/models/subscriptions.js +37 -0
- package/dist/observability/errors.d.ts +8 -0
- package/dist/observability/errors.js +11 -0
- package/dist/platform/platform.d.ts +156 -0
- package/dist/platform/platform.js +11 -0
- package/dist/platform/routing_contract.d.ts +2 -0
- package/dist/platform/routing_contract.js +5 -0
- package/dist/protocol/input/anthropic_messages.d.ts +2 -0
- package/dist/protocol/input/anthropic_messages.js +494 -0
- package/dist/protocol/input/chat_completions.d.ts +4 -0
- package/dist/protocol/input/chat_completions.js +214 -0
- package/dist/protocol/input/chat_completions_validation.d.ts +2 -0
- package/dist/protocol/input/chat_completions_validation.js +258 -0
- package/dist/protocol/input/openai_responses.d.ts +2 -0
- package/dist/protocol/input/openai_responses.js +666 -0
- package/dist/protocol/input/router_model.d.ts +7 -0
- package/dist/protocol/input/router_model.js +43 -0
- package/dist/protocol/output/anthropic_messages.d.ts +10 -0
- package/dist/protocol/output/anthropic_messages.js +15 -0
- package/dist/protocol/output/anthropic_messages_output.d.ts +10 -0
- package/dist/protocol/output/anthropic_messages_output.js +124 -0
- package/dist/protocol/output/anthropic_messages_stream.d.ts +16 -0
- package/dist/protocol/output/anthropic_messages_stream.js +267 -0
- package/dist/protocol/output/chat_completions.d.ts +29 -0
- package/dist/protocol/output/chat_completions.js +406 -0
- package/dist/protocol/output/chat_reasoning_detail.d.ts +2 -0
- package/dist/protocol/output/chat_reasoning_detail.js +13 -0
- package/dist/protocol/output/delivered_stream_snapshot.d.ts +10 -0
- package/dist/protocol/output/delivered_stream_snapshot.js +31 -0
- package/dist/protocol/output/openai_responses.d.ts +10 -0
- package/dist/protocol/output/openai_responses.js +14 -0
- package/dist/protocol/output/openai_responses_output.d.ts +14 -0
- package/dist/protocol/output/openai_responses_output.js +125 -0
- package/dist/protocol/output/openai_responses_stream.d.ts +18 -0
- package/dist/protocol/output/openai_responses_stream.js +546 -0
- package/dist/protocol/output/sse_stream.d.ts +31 -0
- package/dist/protocol/output/sse_stream.js +67 -0
- package/dist/providers/anthropic_safeguards.d.ts +11 -0
- package/dist/providers/anthropic_safeguards.js +81 -0
- package/dist/providers/aws_assume_role.d.ts +17 -0
- package/dist/providers/aws_assume_role.js +107 -0
- package/dist/providers/cancel_estimate.d.ts +43 -0
- package/dist/providers/cancel_estimate.js +89 -0
- package/dist/providers/execution.d.ts +72 -0
- package/dist/providers/execution.js +491 -0
- package/dist/providers/model_capabilities.d.ts +11 -0
- package/dist/providers/model_capabilities.js +29 -0
- package/dist/providers/pi.d.ts +65 -0
- package/dist/providers/pi.js +325 -0
- package/dist/providers/pi_context.d.ts +7 -0
- package/dist/providers/pi_context.js +405 -0
- package/dist/providers/pi_options.d.ts +11 -0
- package/dist/providers/pi_options.js +410 -0
- package/dist/providers/pi_output.d.ts +2 -0
- package/dist/providers/pi_output.js +453 -0
- package/dist/providers/provider_attempt_runner.d.ts +55 -0
- package/dist/providers/provider_attempt_runner.js +90 -0
- package/dist/providers/provider_call.d.ts +77 -0
- package/dist/providers/provider_call.js +296 -0
- package/dist/providers/provider_reported_cost.d.ts +10 -0
- package/dist/providers/provider_reported_cost.js +123 -0
- package/dist/providers/reasoning.d.ts +12 -0
- package/dist/providers/reasoning.js +30 -0
- package/dist/providers/response_capture.d.ts +23 -0
- package/dist/providers/response_capture.js +47 -0
- package/dist/providers/stream_finalization.d.ts +46 -0
- package/dist/providers/stream_finalization.js +165 -0
- package/dist/providers/subscription_limits.d.ts +33 -0
- package/dist/providers/subscription_limits.js +179 -0
- package/dist/providers/subscription_usage.d.ts +10 -0
- package/dist/providers/subscription_usage.js +79 -0
- package/dist/runtime/claude_code/auxiliary_routing.d.ts +3 -0
- package/dist/runtime/claude_code/auxiliary_routing.js +60 -0
- package/dist/runtime/customer_disconnect.d.ts +20 -0
- package/dist/runtime/customer_disconnect.js +49 -0
- package/dist/runtime/explicit_model.d.ts +7 -0
- package/dist/runtime/explicit_model.js +57 -0
- package/dist/runtime/harness_identity/conversation.d.ts +33 -0
- package/dist/runtime/harness_identity/conversation.js +39 -0
- package/dist/runtime/harness_identity/extract.d.ts +8 -0
- package/dist/runtime/harness_identity/extract.js +214 -0
- package/dist/runtime/harness_identity/index.d.ts +2 -0
- package/dist/runtime/harness_identity/index.js +2 -0
- package/dist/runtime/prepare_routed_completion.d.ts +33 -0
- package/dist/runtime/prepare_routed_completion.js +186 -0
- package/dist/runtime/provider_stream_lifecycle.d.ts +31 -0
- package/dist/runtime/provider_stream_lifecycle.js +88 -0
- package/dist/runtime/provider_stream_outcome.d.ts +23 -0
- package/dist/runtime/provider_stream_outcome.js +55 -0
- package/dist/runtime/request_tags.d.ts +7 -0
- package/dist/runtime/request_tags.js +33 -0
- package/dist/runtime/routed_completion.d.ts +17 -0
- package/dist/runtime/routed_completion.js +80 -0
- package/dist/runtime/routed_protocol.d.ts +30 -0
- package/dist/runtime/routed_protocol.js +1 -0
- package/dist/runtime/routed_runtime.d.ts +40 -0
- package/dist/runtime/routed_runtime.js +535 -0
- package/dist/runtime/routing_lease.d.ts +26 -0
- package/dist/runtime/routing_lease.js +210 -0
- package/dist/runtime/runtime_reporter.d.ts +71 -0
- package/dist/runtime/runtime_reporter.js +35 -0
- package/dist/runtime/strict_provider_access.d.ts +6 -0
- package/dist/runtime/strict_provider_access.js +40 -0
- package/dist/self_host/config.d.ts +46 -0
- package/dist/self_host/config.js +105 -0
- package/dist/self_host/main.d.ts +16 -0
- package/dist/self_host/main.js +95 -0
- package/dist/self_host/platform.d.ts +13 -0
- package/dist/self_host/platform.js +50 -0
- package/dist/self_host/prefix_store.d.ts +46 -0
- package/dist/self_host/prefix_store.js +261 -0
- package/dist/self_host/resolve.d.ts +28 -0
- package/dist/self_host/resolve.js +167 -0
- package/dist/self_host/subscriptions/access.d.ts +10 -0
- package/dist/self_host/subscriptions/access.js +37 -0
- package/dist/self_host/subscriptions/http.d.ts +15 -0
- package/dist/self_host/subscriptions/http.js +187 -0
- package/dist/self_host/subscriptions/index.d.ts +24 -0
- package/dist/self_host/subscriptions/index.js +24 -0
- package/dist/self_host/subscriptions/oauth.d.ts +59 -0
- package/dist/self_host/subscriptions/oauth.js +376 -0
- package/dist/self_host/subscriptions/store.d.ts +78 -0
- package/dist/self_host/subscriptions/store.js +236 -0
- package/dist/strategies/auto_routing_selector.d.ts +12 -0
- package/dist/strategies/auto_routing_selector.js +61 -0
- package/dist/strategies/eval_relevance.d.ts +17 -0
- package/dist/strategies/eval_relevance.js +32 -0
- package/dist/strategies/fallback_decision.d.ts +8 -0
- package/dist/strategies/fallback_decision.js +17 -0
- package/dist/strategies/priority_selector.d.ts +7 -0
- package/dist/strategies/priority_selector.js +37 -0
- package/dist/strategies/route_decision.d.ts +22 -0
- package/dist/strategies/route_decision.js +65 -0
- package/dist/strategies/routing.d.ts +74 -0
- package/dist/strategies/routing.js +280 -0
- package/dist/strategies/selector_projection.d.ts +15 -0
- package/dist/strategies/selector_projection.js +161 -0
- package/dist/telemetry/background.d.ts +7 -0
- package/dist/telemetry/background.js +33 -0
- package/dist/telemetry/benchmark_replay.d.ts +37 -0
- package/dist/telemetry/benchmark_replay.js +108 -0
- package/dist/telemetry/billing_finalization.d.ts +64 -0
- package/dist/telemetry/billing_finalization.js +96 -0
- package/dist/telemetry/ingest_values.d.ts +4 -0
- package/dist/telemetry/ingest_values.js +12 -0
- package/dist/telemetry/model_cost.d.ts +3 -0
- package/dist/telemetry/model_cost.js +15 -0
- package/dist/telemetry/prefix_state.d.ts +47 -0
- package/dist/telemetry/prefix_state.js +116 -0
- package/dist/telemetry/report.d.ts +88 -0
- package/dist/telemetry/report.js +621 -0
- package/dist/telemetry/requests/interaction_observability.d.ts +45 -0
- package/dist/telemetry/requests/interaction_observability.js +180 -0
- package/dist/telemetry/requests/retained_interaction_request.d.ts +8 -0
- package/dist/telemetry/requests/retained_interaction_request.js +10 -0
- package/dist/telemetry/scrub.d.ts +2 -0
- package/dist/telemetry/scrub.js +31 -0
- package/dist/telemetry/skills/claude/catalog.d.ts +6 -0
- package/dist/telemetry/skills/claude/catalog.js +99 -0
- package/dist/telemetry/skills/claude/file_reads.d.ts +4 -0
- package/dist/telemetry/skills/claude/file_reads.js +110 -0
- package/dist/telemetry/skills/claude/observations.d.ts +3 -0
- package/dist/telemetry/skills/claude/observations.js +366 -0
- package/dist/telemetry/skills/codex/catalog.d.ts +11 -0
- package/dist/telemetry/skills/codex/catalog.js +138 -0
- package/dist/telemetry/skills/codex/exec_file_reads.d.ts +9 -0
- package/dist/telemetry/skills/codex/exec_file_reads.js +36 -0
- package/dist/telemetry/skills/codex/explicit.d.ts +3 -0
- package/dist/telemetry/skills/codex/explicit.js +90 -0
- package/dist/telemetry/skills/codex/file_reads.d.ts +4 -0
- package/dist/telemetry/skills/codex/file_reads.js +37 -0
- package/dist/telemetry/skills/codex/identity.d.ts +2 -0
- package/dist/telemetry/skills/codex/identity.js +20 -0
- package/dist/telemetry/skills/observations.d.ts +21 -0
- package/dist/telemetry/skills/observations.js +41 -0
- package/dist/telemetry/skills/paths.d.ts +11 -0
- package/dist/telemetry/skills/paths.js +61 -0
- package/dist/telemetry/skills/pi.d.ts +6 -0
- package/dist/telemetry/skills/pi.js +223 -0
- package/dist/telemetry/skills/shell_file_reads.d.ts +7 -0
- package/dist/telemetry/skills/shell_file_reads.js +226 -0
- package/dist/telemetry/skills/shell_words.d.ts +13 -0
- package/dist/telemetry/skills/shell_words.js +189 -0
- package/dist/telemetry/tools/input.d.ts +2 -0
- package/dist/telemetry/tools/input.js +14 -0
- package/dist/telemetry/tools/observations.d.ts +29 -0
- package/dist/telemetry/tools/observations.js +247 -0
- package/dist/telemetry/usage.d.ts +57 -0
- package/dist/telemetry/usage.js +136 -0
- package/dist/types.d.ts +97 -0
- package/dist/types.js +1 -0
- package/package.json +22 -7
- package/src/bun.ts +2 -2
- package/src/context/eval_catalog.ts +1 -1
- package/src/context/interaction_fingerprint.ts +9 -9
- package/src/context/interaction_fingerprint_format.ts +1 -1
- package/src/context/interaction_lease_depth.ts +1 -1
- package/src/context/pricing.ts +6 -3
- package/src/context/provider_prompt_accounting.ts +5 -5
- package/src/context/routing_context.ts +16 -16
- package/src/http/auth.ts +1 -1
- package/src/http/handler.ts +15 -8
- package/src/http/serve.ts +3 -3
- package/src/index.ts +14 -6
- package/src/ingress/anthropic_messages.ts +12 -12
- package/src/ingress/anthropic_models.ts +1 -1
- package/src/ingress/chat_completions.ts +17 -10
- package/src/ingress/claude_code/request_context.ts +2 -2
- package/src/ingress/codex.ts +14 -10
- package/src/ingress/codex_models.ts +4 -4
- package/src/ingress/json.ts +1 -1
- package/src/ingress/models.ts +22 -10
- package/src/ingress/muse_code.ts +9 -0
- package/src/ingress/muse_models.ts +36 -0
- package/src/interaction/capabilities.ts +1 -1
- package/src/interaction/portable_reasoning_state.ts +1 -1
- package/src/interaction/provider_continuation_state.ts +1 -1
- package/src/interaction/tool_identity.ts +2 -2
- package/src/interaction/types.ts +2 -0
- package/src/models/catalog.ts +310 -0
- package/src/models/context_limits.ts +1 -1
- package/src/models/execution_provider.ts +5 -2
- package/src/models/ids.ts +1 -1
- package/src/models/provider_defaults.ts +4 -1
- package/src/models/runtime_overrides.ts +23 -1
- package/src/models/subscriptions.ts +54 -0
- package/src/observability/errors.ts +2 -2
- package/src/platform/platform.ts +9 -5
- package/src/protocol/input/anthropic_messages.ts +7 -7
- package/src/protocol/input/chat_completions.ts +8 -6
- package/src/protocol/input/chat_completions_validation.ts +6 -5
- package/src/protocol/input/openai_responses.ts +6 -6
- package/src/protocol/output/anthropic_messages.ts +3 -3
- package/src/protocol/output/anthropic_messages_output.ts +6 -4
- package/src/protocol/output/anthropic_messages_stream.ts +7 -7
- package/src/protocol/output/chat_completions.ts +13 -13
- package/src/protocol/output/chat_reasoning_detail.ts +1 -1
- package/src/protocol/output/openai_responses.ts +3 -3
- package/src/protocol/output/openai_responses_output.ts +4 -2
- package/src/protocol/output/openai_responses_stream.ts +6 -6
- package/src/protocol/output/sse_stream.ts +3 -3
- package/src/providers/anthropic_safeguards.ts +2 -2
- package/src/providers/aws_assume_role.ts +2 -2
- package/src/providers/cancel_estimate.ts +1 -1
- package/src/providers/execution.ts +17 -17
- package/src/providers/pi.ts +34 -19
- package/src/providers/pi_context.ts +6 -6
- package/src/providers/pi_options.ts +27 -11
- package/src/providers/pi_output.ts +5 -5
- package/src/providers/provider_attempt_runner.ts +1 -1
- package/src/providers/provider_call.ts +21 -17
- package/src/providers/provider_reported_cost.ts +3 -3
- package/src/providers/reasoning.ts +2 -2
- package/src/providers/stream_finalization.ts +9 -9
- package/src/providers/subscription_limits.ts +24 -7
- package/src/runtime/claude_code/auxiliary_routing.ts +5 -5
- package/src/runtime/customer_disconnect.ts +1 -1
- package/src/runtime/explicit_model.ts +19 -20
- package/src/runtime/harness_identity/conversation.ts +1 -1
- package/src/runtime/harness_identity/extract.ts +3 -3
- package/src/runtime/harness_identity/index.ts +2 -2
- package/src/runtime/prepare_routed_completion.ts +35 -16
- package/src/runtime/provider_stream_lifecycle.ts +1 -1
- package/src/runtime/provider_stream_outcome.ts +2 -2
- package/src/runtime/request_tags.ts +2 -2
- package/src/runtime/routed_completion.ts +11 -11
- package/src/runtime/routed_protocol.ts +2 -2
- package/src/runtime/routed_runtime.ts +20 -19
- package/src/runtime/routing_lease.ts +7 -7
- package/src/runtime/runtime_reporter.ts +3 -3
- package/src/runtime/strict_provider_access.ts +42 -0
- package/src/self_host/main.ts +12 -12
- package/src/self_host/platform.ts +5 -5
- package/src/self_host/prefix_store.ts +2 -2
- package/src/self_host/resolve.ts +17 -31
- package/src/self_host/subscriptions/access.ts +2 -2
- package/src/self_host/subscriptions/http.ts +2 -2
- package/src/self_host/subscriptions/index.ts +4 -4
- package/src/self_host/subscriptions/oauth.ts +139 -8
- package/src/self_host/subscriptions/store.ts +2 -1
- package/src/strategies/auto_routing_selector.ts +2 -2
- package/src/strategies/eval_relevance.ts +3 -3
- package/src/strategies/priority_selector.ts +1 -1
- package/src/strategies/route_decision.ts +7 -7
- package/src/strategies/routing.ts +10 -10
- package/src/strategies/selector_projection.ts +2 -2
- package/src/telemetry/billing_finalization.ts +3 -3
- package/src/telemetry/model_cost.ts +1 -1
- package/src/telemetry/prefix_state.ts +4 -4
- package/src/telemetry/report.ts +21 -21
- package/src/telemetry/requests/interaction_observability.ts +1 -1
- package/src/telemetry/requests/retained_interaction_request.ts +1 -1
- package/src/telemetry/skills/claude/catalog.ts +1 -1
- package/src/telemetry/skills/claude/file_reads.ts +6 -6
- package/src/telemetry/skills/claude/observations.ts +3 -3
- package/src/telemetry/skills/codex/catalog.ts +3 -3
- package/src/telemetry/skills/codex/exec_file_reads.ts +4 -4
- package/src/telemetry/skills/codex/explicit.ts +3 -3
- package/src/telemetry/skills/codex/file_reads.ts +5 -5
- package/src/telemetry/skills/observations.ts +7 -7
- package/src/telemetry/skills/pi.ts +3 -3
- package/src/telemetry/skills/shell_file_reads.ts +2 -2
- package/src/telemetry/skills/shell_words.ts +1 -1
- package/src/telemetry/tools/input.ts +1 -1
- package/src/telemetry/tools/observations.ts +9 -9
- package/src/telemetry/usage.ts +5 -5
- package/src/types.ts +20 -3
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
import { isRecord } from "@mupt-ai/dari-router/policy-engine";
|
|
2
|
+
import { HttpError } from "../http/errors.js";
|
|
3
|
+
import { providerToolCallIdentity, toolsByWireName } from "../interaction/tool_identity.js";
|
|
4
|
+
import { isAnthropicEffort } from "../interaction/provider_continuation_state.js";
|
|
5
|
+
import { isBedrockApi, isOpenAIResponsesApi } from "./model_capabilities.js";
|
|
6
|
+
export function piMessageToInteractionOutput(message, source, request) {
|
|
7
|
+
if (isRecord(message.providerResponse) && isOpenAIResponsesApi(source.api)) {
|
|
8
|
+
return openAIProviderResponseToInteractionOutput(message.providerResponse, message, source, request);
|
|
9
|
+
}
|
|
10
|
+
const tools = toolsByWireName(request.tools);
|
|
11
|
+
const items = [];
|
|
12
|
+
const content = message.content;
|
|
13
|
+
if (content !== undefined && !Array.isArray(content))
|
|
14
|
+
throw invalidProviderOutput("content must be an array.");
|
|
15
|
+
let pendingServerToolCall = null;
|
|
16
|
+
for (const block of content ?? []) {
|
|
17
|
+
if (!isRecord(block))
|
|
18
|
+
throw invalidProviderOutput("content blocks must be objects.");
|
|
19
|
+
if (block.type === "text") {
|
|
20
|
+
if (typeof block.text !== "string")
|
|
21
|
+
throw invalidProviderOutput("text content is missing text.");
|
|
22
|
+
const signature = textSignature(block.textSignature);
|
|
23
|
+
items.push({
|
|
24
|
+
type: "message",
|
|
25
|
+
...(signature?.id ? { id: signature.id } : {}),
|
|
26
|
+
role: "assistant",
|
|
27
|
+
content: [{ type: "text", text: block.text }],
|
|
28
|
+
contentShape: "parts",
|
|
29
|
+
...(signature?.phase ? { phase: signature.phase } : {}),
|
|
30
|
+
source,
|
|
31
|
+
});
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (block.type === "thinking") {
|
|
35
|
+
items.push(reasoningItem(block, source, message.providerThinkingLevel));
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (block.type === "toolCall") {
|
|
39
|
+
items.push(toolCallItem(block, source, tools));
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (block.type === "serverToolCall") {
|
|
43
|
+
const serverId = requiredString(block.id, "server tool call ID");
|
|
44
|
+
const serverName = requiredString(block.name, "server tool call name");
|
|
45
|
+
const serverInput = isRecord(block.arguments) ? block.arguments : {};
|
|
46
|
+
pendingServerToolCall = { id: serverId, name: serverName, input: serverInput };
|
|
47
|
+
items.push({
|
|
48
|
+
type: "hosted_tool_call",
|
|
49
|
+
id: requiredString(block.id, "server tool call ID"),
|
|
50
|
+
tool: "server_tool_use",
|
|
51
|
+
providerType: "server_tool_use",
|
|
52
|
+
payload: { id: block.id, name: block.name, input: block.arguments },
|
|
53
|
+
serverToolUseId: requiredString(block.id, "server tool call ID"),
|
|
54
|
+
serverToolName: serverName,
|
|
55
|
+
serverToolInput: serverInput,
|
|
56
|
+
source,
|
|
57
|
+
});
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (block.type === "toolSearchResult") {
|
|
61
|
+
const references = (Array.isArray(block.content) ? block.content : []).filter((ref) => isRecord(ref) && ref.type === "tool_reference").map((ref) => ({
|
|
62
|
+
type: "tool_reference",
|
|
63
|
+
toolName: String(ref.tool_name ?? ""),
|
|
64
|
+
}));
|
|
65
|
+
const serverToolCall = pendingServerToolCall?.id === String(block.toolUseId) ? pendingServerToolCall : null;
|
|
66
|
+
if (serverToolCall)
|
|
67
|
+
pendingServerToolCall = null;
|
|
68
|
+
items.push({
|
|
69
|
+
type: "hosted_tool_call",
|
|
70
|
+
id: `${String(block.toolUseId)}_result`,
|
|
71
|
+
tool: "tool_search",
|
|
72
|
+
providerType: "tool_search_result",
|
|
73
|
+
payload: {
|
|
74
|
+
tool_use_id: block.toolUseId,
|
|
75
|
+
content: references,
|
|
76
|
+
...(serverToolCall ? { name: serverToolCall.name, input: serverToolCall.input } : {}),
|
|
77
|
+
},
|
|
78
|
+
serverToolUseId: requiredString(block.toolUseId, "tool search result tool_use_id"),
|
|
79
|
+
serverToolName: serverToolCall?.name,
|
|
80
|
+
serverToolInput: serverToolCall?.input,
|
|
81
|
+
serverToolResult: references,
|
|
82
|
+
source,
|
|
83
|
+
});
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
throw invalidProviderOutput(`content block type '${String(block.type ?? "unknown")}' is not supported.`);
|
|
87
|
+
}
|
|
88
|
+
if (items.length === 0) {
|
|
89
|
+
items.push({
|
|
90
|
+
type: "message",
|
|
91
|
+
role: "assistant",
|
|
92
|
+
content: [{ type: "text", text: "" }],
|
|
93
|
+
contentShape: "parts",
|
|
94
|
+
source,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
responseId: optionalString(message.responseId),
|
|
99
|
+
createdAtMs: finiteNumber(message.timestamp) ?? Date.now(),
|
|
100
|
+
source,
|
|
101
|
+
items,
|
|
102
|
+
usage: interactionUsage(message.usage, source),
|
|
103
|
+
stopReason: stopReason(message.stopReason),
|
|
104
|
+
...(typeof message.errorMessage === "string" ? { errorMessage: message.errorMessage } : {}),
|
|
105
|
+
...(Array.isArray(message.safeguardResults) ? { safeguardResults: message.safeguardResults } : {}),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function openAIProviderResponseToInteractionOutput(response, message, source, request) {
|
|
109
|
+
if (!Array.isArray(response.output)) {
|
|
110
|
+
throw invalidProviderOutput("OpenAI Responses output must be an array.");
|
|
111
|
+
}
|
|
112
|
+
const tools = toolsByWireName(request.tools);
|
|
113
|
+
const items = response.output.map((value) => {
|
|
114
|
+
if (!isRecord(value) || typeof value.type !== "string") {
|
|
115
|
+
throw invalidProviderOutput("OpenAI Responses output items must be typed objects.");
|
|
116
|
+
}
|
|
117
|
+
if (value.type === "reasoning")
|
|
118
|
+
return openAIProviderReasoningItem(value, source);
|
|
119
|
+
if (value.type === "message")
|
|
120
|
+
return openAIProviderMessageItem(value, source);
|
|
121
|
+
if (value.type === "function_call") {
|
|
122
|
+
const argumentsValue = requiredString(value.arguments, "function call arguments");
|
|
123
|
+
let parsed;
|
|
124
|
+
try {
|
|
125
|
+
parsed = JSON.parse(argumentsValue);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
throw invalidProviderOutput("function call arguments are not valid JSON.");
|
|
129
|
+
}
|
|
130
|
+
if (!isRecord(parsed))
|
|
131
|
+
throw invalidProviderOutput("function call arguments must be an object.");
|
|
132
|
+
return toolCallItem({
|
|
133
|
+
id: `${requiredString(value.call_id, "function call ID")}|${requiredString(value.id, "function item ID")}`,
|
|
134
|
+
name: requiredString(value.name, "function call name"),
|
|
135
|
+
arguments: parsed,
|
|
136
|
+
}, source, tools);
|
|
137
|
+
}
|
|
138
|
+
if (value.type === "web_search_call") {
|
|
139
|
+
return {
|
|
140
|
+
type: "hosted_tool_call",
|
|
141
|
+
id: requiredString(value.id, "web search call ID"),
|
|
142
|
+
tool: "web_search",
|
|
143
|
+
providerType: "web_search_call",
|
|
144
|
+
...(openAIHostedStatus(value.status) ? { status: openAIHostedStatus(value.status) } : {}),
|
|
145
|
+
payload: { ...value },
|
|
146
|
+
source,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
throw invalidProviderOutput(`OpenAI Responses output item type '${value.type}' is not supported.`);
|
|
150
|
+
});
|
|
151
|
+
attachHostedReplayIds(items);
|
|
152
|
+
return {
|
|
153
|
+
responseId: optionalString(response.id) ?? optionalString(message.responseId),
|
|
154
|
+
createdAtMs: (finiteNumber(response.created_at) ?? Date.now() / 1000) * 1000,
|
|
155
|
+
source,
|
|
156
|
+
items,
|
|
157
|
+
usage: interactionUsage(message.usage, source),
|
|
158
|
+
stopReason: stopReason(message.stopReason),
|
|
159
|
+
...(typeof message.errorMessage === "string" ? { errorMessage: message.errorMessage } : {}),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function attachHostedReplayIds(items) {
|
|
163
|
+
const firstReasoningIndex = items.findIndex((item) => item.type === "reasoning");
|
|
164
|
+
if (firstReasoningIndex < 0)
|
|
165
|
+
return;
|
|
166
|
+
const callsByReasoning = new Map();
|
|
167
|
+
// Provider output is ordered into reasoning groups: leading calls belong to
|
|
168
|
+
// the first group, and each later reasoning item starts the next group.
|
|
169
|
+
let currentReasoningIndex = firstReasoningIndex;
|
|
170
|
+
for (let callIndex = 0; callIndex < items.length; callIndex += 1) {
|
|
171
|
+
const item = items[callIndex];
|
|
172
|
+
if (item.type === "reasoning") {
|
|
173
|
+
currentReasoningIndex = callIndex;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (item.type !== "hosted_tool_call")
|
|
177
|
+
continue;
|
|
178
|
+
const reasoning = items[currentReasoningIndex];
|
|
179
|
+
if (reasoning.type !== "reasoning" || reasoning.continuation?.kind !== "openai_reasoning")
|
|
180
|
+
continue;
|
|
181
|
+
const calls = callsByReasoning.get(currentReasoningIndex) ?? [];
|
|
182
|
+
calls.push({ id: item.id, offset: callIndex - currentReasoningIndex });
|
|
183
|
+
callsByReasoning.set(currentReasoningIndex, calls);
|
|
184
|
+
}
|
|
185
|
+
for (const [reasoningIndex, calls] of callsByReasoning) {
|
|
186
|
+
const item = items[reasoningIndex];
|
|
187
|
+
if (item.type !== "reasoning" || item.continuation?.kind !== "openai_reasoning")
|
|
188
|
+
continue;
|
|
189
|
+
item.continuation = {
|
|
190
|
+
...item.continuation,
|
|
191
|
+
hostedToolCallIds: calls.map(({ id }) => id),
|
|
192
|
+
hostedToolCallOffsets: calls.map(({ offset }) => offset),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function openAIProviderReasoningItem(value, source) {
|
|
197
|
+
const encryptedContent = optionalString(value.encrypted_content);
|
|
198
|
+
const id = optionalString(value.id);
|
|
199
|
+
return {
|
|
200
|
+
type: "reasoning",
|
|
201
|
+
...(id ? { id } : {}),
|
|
202
|
+
summary: providerTextEntries(value.summary, "summary_text"),
|
|
203
|
+
content: providerTextEntries(value.content, "reasoning_text"),
|
|
204
|
+
source,
|
|
205
|
+
...(encryptedContent
|
|
206
|
+
? {
|
|
207
|
+
continuation: {
|
|
208
|
+
kind: "openai_reasoning",
|
|
209
|
+
source,
|
|
210
|
+
encryptedContent,
|
|
211
|
+
...(id ? { providerItemId: id } : {}),
|
|
212
|
+
},
|
|
213
|
+
}
|
|
214
|
+
: {}),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function openAIProviderMessageItem(value, source) {
|
|
218
|
+
if (!Array.isArray(value.content))
|
|
219
|
+
throw invalidProviderOutput("message content must be an array.");
|
|
220
|
+
const content = value.content.map((part) => {
|
|
221
|
+
if (!isRecord(part))
|
|
222
|
+
throw invalidProviderOutput("message content parts must be objects.");
|
|
223
|
+
if (part.type !== "output_text" && part.type !== "refusal") {
|
|
224
|
+
throw invalidProviderOutput(`message content type '${String(part.type ?? "unknown")}' is not supported.`);
|
|
225
|
+
}
|
|
226
|
+
const text = requiredStringAllowEmpty(part.type === "refusal" ? part.refusal : part.text, "message content text");
|
|
227
|
+
const annotations = providerAnnotations(part.annotations);
|
|
228
|
+
return {
|
|
229
|
+
type: "text",
|
|
230
|
+
text,
|
|
231
|
+
...(annotations.length ? { annotations } : {}),
|
|
232
|
+
};
|
|
233
|
+
});
|
|
234
|
+
const phase = value.phase === "commentary" || value.phase === "final_answer" ? value.phase : undefined;
|
|
235
|
+
return {
|
|
236
|
+
type: "message",
|
|
237
|
+
...(optionalString(value.id) ? { id: optionalString(value.id) } : {}),
|
|
238
|
+
role: "assistant",
|
|
239
|
+
content,
|
|
240
|
+
contentShape: "parts",
|
|
241
|
+
...(phase ? { phase } : {}),
|
|
242
|
+
source,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function providerTextEntries(value, type) {
|
|
246
|
+
if (value === undefined || value === null)
|
|
247
|
+
return [];
|
|
248
|
+
if (!Array.isArray(value))
|
|
249
|
+
throw invalidProviderOutput(`${type} entries must be an array.`);
|
|
250
|
+
return value.map((entry) => {
|
|
251
|
+
if (!isRecord(entry) || entry.type !== type || typeof entry.text !== "string") {
|
|
252
|
+
throw invalidProviderOutput(`${type} entries are malformed.`);
|
|
253
|
+
}
|
|
254
|
+
return entry.text;
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
function providerAnnotations(value) {
|
|
258
|
+
if (value === undefined || value === null)
|
|
259
|
+
return [];
|
|
260
|
+
if (!Array.isArray(value))
|
|
261
|
+
throw invalidProviderOutput("message annotations must be an array.");
|
|
262
|
+
return value.map((annotation) => {
|
|
263
|
+
if (!isRecord(annotation) || typeof annotation.type !== "string") {
|
|
264
|
+
throw invalidProviderOutput("message annotations must be typed objects.");
|
|
265
|
+
}
|
|
266
|
+
return { ...annotation };
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
function openAIHostedStatus(value) {
|
|
270
|
+
return value === "in_progress" ||
|
|
271
|
+
value === "searching" ||
|
|
272
|
+
value === "completed" ||
|
|
273
|
+
value === "incomplete" ||
|
|
274
|
+
value === "failed"
|
|
275
|
+
? value
|
|
276
|
+
: undefined;
|
|
277
|
+
}
|
|
278
|
+
function reasoningItem(block, source, providerThinkingLevel) {
|
|
279
|
+
const thinking = typeof block.thinking === "string" ? block.thinking : "";
|
|
280
|
+
const signature = optionalString(block.thinkingSignature);
|
|
281
|
+
if (isOpenAIResponsesApi(source.api)) {
|
|
282
|
+
const native = signature ? openAIReasoningItem(signature) : null;
|
|
283
|
+
return {
|
|
284
|
+
type: "reasoning",
|
|
285
|
+
...(native?.id ? { id: native.id } : {}),
|
|
286
|
+
summary: native?.summary ?? (thinking ? [thinking] : []),
|
|
287
|
+
content: native?.content ?? [],
|
|
288
|
+
source,
|
|
289
|
+
...(native?.encryptedContent
|
|
290
|
+
? {
|
|
291
|
+
continuation: {
|
|
292
|
+
kind: "openai_reasoning",
|
|
293
|
+
source,
|
|
294
|
+
encryptedContent: native.encryptedContent,
|
|
295
|
+
...(native.id ? { providerItemId: native.id } : {}),
|
|
296
|
+
},
|
|
297
|
+
}
|
|
298
|
+
: {}),
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
if ((source.api === "anthropic-messages" || isBedrockApi(source.api)) && signature) {
|
|
302
|
+
// Pi stamps the effort marker it sent on managed-effort Claude turns; the
|
|
303
|
+
// envelope carries it so replay can put the marker back (see pi_context).
|
|
304
|
+
const effort = isAnthropicEffort(providerThinkingLevel) ? { effort: providerThinkingLevel } : {};
|
|
305
|
+
const continuation = block.redacted === true
|
|
306
|
+
? { kind: "anthropic_redacted_thinking", source, data: signature, ...effort }
|
|
307
|
+
: { kind: "anthropic_thinking", source, thinking, signature, ...effort };
|
|
308
|
+
return {
|
|
309
|
+
type: "reasoning",
|
|
310
|
+
summary: block.redacted === true || !thinking ? [] : [thinking],
|
|
311
|
+
content: [],
|
|
312
|
+
source,
|
|
313
|
+
continuation,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
type: "reasoning",
|
|
318
|
+
summary: thinking ? [thinking] : [],
|
|
319
|
+
content: [],
|
|
320
|
+
source,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function toolCallItem(block, source, tools) {
|
|
324
|
+
const piId = requiredString(block.id, "tool call ID");
|
|
325
|
+
const flattenedName = requiredString(block.name, "tool call name");
|
|
326
|
+
const identity = providerToolCallIdentity(piId, source);
|
|
327
|
+
const candidate = tools.get(flattenedName);
|
|
328
|
+
const tool = candidate?.kind === "hosted" || candidate?.kind === "server_tool" ? undefined : candidate;
|
|
329
|
+
const kind = tool?.kind === "custom" ? "custom" : "function";
|
|
330
|
+
const argumentsValue = isRecord(block.arguments) ? block.arguments : {};
|
|
331
|
+
return {
|
|
332
|
+
type: "tool_call",
|
|
333
|
+
...(identity.itemId ? { id: identity.itemId } : {}),
|
|
334
|
+
callId: identity.callId,
|
|
335
|
+
kind,
|
|
336
|
+
name: tool?.name ?? flattenedName,
|
|
337
|
+
...(tool && "namespace" in tool && tool.namespace ? { namespace: tool.namespace } : {}),
|
|
338
|
+
input: kind === "custom" ? customInput(argumentsValue) : argumentsValue,
|
|
339
|
+
status: "completed",
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
function customInput(value) {
|
|
343
|
+
return typeof value.input === "string" ? value.input : "";
|
|
344
|
+
}
|
|
345
|
+
function openAIReasoningItem(value) {
|
|
346
|
+
let parsed;
|
|
347
|
+
try {
|
|
348
|
+
parsed = JSON.parse(value);
|
|
349
|
+
}
|
|
350
|
+
catch {
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
if (!isRecord(parsed) || parsed.type !== "reasoning")
|
|
354
|
+
return null;
|
|
355
|
+
return {
|
|
356
|
+
id: optionalString(parsed.id),
|
|
357
|
+
summary: reasoningText(parsed.summary, "summary_text"),
|
|
358
|
+
content: reasoningText(parsed.content, "reasoning_text"),
|
|
359
|
+
encryptedContent: optionalString(parsed.encrypted_content),
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function reasoningText(value, type) {
|
|
363
|
+
if (!Array.isArray(value))
|
|
364
|
+
return [];
|
|
365
|
+
return value.flatMap((entry) => isRecord(entry) && entry.type === type && typeof entry.text === "string" ? [entry.text] : []);
|
|
366
|
+
}
|
|
367
|
+
function textSignature(value) {
|
|
368
|
+
if (typeof value !== "string" || !value)
|
|
369
|
+
return null;
|
|
370
|
+
try {
|
|
371
|
+
const parsed = JSON.parse(value);
|
|
372
|
+
if (!isRecord(parsed) || parsed.v !== 1)
|
|
373
|
+
return { id: value };
|
|
374
|
+
const phase = parsed.phase === "commentary" || parsed.phase === "final_answer" ? parsed.phase : undefined;
|
|
375
|
+
return { id: optionalString(parsed.id), ...(phase ? { phase } : {}) };
|
|
376
|
+
}
|
|
377
|
+
catch {
|
|
378
|
+
return { id: value };
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
function interactionUsage(value, source) {
|
|
382
|
+
const usage = isRecord(value) ? value : {};
|
|
383
|
+
const cost = isRecord(usage.cost) ? usage.cost : {};
|
|
384
|
+
const reportedInput = finiteNumber(usage.input) ?? 0;
|
|
385
|
+
const output = finiteNumber(usage.output) ?? 0;
|
|
386
|
+
const cacheRead = finiteNumber(usage.cacheRead) ?? 0;
|
|
387
|
+
const cacheWrite = finiteNumber(usage.cacheWrite) ?? 0;
|
|
388
|
+
const reportedInputCost = finiteNumber(cost.input) ?? 0;
|
|
389
|
+
const outputCost = finiteNumber(cost.output) ?? 0;
|
|
390
|
+
const cacheReadCost = finiteNumber(cost.cacheRead) ?? 0;
|
|
391
|
+
const cacheWriteCost = finiteNumber(cost.cacheWrite) ?? 0;
|
|
392
|
+
// OpenAI models on Bedrock Converse report cache reads and writes as subsets
|
|
393
|
+
// of inputTokens. Canonical usage keeps those buckets separate. Claude's
|
|
394
|
+
// Bedrock usage is already cache-exclusive.
|
|
395
|
+
const inclusiveCacheTokens = isBedrockApi(source.api) && /(^|[./])openai[./]/.test(source.model);
|
|
396
|
+
const input = inclusiveCacheTokens
|
|
397
|
+
? Math.max(0, reportedInput - cacheRead - cacheWrite)
|
|
398
|
+
: reportedInput;
|
|
399
|
+
const inputCost = inclusiveCacheTokens && reportedInput > 0
|
|
400
|
+
? reportedInputCost * input / reportedInput
|
|
401
|
+
: reportedInputCost;
|
|
402
|
+
const calculatedTotalTokens = input + output + cacheRead + cacheWrite;
|
|
403
|
+
const calculatedTotalCost = inputCost + outputCost + cacheReadCost + cacheWriteCost;
|
|
404
|
+
return {
|
|
405
|
+
input,
|
|
406
|
+
output,
|
|
407
|
+
cacheRead,
|
|
408
|
+
cacheWrite,
|
|
409
|
+
totalTokens: inclusiveCacheTokens
|
|
410
|
+
? calculatedTotalTokens
|
|
411
|
+
: finiteNumber(usage.totalTokens) ?? calculatedTotalTokens,
|
|
412
|
+
cost: {
|
|
413
|
+
input: inputCost,
|
|
414
|
+
output: outputCost,
|
|
415
|
+
cacheRead: cacheReadCost,
|
|
416
|
+
cacheWrite: cacheWriteCost,
|
|
417
|
+
total: inclusiveCacheTokens
|
|
418
|
+
? calculatedTotalCost
|
|
419
|
+
: finiteNumber(cost.total) ?? calculatedTotalCost,
|
|
420
|
+
},
|
|
421
|
+
...(usage.costSource === "provider" ? { costSource: "provider" } : {}),
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
function stopReason(value) {
|
|
425
|
+
if (value === "length")
|
|
426
|
+
return "length";
|
|
427
|
+
if (value === "toolUse")
|
|
428
|
+
return "tool_use";
|
|
429
|
+
if (value === "error")
|
|
430
|
+
return "error";
|
|
431
|
+
if (value === "aborted")
|
|
432
|
+
return "aborted";
|
|
433
|
+
return "stop";
|
|
434
|
+
}
|
|
435
|
+
function requiredString(value, field) {
|
|
436
|
+
if (typeof value !== "string" || !value)
|
|
437
|
+
throw invalidProviderOutput(`${field} is missing.`);
|
|
438
|
+
return value;
|
|
439
|
+
}
|
|
440
|
+
function requiredStringAllowEmpty(value, field) {
|
|
441
|
+
if (typeof value !== "string")
|
|
442
|
+
throw invalidProviderOutput(`${field} is missing.`);
|
|
443
|
+
return value;
|
|
444
|
+
}
|
|
445
|
+
function optionalString(value) {
|
|
446
|
+
return typeof value === "string" && value ? value : undefined;
|
|
447
|
+
}
|
|
448
|
+
function finiteNumber(value) {
|
|
449
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
450
|
+
}
|
|
451
|
+
function invalidProviderOutput(message) {
|
|
452
|
+
return new HttpError(502, `Provider output ${message}`, "provider_output_invalid");
|
|
453
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export type ProviderAttemptFailure = {
|
|
2
|
+
kind: "provider_failed";
|
|
3
|
+
message: Record<string, unknown>;
|
|
4
|
+
latencyMs: number;
|
|
5
|
+
retryable: boolean;
|
|
6
|
+
} | {
|
|
7
|
+
kind: "customer_canceled";
|
|
8
|
+
message: Record<string, unknown>;
|
|
9
|
+
latencyMs: number;
|
|
10
|
+
retryable: false;
|
|
11
|
+
};
|
|
12
|
+
export type ProviderAttemptResult<T> = {
|
|
13
|
+
kind: "succeeded";
|
|
14
|
+
value: T;
|
|
15
|
+
latencyMs: number;
|
|
16
|
+
} | ProviderAttemptFailure;
|
|
17
|
+
export type ProviderAttemptPlanResult<TChoice, TValue> = {
|
|
18
|
+
choice: TChoice;
|
|
19
|
+
attempt: number;
|
|
20
|
+
latencyMs: number;
|
|
21
|
+
} & ({
|
|
22
|
+
kind: "succeeded";
|
|
23
|
+
value: TValue;
|
|
24
|
+
} | {
|
|
25
|
+
kind: "provider_failed";
|
|
26
|
+
failure: Record<string, unknown>;
|
|
27
|
+
} | {
|
|
28
|
+
kind: "customer_canceled";
|
|
29
|
+
failure: Record<string, unknown>;
|
|
30
|
+
});
|
|
31
|
+
type RunProviderAttemptPlanArgs<TChoice, TValue, TInitial> = {
|
|
32
|
+
primary: TChoice;
|
|
33
|
+
retries: number;
|
|
34
|
+
resolveFallback: () => Promise<TChoice | null>;
|
|
35
|
+
primaryInitial?: TInitial;
|
|
36
|
+
isCustomerCanceled: (choice: TChoice) => boolean;
|
|
37
|
+
canceledFailure: () => Record<string, unknown>;
|
|
38
|
+
runAttempt: (args: {
|
|
39
|
+
choice: TChoice;
|
|
40
|
+
attempt: number;
|
|
41
|
+
initial: TInitial | undefined;
|
|
42
|
+
}) => Promise<ProviderAttemptResult<TValue>>;
|
|
43
|
+
recordFailedAttempt: (args: {
|
|
44
|
+
choice: TChoice;
|
|
45
|
+
attempt: number;
|
|
46
|
+
result: ProviderAttemptFailure;
|
|
47
|
+
}) => void;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Owns the order-sensitive provider plan shared by completion and stream setup:
|
|
51
|
+
* retries within one choice, cancellation fences around asynchronous fallback
|
|
52
|
+
* resolution, and one contiguous attempt record for every failed dispatch.
|
|
53
|
+
*/
|
|
54
|
+
export declare function runProviderAttemptPlan<TChoice, TValue, TInitial>(args: RunProviderAttemptPlanArgs<TChoice, TValue, TInitial>): Promise<ProviderAttemptPlanResult<TChoice, TValue>>;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { subscriptionUsageLimitFromFailure } from "./subscription_limits.js";
|
|
2
|
+
/**
|
|
3
|
+
* Owns the order-sensitive provider plan shared by completion and stream setup:
|
|
4
|
+
* retries within one choice, cancellation fences around asynchronous fallback
|
|
5
|
+
* resolution, and one contiguous attempt record for every failed dispatch.
|
|
6
|
+
*/
|
|
7
|
+
export async function runProviderAttemptPlan(args) {
|
|
8
|
+
if (!Number.isSafeInteger(args.retries) || args.retries < 0) {
|
|
9
|
+
throw new Error("Provider retries must be a nonnegative integer.");
|
|
10
|
+
}
|
|
11
|
+
const primary = await runChoice(args, args.primary, args.primaryInitial);
|
|
12
|
+
if (primary.kind !== "provider_failed")
|
|
13
|
+
return primary;
|
|
14
|
+
// The user's next subscription serves a retry of this same choice, which
|
|
15
|
+
// beats a fallback model billed elsewhere.
|
|
16
|
+
if (subscriptionUsageLimitFromFailure(primary.failure)?.switched === true)
|
|
17
|
+
return primary;
|
|
18
|
+
// A disconnect before or during fallback resolution stays attributed to the
|
|
19
|
+
// primary: it is the only choice that was dispatched, and a resolved but
|
|
20
|
+
// undispatched fallback must not appear as the serving model.
|
|
21
|
+
const canceledAfterPrimary = () => syntheticCancellation(args, {
|
|
22
|
+
choice: args.primary,
|
|
23
|
+
attempt: primary.attempt + 1,
|
|
24
|
+
latencyMs: primary.latencyMs,
|
|
25
|
+
});
|
|
26
|
+
if (args.isCustomerCanceled(args.primary))
|
|
27
|
+
return canceledAfterPrimary();
|
|
28
|
+
const fallback = await args.resolveFallback();
|
|
29
|
+
if (args.isCustomerCanceled(args.primary))
|
|
30
|
+
return canceledAfterPrimary();
|
|
31
|
+
if (fallback === null)
|
|
32
|
+
return primary;
|
|
33
|
+
const fallbackResult = await runChoice(args, fallback, undefined);
|
|
34
|
+
return {
|
|
35
|
+
...fallbackResult,
|
|
36
|
+
latencyMs: primary.latencyMs + fallbackResult.latencyMs,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async function runChoice(args, choice, initial) {
|
|
40
|
+
let latencyMs = 0;
|
|
41
|
+
let lastFailure = null;
|
|
42
|
+
let lastAttempt = 0;
|
|
43
|
+
for (let attempt = 1; attempt <= args.retries + 1; attempt += 1) {
|
|
44
|
+
lastAttempt = attempt;
|
|
45
|
+
if (attempt !== 1 || initial === undefined) {
|
|
46
|
+
if (args.isCustomerCanceled(choice)) {
|
|
47
|
+
return syntheticCancellation(args, { choice, attempt, latencyMs });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const result = await args.runAttempt({
|
|
51
|
+
choice,
|
|
52
|
+
attempt,
|
|
53
|
+
initial: attempt === 1 ? initial : undefined,
|
|
54
|
+
});
|
|
55
|
+
latencyMs += result.latencyMs;
|
|
56
|
+
if (result.kind === "succeeded") {
|
|
57
|
+
return { kind: "succeeded", choice, attempt, latencyMs, value: result.value };
|
|
58
|
+
}
|
|
59
|
+
args.recordFailedAttempt({ choice, attempt, result });
|
|
60
|
+
lastFailure = result.message;
|
|
61
|
+
if (result.kind === "customer_canceled") {
|
|
62
|
+
return {
|
|
63
|
+
kind: "customer_canceled",
|
|
64
|
+
choice,
|
|
65
|
+
attempt,
|
|
66
|
+
latencyMs,
|
|
67
|
+
failure: result.message,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (!result.retryable)
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
if (lastFailure === null) {
|
|
74
|
+
throw new Error("Provider attempt plan completed without an attempt.");
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
kind: "provider_failed",
|
|
78
|
+
choice,
|
|
79
|
+
attempt: lastAttempt,
|
|
80
|
+
latencyMs,
|
|
81
|
+
failure: lastFailure,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function syntheticCancellation(args, state) {
|
|
85
|
+
return {
|
|
86
|
+
kind: "customer_canceled",
|
|
87
|
+
...state,
|
|
88
|
+
failure: args.canceledFailure(),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type CandidateCostEstimate, type ModelPricing, type PricingLookup, type Provider, type ReasoningEffort, type RoutingDecision } from "@mupt-ai/dari-router/policy-engine";
|
|
2
|
+
import type { RequestTags } from "../platform/platform.js";
|
|
3
|
+
import type { InteractionRequest, ProviderIdentity } from "../interaction/types.js";
|
|
4
|
+
import { type ProviderAttemptAbort } from "../runtime/customer_disconnect.js";
|
|
5
|
+
import { type RoutingUsageContext } from "../telemetry/usage.js";
|
|
6
|
+
import type { ProviderAuth, ProviderKeySource, ResolvedRouter, ResolvedRouterModelConfig } from "../types.js";
|
|
7
|
+
import { type ProviderResponseCapture } from "./response_capture.js";
|
|
8
|
+
import { type ProviderEndpoint, type ProviderEventStream } from "./pi.js";
|
|
9
|
+
import { type PromptTokenEstimate } from "./cancel_estimate.js";
|
|
10
|
+
type ProviderCallConfig = {
|
|
11
|
+
model: string;
|
|
12
|
+
apiKey: string;
|
|
13
|
+
auth: ProviderAuth;
|
|
14
|
+
pricing: ModelPricing | null;
|
|
15
|
+
config: ResolvedRouterModelConfig | undefined;
|
|
16
|
+
conversationId: string;
|
|
17
|
+
sessionId: string;
|
|
18
|
+
reasoningEffort: ReasoningEffort;
|
|
19
|
+
promptEstimate: PromptTokenEstimate | undefined;
|
|
20
|
+
endpoint?: ProviderEndpoint;
|
|
21
|
+
};
|
|
22
|
+
export type ProviderExecution = ProviderCallConfig & {
|
|
23
|
+
provider: Provider;
|
|
24
|
+
providerKeySource: ProviderKeySource;
|
|
25
|
+
subscriptionUserId?: string;
|
|
26
|
+
subscriptionCredentialId?: string;
|
|
27
|
+
usageContext: RoutingUsageContext | undefined;
|
|
28
|
+
headers: Record<string, string>;
|
|
29
|
+
};
|
|
30
|
+
export type CompletedProviderCall = {
|
|
31
|
+
message: Record<string, unknown>;
|
|
32
|
+
source: ProviderIdentity;
|
|
33
|
+
providerLatencyMs: number;
|
|
34
|
+
providerStartedAt: Date;
|
|
35
|
+
};
|
|
36
|
+
export type StartedCompletion = {
|
|
37
|
+
promise: Promise<CompletedProviderCall>;
|
|
38
|
+
customerAbort: ProviderAttemptAbort;
|
|
39
|
+
responseCapture?: ProviderResponseCapture;
|
|
40
|
+
};
|
|
41
|
+
export type StartedStream = {
|
|
42
|
+
providerStream: ProviderEventStream;
|
|
43
|
+
providerStartedMs: number;
|
|
44
|
+
customerAbort: ProviderAttemptAbort;
|
|
45
|
+
responseCapture?: ProviderResponseCapture;
|
|
46
|
+
};
|
|
47
|
+
export declare function prepareProviderExecution(args: {
|
|
48
|
+
decision: RoutingDecision;
|
|
49
|
+
credentials: ResolvedRouter;
|
|
50
|
+
billable: boolean;
|
|
51
|
+
routerId: string;
|
|
52
|
+
pricing: PricingLookup;
|
|
53
|
+
conversationId: string;
|
|
54
|
+
promptCacheKey?: string;
|
|
55
|
+
costEstimates?: readonly CandidateCostEstimate[];
|
|
56
|
+
tags?: RequestTags;
|
|
57
|
+
}): ProviderExecution;
|
|
58
|
+
export declare function startProviderCompletion(args: {
|
|
59
|
+
interaction: InteractionRequest;
|
|
60
|
+
execution: ProviderExecution;
|
|
61
|
+
clientSignal?: AbortSignal;
|
|
62
|
+
}): StartedCompletion;
|
|
63
|
+
export declare function startProviderStream(args: {
|
|
64
|
+
interaction: InteractionRequest;
|
|
65
|
+
execution: ProviderExecution;
|
|
66
|
+
clientSignal?: AbortSignal;
|
|
67
|
+
}): Promise<StartedStream>;
|
|
68
|
+
type PrimedStream = {
|
|
69
|
+
outcome: "continue";
|
|
70
|
+
events: AsyncIterable<Record<string, unknown>>;
|
|
71
|
+
} | {
|
|
72
|
+
outcome: "error";
|
|
73
|
+
failure: Record<string, unknown>;
|
|
74
|
+
};
|
|
75
|
+
export declare function primeProviderStream(events: AsyncIterable<Record<string, unknown>>, customerAbort: ProviderAttemptAbort): Promise<PrimedStream>;
|
|
76
|
+
export declare function scrubProviderMessage(message: Record<string, unknown>, auth: ProviderAuth): Record<string, unknown>;
|
|
77
|
+
export {};
|