@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,296 @@
|
|
|
1
|
+
import { isRecord, } from "@mupt-ai/dari-router/policy-engine";
|
|
2
|
+
import { executionProviderForModel, keySourceForModel } from "../models/execution_provider.js";
|
|
3
|
+
import { HttpError } from "../http/errors.js";
|
|
4
|
+
import { CustomerDisconnectedError, createProviderAttemptAbort, } from "../runtime/customer_disconnect.js";
|
|
5
|
+
import { isProviderFailureMessage, providerFailureFromCaught, providerFailureFromEvent, } from "../runtime/provider_stream_outcome.js";
|
|
6
|
+
import { providerAuthForSelectedModel } from "../strategies/routing.js";
|
|
7
|
+
import { scrubSecretValues } from "../telemetry/scrub.js";
|
|
8
|
+
import { usageContextFor, } from "../telemetry/usage.js";
|
|
9
|
+
import { awsRoleCredentials } from "./aws_assume_role.js";
|
|
10
|
+
import { attachProviderResponseCapture, createProviderResponseCapture, } from "./response_capture.js";
|
|
11
|
+
import { completeInteractionModel, streamInteractionModel, } from "./pi.js";
|
|
12
|
+
import { promptTokenEstimateFor } from "./cancel_estimate.js";
|
|
13
|
+
export function prepareProviderExecution(args) {
|
|
14
|
+
const model = args.decision.selectedModel;
|
|
15
|
+
const promptEstimate = promptTokenEstimateFor(args.costEstimates, model, args.decision.reasoningEffort);
|
|
16
|
+
const limit = args.credentials.model_configs?.[model]?.standard_context_limit;
|
|
17
|
+
if (args.credentials.allow_long_context !== true && limit != null && (promptEstimate === undefined || promptEstimate.promptTokens > limit)) {
|
|
18
|
+
throw new HttpError(400, "The prompt exceeds this model's standard-price context range. Shorten or compact the conversation.", "context_length_exceeded");
|
|
19
|
+
}
|
|
20
|
+
const provider = executionProviderForModel(args.credentials, model);
|
|
21
|
+
const supplied = args.credentials.provider_credentials?.[model];
|
|
22
|
+
const providerKeySource = keySourceForModel(args.credentials, model);
|
|
23
|
+
// A strict router serves a plan only when the platform supplied it for this
|
|
24
|
+
// request, never a pooled or personal one it resolved.
|
|
25
|
+
if (args.credentials.strict === true && providerKeySource === "subscription" && !supplied) {
|
|
26
|
+
throw new HttpError(400, `Strict routers do not serve '${model}' from a personal subscription.`, "strict_subscription_refused", "model");
|
|
27
|
+
}
|
|
28
|
+
const auth = supplied
|
|
29
|
+
? { type: "bearer", apiKey: supplied.apiKey.trim() }
|
|
30
|
+
: providerAuthForSelectedModel({ selectedModel: model, credentials: args.credentials });
|
|
31
|
+
return {
|
|
32
|
+
model,
|
|
33
|
+
apiKey: auth.type === "bearer" ? auth.apiKey : "",
|
|
34
|
+
auth,
|
|
35
|
+
pricing: args.pricing(model),
|
|
36
|
+
config: args.credentials.model_configs?.[model] ? {
|
|
37
|
+
...args.credentials.model_configs[model],
|
|
38
|
+
allow_long_context: args.credentials.allow_long_context === true,
|
|
39
|
+
zdr: args.credentials.zdr === true,
|
|
40
|
+
} : undefined,
|
|
41
|
+
conversationId: args.conversationId,
|
|
42
|
+
sessionId: args.promptCacheKey?.trim()
|
|
43
|
+
? args.promptCacheKey
|
|
44
|
+
: args.conversationId,
|
|
45
|
+
reasoningEffort: args.decision.reasoningEffort,
|
|
46
|
+
promptEstimate,
|
|
47
|
+
...(supplied?.baseUrl || supplied?.headers
|
|
48
|
+
? { endpoint: { baseUrl: supplied.baseUrl, headers: supplied.headers } }
|
|
49
|
+
: {}),
|
|
50
|
+
provider,
|
|
51
|
+
providerKeySource,
|
|
52
|
+
// Only resolved personal subscriptions are held at their usage limit;
|
|
53
|
+
// the platform manages the plans it supplies.
|
|
54
|
+
...(providerKeySource === "subscription" && !supplied && args.credentials.attributed_user_id
|
|
55
|
+
? {
|
|
56
|
+
subscriptionUserId: args.credentials.attributed_user_id,
|
|
57
|
+
subscriptionCredentialId: args.credentials.subscription_credential_ids?.[provider],
|
|
58
|
+
}
|
|
59
|
+
: {}),
|
|
60
|
+
usageContext: usageContextFor({
|
|
61
|
+
billable: args.billable,
|
|
62
|
+
credentials: args.credentials,
|
|
63
|
+
routerId: args.routerId,
|
|
64
|
+
selectedModel: model,
|
|
65
|
+
keySource: providerKeySource,
|
|
66
|
+
tags: args.tags ?? {},
|
|
67
|
+
}),
|
|
68
|
+
headers: {
|
|
69
|
+
"X-Dari-Selected-Model": model,
|
|
70
|
+
"X-Dari-Thinking-Level": args.decision.reasoningEffort,
|
|
71
|
+
"X-Dari-Provider-Key-Source": providerKeySource,
|
|
72
|
+
"X-Dari-Conversation-Id": args.conversationId,
|
|
73
|
+
...(args.decision.leaseTurnsRemaining === undefined
|
|
74
|
+
? {}
|
|
75
|
+
: { "X-Dari-Lease-Turns-Remaining": String(args.decision.leaseTurnsRemaining) }),
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export function startProviderCompletion(args) {
|
|
80
|
+
const customerAbort = createProviderAttemptAbort({
|
|
81
|
+
clientSignal: args.clientSignal,
|
|
82
|
+
});
|
|
83
|
+
const responseCapture = responseCaptureFor(args.execution);
|
|
84
|
+
const promise = customerAbort.aborted
|
|
85
|
+
? Promise.reject(new CustomerDisconnectedError())
|
|
86
|
+
: completeProvider({
|
|
87
|
+
interaction: args.interaction,
|
|
88
|
+
execution: args.execution,
|
|
89
|
+
signal: customerAbort.signal,
|
|
90
|
+
fetch: responseCapture?.fetch,
|
|
91
|
+
});
|
|
92
|
+
void promise.then(() => customerAbort.dispose(), () => customerAbort.dispose());
|
|
93
|
+
promise.catch(() => undefined);
|
|
94
|
+
return { promise, customerAbort, responseCapture };
|
|
95
|
+
}
|
|
96
|
+
function responseCaptureFor(execution) {
|
|
97
|
+
return execution.providerKeySource === "subscription"
|
|
98
|
+
? createProviderResponseCapture()
|
|
99
|
+
: undefined;
|
|
100
|
+
}
|
|
101
|
+
export async function startProviderStream(args) {
|
|
102
|
+
const providerStartedMs = Date.now();
|
|
103
|
+
const customerAbort = createProviderAttemptAbort({
|
|
104
|
+
clientSignal: args.clientSignal,
|
|
105
|
+
});
|
|
106
|
+
if (customerAbort.aborted) {
|
|
107
|
+
customerAbort.dispose();
|
|
108
|
+
throw new CustomerDisconnectedError();
|
|
109
|
+
}
|
|
110
|
+
const responseCapture = responseCaptureFor(args.execution);
|
|
111
|
+
try {
|
|
112
|
+
const providerStream = await streamInteractionModel({
|
|
113
|
+
model: args.execution.model,
|
|
114
|
+
request: args.interaction,
|
|
115
|
+
apiKey: args.execution.apiKey,
|
|
116
|
+
auth: await awsRoleCredentials.resolve(args.execution.auth),
|
|
117
|
+
pricing: args.execution.pricing,
|
|
118
|
+
config: args.execution.config,
|
|
119
|
+
sessionId: args.execution.sessionId,
|
|
120
|
+
selectedReasoningEffort: args.execution.reasoningEffort,
|
|
121
|
+
endpoint: args.execution.endpoint,
|
|
122
|
+
signal: customerAbort.signal,
|
|
123
|
+
fetch: responseCapture?.fetch,
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
providerStream: {
|
|
127
|
+
...providerStream,
|
|
128
|
+
events: scrubProviderEvents(providerStream.events, args.execution.auth),
|
|
129
|
+
},
|
|
130
|
+
providerStartedMs,
|
|
131
|
+
customerAbort,
|
|
132
|
+
responseCapture,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const canceled = customerAbort.aborted;
|
|
137
|
+
customerAbort.dispose();
|
|
138
|
+
if (canceled)
|
|
139
|
+
throw new CustomerDisconnectedError();
|
|
140
|
+
throw attachProviderResponseCapture(error, responseCapture);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
export async function primeProviderStream(events, customerAbort) {
|
|
144
|
+
const iterator = events[Symbol.asyncIterator]();
|
|
145
|
+
const prefix = [];
|
|
146
|
+
try {
|
|
147
|
+
let result = await iterator.next();
|
|
148
|
+
while (!result.done) {
|
|
149
|
+
if (customerAbort.aborted)
|
|
150
|
+
throw new CustomerDisconnectedError();
|
|
151
|
+
const event = result.value;
|
|
152
|
+
const failure = initialStreamFailure(event);
|
|
153
|
+
if (failure) {
|
|
154
|
+
await closeAsyncIterator(iterator);
|
|
155
|
+
return { outcome: "error", failure };
|
|
156
|
+
}
|
|
157
|
+
prefix.push(event);
|
|
158
|
+
if (isMeaningfulStreamEvent(event)) {
|
|
159
|
+
return continueWithPrefix(prefix, iterator);
|
|
160
|
+
}
|
|
161
|
+
result = await iterator.next();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
if (customerAbort.aborted) {
|
|
166
|
+
void closeAsyncIterator(iterator);
|
|
167
|
+
throw new CustomerDisconnectedError();
|
|
168
|
+
}
|
|
169
|
+
await closeAsyncIterator(iterator);
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
if (customerAbort.aborted) {
|
|
173
|
+
void closeAsyncIterator(iterator);
|
|
174
|
+
throw new CustomerDisconnectedError();
|
|
175
|
+
}
|
|
176
|
+
await closeAsyncIterator(iterator);
|
|
177
|
+
return {
|
|
178
|
+
outcome: "error",
|
|
179
|
+
failure: providerFailureFromCaught("Provider stream ended without a terminal event."),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
export function scrubProviderMessage(message, auth) {
|
|
183
|
+
const scrubbed = scrubSecretValues(message, providerSecrets(auth));
|
|
184
|
+
if (!isRecord(scrubbed)) {
|
|
185
|
+
throw new Error("Scrubbing a provider message changed its object shape.");
|
|
186
|
+
}
|
|
187
|
+
return scrubbed;
|
|
188
|
+
}
|
|
189
|
+
async function completeProvider(args) {
|
|
190
|
+
const providerStartedAt = new Date();
|
|
191
|
+
const completion = await completeInteractionModel({
|
|
192
|
+
model: args.execution.model,
|
|
193
|
+
request: args.interaction,
|
|
194
|
+
apiKey: args.execution.apiKey,
|
|
195
|
+
auth: await awsRoleCredentials.resolve(args.execution.auth),
|
|
196
|
+
pricing: args.execution.pricing,
|
|
197
|
+
config: args.execution.config,
|
|
198
|
+
sessionId: args.execution.sessionId,
|
|
199
|
+
selectedReasoningEffort: args.execution.reasoningEffort,
|
|
200
|
+
endpoint: args.execution.endpoint,
|
|
201
|
+
signal: args.signal,
|
|
202
|
+
fetch: args.fetch,
|
|
203
|
+
});
|
|
204
|
+
return {
|
|
205
|
+
...completion,
|
|
206
|
+
message: scrubProviderMessage(completion.message, args.execution.auth),
|
|
207
|
+
providerLatencyMs: Date.now() - providerStartedAt.getTime(),
|
|
208
|
+
providerStartedAt,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function initialStreamFailure(event) {
|
|
212
|
+
if (event.type === "error")
|
|
213
|
+
return providerFailureFromEvent(event);
|
|
214
|
+
if (event.type === "done" &&
|
|
215
|
+
isRecord(event.message) &&
|
|
216
|
+
isProviderFailureMessage(event.message)) {
|
|
217
|
+
return event.message;
|
|
218
|
+
}
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
function isMeaningfulStreamEvent(event) {
|
|
222
|
+
if (event.type === "done")
|
|
223
|
+
return true;
|
|
224
|
+
if (event.type === "text_delta" || event.type === "thinking_delta") {
|
|
225
|
+
return typeof event.delta === "string" && event.delta.length > 0;
|
|
226
|
+
}
|
|
227
|
+
if (event.type === "toolcall_start" ||
|
|
228
|
+
event.type === "toolcall_delta" ||
|
|
229
|
+
event.type === "toolcall_end" ||
|
|
230
|
+
event.type === "server_tool_call_start" ||
|
|
231
|
+
event.type === "server_tool_call_end" ||
|
|
232
|
+
event.type === "tool_search_result_start" ||
|
|
233
|
+
event.type === "tool_search_result_end") {
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
if (event.type !== "provider_event" || !isRecord(event.event))
|
|
237
|
+
return false;
|
|
238
|
+
const type = event.event.type;
|
|
239
|
+
if (typeof type !== "string")
|
|
240
|
+
return false;
|
|
241
|
+
if (type.startsWith("response.web_search_call."))
|
|
242
|
+
return true;
|
|
243
|
+
return type === "response.output_item.added" &&
|
|
244
|
+
isRecord(event.event.item) && event.event.item.type === "web_search_call";
|
|
245
|
+
}
|
|
246
|
+
function continueWithPrefix(prefix, iterator) {
|
|
247
|
+
return {
|
|
248
|
+
outcome: "continue",
|
|
249
|
+
events: {
|
|
250
|
+
async *[Symbol.asyncIterator]() {
|
|
251
|
+
let exhausted = false;
|
|
252
|
+
try {
|
|
253
|
+
yield* prefix;
|
|
254
|
+
let result = await iterator.next();
|
|
255
|
+
while (!result.done) {
|
|
256
|
+
yield result.value;
|
|
257
|
+
result = await iterator.next();
|
|
258
|
+
}
|
|
259
|
+
exhausted = true;
|
|
260
|
+
}
|
|
261
|
+
finally {
|
|
262
|
+
if (!exhausted)
|
|
263
|
+
await closeAsyncIterator(iterator);
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
async function closeAsyncIterator(iterator) {
|
|
270
|
+
try {
|
|
271
|
+
await iterator.return?.();
|
|
272
|
+
}
|
|
273
|
+
catch {
|
|
274
|
+
// Cleanup must not replace the provider failure or client cancellation.
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
function providerSecrets(auth) {
|
|
278
|
+
if (auth.type === "bearer")
|
|
279
|
+
return [auth.apiKey];
|
|
280
|
+
if (auth.type === "aws_assume_role")
|
|
281
|
+
return awsRoleCredentials.secrets(auth);
|
|
282
|
+
return [
|
|
283
|
+
auth.access_key_id,
|
|
284
|
+
auth.secret_access_key,
|
|
285
|
+
...(auth.session_token ? [auth.session_token] : []),
|
|
286
|
+
];
|
|
287
|
+
}
|
|
288
|
+
function scrubProviderEvents(events, auth) {
|
|
289
|
+
return {
|
|
290
|
+
async *[Symbol.asyncIterator]() {
|
|
291
|
+
for await (const event of events) {
|
|
292
|
+
yield scrubProviderMessage(event, auth);
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ProviderFetch } from "./response_capture.js";
|
|
2
|
+
export declare function reportsProviderCost(model: Record<string, unknown>): boolean;
|
|
3
|
+
export type ProviderReportedCostTap = {
|
|
4
|
+
fetch: ProviderFetch;
|
|
5
|
+
cost: () => number | undefined;
|
|
6
|
+
};
|
|
7
|
+
export declare function providerReportedCostTap(fetch?: ProviderFetch): ProviderReportedCostTap;
|
|
8
|
+
export declare function messageWithProviderReportedCost(message: Record<string, unknown>, cost: number | undefined): Record<string, unknown>;
|
|
9
|
+
export declare function eventsWithProviderReportedCost(events: AsyncIterable<Record<string, unknown>>, tap: ProviderReportedCostTap): AsyncIterable<Record<string, unknown>>;
|
|
10
|
+
export declare function reportedCost(body: unknown): number | undefined;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { isRecord } from "@mupt-ai/dari-router/policy-engine";
|
|
2
|
+
import { gatewayFor } from "../models/gateways.js";
|
|
3
|
+
import { providerFailureFromCaught } from "../runtime/provider_stream_outcome.js";
|
|
4
|
+
// Gateways bill per call and say what they billed: OpenRouter as `usage.cost`
|
|
5
|
+
// on the final chunk, Vercel AI Gateway as `providerMetadata.gateway.cost`.
|
|
6
|
+
// Pi prices usage from model rates and drops both, so the amount is read off
|
|
7
|
+
// the raw response bytes and replaces the priced total.
|
|
8
|
+
export function reportsProviderCost(model) {
|
|
9
|
+
return gatewayFor(model.provider) !== undefined;
|
|
10
|
+
}
|
|
11
|
+
export function providerReportedCostTap(fetch = globalThis.fetch) {
|
|
12
|
+
let cost;
|
|
13
|
+
return {
|
|
14
|
+
cost: () => cost,
|
|
15
|
+
fetch: async (input, init) => {
|
|
16
|
+
const response = await fetch(input, init);
|
|
17
|
+
if (!response.ok || response.body === null)
|
|
18
|
+
return response;
|
|
19
|
+
cost = undefined;
|
|
20
|
+
return new Response(response.body.pipeThrough(costScanner((value) => {
|
|
21
|
+
cost = value;
|
|
22
|
+
})), { status: response.status, statusText: response.statusText, headers: response.headers });
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function messageWithProviderReportedCost(message, cost) {
|
|
27
|
+
if (cost === undefined)
|
|
28
|
+
return message;
|
|
29
|
+
// A thrown error (or other record without a stop reason) becomes a failure
|
|
30
|
+
// message first: spreading an Error drops its non-enumerable `message`, and
|
|
31
|
+
// failure handling keeps usage only on messages that stopped in error.
|
|
32
|
+
const base = message.stopReason === undefined
|
|
33
|
+
? { ...providerFailureFromCaught(message), ...(isRecord(message.usage) ? { usage: message.usage } : {}) }
|
|
34
|
+
: message;
|
|
35
|
+
const usage = isRecord(base.usage) ? base.usage : {};
|
|
36
|
+
return {
|
|
37
|
+
...base,
|
|
38
|
+
usage: {
|
|
39
|
+
...usage,
|
|
40
|
+
cost: { ...(isRecord(usage.cost) ? usage.cost : {}), total: cost },
|
|
41
|
+
costSource: "provider",
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// Aborted and failed calls end in an error event carrying the partial
|
|
46
|
+
// message; it keeps whatever cost the provider reported before the end.
|
|
47
|
+
export async function* eventsWithProviderReportedCost(events, tap) {
|
|
48
|
+
for await (const event of events) {
|
|
49
|
+
if (event.type === "done" && isRecord(event.message)) {
|
|
50
|
+
yield { ...event, message: messageWithProviderReportedCost(event.message, tap.cost()) };
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (event.type === "error" && isRecord(event.error)) {
|
|
54
|
+
yield { ...event, error: messageWithProviderReportedCost(event.error, tap.cost()) };
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
yield event;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function reportedCost(body) {
|
|
61
|
+
if (!isRecord(body))
|
|
62
|
+
return undefined;
|
|
63
|
+
const gateway = isRecord(body.providerMetadata) && isRecord(body.providerMetadata.gateway)
|
|
64
|
+
? body.providerMetadata.gateway
|
|
65
|
+
: undefined;
|
|
66
|
+
return usd(isRecord(body.usage) ? body.usage.cost : undefined) ?? usd(gateway?.cost);
|
|
67
|
+
}
|
|
68
|
+
function usd(value) {
|
|
69
|
+
const amount = typeof value === "string" && value.trim() !== "" ? Number(value) : value;
|
|
70
|
+
return typeof amount === "number" && Number.isFinite(amount) && amount >= 0 ? amount : undefined;
|
|
71
|
+
}
|
|
72
|
+
// Reads SSE `data:` lines and plain JSON bodies alike; the last reported
|
|
73
|
+
// amount wins.
|
|
74
|
+
function costScanner(onCost) {
|
|
75
|
+
const decoder = new TextDecoder();
|
|
76
|
+
let pending = "";
|
|
77
|
+
let body = "";
|
|
78
|
+
let sse = false;
|
|
79
|
+
const scan = (line) => {
|
|
80
|
+
if (!line.startsWith("data:") || !line.includes("cost"))
|
|
81
|
+
return;
|
|
82
|
+
try {
|
|
83
|
+
const cost = reportedCost(JSON.parse(line.slice("data:".length)));
|
|
84
|
+
if (cost !== undefined)
|
|
85
|
+
onCost(cost);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// Not JSON: [DONE] or a keep-alive.
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
return new TransformStream({
|
|
92
|
+
transform(chunk, controller) {
|
|
93
|
+
controller.enqueue(chunk);
|
|
94
|
+
const text = decoder.decode(chunk, { stream: true });
|
|
95
|
+
pending += text;
|
|
96
|
+
const lines = pending.split("\n");
|
|
97
|
+
pending = lines.pop() ?? "";
|
|
98
|
+
for (const line of lines) {
|
|
99
|
+
const trimmed = line.trimEnd();
|
|
100
|
+
if (trimmed.startsWith("data:"))
|
|
101
|
+
sse = true;
|
|
102
|
+
scan(trimmed);
|
|
103
|
+
}
|
|
104
|
+
if (!sse && body.length < 1024 * 1024)
|
|
105
|
+
body += text;
|
|
106
|
+
},
|
|
107
|
+
flush() {
|
|
108
|
+
const tail = decoder.decode();
|
|
109
|
+
scan((pending + tail).trimEnd());
|
|
110
|
+
body += tail;
|
|
111
|
+
if (sse || !body.includes("cost"))
|
|
112
|
+
return;
|
|
113
|
+
try {
|
|
114
|
+
const cost = reportedCost(JSON.parse(body));
|
|
115
|
+
if (cost !== undefined)
|
|
116
|
+
onCost(cost);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Not a JSON body.
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReasoningEffort } from "@mupt-ai/dari-router/policy-engine";
|
|
2
|
+
import type { InteractionRequest } from "../interaction/types.js";
|
|
3
|
+
type ReasoningRequest = Pick<InteractionRequest, "reasoning">;
|
|
4
|
+
export declare function effectiveReasoningForModel(args: {
|
|
5
|
+
request: ReasoningRequest;
|
|
6
|
+
selectedModel: string;
|
|
7
|
+
supportedLevels: string[];
|
|
8
|
+
selectedReasoningEffort?: ReasoningEffort;
|
|
9
|
+
defaultReasoningEffort?: ReasoningEffort;
|
|
10
|
+
}): ReasoningEffort | undefined;
|
|
11
|
+
export declare function validateReasoningEffortForModel(effort: ReasoningEffort, selectedModel: string, supportedLevels: string[]): void;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { HttpError } from "../http/errors.js";
|
|
2
|
+
function requestedReasoningEffort(request) {
|
|
3
|
+
return request.reasoning?.effort;
|
|
4
|
+
}
|
|
5
|
+
export function effectiveReasoningForModel(args) {
|
|
6
|
+
const requested = requestedReasoningEffort(args.request) ?? args.selectedReasoningEffort;
|
|
7
|
+
const effective = requested ??
|
|
8
|
+
args.defaultReasoningEffort ??
|
|
9
|
+
implicitReasoningEffort(args.supportedLevels);
|
|
10
|
+
if (effective === undefined)
|
|
11
|
+
return undefined;
|
|
12
|
+
validateReasoningEffortForModel(effective, args.selectedModel, args.supportedLevels);
|
|
13
|
+
return effective;
|
|
14
|
+
}
|
|
15
|
+
export function validateReasoningEffortForModel(effort, selectedModel, supportedLevels) {
|
|
16
|
+
if (supportedLevels.includes(effort))
|
|
17
|
+
return;
|
|
18
|
+
throw new HttpError(400, `reasoning_effort '${effort}' is not supported by ${selectedModel}. Supported values: ${supportedLevels.join(", ")}.`, "unsupported_reasoning_effort", "reasoning_effort");
|
|
19
|
+
}
|
|
20
|
+
// Routed serving always supplies the selected pair's effort. For direct
|
|
21
|
+
// internal provider calls that do not (currently the selector), use cataloged
|
|
22
|
+
// provider defaults when available, then fall back to medium or the closest
|
|
23
|
+
// supported level for custom models. Explicit "off" remains available for
|
|
24
|
+
// routed candidates that support a true non-reasoning mode.
|
|
25
|
+
const IMPLICIT_REASONING_PREFERENCE = ["medium", "low", "high", "minimal", "xhigh", "max"];
|
|
26
|
+
function implicitReasoningEffort(supportedLevels) {
|
|
27
|
+
// Models with no non-off level (non-reasoning models) keep omitting the
|
|
28
|
+
// reasoning field entirely.
|
|
29
|
+
return IMPLICIT_REASONING_PREFERENCE.find((level) => supportedLevels.includes(level));
|
|
30
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type CapturedProviderResponse = {
|
|
2
|
+
status: number;
|
|
3
|
+
headers: Headers;
|
|
4
|
+
bodyText: string;
|
|
5
|
+
};
|
|
6
|
+
export type ProviderFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
7
|
+
export type ProviderResponseCapture = {
|
|
8
|
+
fetch: ProviderFetch;
|
|
9
|
+
last: CapturedProviderResponse | undefined;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* A fetch wrapper that remembers the last failed provider response. pi-ai
|
|
13
|
+
* flattens provider errors into one message string before they reach the
|
|
14
|
+
* runtime, so this is the only place the status, rate-limit headers, and
|
|
15
|
+
* structured error body of a rejected call can still be read.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createProviderResponseCapture(): ProviderResponseCapture;
|
|
18
|
+
/**
|
|
19
|
+
* A provider call that throws before returning a stream loses its capture with
|
|
20
|
+
* the started state, so the error carries it to the attempt runner instead.
|
|
21
|
+
*/
|
|
22
|
+
export declare function attachProviderResponseCapture(error: unknown, capture: ProviderResponseCapture | undefined): unknown;
|
|
23
|
+
export declare function providerResponseCaptureFromError(error: unknown): ProviderResponseCapture | undefined;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const CAPTURED_BODY_MAX_BYTES = 64 * 1024;
|
|
2
|
+
/**
|
|
3
|
+
* A fetch wrapper that remembers the last failed provider response. pi-ai
|
|
4
|
+
* flattens provider errors into one message string before they reach the
|
|
5
|
+
* runtime, so this is the only place the status, rate-limit headers, and
|
|
6
|
+
* structured error body of a rejected call can still be read.
|
|
7
|
+
*/
|
|
8
|
+
export function createProviderResponseCapture() {
|
|
9
|
+
const capture = {
|
|
10
|
+
last: undefined,
|
|
11
|
+
fetch: async (input, init) => {
|
|
12
|
+
const response = await globalThis.fetch(input, init);
|
|
13
|
+
if (response.ok)
|
|
14
|
+
return response;
|
|
15
|
+
const bodyText = await readBodyPrefix(response.clone());
|
|
16
|
+
capture.last = { status: response.status, headers: response.headers, bodyText };
|
|
17
|
+
return response;
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
return capture;
|
|
21
|
+
}
|
|
22
|
+
async function readBodyPrefix(response) {
|
|
23
|
+
try {
|
|
24
|
+
const text = await response.text();
|
|
25
|
+
return text.length > CAPTURED_BODY_MAX_BYTES ? text.slice(0, CAPTURED_BODY_MAX_BYTES) : text;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return "";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const CAPTURE_KEY = Symbol("providerResponseCapture");
|
|
32
|
+
/**
|
|
33
|
+
* A provider call that throws before returning a stream loses its capture with
|
|
34
|
+
* the started state, so the error carries it to the attempt runner instead.
|
|
35
|
+
*/
|
|
36
|
+
export function attachProviderResponseCapture(error, capture) {
|
|
37
|
+
if (capture !== undefined && typeof error === "object" && error !== null) {
|
|
38
|
+
error[CAPTURE_KEY] = capture;
|
|
39
|
+
}
|
|
40
|
+
return error;
|
|
41
|
+
}
|
|
42
|
+
export function providerResponseCaptureFromError(error) {
|
|
43
|
+
if (typeof error !== "object" || error === null)
|
|
44
|
+
return undefined;
|
|
45
|
+
const capture = error[CAPTURE_KEY];
|
|
46
|
+
return capture === undefined ? undefined : capture;
|
|
47
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ModelPricing, RoutingDecision } from "@mupt-ai/dari-router/policy-engine";
|
|
2
|
+
import type { InteractionRequest, ProviderIdentity } from "../interaction/types.js";
|
|
3
|
+
import type { ProviderStreamOutcome } from "../runtime/provider_stream_outcome.js";
|
|
4
|
+
import type { RoutedProtocol } from "../runtime/routed_protocol.js";
|
|
5
|
+
import { type RoutedRuntimeReporter } from "../runtime/runtime_reporter.js";
|
|
6
|
+
import type { ProviderKeySource } from "../types.js";
|
|
7
|
+
import { type RoutingUsageContext } from "../telemetry/usage.js";
|
|
8
|
+
import { type DeliveredOutput, type PromptTokenEstimate } from "./cancel_estimate.js";
|
|
9
|
+
type StreamExecutionFacts = {
|
|
10
|
+
provider: string;
|
|
11
|
+
model: string;
|
|
12
|
+
providerKeySource: ProviderKeySource;
|
|
13
|
+
conversationId: string;
|
|
14
|
+
usageContext: RoutingUsageContext | undefined;
|
|
15
|
+
pricing: ModelPricing | null;
|
|
16
|
+
promptEstimate: PromptTokenEstimate | undefined;
|
|
17
|
+
};
|
|
18
|
+
type CreateStreamFinalizerArgs = {
|
|
19
|
+
requestId: string;
|
|
20
|
+
interaction: InteractionRequest;
|
|
21
|
+
decision: RoutingDecision;
|
|
22
|
+
execution: StreamExecutionFacts;
|
|
23
|
+
reporter: RoutedRuntimeReporter;
|
|
24
|
+
protocol: RoutedProtocol;
|
|
25
|
+
providerLatencyMs: () => number;
|
|
26
|
+
role: "primary" | "fallback";
|
|
27
|
+
attempt: number;
|
|
28
|
+
reportBarrier?: Promise<unknown>;
|
|
29
|
+
delivered: () => DeliveredOutput;
|
|
30
|
+
source: ProviderIdentity;
|
|
31
|
+
startedAtMs: number;
|
|
32
|
+
cancelBarrierCapMs?: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* A client cancel runs its finalization in the background, where a slow
|
|
36
|
+
* selector would only delay the record and, at shutdown, eat the drain budget.
|
|
37
|
+
* The record still gets the selector's run when it arrives within the cap;
|
|
38
|
+
* otherwise it is written without it. The response-owned path is not capped.
|
|
39
|
+
*/
|
|
40
|
+
export declare const CANCEL_REPORT_BARRIER_CAP_MS = 2000;
|
|
41
|
+
export type StreamFinalizer = {
|
|
42
|
+
beforeResponseClose(outcome: ProviderStreamOutcome): Promise<void>;
|
|
43
|
+
afterResponseDetached(outcome: ProviderStreamOutcome): Promise<void>;
|
|
44
|
+
};
|
|
45
|
+
export declare function createStreamFinalizer(args: CreateStreamFinalizerArgs): StreamFinalizer;
|
|
46
|
+
export {};
|