@oneciel-ai/ciel-runtime 0.2.37 → 0.2.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -0
- package/README.md +5 -2
- package/ciel_runtime.py +94 -96
- package/ciel_runtime_support/anthropic_model_policy.py +20 -3
- package/ciel_runtime_support/architecture.py +5 -0
- package/ciel_runtime_support/channel_inflight.py +4 -4
- package/ciel_runtime_support/channel_injection.py +56 -1
- package/ciel_runtime_support/channel_mcp_tools.py +34 -0
- package/ciel_runtime_support/channel_message_policy.py +9 -1
- package/ciel_runtime_support/channel_message_prompt.py +23 -0
- package/ciel_runtime_support/channel_pending_injection.py +86 -32
- package/ciel_runtime_support/channel_pending_poll.py +6 -2
- package/ciel_runtime_support/channel_runtime_environment.py +0 -11
- package/ciel_runtime_support/channel_terminal_context.py +0 -6
- package/ciel_runtime_support/channel_terminal_proxy.py +3 -42
- package/ciel_runtime_support/channel_transcript_repository.py +16 -1
- package/ciel_runtime_support/channel_wake_claim_repository.py +0 -19
- package/ciel_runtime_support/channel_wake_context.py +6 -13
- package/ciel_runtime_support/channel_wake_delivery_repository.py +50 -0
- package/ciel_runtime_support/chat_http_controller.py +88 -5
- package/ciel_runtime_support/claude_environment.py +100 -3
- package/ciel_runtime_support/claude_launch_assembly.py +4 -0
- package/ciel_runtime_support/claude_session_socket.py +181 -0
- package/ciel_runtime_support/cli_application_context.py +18 -10
- package/ciel_runtime_support/cli_dispatch.py +19 -3
- package/ciel_runtime_support/cli_parser.py +2 -0
- package/ciel_runtime_support/cli_usage.py +3 -2
- package/ciel_runtime_support/codex_backend_context.py +8 -3
- package/ciel_runtime_support/codex_completion_gate.py +198 -0
- package/ciel_runtime_support/codex_turn_recovery.py +240 -83
- package/ciel_runtime_support/compatibility_protocol.py +5 -2
- package/ciel_runtime_support/config_migrations.py +79 -0
- package/ciel_runtime_support/config_repository.py +7 -0
- package/ciel_runtime_support/context_summary_policy.py +24 -4
- package/ciel_runtime_support/external_event_menu.py +107 -0
- package/ciel_runtime_support/external_event_receiver.py +19 -1
- package/ciel_runtime_support/launch_state.py +2 -0
- package/ciel_runtime_support/managed_tool_injection.py +33 -0
- package/ciel_runtime_support/muse_runtime_context.py +291 -0
- package/ciel_runtime_support/ollama_thinking.py +12 -26
- package/ciel_runtime_support/prelaunch.py +13 -0
- package/ciel_runtime_support/prelaunch_launch_panel.py +2 -1
- package/ciel_runtime_support/prompt_compaction.py +39 -0
- package/ciel_runtime_support/provider_files_proxy.py +248 -0
- package/ciel_runtime_support/provider_model_identity.py +10 -2
- package/ciel_runtime_support/provider_option_cli.py +1 -1
- package/ciel_runtime_support/provider_request_access.py +54 -1
- package/ciel_runtime_support/provider_responses_passthrough.py +152 -15
- package/ciel_runtime_support/providers/alibaba.py +34 -1
- package/ciel_runtime_support/providers/anthropic.py +18 -1
- package/ciel_runtime_support/providers/meta.py +252 -21
- package/ciel_runtime_support/pseudo_tool_parser.py +17 -1
- package/ciel_runtime_support/remote_bridge.py +4 -0
- package/ciel_runtime_support/remote_instructions.py +5 -0
- package/ciel_runtime_support/remote_memory.py +1 -1
- package/ciel_runtime_support/responses_cache_diagnostics.py +82 -0
- package/ciel_runtime_support/responses_custom_tool_bridge.py +282 -0
- package/ciel_runtime_support/responses_input_compatibility.py +19 -3
- package/ciel_runtime_support/router_http.py +301 -4
- package/ciel_runtime_support/router_observability_context.py +26 -0
- package/ciel_runtime_support/router_server_context.py +1 -0
- package/ciel_runtime_support/runtime_adapters.py +31 -0
- package/ciel_runtime_support/runtime_constants.py +23 -1
- package/ciel_runtime_support/runtime_input_gateway.py +85 -5
- package/ciel_runtime_support/runtime_input_status.py +150 -0
- package/ciel_runtime_support/runtime_launch.py +27 -4
- package/ciel_runtime_support/runtime_paths.py +1 -0
- package/ciel_runtime_support/speech_http_controller.py +3 -2
- package/ciel_runtime_support/streaming_anthropic.py +3 -0
- package/ciel_runtime_support/tool_call_events.py +98 -0
- package/ciel_runtime_support/transcript_delta_delivery.py +140 -1
- package/ciel_runtime_support/ui_text.py +1 -0
- package/ciel_runtime_support/web_search_result_events.py +130 -0
- package/ciel_runtime_support/web_ui.py +1 -0
- package/ciel_runtime_support/windows_conpty.py +92 -8
- package/ciel_runtime_support/workspace_mcp.py +4 -1
- package/ciel_runtime_support/workspace_state.py +1 -0
- package/docs/Configuration.md +20 -4
- package/docs/MCP-Channels.md +79 -6
- package/docs/Managed-Tool-Injection.md +25 -0
- package/docs/Module-Map.md +4 -0
- package/docs/Muse-Code.md +73 -0
- package/docs/Observability.md +39 -0
- package/docs/Providers.md +29 -2
- package/docs/Remote-Bridge.md +12 -0
- package/docs/Router.md +1 -0
- package/docs/journal/2026/09/01/diagnostics/anthropic/router/fable51-usage-credits.okf +70 -0
- package/docs/journal/2026/09/01/implementation/claude/session-socket/all-input-paths/default-delivery.okf +133 -0
- package/docs/journal/2026/09/01/implementation/claude/session-socket/windows-direct-input.okf +112 -0
- package/docs/journal/2026/09/02/diagnostics/cache/alibaba/qwen38-post-restart-hit-rate.okf +107 -0
- package/docs/journal/2026/09/02/diagnostics/cache/ollama-cloud/kimi-k3-codex-hit-rate.okf +91 -0
- package/docs/journal/2026/09/02/diagnostics/codex/tui/statusline-cache-metrics.okf +44 -0
- package/docs/journal/2026/09/02/diagnostics/input/transport/fallback-behavior.okf +31 -0
- package/docs/journal/2026/09/02/diagnostics/providers/ollama-cloud/kimi-k3-agent-turn-recovery.okf +125 -0
- package/docs/journal/2026/09/02/diagnostics/providers/ollama-cloud/kimi-k3-parameters.okf +128 -0
- package/docs/journal/2026/09/02/diagnostics/remote/mia/socket-tui-visibility.okf +47 -0
- package/docs/journal/2026/09/02/diagnostics/runtime/alibaba/token-plan/qwen38-latency.okf +108 -0
- package/docs/journal/2026/09/02/diagnostics/runtime/alibaba/token-plan/qwen38-vs-gpt56-latency.okf +92 -0
- package/docs/journal/2026/09/02/implementation/anthropic/context/one-million-defaults.okf +85 -0
- package/docs/journal/2026/09/02/implementation/cache/alibaba/qwen38-cache-hit-improvement.okf +104 -0
- package/docs/journal/2026/09/02/implementation/cache/alibaba/qwen38-cache-hit-improvement.png +0 -0
- package/docs/journal/2026/09/02/implementation/cache/alibaba/responses-session-cache.okf +97 -0
- package/docs/journal/2026/09/02/implementation/providers/alibaba/qwen38/0902-parameter-alignment.okf +97 -0
- package/docs/journal/2026/09/02/implementation/providers/meta/multimodal-tools/contributor-protocol-adoption.okf +140 -0
- package/docs/journal/2026/09/02/implementation/providers/meta/muse-spark-1.3-support.okf +53 -0
- package/docs/journal/2026/09/02/monitoring/cache/alibaba/cielarvis-qwen38-live-hit-rate.okf +858 -0
- package/docs/journal/2026/09/02/operations/release/main-merge-local-deploy.okf +36 -0
- package/docs/journal/2026/09/02/operations/release/nightly/local-cache-deployment.okf +54 -0
- package/docs/journal/2026/09/02/operations/release/nightly/ollama-kimi-recovery-model-audit-deployment.okf +58 -0
- package/docs/journal/2026/09/02/operations/release/nightly/qwen38-cache-improvement-deployment.okf +72 -0
- package/docs/journal/2026/09/02/research/cache/alibaba/qwen38-hit-rate-improvement.okf +233 -0
- package/docs/journal/2026/09/02/research/cache/codex/provider-scope.okf +77 -0
- package/docs/journal/2026/09/02/research/providers/ollama-cloud/desktop-model-exhaustive-audit.okf +159 -0
- package/docs/journal/2026/09/03/diagnostics/providers/meta/muse-spark-contributor-cache-hit.okf +148 -0
- package/docs/journal/2026/09/03/diagnostics/providers/meta/muse-spark-contributor-required-schema.okf +127 -0
- package/docs/journal/2026/09/03/diagnostics/providers/ollama-cloud/kimi-k3-resumed-session-stall.okf +160 -0
- package/docs/journal/2026/09/03/diagnostics/providers/ollama-cloud/kimi-k3-substantive-dangling-action.okf +94 -0
- package/docs/journal/2026/09/03/diagnostics/remote/kevin/codex-gpt-early-turn-completion.okf +162 -0
- package/docs/journal/2026/09/03/implementation/runtimes/meta/muse-code/default-yolo.okf +40 -0
- package/docs/journal/2026/09/03/implementation/runtimes/meta/muse-code/native-subscription-router.okf +86 -0
- package/docs/journal/2026/09/03/operations/deployment/local/session-socket-default-fallback.okf +41 -0
- package/docs/journal/2026/09/03/research/deployment/colab/tailscale/credential-storage.okf +41 -0
- package/docs/journal/2026/09/03/research/providers/meta/muse-code/subscription-billing-boundary.okf +64 -0
- package/docs/journal/2026/09/03/research/web-chat/voice/instruction-format.okf +135 -0
- package/docs/journal/2026/09/04/diagnostics/claude/context/early-auto-compaction.okf +75 -0
- package/docs/journal/2026/09/04/diagnostics/claude/context/fable-51-status-200k.okf +54 -0
- package/docs/journal/2026/09/04/diagnostics/runtime/codex/responses/replayed-item-id-validation.okf +74 -0
- package/docs/journal/2026/09/04/diagnostics/workspaces/onecieldmsui/codex/replay-stall.okf +100 -0
- package/docs/journal/2026/09/04/implementation/observability/tool-calls/websocket-stream.okf +49 -0
- package/docs/journal/2026/09/04/implementation/web-chat/input/raw-injection.okf +42 -0
- package/docs/journal/2026/09/05/diagnostics/tty/claude-raw-idle-render.okf +25 -0
- package/docs/journal/2026/09/05/implementation/events/search-response-urls.okf +23 -0
- package/docs/journal/2026/09/05/implementation/tools/native-injection.okf +19 -0
- package/docs/journal/2026/09/05/implementation/windows/conpty/prompt-delivery-lifecycle.okf +43 -0
- package/docs/journal/2026/09/05/release/nightly/conpty-native-tools.okf +13 -0
- package/docs/journal/2026/09/05/release/nightly/search-result-urls.okf +14 -0
- package/docs/journal/2026/09/06/implementation/codex/inherited-web-mcp.okf +22 -0
- package/docs/journal/2026/09/07/integration/main/nightly-merge.okf +13 -0
- package/docs/journal/2026/09/07/release/stable/0.2.38.okf +10 -0
- package/package.json +1 -1
|
@@ -12,7 +12,17 @@ from http.client import IncompleteRead
|
|
|
12
12
|
from typing import Any, Callable, Mapping
|
|
13
13
|
|
|
14
14
|
from .responses_usage_observer import ResponsesUsageObserver
|
|
15
|
+
from .responses_cache_diagnostics import (
|
|
16
|
+
cache_trace,
|
|
17
|
+
request_cache_profile,
|
|
18
|
+
usage_with_cache_profile,
|
|
19
|
+
)
|
|
15
20
|
from .responses_input_compatibility import repair_replayed_response_items
|
|
21
|
+
from .responses_custom_tool_bridge import (
|
|
22
|
+
ResponsesCustomToolStreamProjector,
|
|
23
|
+
project_response_payload,
|
|
24
|
+
tool_definitions,
|
|
25
|
+
)
|
|
16
26
|
from .remote_bridge import is_remote_bridge_request
|
|
17
27
|
from .upstream_dump import dump_upstream_request
|
|
18
28
|
from .upstream_error_policy import UpstreamStreamReadError
|
|
@@ -34,7 +44,7 @@ class ProviderResponsesPassthroughPorts:
|
|
|
34
44
|
urlopen: Callable[..., Any]
|
|
35
45
|
timeout_seconds: Callable[[dict[str, Any]], float]
|
|
36
46
|
copy_response_headers: Callable[[Any, Any], None]
|
|
37
|
-
record_usage: Callable[[str, str, dict[str,
|
|
47
|
+
record_usage: Callable[[str, str, dict[str, Any]], None] = (
|
|
38
48
|
lambda _provider, _model, _usage: None
|
|
39
49
|
)
|
|
40
50
|
log: Callable[[str, str], Any] = lambda _level, _message: None
|
|
@@ -73,6 +83,44 @@ class ProviderResponsesPassthrough:
|
|
|
73
83
|
)
|
|
74
84
|
return self._ports.join_url(self._ports.upstream_base(provider, config), path)
|
|
75
85
|
|
|
86
|
+
def _request_headers(
|
|
87
|
+
self,
|
|
88
|
+
provider: str,
|
|
89
|
+
config: dict[str, Any],
|
|
90
|
+
inbound_headers: Any,
|
|
91
|
+
body: Mapping[str, Any],
|
|
92
|
+
) -> dict[str, str]:
|
|
93
|
+
headers = self._ports.headers(provider, config, inbound_headers)
|
|
94
|
+
if not config.get("responses_session_cache_requires_previous_response_id"):
|
|
95
|
+
return headers
|
|
96
|
+
if str(body.get("previous_response_id") or "").strip():
|
|
97
|
+
return headers
|
|
98
|
+
filtered = {
|
|
99
|
+
name: value
|
|
100
|
+
for name, value in headers.items()
|
|
101
|
+
if str(name).casefold() != "x-dashscope-session-cache"
|
|
102
|
+
}
|
|
103
|
+
if len(filtered) != len(headers):
|
|
104
|
+
self._ports.log(
|
|
105
|
+
"INFO",
|
|
106
|
+
"provider_responses_session_cache_deferred "
|
|
107
|
+
f"provider={provider} reason=missing_previous_response_id",
|
|
108
|
+
)
|
|
109
|
+
return filtered
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def _response_headers(headers: Any, *, transformed: bool) -> Any:
|
|
113
|
+
if not transformed:
|
|
114
|
+
return headers
|
|
115
|
+
try:
|
|
116
|
+
return {
|
|
117
|
+
key: value
|
|
118
|
+
for key, value in headers.items()
|
|
119
|
+
if str(key).casefold() != "content-length"
|
|
120
|
+
}
|
|
121
|
+
except (AttributeError, TypeError):
|
|
122
|
+
return headers
|
|
123
|
+
|
|
76
124
|
def forward_compact(
|
|
77
125
|
self,
|
|
78
126
|
handler: Any,
|
|
@@ -90,11 +138,16 @@ class ProviderResponsesPassthrough:
|
|
|
90
138
|
upstream_body = self._ports.finalize_body(upstream_body)
|
|
91
139
|
data = self._encode(upstream_body)
|
|
92
140
|
url = self._endpoint(provider, config, "openai_responses_compact")
|
|
93
|
-
|
|
141
|
+
request_headers = self._request_headers(
|
|
142
|
+
provider, config, handler.headers, upstream_body
|
|
143
|
+
)
|
|
144
|
+
dump_upstream_request(
|
|
145
|
+
url, data, self._ports.log, headers=request_headers
|
|
146
|
+
)
|
|
94
147
|
request = urllib.request.Request(
|
|
95
148
|
url,
|
|
96
149
|
data=data,
|
|
97
|
-
headers=
|
|
150
|
+
headers=request_headers,
|
|
98
151
|
method="POST",
|
|
99
152
|
)
|
|
100
153
|
with self._ports.urlopen(
|
|
@@ -168,6 +221,9 @@ class ProviderResponsesPassthrough:
|
|
|
168
221
|
provider=provider,
|
|
169
222
|
model=str(current.get("model") or ""),
|
|
170
223
|
remote_bridge=remote_bridge,
|
|
224
|
+
stable_prefix_checkpoint_items=config.get(
|
|
225
|
+
"responses_cache_checkpoint_items", 0
|
|
226
|
+
),
|
|
171
227
|
)
|
|
172
228
|
if not remote_bridge:
|
|
173
229
|
compacted = self._ports.finalize_body(compacted)
|
|
@@ -228,6 +284,8 @@ class ProviderResponsesPassthrough:
|
|
|
228
284
|
provider: str,
|
|
229
285
|
config: dict[str, Any],
|
|
230
286
|
upstream_body: dict[str, Any],
|
|
287
|
+
response_tools: Mapping[str, Mapping[str, Any]],
|
|
288
|
+
cache_profile: Mapping[str, Any],
|
|
231
289
|
) -> None:
|
|
232
290
|
"""Validate a native Responses stream before exposing it downstream."""
|
|
233
291
|
|
|
@@ -297,14 +355,33 @@ class ProviderResponsesPassthrough:
|
|
|
297
355
|
) from failure
|
|
298
356
|
|
|
299
357
|
handler.send_response(getattr(response, "status", 200))
|
|
300
|
-
self._ports.copy_response_headers(
|
|
358
|
+
self._ports.copy_response_headers(
|
|
359
|
+
handler,
|
|
360
|
+
self._response_headers(
|
|
361
|
+
response.headers, transformed=bool(response_tools)
|
|
362
|
+
),
|
|
363
|
+
)
|
|
301
364
|
handler.end_headers()
|
|
302
365
|
spool.seek(0)
|
|
366
|
+
projector = (
|
|
367
|
+
ResponsesCustomToolStreamProjector(response_tools)
|
|
368
|
+
if response_tools
|
|
369
|
+
else None
|
|
370
|
+
)
|
|
303
371
|
while chunk := spool.read(65_536):
|
|
304
|
-
|
|
305
|
-
|
|
372
|
+
output = projector.feed(chunk) if projector is not None else chunk
|
|
373
|
+
if output:
|
|
374
|
+
handler.wfile.write(output)
|
|
375
|
+
handler.wfile.flush()
|
|
376
|
+
if projector is not None:
|
|
377
|
+
tail = projector.finish()
|
|
378
|
+
if tail:
|
|
379
|
+
handler.wfile.write(tail)
|
|
380
|
+
handler.wfile.flush()
|
|
306
381
|
if observed:
|
|
307
|
-
|
|
382
|
+
observation = usage_with_cache_profile(observed, cache_profile)
|
|
383
|
+
self._ports.record_usage(provider, model, observation)
|
|
384
|
+
self._ports.log(*cache_trace(provider, model, observation))
|
|
308
385
|
return
|
|
309
386
|
|
|
310
387
|
def forward(
|
|
@@ -318,6 +395,11 @@ class ProviderResponsesPassthrough:
|
|
|
318
395
|
upstream_body = dict(
|
|
319
396
|
body if remote_bridge else repair_replayed_response_items(body)
|
|
320
397
|
)
|
|
398
|
+
response_tools = (
|
|
399
|
+
tool_definitions(upstream_body)
|
|
400
|
+
if config.get("responses_custom_tools_as_functions")
|
|
401
|
+
else {}
|
|
402
|
+
)
|
|
321
403
|
upstream_body["model"] = self._ports.normalize_model(
|
|
322
404
|
provider, config, str(body.get("model") or "")
|
|
323
405
|
)
|
|
@@ -340,11 +422,17 @@ class ProviderResponsesPassthrough:
|
|
|
340
422
|
upstream_body,
|
|
341
423
|
remote_bridge=remote_bridge,
|
|
342
424
|
)
|
|
343
|
-
|
|
425
|
+
cache_profile = request_cache_profile(upstream_body, len(data))
|
|
426
|
+
request_headers = self._request_headers(
|
|
427
|
+
provider, config, handler.headers, upstream_body
|
|
428
|
+
)
|
|
429
|
+
dump_upstream_request(
|
|
430
|
+
url, data, self._ports.log, headers=request_headers
|
|
431
|
+
)
|
|
344
432
|
request = urllib.request.Request(
|
|
345
433
|
url,
|
|
346
434
|
data=data,
|
|
347
|
-
headers=
|
|
435
|
+
headers=request_headers,
|
|
348
436
|
method="POST",
|
|
349
437
|
)
|
|
350
438
|
if not remote_bridge and self._stream_truncation_retries(config):
|
|
@@ -354,6 +442,8 @@ class ProviderResponsesPassthrough:
|
|
|
354
442
|
provider,
|
|
355
443
|
config,
|
|
356
444
|
upstream_body,
|
|
445
|
+
response_tools,
|
|
446
|
+
cache_profile,
|
|
357
447
|
)
|
|
358
448
|
return delivery_body
|
|
359
449
|
with self._ports.urlopen(
|
|
@@ -365,21 +455,46 @@ class ProviderResponsesPassthrough:
|
|
|
365
455
|
usage = ResponsesUsageObserver()
|
|
366
456
|
received_bytes = 0
|
|
367
457
|
handler.send_response(getattr(response, "status", 200))
|
|
368
|
-
self._ports.copy_response_headers(
|
|
458
|
+
self._ports.copy_response_headers(
|
|
459
|
+
handler,
|
|
460
|
+
self._response_headers(
|
|
461
|
+
response.headers, transformed=bool(response_tools)
|
|
462
|
+
),
|
|
463
|
+
)
|
|
369
464
|
handler.end_headers()
|
|
465
|
+
projector = (
|
|
466
|
+
ResponsesCustomToolStreamProjector(response_tools)
|
|
467
|
+
if response_tools and bool(upstream_body.get("stream", True))
|
|
468
|
+
else None
|
|
469
|
+
)
|
|
470
|
+
response_body = bytearray()
|
|
370
471
|
try:
|
|
371
472
|
while chunk := response.read(65_536):
|
|
372
473
|
received_bytes += len(chunk)
|
|
373
474
|
usage.feed(chunk)
|
|
374
|
-
|
|
375
|
-
|
|
475
|
+
if response_tools and projector is None:
|
|
476
|
+
response_body.extend(chunk)
|
|
477
|
+
continue
|
|
478
|
+
output = projector.feed(chunk) if projector is not None else chunk
|
|
479
|
+
if output:
|
|
480
|
+
handler.wfile.write(output)
|
|
481
|
+
handler.wfile.flush()
|
|
376
482
|
except IncompleteRead as exc:
|
|
377
483
|
partial = bytes(exc.partial or b"")
|
|
378
484
|
if partial:
|
|
379
485
|
received_bytes += len(partial)
|
|
380
486
|
usage.feed(partial)
|
|
381
|
-
|
|
382
|
-
|
|
487
|
+
if response_tools and projector is None:
|
|
488
|
+
response_body.extend(partial)
|
|
489
|
+
else:
|
|
490
|
+
output = (
|
|
491
|
+
projector.feed(partial)
|
|
492
|
+
if projector is not None
|
|
493
|
+
else partial
|
|
494
|
+
)
|
|
495
|
+
if output:
|
|
496
|
+
handler.wfile.write(output)
|
|
497
|
+
handler.wfile.flush()
|
|
383
498
|
usage.finish()
|
|
384
499
|
if usage.terminal_event is None:
|
|
385
500
|
self._ports.log(
|
|
@@ -403,6 +518,20 @@ class ProviderResponsesPassthrough:
|
|
|
403
518
|
f"provider={provider} model={upstream_body.get('model')} "
|
|
404
519
|
f"terminal={usage.terminal_event} bytes={received_bytes}",
|
|
405
520
|
)
|
|
521
|
+
if projector is not None:
|
|
522
|
+
tail = projector.finish()
|
|
523
|
+
if tail:
|
|
524
|
+
handler.wfile.write(tail)
|
|
525
|
+
handler.wfile.flush()
|
|
526
|
+
elif response_tools:
|
|
527
|
+
try:
|
|
528
|
+
decoded = json.loads(response_body)
|
|
529
|
+
projected_body = project_response_payload(decoded, response_tools)
|
|
530
|
+
handler.wfile.write(self._encode(projected_body))
|
|
531
|
+
handler.wfile.flush()
|
|
532
|
+
except (UnicodeDecodeError, ValueError, TypeError):
|
|
533
|
+
handler.wfile.write(response_body)
|
|
534
|
+
handler.wfile.flush()
|
|
406
535
|
observed = usage.finish()
|
|
407
536
|
if bool(upstream_body.get("stream", True)) and usage.terminal_event is None:
|
|
408
537
|
error = EOFError("upstream Responses stream ended without a terminal event")
|
|
@@ -422,10 +551,18 @@ class ProviderResponsesPassthrough:
|
|
|
422
551
|
received_bytes=received_bytes,
|
|
423
552
|
) from error
|
|
424
553
|
if observed and not remote_bridge:
|
|
554
|
+
observation = usage_with_cache_profile(observed, cache_profile)
|
|
425
555
|
self._ports.record_usage(
|
|
426
556
|
provider,
|
|
427
557
|
str(upstream_body.get("model") or ""),
|
|
428
|
-
|
|
558
|
+
observation,
|
|
559
|
+
)
|
|
560
|
+
self._ports.log(
|
|
561
|
+
*cache_trace(
|
|
562
|
+
provider,
|
|
563
|
+
str(upstream_body.get("model") or ""),
|
|
564
|
+
observation,
|
|
565
|
+
)
|
|
429
566
|
)
|
|
430
567
|
return delivery_body
|
|
431
568
|
|
|
@@ -19,6 +19,7 @@ from .base import HttpBearerProviderAdapter, provider_configuration
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
QWEN38_MAX_MODEL = "qwen3.8-max"
|
|
22
|
+
QWEN38_MAX_SNAPSHOT_MODEL = "qwen3.8-max-0902"
|
|
22
23
|
QWEN38_MAX_PREVIEW_MODEL = "qwen3.8-max-preview"
|
|
23
24
|
QWEN38_CONTEXT_WINDOW = 1_000_000
|
|
24
25
|
QWEN38_MAX_INPUT = 991_808
|
|
@@ -40,10 +41,15 @@ QWEN38_CODEX_CATALOG = {
|
|
|
40
41
|
"experimental_supported_tools": [],
|
|
41
42
|
"truncation_policy": {"mode": "bytes", "limit": 10_000},
|
|
42
43
|
"supported_reasoning_levels": [
|
|
44
|
+
{"effort": "none", "description": "Disable reasoning"},
|
|
45
|
+
{"effort": "minimal", "description": "Minimal reasoning for fastest responses"},
|
|
43
46
|
{"effort": "low", "description": "Fast responses with lighter reasoning"},
|
|
44
47
|
{"effort": "medium", "description": "Greater reasoning depth for complex problems"},
|
|
48
|
+
{"effort": "high", "description": "High reasoning depth for complex problems"},
|
|
45
49
|
{"effort": "xhigh", "description": "Extra high reasoning depth for complex problems"},
|
|
50
|
+
{"effort": "max", "description": "Maximum reasoning depth"},
|
|
46
51
|
],
|
|
52
|
+
"default_reasoning_level": "xhigh",
|
|
47
53
|
}
|
|
48
54
|
QWEN37_MAX_MODEL = "qwen3.7-max"
|
|
49
55
|
QWEN37_CONTEXT_WINDOW = 1_000_000
|
|
@@ -84,6 +90,7 @@ ALIBABA_CODING_PLAN_MODELS = (
|
|
|
84
90
|
)
|
|
85
91
|
ALIBABA_MODEL_STUDIO_MODELS = (
|
|
86
92
|
QWEN38_MAX_MODEL,
|
|
93
|
+
QWEN38_MAX_SNAPSHOT_MODEL,
|
|
87
94
|
QWEN37_MAX_MODEL,
|
|
88
95
|
"qwen3.7-plus",
|
|
89
96
|
"qwen3.6-plus",
|
|
@@ -173,6 +180,11 @@ class AlibabaModelStudioProviderAdapter(HttpBearerProviderAdapter):
|
|
|
173
180
|
effort_level="xhigh",
|
|
174
181
|
explicit_cache=True,
|
|
175
182
|
explicit_cache_markers=4,
|
|
183
|
+
protocol_headers={
|
|
184
|
+
"openai_responses": {
|
|
185
|
+
"x-dashscope-session-cache": "enable",
|
|
186
|
+
},
|
|
187
|
+
},
|
|
176
188
|
haiku_model="qwen3.6-flash",
|
|
177
189
|
opus_model=QWEN38_MAX_MODEL,
|
|
178
190
|
sonnet_model="qwen3.7-plus",
|
|
@@ -204,6 +216,9 @@ class AlibabaModelStudioProviderAdapter(HttpBearerProviderAdapter):
|
|
|
204
216
|
fallback_models=ALIBABA_MODEL_STUDIO_MODELS,
|
|
205
217
|
allow_configured_fallback=True,
|
|
206
218
|
authoritative_upstream_catalog=True,
|
|
219
|
+
supplemental_model_aliases=(
|
|
220
|
+
(QWEN38_MAX_MODEL, QWEN38_MAX_SNAPSHOT_MODEL),
|
|
221
|
+
),
|
|
207
222
|
)
|
|
208
223
|
)
|
|
209
224
|
|
|
@@ -402,7 +417,7 @@ class AlibabaModelStudioProviderAdapter(HttpBearerProviderAdapter):
|
|
|
402
417
|
projected = dict(reasoning)
|
|
403
418
|
effort = str(projected.get("effort") or "xhigh").strip().lower()
|
|
404
419
|
projected["effort"] = (
|
|
405
|
-
cls.
|
|
420
|
+
cls._normalize_qwen38_responses_effort(effort)
|
|
406
421
|
if cls._is_qwen38(model)
|
|
407
422
|
else effort if effort in _EFFORTS else "xhigh"
|
|
408
423
|
)
|
|
@@ -505,6 +520,11 @@ class AlibabaModelStudioProviderAdapter(HttpBearerProviderAdapter):
|
|
|
505
520
|
return "none"
|
|
506
521
|
return "xhigh"
|
|
507
522
|
|
|
523
|
+
@staticmethod
|
|
524
|
+
def _normalize_qwen38_responses_effort(value: Any) -> str:
|
|
525
|
+
effort = str(value or "xhigh").strip().lower()
|
|
526
|
+
return effort if effort in _EFFORTS else "xhigh"
|
|
527
|
+
|
|
508
528
|
@classmethod
|
|
509
529
|
def _apply_explicit_cache_markers(
|
|
510
530
|
cls, messages: list[Any], configured_limit: Any
|
|
@@ -687,11 +707,23 @@ class AlibabaTokenPlanProviderAdapter(AlibabaModelStudioProviderAdapter):
|
|
|
687
707
|
codex_auto_compact_window=QWEN38_AUTO_COMPACT,
|
|
688
708
|
request_timeout_ms=DEFAULT_REQUEST_TIMEOUT_MS,
|
|
689
709
|
responses_stream_truncation_retries=1,
|
|
710
|
+
# Alibaba documents this header together with a response-id-linked
|
|
711
|
+
# session. Stateless Codex replay uses the model's implicit prefix
|
|
712
|
+
# cache until Ciel has a validated previous_response_id chain.
|
|
713
|
+
responses_session_cache_requires_previous_response_id=True,
|
|
714
|
+
# Keep the summarized Responses prefix byte-stable across several
|
|
715
|
+
# appended Codex tool turns so Alibaba can reuse its session cache.
|
|
716
|
+
responses_cache_checkpoint_items=24,
|
|
690
717
|
stream_enabled=True,
|
|
691
718
|
stream_word_chunking=False,
|
|
692
719
|
effort_level="xhigh",
|
|
693
720
|
explicit_cache=True,
|
|
694
721
|
explicit_cache_markers=4,
|
|
722
|
+
protocol_headers={
|
|
723
|
+
"openai_responses": {
|
|
724
|
+
"x-dashscope-session-cache": "enable",
|
|
725
|
+
},
|
|
726
|
+
},
|
|
695
727
|
haiku_model="qwen3.6-flash",
|
|
696
728
|
opus_model=QWEN38_MAX_MODEL,
|
|
697
729
|
sonnet_model="qwen3.7-plus",
|
|
@@ -765,6 +797,7 @@ __all__ = [
|
|
|
765
797
|
"QWEN38_CONTEXT_WINDOW",
|
|
766
798
|
"QWEN38_MAX_INPUT",
|
|
767
799
|
"QWEN38_MAX_MODEL",
|
|
800
|
+
"QWEN38_MAX_SNAPSHOT_MODEL",
|
|
768
801
|
"QWEN38_MAX_OUTPUT",
|
|
769
802
|
"QWEN38_MAX_REASONING",
|
|
770
803
|
"QWEN38_THINKING_MAX_INPUT",
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from dataclasses import dataclass, field
|
|
6
|
+
import re
|
|
6
7
|
from typing import Any, Mapping
|
|
7
8
|
|
|
8
9
|
from ..architecture import (
|
|
@@ -17,6 +18,7 @@ from ..architecture import (
|
|
|
17
18
|
)
|
|
18
19
|
from .base import NoAuthProviderAdapter, provider_configuration
|
|
19
20
|
from .constants import PROVIDER_DEFAULT_BASE_URLS
|
|
21
|
+
from ..runtime_constants import ANTHROPIC_ONE_MILLION_MODEL_IDS
|
|
20
22
|
|
|
21
23
|
|
|
22
24
|
@dataclass(frozen=True)
|
|
@@ -25,7 +27,9 @@ class AnthropicProviderAdapter(NoAuthProviderAdapter):
|
|
|
25
27
|
base_url: str = PROVIDER_DEFAULT_BASE_URLS["anthropic"]
|
|
26
28
|
configuration_defaults_value: dict = field(
|
|
27
29
|
default_factory=lambda: provider_configuration(
|
|
28
|
-
"claude-
|
|
30
|
+
"claude-opus-5[1m]",
|
|
31
|
+
custom_models=ANTHROPIC_ONE_MILLION_MODEL_IDS,
|
|
32
|
+
route_through_router=False,
|
|
29
33
|
)
|
|
30
34
|
)
|
|
31
35
|
capabilities_value: ProviderCapabilities = field(
|
|
@@ -50,6 +54,19 @@ class AnthropicProviderAdapter(NoAuthProviderAdapter):
|
|
|
50
54
|
default_factory=lambda: ProviderModelCatalogPolicy(kind="anthropic")
|
|
51
55
|
)
|
|
52
56
|
|
|
57
|
+
def normalize_model_id(self, model_id: str) -> str:
|
|
58
|
+
text = str(model_id or "").strip()
|
|
59
|
+
base = re.sub(r"\[1m\]\s*$", "", text, flags=re.IGNORECASE).strip()
|
|
60
|
+
return f"{base}[1m]" if base and re.search(r"\[1m\]\s*$", text, re.IGNORECASE) else base
|
|
61
|
+
|
|
62
|
+
def upstream_api_model_id(self, model_id: str) -> str:
|
|
63
|
+
return re.sub(
|
|
64
|
+
r"\[1m\]\s*$", "", str(model_id or "").strip(), flags=re.IGNORECASE
|
|
65
|
+
).strip()
|
|
66
|
+
|
|
67
|
+
def preserves_claude_context_suffix_in_alias(self) -> bool:
|
|
68
|
+
return True
|
|
69
|
+
|
|
53
70
|
def advisor_panel_notice(
|
|
54
71
|
self, config: ProviderConfig
|
|
55
72
|
) -> tuple[tuple[str, ...], tuple[str, ...]]:
|