@mupt-ai/dari-gateway 0.1.0 → 0.2.1
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 -1
- 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 +23 -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 +81 -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 +6 -0
- package/dist/index.js +8 -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 +37 -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 +65 -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 +53 -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 +203 -0
- package/dist/interaction/types.js +5 -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 +8 -0
- package/dist/models/execution_provider.js +13 -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 +41 -0
- package/dist/models/runtime_overrides.d.ts +4 -0
- package/dist/models/runtime_overrides.js +209 -0
- package/dist/observability/errors.d.ts +8 -0
- package/dist/observability/errors.js +11 -0
- package/dist/platform/platform.d.ts +152 -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 +212 -0
- package/dist/protocol/input/chat_completions_validation.d.ts +2 -0
- package/dist/protocol/input/chat_completions_validation.js +257 -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 +319 -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 +398 -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 +292 -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 +31 -0
- package/dist/providers/subscription_limits.js +163 -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 +4 -0
- package/dist/runtime/explicit_model.js +53 -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 +167 -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/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 +171 -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 +55 -0
- package/dist/self_host/subscriptions/oauth.js +281 -0
- package/dist/self_host/subscriptions/store.d.ts +78 -0
- package/dist/self_host/subscriptions/store.js +235 -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 +94 -0
- package/dist/types.js +1 -0
- package/package.json +22 -5
- package/src/bun.ts +4 -0
- 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 +1 -1
- package/src/context/provider_prompt_accounting.ts +5 -5
- package/src/context/routing_context.ts +17 -17
- package/src/http/auth.ts +1 -1
- package/src/http/handler.ts +8 -8
- package/src/http/serve.ts +3 -3
- package/src/index.ts +10 -9
- package/src/ingress/anthropic_messages.ts +12 -12
- package/src/ingress/anthropic_models.ts +1 -1
- package/src/ingress/chat_completions.ts +9 -9
- package/src/ingress/claude_code/request_context.ts +2 -2
- package/src/ingress/codex.ts +10 -10
- package/src/ingress/codex_models.ts +4 -4
- package/src/ingress/json.ts +1 -1
- package/src/ingress/models.ts +10 -10
- 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 +3 -0
- package/src/models/context_limits.ts +1 -1
- package/src/models/execution_provider.ts +1 -1
- package/src/models/ids.ts +1 -1
- package/src/models/provider_defaults.ts +1 -1
- package/src/models/runtime_overrides.ts +1 -1
- package/src/observability/errors.ts +2 -2
- package/src/platform/platform.ts +36 -4
- package/src/protocol/input/anthropic_messages.ts +7 -7
- package/src/protocol/input/chat_completions.ts +5 -5
- package/src/protocol/input/chat_completions_validation.ts +4 -4
- 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 +115 -41
- package/src/providers/pi_context.ts +6 -6
- package/src/providers/pi_options.ts +283 -453
- package/src/providers/pi_output.ts +6 -5
- package/src/providers/provider_attempt_runner.ts +1 -1
- package/src/providers/provider_call.ts +37 -18
- package/src/providers/provider_reported_cost.ts +138 -0
- package/src/providers/reasoning.ts +2 -2
- package/src/providers/stream_finalization.ts +10 -10
- package/src/providers/subscription_limits.ts +3 -3
- package/src/runtime/claude_code/auxiliary_routing.ts +5 -5
- package/src/runtime/customer_disconnect.ts +1 -1
- package/src/runtime/explicit_model.ts +31 -4
- 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 +46 -10
- package/src/runtime/provider_stream_lifecycle.ts +1 -1
- package/src/runtime/provider_stream_outcome.ts +2 -2
- package/src/runtime/request_tags.ts +34 -0
- package/src/runtime/routed_completion.ts +13 -11
- package/src/runtime/routed_protocol.ts +2 -2
- package/src/runtime/routed_runtime.ts +38 -20
- package/src/runtime/routing_lease.ts +7 -7
- package/src/runtime/runtime_reporter.ts +3 -3
- package/src/self_host/main.ts +19 -14
- package/src/self_host/platform.ts +5 -5
- package/src/self_host/prefix_store.ts +2 -2
- package/src/self_host/resolve.ts +11 -11
- 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/store.ts +1 -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 +11 -11
- 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 +30 -25
- 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 +9 -5
- package/src/types.ts +15 -0
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
import { HttpError } from "../http/errors.js";
|
|
2
|
+
import { piMessageToInteractionOutput } from "./pi_output.js";
|
|
3
|
+
import { captureOperationalError } from "../observability/errors.js";
|
|
4
|
+
import { CustomerDisconnectedError, customerCanceledProviderMessage, } from "../runtime/customer_disconnect.js";
|
|
5
|
+
import { isProviderFailureMessage, providerFailureFromCaught, providerFailureFromTerminal, providerFailureMessage, } from "../runtime/provider_stream_outcome.js";
|
|
6
|
+
import { reportedExecution, } from "../runtime/runtime_reporter.js";
|
|
7
|
+
import { trackBackgroundTelemetry } from "../telemetry/background.js";
|
|
8
|
+
import { gatewayPlatform } from "../platform/platform.js";
|
|
9
|
+
import { reportRoutingUsage } from "../telemetry/usage.js";
|
|
10
|
+
import { primeProviderStream, scrubProviderMessage, startProviderCompletion, startProviderStream, } from "./provider_call.js";
|
|
11
|
+
import { runProviderAttemptPlan, } from "./provider_attempt_runner.js";
|
|
12
|
+
import { estimatedCancelUsage, NO_DELIVERED_OUTPUT, observeDeliveredOutput, } from "./cancel_estimate.js";
|
|
13
|
+
import { providerResponseCaptureFromError } from "./response_capture.js";
|
|
14
|
+
import { createStreamFinalizer } from "./stream_finalization.js";
|
|
15
|
+
import { detectSubscriptionUsageLimit, failureWithSubscriptionUsageLimit, retryAfterSeconds, subscriptionUsageLimitFromFailure, subscriptionSwitchedMessage, subscriptionUsageLimitMessage, } from "./subscription_limits.js";
|
|
16
|
+
export async function executeNonStreaming(args) {
|
|
17
|
+
const result = await completeNonStreaming(args);
|
|
18
|
+
if (result.reportBarrierError !== undefined) {
|
|
19
|
+
captureOperationalError(result.reportBarrierError, {
|
|
20
|
+
code: "routing_report_barrier_failed",
|
|
21
|
+
requestId: args.requestId,
|
|
22
|
+
routerId: result.choice.execution.usageContext?.routerId,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return Response.json(result.responseBody, {
|
|
26
|
+
headers: result.choice.execution.headers,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export async function completeNonStreaming(args) {
|
|
30
|
+
const result = await completeWithRetries(args);
|
|
31
|
+
args.reporter.attachServingDecision(result.choice.decision);
|
|
32
|
+
if (result.kind === "customer_canceled") {
|
|
33
|
+
return reportCustomerCancellation({
|
|
34
|
+
requestId: args.requestId,
|
|
35
|
+
reporter: args.reporter,
|
|
36
|
+
choice: result.choice,
|
|
37
|
+
providerLatencyMs: result.latencyMs,
|
|
38
|
+
providerMessage: result.failure,
|
|
39
|
+
reportBarrier: args.reportBarrier,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (result.kind === "provider_failed") {
|
|
43
|
+
return throwProviderFailure({
|
|
44
|
+
requestId: args.requestId,
|
|
45
|
+
reporter: args.reporter,
|
|
46
|
+
reportBarrier: args.reportBarrier,
|
|
47
|
+
result,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const { value: { completion }, choice, } = result;
|
|
51
|
+
let output;
|
|
52
|
+
let responseBody;
|
|
53
|
+
try {
|
|
54
|
+
output = piMessageToInteractionOutput(completion.message, completion.source, args.interaction);
|
|
55
|
+
responseBody = args.protocol.responseBody({
|
|
56
|
+
id: args.requestId,
|
|
57
|
+
model: choice.execution.model,
|
|
58
|
+
output,
|
|
59
|
+
modelCost: args.reporter.modelCost({
|
|
60
|
+
model: choice.decision.selectedModel, reasoning_effort: choice.decision.reasoningEffort,
|
|
61
|
+
role: choice.role, attempt: result.attempt, outcome: "completed", billingOutcome: "completed",
|
|
62
|
+
execution: reportedExecution(choice.execution), message: completion.message,
|
|
63
|
+
}),
|
|
64
|
+
request: args.interaction,
|
|
65
|
+
routing: choice.decision,
|
|
66
|
+
conversationId: choice.execution.conversationId,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
await reportTerminalProviderFailure({
|
|
71
|
+
requestId: args.requestId,
|
|
72
|
+
reporter: args.reporter,
|
|
73
|
+
choice,
|
|
74
|
+
attempt: result.attempt,
|
|
75
|
+
providerLatencyMs: result.latencyMs,
|
|
76
|
+
providerMessage: completion.message,
|
|
77
|
+
reportBarrier: args.reportBarrier,
|
|
78
|
+
error,
|
|
79
|
+
});
|
|
80
|
+
// reportTerminalProviderFailure always throws the original translation
|
|
81
|
+
// error after settling exact billing. Keep this explicit for TypeScript's
|
|
82
|
+
// definite-assignment analysis.
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
recordProviderAttempt(args.reporter, choice, result.attempt, "completed", "completed", completion.message);
|
|
86
|
+
const providerOutcome = {
|
|
87
|
+
status: "completed",
|
|
88
|
+
output,
|
|
89
|
+
message: completion.message,
|
|
90
|
+
responseBody,
|
|
91
|
+
providerLatencyMs: result.latencyMs,
|
|
92
|
+
execution: reportedExecution(choice.execution),
|
|
93
|
+
};
|
|
94
|
+
// Provider economics are terminal now. Register them before the speculative
|
|
95
|
+
// selector/report barrier so the frozen facts cannot change afterwards.
|
|
96
|
+
const terminal = args.reporter.freezeProviderTerminal(providerOutcome);
|
|
97
|
+
// Settle the speculative selector before reporting, mirroring the stream
|
|
98
|
+
// path: the report builds the prefix entry, whose next_model must carry
|
|
99
|
+
// the selector's next-turn choice (and its trace), not the speculative
|
|
100
|
+
// serving pick that happened to win the provider race.
|
|
101
|
+
let reportBarrierError;
|
|
102
|
+
try {
|
|
103
|
+
await args.reportBarrier;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
reportBarrierError = error;
|
|
107
|
+
}
|
|
108
|
+
terminal.report();
|
|
109
|
+
// Every turn — speculative or not — holds its response on the fast
|
|
110
|
+
// prefix-state write, so an immediate continuation always resolves this
|
|
111
|
+
// turn's entry. Bounded by PREFIX_STATE_WRITE_WAIT_MS.
|
|
112
|
+
await args.reporter.waitForPrefixEntryWrite();
|
|
113
|
+
return {
|
|
114
|
+
choice,
|
|
115
|
+
output,
|
|
116
|
+
responseBody,
|
|
117
|
+
...(reportBarrierError === undefined ? {} : { reportBarrierError }),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async function completeWithRetries(args) {
|
|
121
|
+
return runProviderAttemptPlan({
|
|
122
|
+
primary: args.primary,
|
|
123
|
+
retries: args.primaryRetries,
|
|
124
|
+
resolveFallback: args.resolveFallback,
|
|
125
|
+
primaryInitial: args.startedCompletion,
|
|
126
|
+
isCustomerCanceled: () => customerAbortRequested(args.clientSignal),
|
|
127
|
+
canceledFailure: customerCanceledProviderMessage,
|
|
128
|
+
runAttempt: ({ choice, initial }) => runCompletionAttempt({
|
|
129
|
+
interaction: args.interaction,
|
|
130
|
+
choice,
|
|
131
|
+
reporter: args.reporter,
|
|
132
|
+
startedCompletion: initial,
|
|
133
|
+
clientSignal: args.clientSignal,
|
|
134
|
+
}),
|
|
135
|
+
recordFailedAttempt: ({ choice, attempt, result }) => recordSettledFailure(args.reporter, choice, attempt, result),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
async function runCompletionAttempt(args) {
|
|
139
|
+
const startedAt = Date.now();
|
|
140
|
+
const started = args.startedCompletion ?? startProviderCompletion({
|
|
141
|
+
interaction: args.interaction,
|
|
142
|
+
execution: args.choice.execution,
|
|
143
|
+
clientSignal: args.clientSignal,
|
|
144
|
+
});
|
|
145
|
+
try {
|
|
146
|
+
const completion = await started.promise;
|
|
147
|
+
if (started.customerAbort.aborted) {
|
|
148
|
+
return customerCanceledAttempt(completion.providerLatencyMs, args.choice.execution, completion.message);
|
|
149
|
+
}
|
|
150
|
+
if (isProviderFailureMessage(completion.message)) {
|
|
151
|
+
return providerFailedAttempt(completion.message, completion.providerLatencyMs, args.choice.execution, started.responseCapture);
|
|
152
|
+
}
|
|
153
|
+
if (args.choice.execution.usageContext && hasUsage(completion.message)) {
|
|
154
|
+
await reportRoutingUsage({
|
|
155
|
+
...args.choice.execution.usageContext,
|
|
156
|
+
startedAt: completion.providerStartedAt,
|
|
157
|
+
}, completion.message);
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
kind: "succeeded",
|
|
161
|
+
value: { completion },
|
|
162
|
+
latencyMs: completion.providerLatencyMs,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
const latencyMs = Date.now() - startedAt;
|
|
167
|
+
if (started.customerAbort.aborted ||
|
|
168
|
+
error instanceof CustomerDisconnectedError) {
|
|
169
|
+
return customerCanceledAttempt(latencyMs, args.choice.execution);
|
|
170
|
+
}
|
|
171
|
+
return providerFailedAttempt(scrubProviderMessage(providerFailureFromCaught(error), args.choice.execution.auth), latencyMs, args.choice.execution, started.responseCapture);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async function settleTerminal(args) {
|
|
175
|
+
const terminal = args.reporter.freezeProviderTerminal(args.outcome);
|
|
176
|
+
try {
|
|
177
|
+
await args.reportBarrier;
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
captureOperationalError(error, {
|
|
181
|
+
code: "routing_report_barrier_failed",
|
|
182
|
+
requestId: args.requestId,
|
|
183
|
+
routerId: args.routerId,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
terminal.report();
|
|
187
|
+
}
|
|
188
|
+
async function reportTerminalProviderFailure(args) {
|
|
189
|
+
const failure = scrubProviderMessage(providerFailureFromTerminal(args.error, args.providerMessage), args.choice.execution.auth);
|
|
190
|
+
recordProviderAttempt(args.reporter, args.choice, args.attempt, "terminal_error", "provider_failed", failure);
|
|
191
|
+
await settleTerminal({
|
|
192
|
+
reporter: args.reporter,
|
|
193
|
+
outcome: {
|
|
194
|
+
status: "provider_error",
|
|
195
|
+
message: failure,
|
|
196
|
+
providerLatencyMs: args.providerLatencyMs,
|
|
197
|
+
execution: reportedExecution(args.choice.execution),
|
|
198
|
+
},
|
|
199
|
+
requestId: args.requestId,
|
|
200
|
+
routerId: args.choice.execution.usageContext?.routerId,
|
|
201
|
+
reportBarrier: args.reportBarrier,
|
|
202
|
+
});
|
|
203
|
+
throw args.error;
|
|
204
|
+
}
|
|
205
|
+
async function reportCustomerCancellation(args) {
|
|
206
|
+
const usageContext = args.choice.execution.usageContext;
|
|
207
|
+
if (usageContext && hasUsage(args.providerMessage)) {
|
|
208
|
+
await reportRoutingUsage(usageContext, args.providerMessage);
|
|
209
|
+
}
|
|
210
|
+
await settleTerminal({
|
|
211
|
+
reporter: args.reporter,
|
|
212
|
+
outcome: {
|
|
213
|
+
status: "customer_canceled",
|
|
214
|
+
message: args.providerMessage,
|
|
215
|
+
responseBody: null,
|
|
216
|
+
providerLatencyMs: args.providerLatencyMs,
|
|
217
|
+
execution: reportedExecution(args.choice.execution),
|
|
218
|
+
},
|
|
219
|
+
requestId: args.requestId,
|
|
220
|
+
routerId: args.choice.execution.usageContext?.routerId,
|
|
221
|
+
reportBarrier: args.reportBarrier,
|
|
222
|
+
});
|
|
223
|
+
throw new CustomerDisconnectedError();
|
|
224
|
+
}
|
|
225
|
+
async function throwProviderFailure(args) {
|
|
226
|
+
const { result } = args;
|
|
227
|
+
await settleTerminal({
|
|
228
|
+
reporter: args.reporter,
|
|
229
|
+
outcome: {
|
|
230
|
+
status: "provider_error",
|
|
231
|
+
message: result.failure,
|
|
232
|
+
providerLatencyMs: result.latencyMs,
|
|
233
|
+
execution: reportedExecution(result.choice.execution),
|
|
234
|
+
},
|
|
235
|
+
requestId: args.requestId,
|
|
236
|
+
routerId: result.choice.execution.usageContext?.routerId,
|
|
237
|
+
reportBarrier: args.reportBarrier,
|
|
238
|
+
});
|
|
239
|
+
const limit = subscriptionUsageLimitFromFailure(result.failure);
|
|
240
|
+
if (limit?.switched === true) {
|
|
241
|
+
// The client's retry is served by the user's next subscription.
|
|
242
|
+
throw new HttpError(503, subscriptionSwitchedMessage(limit), "subscription_switched", undefined, { "retry-after": "1" });
|
|
243
|
+
}
|
|
244
|
+
if (limit !== null) {
|
|
245
|
+
throw new HttpError(429, subscriptionUsageLimitMessage(limit), "subscription_usage_limit", undefined, { "retry-after": String(retryAfterSeconds(limit)) });
|
|
246
|
+
}
|
|
247
|
+
throw new HttpError(502, providerFailureMessage(result.failure), "provider_execution_failed");
|
|
248
|
+
}
|
|
249
|
+
export async function prepareStreamingExecution(args) {
|
|
250
|
+
const primaryInitial = args.initialError !== undefined
|
|
251
|
+
? { kind: "error", error: args.initialError }
|
|
252
|
+
: args.startedStream === undefined
|
|
253
|
+
? undefined
|
|
254
|
+
: { kind: "started", started: args.startedStream };
|
|
255
|
+
const result = await runProviderAttemptPlan({
|
|
256
|
+
primary: args.primary,
|
|
257
|
+
retries: args.primaryRetries,
|
|
258
|
+
resolveFallback: args.resolveFallback,
|
|
259
|
+
primaryInitial,
|
|
260
|
+
isCustomerCanceled: () => customerAbortRequested(args.clientSignal),
|
|
261
|
+
canceledFailure: customerCanceledProviderMessage,
|
|
262
|
+
runAttempt: ({ choice, initial }) => runStreamSetupAttempt({
|
|
263
|
+
interaction: args.interaction,
|
|
264
|
+
choice,
|
|
265
|
+
initial,
|
|
266
|
+
clientSignal: args.clientSignal,
|
|
267
|
+
}),
|
|
268
|
+
recordFailedAttempt: ({ choice, attempt, result }) => recordSettledFailure(args.reporter, choice, attempt, result),
|
|
269
|
+
});
|
|
270
|
+
args.reporter.attachServingDecision(result.choice.decision);
|
|
271
|
+
if (result.kind === "customer_canceled") {
|
|
272
|
+
return reportCustomerCancellation({
|
|
273
|
+
requestId: args.requestId,
|
|
274
|
+
reporter: args.reporter,
|
|
275
|
+
choice: result.choice,
|
|
276
|
+
providerLatencyMs: result.latencyMs,
|
|
277
|
+
providerMessage: result.failure,
|
|
278
|
+
reportBarrier: args.reportBarrier,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
if (result.kind === "provider_failed") {
|
|
282
|
+
return throwProviderFailure({
|
|
283
|
+
requestId: args.requestId,
|
|
284
|
+
reporter: args.reporter,
|
|
285
|
+
reportBarrier: args.reportBarrier,
|
|
286
|
+
result,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
return {
|
|
290
|
+
choice: result.choice,
|
|
291
|
+
started: result.value,
|
|
292
|
+
attempt: result.attempt,
|
|
293
|
+
failedSetupLatencyMs: result.latencyMs,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
async function runStreamSetupAttempt(args) {
|
|
297
|
+
const startedAt = Date.now();
|
|
298
|
+
let started;
|
|
299
|
+
try {
|
|
300
|
+
if (args.initial?.kind === "error")
|
|
301
|
+
throw args.initial.error;
|
|
302
|
+
started = args.initial?.kind === "started"
|
|
303
|
+
? args.initial.started
|
|
304
|
+
: await startProviderStream({
|
|
305
|
+
interaction: args.interaction,
|
|
306
|
+
execution: args.choice.execution,
|
|
307
|
+
clientSignal: args.clientSignal,
|
|
308
|
+
});
|
|
309
|
+
// Prime before committing so connection failures and prompt rejections
|
|
310
|
+
// stay inside the one shared retry/fallback state machine.
|
|
311
|
+
const primed = await primeProviderStream(started.providerStream.events, started.customerAbort);
|
|
312
|
+
if (primed.outcome === "error") {
|
|
313
|
+
started.customerAbort.dispose();
|
|
314
|
+
return providerFailedAttempt(scrubProviderMessage(primed.failure, args.choice.execution.auth), Date.now() - startedAt, args.choice.execution, started.responseCapture);
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
kind: "succeeded",
|
|
318
|
+
value: {
|
|
319
|
+
providerStartedMs: started.providerStartedMs,
|
|
320
|
+
providerStream: {
|
|
321
|
+
events: primed.events,
|
|
322
|
+
source: started.providerStream.source,
|
|
323
|
+
},
|
|
324
|
+
customerAbort: started.customerAbort,
|
|
325
|
+
},
|
|
326
|
+
latencyMs: 0,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
const customerCanceled = started?.customerAbort.aborted === true ||
|
|
331
|
+
error instanceof CustomerDisconnectedError;
|
|
332
|
+
started?.customerAbort.dispose();
|
|
333
|
+
if (customerCanceled) {
|
|
334
|
+
return customerCanceledAttempt(Date.now() - startedAt, args.choice.execution);
|
|
335
|
+
}
|
|
336
|
+
return providerFailedAttempt(scrubProviderMessage(providerFailureFromCaught(error), args.choice.execution.auth), Date.now() - startedAt, args.choice.execution, started?.responseCapture ?? providerResponseCaptureFromError(error));
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
export async function executeStreaming(args) {
|
|
340
|
+
const { execution } = args.choice;
|
|
341
|
+
const started = args.startedStream;
|
|
342
|
+
args.reporter.attachServingDecision(args.choice.decision);
|
|
343
|
+
const observed = observeDeliveredOutput(started.providerStream.events);
|
|
344
|
+
const finalizer = createStreamFinalizer({
|
|
345
|
+
requestId: args.requestId,
|
|
346
|
+
interaction: args.interaction,
|
|
347
|
+
decision: args.choice.decision,
|
|
348
|
+
execution,
|
|
349
|
+
reporter: args.reporter,
|
|
350
|
+
protocol: args.protocol,
|
|
351
|
+
providerLatencyMs: () => args.failedSetupLatencyMs + Date.now() - started.providerStartedMs,
|
|
352
|
+
role: args.choice.role,
|
|
353
|
+
attempt: args.attempt,
|
|
354
|
+
reportBarrier: args.reportBarrier,
|
|
355
|
+
delivered: observed.delivered,
|
|
356
|
+
source: started.providerStream.source,
|
|
357
|
+
startedAtMs: started.providerStartedMs,
|
|
358
|
+
});
|
|
359
|
+
return new Response(args.protocol.streamBody({
|
|
360
|
+
id: args.requestId,
|
|
361
|
+
model: execution.model,
|
|
362
|
+
routing: args.choice.decision,
|
|
363
|
+
events: observed.events,
|
|
364
|
+
source: started.providerStream.source,
|
|
365
|
+
request: args.interaction,
|
|
366
|
+
conversationId: execution.conversationId,
|
|
367
|
+
clientSignal: args.clientSignal,
|
|
368
|
+
modelCost: (message, failed) => args.reporter.modelCost({
|
|
369
|
+
model: args.choice.decision.selectedModel, reasoning_effort: args.choice.decision.reasoningEffort,
|
|
370
|
+
role: args.choice.role, attempt: args.attempt,
|
|
371
|
+
outcome: failed ? "terminal_error" : "completed",
|
|
372
|
+
billingOutcome: failed ? "provider_failed" : "completed",
|
|
373
|
+
execution: reportedExecution(execution), message,
|
|
374
|
+
}),
|
|
375
|
+
onAbort: () => started.customerAbort.abort(),
|
|
376
|
+
beforeClose: finalizer.beforeResponseClose,
|
|
377
|
+
onFinal: (outcome) => {
|
|
378
|
+
started.customerAbort.dispose();
|
|
379
|
+
trackBackgroundTelemetry(finalizer.afterResponseDetached(outcome));
|
|
380
|
+
},
|
|
381
|
+
}), { headers: streamHeaders(execution) });
|
|
382
|
+
}
|
|
383
|
+
function streamHeaders(execution) {
|
|
384
|
+
return {
|
|
385
|
+
"Content-Type": "text/event-stream",
|
|
386
|
+
"Cache-Control": "no-cache",
|
|
387
|
+
"Connection": "keep-alive",
|
|
388
|
+
...execution.headers,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
function customerAbortRequested(clientSignal) {
|
|
392
|
+
// A disconnected client never starts new paid work that nobody can receive.
|
|
393
|
+
return clientSignal?.aborted === true;
|
|
394
|
+
}
|
|
395
|
+
function recordProviderAttempt(reporter, choice, attempt, outcome, billingOutcome, message) {
|
|
396
|
+
reporter.recordProviderAttempt({
|
|
397
|
+
model: choice.decision.selectedModel,
|
|
398
|
+
reasoning_effort: choice.decision.reasoningEffort,
|
|
399
|
+
role: choice.role,
|
|
400
|
+
attempt,
|
|
401
|
+
outcome,
|
|
402
|
+
execution: reportedExecution(choice.execution),
|
|
403
|
+
message,
|
|
404
|
+
billingOutcome,
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
function recordSettledFailure(reporter, choice, attempt, result) {
|
|
408
|
+
recordProviderAttempt(reporter, choice, attempt, result.kind === "customer_canceled" ? "canceled" : "error", result.kind, result.message);
|
|
409
|
+
}
|
|
410
|
+
async function providerFailedAttempt(message, latencyMs, execution, responseCapture) {
|
|
411
|
+
const limit = detectSubscriptionUsageLimit({
|
|
412
|
+
provider: execution.provider,
|
|
413
|
+
keySource: execution.providerKeySource,
|
|
414
|
+
captured: responseCapture?.last,
|
|
415
|
+
failure: message,
|
|
416
|
+
});
|
|
417
|
+
if (limit === null) {
|
|
418
|
+
return {
|
|
419
|
+
kind: "provider_failed",
|
|
420
|
+
message,
|
|
421
|
+
latencyMs,
|
|
422
|
+
retryable: !isPromptPolicyRejection(message),
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
// Retrying an exhausted plan cannot succeed. The platform learns about it
|
|
426
|
+
// before this request returns so the next resolve already serves the
|
|
427
|
+
// user's next subscription, or the router's subscription fallback model.
|
|
428
|
+
const switched = execution.subscriptionUserId !== undefined
|
|
429
|
+
&& await holdSubscription({
|
|
430
|
+
userId: execution.subscriptionUserId,
|
|
431
|
+
credentialId: execution.subscriptionCredentialId,
|
|
432
|
+
limit,
|
|
433
|
+
});
|
|
434
|
+
return {
|
|
435
|
+
kind: "provider_failed",
|
|
436
|
+
message: failureWithSubscriptionUsageLimit(message, { ...limit, switched }),
|
|
437
|
+
latencyMs,
|
|
438
|
+
retryable: false,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
// The provider call was in flight, so the prompt was paid for. A completion
|
|
442
|
+
// that returned before the abort was observed carries exact usage; otherwise
|
|
443
|
+
// the prompt is estimated and nothing was delivered. A usage object with no
|
|
444
|
+
// tokens at all is the SDK's placeholder for an interrupted call, not a
|
|
445
|
+
// measurement, so it falls back to the estimate too.
|
|
446
|
+
function customerCanceledAttempt(latencyMs, execution, completed) {
|
|
447
|
+
const exactUsage = completed !== undefined && hasUsage(completed) && usageHasTokens(completed.usage)
|
|
448
|
+
? completed.usage
|
|
449
|
+
: null;
|
|
450
|
+
return {
|
|
451
|
+
kind: "customer_canceled",
|
|
452
|
+
message: customerCanceledProviderMessage(exactUsage ??
|
|
453
|
+
estimatedCancelUsage({
|
|
454
|
+
pricing: execution.pricing,
|
|
455
|
+
promptEstimate: execution.promptEstimate,
|
|
456
|
+
delivered: NO_DELIVERED_OUTPUT,
|
|
457
|
+
}), typeof completed?.responseId === "string" ? completed.responseId : undefined),
|
|
458
|
+
latencyMs,
|
|
459
|
+
retryable: false,
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
function hasUsage(message) {
|
|
463
|
+
return (typeof message.usage === "object" &&
|
|
464
|
+
message.usage !== null &&
|
|
465
|
+
!Array.isArray(message.usage));
|
|
466
|
+
}
|
|
467
|
+
function usageHasTokens(usage) {
|
|
468
|
+
if (typeof usage !== "object" || usage === null)
|
|
469
|
+
return false;
|
|
470
|
+
const counts = usage;
|
|
471
|
+
return ["input", "output", "cacheRead", "cacheWrite"].some((key) => {
|
|
472
|
+
const value = counts[key];
|
|
473
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
function isPromptPolicyRejection(message) {
|
|
477
|
+
const text = providerFailureMessage(message).toLowerCase();
|
|
478
|
+
return text.includes("invalid prompt") && text.includes("usage policy");
|
|
479
|
+
}
|
|
480
|
+
// Never fails the request: the provider already refused. Resolves whether
|
|
481
|
+
// another subscription now serves.
|
|
482
|
+
async function holdSubscription(hold) {
|
|
483
|
+
try {
|
|
484
|
+
return await gatewayPlatform().markSubscriptionUnavailable(hold);
|
|
485
|
+
}
|
|
486
|
+
catch (error) {
|
|
487
|
+
console.error("subscription-unavailable write failed", error);
|
|
488
|
+
captureOperationalError(error, { code: "subscription_unavailable_ingest_failed" });
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type ModelCapabilityMetadata = {
|
|
2
|
+
model: Record<string, unknown>;
|
|
3
|
+
};
|
|
4
|
+
export declare const BEDROCK_API = "bedrock-converse-stream";
|
|
5
|
+
export declare function isBedrockApi(api: unknown): boolean;
|
|
6
|
+
export declare function modelSupportsImageInput(metadata: ModelCapabilityMetadata): boolean;
|
|
7
|
+
export declare function providerApiCanSerializeResponseFormat(metadata: ModelCapabilityMetadata): boolean;
|
|
8
|
+
export declare function isOpenAIResponsesApi(api: unknown): boolean;
|
|
9
|
+
export declare function modelSupportsReasoningConfigurationUpdate(metadata: ModelCapabilityMetadata): boolean;
|
|
10
|
+
export declare function modelSupportsHostedWebSearch(metadata: ModelCapabilityMetadata): boolean;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { isRecord } from "@mupt-ai/dari-router/policy-engine";
|
|
2
|
+
export const BEDROCK_API = "bedrock-converse-stream";
|
|
3
|
+
export function isBedrockApi(api) {
|
|
4
|
+
return api === BEDROCK_API;
|
|
5
|
+
}
|
|
6
|
+
export function modelSupportsImageInput(metadata) {
|
|
7
|
+
return Array.isArray(metadata.model.input) && metadata.model.input.includes("image");
|
|
8
|
+
}
|
|
9
|
+
export function providerApiCanSerializeResponseFormat(metadata) {
|
|
10
|
+
return (metadata.model.api === "openai-responses" ||
|
|
11
|
+
metadata.model.api === "azure-openai-responses" ||
|
|
12
|
+
metadata.model.api === "openai-completions" ||
|
|
13
|
+
metadata.model.api === "anthropic-messages");
|
|
14
|
+
}
|
|
15
|
+
export function isOpenAIResponsesApi(api) {
|
|
16
|
+
return (api === "openai-responses"
|
|
17
|
+
|| api === "openai-codex-responses"
|
|
18
|
+
|| api === "azure-openai-responses");
|
|
19
|
+
}
|
|
20
|
+
export function modelSupportsReasoningConfigurationUpdate(metadata) {
|
|
21
|
+
return isRecord(metadata.model.compat)
|
|
22
|
+
&& metadata.model.compat.supportsReasoningConfigurationUpdate === true;
|
|
23
|
+
}
|
|
24
|
+
export function modelSupportsHostedWebSearch(metadata) {
|
|
25
|
+
return ((metadata.model.provider === "openai" && metadata.model.api === "openai-responses")
|
|
26
|
+
|| (metadata.model.provider === "openai-codex"
|
|
27
|
+
&& metadata.model.api === "openai-codex-responses")
|
|
28
|
+
|| metadata.model.api === "azure-openai-responses");
|
|
29
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type ModelPricing, type ReasoningEffort, type RouterModelPrice } from "@mupt-ai/dari-router/policy-engine";
|
|
2
|
+
import type { ProviderFetch } from "./response_capture.js";
|
|
3
|
+
import type { InteractionRequest, ProviderIdentity } from "../interaction/types.js";
|
|
4
|
+
import type { ResolvedProviderAuth, ResolvedRouterModelConfig } from "../types.js";
|
|
5
|
+
type PiAi = {
|
|
6
|
+
completeSimple: (model: Record<string, unknown>, context: Record<string, unknown>, options: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
7
|
+
streamSimple: (model: Record<string, unknown>, context: Record<string, unknown>, options: Record<string, unknown>) => AsyncIterable<Record<string, unknown>>;
|
|
8
|
+
getModel?: (provider: string, id: string) => Record<string, unknown> | undefined;
|
|
9
|
+
getSupportedThinkingLevels?: (model: Record<string, unknown>) => string[];
|
|
10
|
+
};
|
|
11
|
+
export type ModelRuntimeMetadata = {
|
|
12
|
+
model: Record<string, unknown>;
|
|
13
|
+
supportedThinkingLevels: string[];
|
|
14
|
+
};
|
|
15
|
+
export type ProviderEndpoint = {
|
|
16
|
+
baseUrl?: string;
|
|
17
|
+
headers?: Record<string, string>;
|
|
18
|
+
};
|
|
19
|
+
export type ProviderCompletion = {
|
|
20
|
+
message: Record<string, unknown>;
|
|
21
|
+
source: ProviderIdentity;
|
|
22
|
+
};
|
|
23
|
+
export type ProviderEventStream = {
|
|
24
|
+
events: AsyncIterable<Record<string, unknown>>;
|
|
25
|
+
source: ProviderIdentity;
|
|
26
|
+
};
|
|
27
|
+
export type ModelMetadataLookup = (modelId: string, pricing?: ModelPricing | null) => ModelRuntimeMetadata;
|
|
28
|
+
export declare const pi: PiAi;
|
|
29
|
+
export declare function completeInteractionModel(args: {
|
|
30
|
+
model: string;
|
|
31
|
+
request: InteractionRequest;
|
|
32
|
+
apiKey: string;
|
|
33
|
+
auth?: ResolvedProviderAuth;
|
|
34
|
+
pricing?: ModelPricing | null;
|
|
35
|
+
config?: ResolvedRouterModelConfig;
|
|
36
|
+
endpoint?: ProviderEndpoint;
|
|
37
|
+
sessionId?: string;
|
|
38
|
+
selectedReasoningEffort?: ReasoningEffort;
|
|
39
|
+
timeoutMs?: number;
|
|
40
|
+
signal?: AbortSignal;
|
|
41
|
+
fetch?: ProviderFetch;
|
|
42
|
+
}): Promise<ProviderCompletion>;
|
|
43
|
+
export declare function completeProviderEventStream(events: AsyncIterable<Record<string, unknown>>): Promise<Record<string, unknown>>;
|
|
44
|
+
export declare function streamInteractionModel(args: {
|
|
45
|
+
model: string;
|
|
46
|
+
request: InteractionRequest;
|
|
47
|
+
apiKey: string;
|
|
48
|
+
auth?: ResolvedProviderAuth;
|
|
49
|
+
pricing?: ModelPricing | null;
|
|
50
|
+
config?: ResolvedRouterModelConfig;
|
|
51
|
+
endpoint?: ProviderEndpoint;
|
|
52
|
+
sessionId?: string;
|
|
53
|
+
selectedReasoningEffort?: ReasoningEffort;
|
|
54
|
+
signal?: AbortSignal;
|
|
55
|
+
fetch?: ProviderFetch;
|
|
56
|
+
}): Promise<ProviderEventStream>;
|
|
57
|
+
export declare function modelContextWindow(modelId: string): number | null;
|
|
58
|
+
/**
|
|
59
|
+
* Pi's catalog price for a canonical model served by `provider`, in USD per
|
|
60
|
+
* million tokens. Null when Pi does not list the model.
|
|
61
|
+
*/
|
|
62
|
+
export declare function registeredModelPrice(modelId: string, provider?: string): RouterModelPrice | null;
|
|
63
|
+
export declare function modelMetadataLookup(configs?: Record<string, ResolvedRouterModelConfig>): ModelMetadataLookup;
|
|
64
|
+
export declare function buildModel(pi: PiAi, modelId: string, pricing?: ModelPricing | null, config?: ResolvedRouterModelConfig): Record<string, unknown>;
|
|
65
|
+
export {};
|