@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.
Files changed (140) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +5 -2
  3. package/ciel_runtime.py +94 -96
  4. package/ciel_runtime_support/anthropic_model_policy.py +20 -3
  5. package/ciel_runtime_support/architecture.py +5 -0
  6. package/ciel_runtime_support/channel_inflight.py +4 -4
  7. package/ciel_runtime_support/channel_injection.py +56 -1
  8. package/ciel_runtime_support/channel_mcp_tools.py +34 -0
  9. package/ciel_runtime_support/channel_message_policy.py +9 -1
  10. package/ciel_runtime_support/channel_message_prompt.py +23 -0
  11. package/ciel_runtime_support/channel_pending_injection.py +86 -32
  12. package/ciel_runtime_support/channel_pending_poll.py +6 -2
  13. package/ciel_runtime_support/channel_runtime_environment.py +0 -11
  14. package/ciel_runtime_support/channel_terminal_context.py +0 -6
  15. package/ciel_runtime_support/channel_terminal_proxy.py +3 -42
  16. package/ciel_runtime_support/channel_transcript_repository.py +16 -1
  17. package/ciel_runtime_support/channel_wake_claim_repository.py +0 -19
  18. package/ciel_runtime_support/channel_wake_context.py +6 -13
  19. package/ciel_runtime_support/channel_wake_delivery_repository.py +50 -0
  20. package/ciel_runtime_support/chat_http_controller.py +88 -5
  21. package/ciel_runtime_support/claude_environment.py +100 -3
  22. package/ciel_runtime_support/claude_launch_assembly.py +4 -0
  23. package/ciel_runtime_support/claude_session_socket.py +181 -0
  24. package/ciel_runtime_support/cli_application_context.py +18 -10
  25. package/ciel_runtime_support/cli_dispatch.py +19 -3
  26. package/ciel_runtime_support/cli_parser.py +2 -0
  27. package/ciel_runtime_support/cli_usage.py +3 -2
  28. package/ciel_runtime_support/codex_backend_context.py +8 -3
  29. package/ciel_runtime_support/codex_completion_gate.py +198 -0
  30. package/ciel_runtime_support/codex_turn_recovery.py +240 -83
  31. package/ciel_runtime_support/compatibility_protocol.py +5 -2
  32. package/ciel_runtime_support/config_migrations.py +79 -0
  33. package/ciel_runtime_support/config_repository.py +7 -0
  34. package/ciel_runtime_support/context_summary_policy.py +24 -4
  35. package/ciel_runtime_support/external_event_menu.py +107 -0
  36. package/ciel_runtime_support/external_event_receiver.py +19 -1
  37. package/ciel_runtime_support/launch_state.py +2 -0
  38. package/ciel_runtime_support/managed_tool_injection.py +33 -0
  39. package/ciel_runtime_support/muse_runtime_context.py +291 -0
  40. package/ciel_runtime_support/ollama_thinking.py +12 -26
  41. package/ciel_runtime_support/prelaunch.py +13 -0
  42. package/ciel_runtime_support/prelaunch_launch_panel.py +2 -1
  43. package/ciel_runtime_support/prompt_compaction.py +39 -0
  44. package/ciel_runtime_support/provider_files_proxy.py +248 -0
  45. package/ciel_runtime_support/provider_model_identity.py +10 -2
  46. package/ciel_runtime_support/provider_option_cli.py +1 -1
  47. package/ciel_runtime_support/provider_request_access.py +54 -1
  48. package/ciel_runtime_support/provider_responses_passthrough.py +152 -15
  49. package/ciel_runtime_support/providers/alibaba.py +34 -1
  50. package/ciel_runtime_support/providers/anthropic.py +18 -1
  51. package/ciel_runtime_support/providers/meta.py +252 -21
  52. package/ciel_runtime_support/pseudo_tool_parser.py +17 -1
  53. package/ciel_runtime_support/remote_bridge.py +4 -0
  54. package/ciel_runtime_support/remote_instructions.py +5 -0
  55. package/ciel_runtime_support/remote_memory.py +1 -1
  56. package/ciel_runtime_support/responses_cache_diagnostics.py +82 -0
  57. package/ciel_runtime_support/responses_custom_tool_bridge.py +282 -0
  58. package/ciel_runtime_support/responses_input_compatibility.py +19 -3
  59. package/ciel_runtime_support/router_http.py +301 -4
  60. package/ciel_runtime_support/router_observability_context.py +26 -0
  61. package/ciel_runtime_support/router_server_context.py +1 -0
  62. package/ciel_runtime_support/runtime_adapters.py +31 -0
  63. package/ciel_runtime_support/runtime_constants.py +23 -1
  64. package/ciel_runtime_support/runtime_input_gateway.py +85 -5
  65. package/ciel_runtime_support/runtime_input_status.py +150 -0
  66. package/ciel_runtime_support/runtime_launch.py +27 -4
  67. package/ciel_runtime_support/runtime_paths.py +1 -0
  68. package/ciel_runtime_support/speech_http_controller.py +3 -2
  69. package/ciel_runtime_support/streaming_anthropic.py +3 -0
  70. package/ciel_runtime_support/tool_call_events.py +98 -0
  71. package/ciel_runtime_support/transcript_delta_delivery.py +140 -1
  72. package/ciel_runtime_support/ui_text.py +1 -0
  73. package/ciel_runtime_support/web_search_result_events.py +130 -0
  74. package/ciel_runtime_support/web_ui.py +1 -0
  75. package/ciel_runtime_support/windows_conpty.py +92 -8
  76. package/ciel_runtime_support/workspace_mcp.py +4 -1
  77. package/ciel_runtime_support/workspace_state.py +1 -0
  78. package/docs/Configuration.md +20 -4
  79. package/docs/MCP-Channels.md +79 -6
  80. package/docs/Managed-Tool-Injection.md +25 -0
  81. package/docs/Module-Map.md +4 -0
  82. package/docs/Muse-Code.md +73 -0
  83. package/docs/Observability.md +39 -0
  84. package/docs/Providers.md +29 -2
  85. package/docs/Remote-Bridge.md +12 -0
  86. package/docs/Router.md +1 -0
  87. package/docs/journal/2026/09/01/diagnostics/anthropic/router/fable51-usage-credits.okf +70 -0
  88. package/docs/journal/2026/09/01/implementation/claude/session-socket/all-input-paths/default-delivery.okf +133 -0
  89. package/docs/journal/2026/09/01/implementation/claude/session-socket/windows-direct-input.okf +112 -0
  90. package/docs/journal/2026/09/02/diagnostics/cache/alibaba/qwen38-post-restart-hit-rate.okf +107 -0
  91. package/docs/journal/2026/09/02/diagnostics/cache/ollama-cloud/kimi-k3-codex-hit-rate.okf +91 -0
  92. package/docs/journal/2026/09/02/diagnostics/codex/tui/statusline-cache-metrics.okf +44 -0
  93. package/docs/journal/2026/09/02/diagnostics/input/transport/fallback-behavior.okf +31 -0
  94. package/docs/journal/2026/09/02/diagnostics/providers/ollama-cloud/kimi-k3-agent-turn-recovery.okf +125 -0
  95. package/docs/journal/2026/09/02/diagnostics/providers/ollama-cloud/kimi-k3-parameters.okf +128 -0
  96. package/docs/journal/2026/09/02/diagnostics/remote/mia/socket-tui-visibility.okf +47 -0
  97. package/docs/journal/2026/09/02/diagnostics/runtime/alibaba/token-plan/qwen38-latency.okf +108 -0
  98. package/docs/journal/2026/09/02/diagnostics/runtime/alibaba/token-plan/qwen38-vs-gpt56-latency.okf +92 -0
  99. package/docs/journal/2026/09/02/implementation/anthropic/context/one-million-defaults.okf +85 -0
  100. package/docs/journal/2026/09/02/implementation/cache/alibaba/qwen38-cache-hit-improvement.okf +104 -0
  101. package/docs/journal/2026/09/02/implementation/cache/alibaba/qwen38-cache-hit-improvement.png +0 -0
  102. package/docs/journal/2026/09/02/implementation/cache/alibaba/responses-session-cache.okf +97 -0
  103. package/docs/journal/2026/09/02/implementation/providers/alibaba/qwen38/0902-parameter-alignment.okf +97 -0
  104. package/docs/journal/2026/09/02/implementation/providers/meta/multimodal-tools/contributor-protocol-adoption.okf +140 -0
  105. package/docs/journal/2026/09/02/implementation/providers/meta/muse-spark-1.3-support.okf +53 -0
  106. package/docs/journal/2026/09/02/monitoring/cache/alibaba/cielarvis-qwen38-live-hit-rate.okf +858 -0
  107. package/docs/journal/2026/09/02/operations/release/main-merge-local-deploy.okf +36 -0
  108. package/docs/journal/2026/09/02/operations/release/nightly/local-cache-deployment.okf +54 -0
  109. package/docs/journal/2026/09/02/operations/release/nightly/ollama-kimi-recovery-model-audit-deployment.okf +58 -0
  110. package/docs/journal/2026/09/02/operations/release/nightly/qwen38-cache-improvement-deployment.okf +72 -0
  111. package/docs/journal/2026/09/02/research/cache/alibaba/qwen38-hit-rate-improvement.okf +233 -0
  112. package/docs/journal/2026/09/02/research/cache/codex/provider-scope.okf +77 -0
  113. package/docs/journal/2026/09/02/research/providers/ollama-cloud/desktop-model-exhaustive-audit.okf +159 -0
  114. package/docs/journal/2026/09/03/diagnostics/providers/meta/muse-spark-contributor-cache-hit.okf +148 -0
  115. package/docs/journal/2026/09/03/diagnostics/providers/meta/muse-spark-contributor-required-schema.okf +127 -0
  116. package/docs/journal/2026/09/03/diagnostics/providers/ollama-cloud/kimi-k3-resumed-session-stall.okf +160 -0
  117. package/docs/journal/2026/09/03/diagnostics/providers/ollama-cloud/kimi-k3-substantive-dangling-action.okf +94 -0
  118. package/docs/journal/2026/09/03/diagnostics/remote/kevin/codex-gpt-early-turn-completion.okf +162 -0
  119. package/docs/journal/2026/09/03/implementation/runtimes/meta/muse-code/default-yolo.okf +40 -0
  120. package/docs/journal/2026/09/03/implementation/runtimes/meta/muse-code/native-subscription-router.okf +86 -0
  121. package/docs/journal/2026/09/03/operations/deployment/local/session-socket-default-fallback.okf +41 -0
  122. package/docs/journal/2026/09/03/research/deployment/colab/tailscale/credential-storage.okf +41 -0
  123. package/docs/journal/2026/09/03/research/providers/meta/muse-code/subscription-billing-boundary.okf +64 -0
  124. package/docs/journal/2026/09/03/research/web-chat/voice/instruction-format.okf +135 -0
  125. package/docs/journal/2026/09/04/diagnostics/claude/context/early-auto-compaction.okf +75 -0
  126. package/docs/journal/2026/09/04/diagnostics/claude/context/fable-51-status-200k.okf +54 -0
  127. package/docs/journal/2026/09/04/diagnostics/runtime/codex/responses/replayed-item-id-validation.okf +74 -0
  128. package/docs/journal/2026/09/04/diagnostics/workspaces/onecieldmsui/codex/replay-stall.okf +100 -0
  129. package/docs/journal/2026/09/04/implementation/observability/tool-calls/websocket-stream.okf +49 -0
  130. package/docs/journal/2026/09/04/implementation/web-chat/input/raw-injection.okf +42 -0
  131. package/docs/journal/2026/09/05/diagnostics/tty/claude-raw-idle-render.okf +25 -0
  132. package/docs/journal/2026/09/05/implementation/events/search-response-urls.okf +23 -0
  133. package/docs/journal/2026/09/05/implementation/tools/native-injection.okf +19 -0
  134. package/docs/journal/2026/09/05/implementation/windows/conpty/prompt-delivery-lifecycle.okf +43 -0
  135. package/docs/journal/2026/09/05/release/nightly/conpty-native-tools.okf +13 -0
  136. package/docs/journal/2026/09/05/release/nightly/search-result-urls.okf +14 -0
  137. package/docs/journal/2026/09/06/implementation/codex/inherited-web-mcp.okf +22 -0
  138. package/docs/journal/2026/09/07/integration/main/nightly-merge.okf +13 -0
  139. package/docs/journal/2026/09/07/release/stable/0.2.38.okf +10 -0
  140. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,84 @@ capability, followed by the complete commit ledger merged into each release.
5
5
 
6
6
  ## Unreleased
7
7
 
8
+ ## 0.2.38 — 2026-09-07
9
+
10
+ - Disable inherited DuckDuckGo and web_fetch MCP servers with per-launch
11
+ overrides for native Codex (direct/routed and app-server), without editing
12
+ global settings or changing non-native provider launches.
13
+ - Emit URL-only web search result events over the existing `tool.call` event
14
+ stream, parsing Claude search result links and available Codex response
15
+ sources. Persist bounded call correlation and result deduplication state.
16
+ - Select Ciel-managed MCP tools by native/non-native launch mode without
17
+ filtering user MCP definitions. Keep generated DuckDuckGo/fetch tools out
18
+ of Anthropic launches even when Ciel web search is explicitly enabled.
19
+ - Make Windows ConPTY prompt-render detection ANSI- and UTF-8-aware, and make
20
+ unconfirmed TUI delivery fail closed without retyping, ASCII sentinel wakes,
21
+ or automatic router fallback. Runtime Input requests now expose durable
22
+ `queued -> submitted -> replied|failed` status queries and real-time events;
23
+ unresolved earlier requests block later TUI drafts. ConPTY resize failures
24
+ and post-resize redraw observations are logged explicitly.
25
+ - Add `raw_injection=true` to the Web Chat message APIs so a caller can inject
26
+ only the exact `message` text without an envelope, attachment projection, or
27
+ response-routing instruction, independently of input transport and response
28
+ destination.
29
+ - Publish normalized Claude, Codex, Muse Code, and routed-provider tool-call
30
+ starts as `tool.call` observability events, with incremental transcript cursors and
31
+ duplicate call-ID suppression. Add authenticated WebSocket event streaming at
32
+ `/ca/events/ws`, including `after`, `level`, and `category` filters.
33
+
34
+ - Repair resumed Codex Responses history whose item IDs contain characters the
35
+ OpenAI backend rejects, and discard projected encrypted reasoning that the
36
+ destination backend cannot authenticate instead of rejecting it one item per
37
+ retry.
38
+
39
+ - Add Muse Code as a native Ciel runtime through `ciel-runtime muse`, including
40
+ official installer discovery, Windows WSL2 execution, Muse 1.3 model and
41
+ reasoning flags, launch-menu/CLI selection, channel-proxy input, and remote
42
+ AGENTS.md synchronization. Native launches remove `META_API_KEY` and
43
+ `MODEL_API_KEY` so Muse browser sign-in remains eligible for Muse Code
44
+ subscription billing instead of silently switching to API pay-as-you-go.
45
+ Normal Muse sessions now include the CLI's native `--yolo` option by default,
46
+ while utility subcommands remain side-effect-free passthrough commands.
47
+ - Make `session_socket` the explicit default for Web Chat and every Runtime
48
+ Input Gateway source. When a runtime has no usable Claude messaging socket,
49
+ idle delivery now falls back to TTY; an active turn retains the durable input
50
+ until terminal injection is safe. Explicit TTY and router selections remain.
51
+ - Improve Meta Muse Spark cache reuse for Codex Responses sessions by adding
52
+ the provider-documented `24h` retention hint when Codex supplies a stable
53
+ `prompt_cache_key`. Cache activity now records privacy-safe request-shape
54
+ fingerprints so intermittent misses can be distinguished from prefix/tool
55
+ changes without logging prompt contents.
56
+ - Complete Meta Muse Spark's native agent surface across Responses, Chat
57
+ Completions, and Messages. Hosted `web_search`/`tool_search`, deferred tools,
58
+ multimodal request blocks, and streaming `/v1/files` upload/list/download/
59
+ delete routes now pass through without lossy protocol conversion; Muse
60
+ compatibility probes reserve enough output budget for reasoning tool calls.
61
+ - Add Meta Muse Spark 1.3 and `muse-spark-1.3-contributor` as first-class
62
+ Meta Model API models. New configurations default to 1.3, existing catalogs
63
+ are migrated without overwriting the selected model, and Codex/Claude receive
64
+ the documented 1M context and `minimal` through `xhigh` reasoning controls.
65
+ - Improve Alibaba Singapore Token Plan cache reuse for Codex: stateless
66
+ full-history Responses requests now use Qwen's implicit prefix cache instead
67
+ of forcing the response-ID session-cache header, while oversized requests
68
+ align their summarized prefix to pair-safe 24-item checkpoints.
69
+ - Deliver Web Chat, configured external event streams/webhooks, and Ciel MCP
70
+ `submit_input` calls to interactive Claude Code sessions through Claude's
71
+ authenticated session socket by default. Windows named pipes and Unix
72
+ AF_UNIX sockets are supported; explicit TTY and router overrides remain.
73
+ - Add Claude Fable 5.1 to the Anthropic catalog and model policy.
74
+ - Stop forcing current Anthropic 1M-default models down to a 200K Claude Code
75
+ auto-compaction window when their configured model ID has no legacy `[1m]`
76
+ marker. Routed Opus 4.6+ / Opus 5, Sonnet 4.6+ / Sonnet 5, and current
77
+ Fable/Mythos models now follow Anthropic's documented default 1M capacity;
78
+ their Claude-facing gateway aliases carry the local `[1m]` context hint even
79
+ when the selected upstream ID does not. Legacy models such as Sonnet 4.5 and
80
+ Haiku 4.5 remain at 200K.
81
+ - Advertise provider descriptions in the gateway model catalog for Claude Code
82
+ 2.1.257 and later model-picker discovery.
83
+ - Apply each routed provider's configured subagent model to every Claude Code
84
+ 2.1.257+ subagent with the new force-model environment switch.
85
+
8
86
  ## 0.2.37 — 2026-09-01
9
87
 
10
88
  - Add the authenticated remote runtime bridge with shared OpenAI-compatible and
package/README.md CHANGED
@@ -77,6 +77,7 @@ ciel-runtime codex
77
77
  ciel-runtime agy
78
78
  ciel-runtime grok
79
79
  ciel-runtime zcode
80
+ ciel-runtime muse
80
81
  ciel-runtime --ca-runtime codex-app-server
81
82
  ```
82
83
 
@@ -92,7 +93,7 @@ ciel-runtimectl test
92
93
 
93
94
  | Capability | What it provides |
94
95
  |---|---|
95
- | Runtime launch | Claude Code, Codex, Codex App Server, AGY, Grok Build, and ZCode from one entrypoint |
96
+ | Runtime launch | Claude Code, Codex, Codex App Server, AGY, Grok Build, ZCode, and Muse Code from one entrypoint |
96
97
  | Provider routing | Native connections where supported; otherwise a loopback HTTP router with provider-owned endpoint and authentication rules |
97
98
  | Remote Runtime Bridge | One authenticated OpenAI/Anthropic-compatible network endpoint with per-request provider/model routing, protocol projection, Router-host OAuth, and isolated request keys where allowed |
98
99
  | Protocol adaptation | Anthropic Messages, OpenAI Chat, OpenAI Responses, Ollama Chat, tool calls, thinking blocks, and SSE streams |
@@ -146,7 +147,9 @@ See [Remote Memory](docs/Remote-Memory.md) and [Configuration](docs/Configuratio
146
147
  Ciel's router exposes separate interfaces for inbound work and outbound
147
148
  observability:
148
149
 
149
- - external events and Web Chat messages can wake an active routed session;
150
+ - external events, Web Chat, and Ciel MCP inputs use Claude Code's authenticated
151
+ session socket by default while an interactive Claude session is active, with
152
+ Windows named-pipe and Unix AF_UNIX support;
150
153
  - transcript webhooks emit only new deltas and retain a retry cursor;
151
154
  - routed token usage is stored per workspace without prompt or credential bodies;
152
155
  - authenticated consumers can read immutable usage events, resume an SSE stream,
package/ciel_runtime.py CHANGED
@@ -113,8 +113,11 @@ from ciel_runtime_support.channel_wake_delivery_repository import ChannelWakeDel
113
113
  from ciel_runtime_support.chat_files import ChatFilePorts, ChatFileRepository
114
114
  from ciel_runtime_support.chat_http_controller import ChatHttpController, ChatHttpReadServices, ChatHttpWriteServices
115
115
  from ciel_runtime_support.runtime_input_gateway import RuntimeInputGateway
116
+ from ciel_runtime_support.runtime_input_status import RuntimeInputStatusRepository
116
117
  from ciel_runtime_support.external_event_receiver import EventReceiverSecretVault, ExternalEventReceiverService
118
+ from ciel_runtime_support.external_event_menu import panel_rows as project_external_event_panel_rows, update_config as project_set_external_event_config
117
119
  from ciel_runtime_support.claude_environment import ClaudeEnvironmentFeaturePorts, ClaudeEnvironmentProjection, ClaudeEnvironmentShellRenderer, ClaudeEnvironmentSourcePorts, ClaudeLimitPolicy, ClaudeLimitPorts, ClaudeModelAliasCompatibilityApi, ClaudeModelAliasPolicy, ClaudeModelPorts, ClaudeRuntimeSettingsPolicy, ClaudeRuntimeSettingsPorts
120
+ from ciel_runtime_support.claude_session_socket import ClaudeSessionSocketClient, prepared_socket_path
118
121
  from ciel_runtime_support.cli_application_context import CliApplicationCompatibilityApi, CliApplicationContext, CliApplicationDispatchPorts, CliApplicationPresentationPorts
119
122
  from ciel_runtime_support.cli_usage import cli_usage_text
120
123
  from ciel_runtime_support.codex_app_server import codex_app_server_launch_args
@@ -175,6 +178,7 @@ from ciel_runtime_support.zai_start_plan_captcha import zai_start_plan_runtime_h
175
178
  from ciel_runtime_support.headless_config import HeadlessConfigCommands, HeadlessConfigServices, HeadlessEnvFileLoader, apply_headless_config
176
179
  from ciel_runtime_support.http_response import ChannelDeliveryGuard, HttpResponseAdapter
177
180
  from ciel_runtime_support.kimi_runtime_context import KimiConfigurationPorts, KimiIdentityPorts, KimiLifecyclePorts, KimiProcessPorts, KimiRuntimeCompatibilityApi, KimiRuntimeContext
181
+ from ciel_runtime_support.muse_runtime_context import MuseConfigurationPorts, MuseLifecyclePorts, MuseProcessPorts, MuseRuntimeCompatibilityApi, MuseRuntimeContext
178
182
  from ciel_runtime_support.zcode_runtime_context import ZcodeConfigurationPorts, ZcodeLifecyclePorts, ZcodeProcessPorts, ZcodeRuntimeCompatibilityApi, ZcodeRuntimeContext
179
183
  from ciel_runtime_support.launch_diagnostics import LaunchCommandDiagnostics, StderrCaptureAdapter
180
184
  from ciel_runtime_support.launch_state import LaunchStateRepository
@@ -371,6 +375,8 @@ from ciel_runtime_support.router_access import RouterAccessConfigService, Router
371
375
  from ciel_runtime_support.router_client_lifecycle import ManagedRouterLifetime, ManagedRouterLifetimePorts, RoutedLaunchDiagnosticPorts, RoutedLaunchDiagnostics, RouterClientRegistry, RouterClientRegistryPorts, RouterClientSupervisor, RouterClientSupervisorPorts, RouterLifetimeRunner, RouterLifetimeRunnerPorts
372
376
  from ciel_runtime_support.router_health_policy import RouterHealthPolicy
373
377
  from ciel_runtime_support.router_http import EventHttpAdapter, EventHttpPorts, RouterHttpCore, RouterHttpErrors, RouterHttpGetEndpoints, RouterHttpHandler, RouterHttpPostEndpoints, RouterHttpPresentation, RouterHttpRemoteBridge, RouterHttpServices
378
+ from ciel_runtime_support.router_http import RouterHttpFileEndpoints
379
+ from ciel_runtime_support.provider_files_proxy import ProviderFilesProxy, ProviderFilesProxyPorts
374
380
  from ciel_runtime_support.remote_bridge_runtime import RemoteBridgeRuntimeApi
375
381
  from ciel_runtime_support.router_observability_context import RequestTraceConfiguration
376
382
  from ciel_runtime_support.router_observability_context import RequestTracePorts as RouterRequestTracePorts
@@ -436,7 +442,7 @@ from ciel_runtime_support.runtime_maintenance_services import MaintenanceAgyPort
436
442
  from ciel_runtime_support.runtime_paths import (CHANNEL_COMPACT_REQUEST_PATH, # noqa: F401
437
443
  CHANNEL_LLM_CLEAR_FLOOR_PATH, CHANNEL_LLM_CURSOR_PATH,
438
444
  CHANNEL_LLM_LAUNCH_GUARD_PATH,
439
- CHANNEL_STDIN_WAKE_CLAIMS_PATH, CHAT_FILES_DIR, CHAT_MESSAGES_PATH, RUNTIME_INPUTS_PATH,
445
+ CHANNEL_STDIN_WAKE_CLAIMS_PATH, CHAT_FILES_DIR, CHAT_MESSAGES_PATH, RUNTIME_INPUTS_PATH, RUNTIME_INPUT_STATUS_PATH,
440
446
  CIEL_RUNTIME_STATUSLINE_PATH, CLAUDE_COMMANDS_DIR, CLAUDE_GATEWAY_CACHE,
441
447
  CLAUDE_SETTINGS_PATH, CODEX_PROCESS_DIR,
442
448
  CODEX_PROMPTS_DIR_NAME, CONFIG_DIR, CONFIG_PATH, LEGACY_CONFIG_PATH,
@@ -584,19 +590,26 @@ _CHANNEL_STDIN_INJECT_LOCK = threading.Lock()
584
590
  _CHANNEL_STDIN_WAKE_DELIVERED: set[int] = set()
585
591
  _CHANNEL_STDIN_WAKE_PROMPTS: dict[int, str] = {}
586
592
  _CHANNEL_STDIN_WAKE_BATCHES: dict[int, frozenset[int]] = {}
593
+ _CHANNEL_STDIN_WAKE_FAILED: dict[int, str] = {}
594
+ EVENT_BUS, TUI_OBSERVATION_BUS = EventBus(), TuiObservationBus()
595
+ _RUNTIME_INPUT_STATUS_REPOSITORY = RuntimeInputStatusRepository(
596
+ RUNTIME_INPUT_STATUS_PATH, EVENT_BUS.publish,
597
+ lambda level, message: router_log(level, message), threading.RLock(),
598
+ )
587
599
  _CHANNEL_WAKE_DELIVERY_REPOSITORY = ChannelWakeDeliveryRepository(
588
600
  lock=_CHANNEL_STDIN_WAKE_LOCK,
589
601
  delivered=_CHANNEL_STDIN_WAKE_DELIVERED,
590
602
  prompts=_CHANNEL_STDIN_WAKE_PROMPTS,
591
603
  batches=_CHANNEL_STDIN_WAKE_BATCHES,
604
+ failed=_CHANNEL_STDIN_WAKE_FAILED,
592
605
  clear_claim=lambda message_id: _channel_stdin_clear_wake_claim(message_id),
593
606
  commit_cursor=lambda message_id: _commit_channel_llm_cursor_if_newer(message_id),
607
+ status=_RUNTIME_INPUT_STATUS_REPOSITORY,
594
608
  )
595
609
  _CHANNEL_COMPACT_REQUEST_LOCK = threading.Lock()
596
610
  _TOOL_SIDE_EFFECT_DEDUP_TTL_SECONDS = 10 * 60.0
597
611
  _TOOL_SIDE_EFFECT_DEDUP_LOCK = threading.Lock()
598
612
  _TOOL_SIDE_EFFECT_DEDUP_RECENT: dict[str, float] = {}
599
- EVENT_BUS, TUI_OBSERVATION_BUS = EventBus(), TuiObservationBus()
600
613
  USAGE_API_KEYS = UsageApiKeyRepository(USAGE_LEDGER := SqliteUsageLedger(WORKSPACE_STATE_DIR / "usage" / "usage.sqlite3", ROUTER_WORKSPACE_ID), WORKSPACE_STATE_DIR / "usage" / "api-key.pepper", os.environ)
601
614
  USAGE_EVENT_SINK = CompositeUsageEventSink(JsonlUsageEventSink(USAGE_EVENTS_PATH, enabled=lambda: usage_jsonl_enabled(load_config(), os.environ)), USAGE_LEDGER)
602
615
  # Tools Claude Code injects into every model's tool list that misfire when called
@@ -743,6 +756,7 @@ def apply_config_migrations(cfg: dict[str, Any]) -> None:
743
756
  run_config_migrations(
744
757
  cfg,
745
758
  policy=ConfigMigrationPolicy(
759
+ anthropic_defaults_to_one_million_context=anthropic_model_policy.defaults_to_one_million_context,
746
760
  default_request_timeout_ms=DEFAULT_REQUEST_TIMEOUT_MS,
747
761
  kimi_k3_model=KIMI_K3_MODEL,
748
762
  opencode_provider_names=OPENCODE_PROVIDER_NAMES,
@@ -871,6 +885,7 @@ def model_object(provider: str, model_id: str, pcfg: dict[str, Any] | None = Non
871
885
  "id": alias,
872
886
  "type": "model",
873
887
  "display_name": display_name(provider, model_id),
888
+ "description": f"Routed through Ciel Runtime provider '{provider}'.",
874
889
  "created_at": 1700000000,
875
890
  "object": "model",
876
891
  "created": 1700000000,
@@ -883,7 +898,6 @@ def model_object(provider: str, model_id: str, pcfg: dict[str, Any] | None = Non
883
898
  )
884
899
  )
885
900
  return obj
886
-
887
901
  join_url = runtime_primitives.join_url
888
902
  def inbound_query_has_beta_flag(request_path: str) -> bool: return provider_query_policy().inbound_has_beta(request_path)
889
903
  def provider_query_policy() -> ProviderQueryPolicy: return ProviderQueryPolicy(normalize_provider=normalize_provider, propagates_inbound_beta=lambda provider, config: configured_provider_adapter(provider, config).propagates_inbound_beta_query(provider_contract_config(provider, config)))
@@ -1135,7 +1149,7 @@ def router_observability_context() -> RouterObservabilityContext:
1135
1149
  anthropic_tool_continuation_block_count, router_log, USAGE_EVENT_SINK.record, EVENT_BUS.publish),
1136
1150
  sse_config=SseTraceConfiguration(CONFIG_DIR, SSE_LAST_PATH, SSE_TRACE_PATH, TOOL_CALL_LOG_PATH, SSE_TRACE_EVENT_LIMIT,
1137
1151
  SSE_TRACE_PAYLOAD_LIMIT, SSE_TRACE_MAX_BYTES, LOG_LEVELS["TRACE"]),
1138
- sse=SseObservabilityPorts(os.environ, current_log_level, _truncate_for_dump, router_log),
1152
+ sse=SseObservabilityPorts(os.environ, current_log_level, _truncate_for_dump, router_log, EVENT_BUS.publish),
1139
1153
  )
1140
1154
 
1141
1155
  _ROUTER_OBSERVABILITY_API = RouterObservabilityCompatibilityApi(router_observability_context)
@@ -1860,6 +1874,8 @@ def runtime_input_gateway() -> RuntimeInputGateway:
1860
1874
  return RuntimeInputGateway(
1861
1875
  append_runtime_input,
1862
1876
  chat_file_repository().runtime_attachment,
1877
+ _default_channel_input_transport,
1878
+ _RUNTIME_INPUT_STATUS_REPOSITORY,
1863
1879
  )
1864
1880
 
1865
1881
  def external_event_receiver_service() -> ExternalEventReceiverService:
@@ -1895,63 +1911,10 @@ def handle_external_event_raw_post(handler: BaseHTTPRequestHandler, path: str, r
1895
1911
  return external_event_receiver_service().handle_raw_post(handler, path, raw)
1896
1912
 
1897
1913
  def external_event_panel_rows(_cfg: dict[str, Any]) -> tuple[list[str], list[str]]:
1898
- service = external_event_receiver_service()
1899
- receiver = service.receiver_configs().get("default", {})
1900
- public_receiver = service.public_receiver("default", receiver)
1901
- environment_references = public_receiver.get("environment_references", {})
1902
- enabled = bool(receiver.get("enabled", False))
1903
- transport = str(receiver.get("transport") or "webhook")
1904
- event_types = receiver.get("event_types") if isinstance(receiver.get("event_types"), list) else []
1905
- secret_status = service.vault.status("default")
1906
- def secret_source(field_name: str, stored_key: str) -> str:
1907
- reference = environment_references.get(field_name, {})
1908
- if isinstance(reference, dict) and reference.get("name"):
1909
- availability = "available" if reference.get("available") else "missing"
1910
- return f"env:{reference['name']} {availability}"
1911
- return "stored" if secret_status[stored_key] else "unset"
1912
- rows = [
1913
- f"Enabled [{'on' if enabled else 'off'}]",
1914
- f"Transport [{transport}]",
1915
- f"SSE URL [{str(receiver.get('url') or 'unset')}]",
1916
- "SSE content mode [CloudEvents 1.0 structured JSON]",
1917
- f"Allowed CloudEvent types [{', '.join(str(value) for value in event_types) if event_types else 'all'}]",
1918
- f"Cursor JSON pointer [{str(receiver.get('cursor_json_pointer') or 'SSE id field')}]",
1919
- f"Reconnect query parameter [{str(receiver.get('cursor_query_parameter') or 'Last-Event-ID header')}]",
1920
- f"Webhook signing secret [{secret_source('webhook_secret', 'stored_webhook_secret')}]",
1921
- f"SSE authorization [{secret_source('authorization', 'stored_authorization')}]",
1922
- f"Webhook endpoint [{ROUTER_BASE}/ca/events/webhooks/default]",
1923
- "Back",
1924
- ]
1925
- return rows, ["enabled", "transport", "url", "__info__", "event_types", "cursor_json_pointer", "cursor_query_parameter",
1926
- "webhook_secret", "authorization", "__info__", "back"]
1914
+ return project_external_event_panel_rows(external_event_receiver_service(), ROUTER_BASE)
1927
1915
 
1928
1916
  def set_external_event_config(key: str, value: Any) -> list[str]:
1929
- service = external_event_receiver_service()
1930
- current = service.receiver_configs().get("default", {})
1931
- body: dict[str, Any] = {
1932
- "enabled": bool(current.get("enabled", False)),
1933
- "transport": str(current.get("transport") or "webhook"),
1934
- "url": str(current.get("url") or ""),
1935
- "event_types": current.get("event_types") if isinstance(current.get("event_types"), list) else [],
1936
- "cursor_json_pointer": str(current.get("cursor_json_pointer") or ""),
1937
- "cursor_query_parameter": str(current.get("cursor_query_parameter") or ""),
1938
- }
1939
- if key == "enabled":
1940
- body["enabled"] = not body["enabled"]
1941
- elif key == "transport":
1942
- body["transport"] = "sse" if body["transport"] == "webhook" else "webhook"
1943
- elif key == "event_types":
1944
- body["event_types"] = [part.strip() for part in str(value or "").split(",") if part.strip()]
1945
- elif key in {"url", "cursor_json_pointer", "cursor_query_parameter", "webhook_secret", "authorization"}:
1946
- body[key] = str(value or "")
1947
- else:
1948
- raise ValueError(f"unsupported external event option: {key}")
1949
- updated = service.save_receiver("default", body)
1950
- return [
1951
- f"External event receiver updated: enabled={updated.get('enabled')} transport={updated.get('transport')}.",
1952
- "The router owns receiver connections; the prelaunch configuration process does not open a duplicate stream.",
1953
- "External events use the private Runtime Input Gateway and are never published to Web Chat.",
1954
- ]
1917
+ return project_set_external_event_config(external_event_receiver_service(), key, value)
1955
1918
 
1956
1919
  def remote_instruction_synchronizer() -> RemoteInstructionSynchronizer: return RemoteInstructionSynchronizer(load_config=load_config, workspace=lambda: Path(ROUTER_WORKSPACE), state_dir=WORKSPACE_STATE_DIR, log=router_log)
1957
1920
  def remote_memory_synchronizer() -> RemoteMemorySynchronizer: return RemoteMemorySynchronizer(load_config=load_config, workspace=lambda: Path(ROUTER_WORKSPACE), state_dir=WORKSPACE_STATE_DIR, log=router_log)
@@ -1977,7 +1940,7 @@ def set_remote_instruction_config(key: str, value: Any) -> list[str]:
1977
1940
  remote[key] = max(1, min(30, int(str(value).strip())))
1978
1941
  except ValueError:
1979
1942
  return ["HTTP timeout must be a whole number from 1 to 30 seconds."]
1980
- elif key in {"claude_url", "codex_url", "agy_url", "kimi_url", "grok_url"}:
1943
+ elif key in {"claude_url", "codex_url", "agy_url", "kimi_url", "grok_url", "muse_url"}:
1981
1944
  url = str(value or "").strip()
1982
1945
  if url:
1983
1946
  parsed = urllib.parse.urlparse(url)
@@ -1989,7 +1952,7 @@ def set_remote_instruction_config(key: str, value: Any) -> list[str]:
1989
1952
  elif key == "sync":
1990
1953
  results = [
1991
1954
  sync_remote_instruction(runtime, reason="manual")
1992
- for runtime in ("claude", "codex", "agy", "kimi", "grok")
1955
+ for runtime in ("claude", "codex", "agy", "kimi", "grok", "muse")
1993
1956
  ]
1994
1957
  visible = [result for result in results if result.status != "not-configured"]
1995
1958
  return [
@@ -2110,6 +2073,7 @@ def _channel_mcp_tool_call_response(request_id: Any, params: dict[str, Any]) ->
2110
2073
  handle_llm_options=handle_live_llm_options_action,
2111
2074
  read_runtime_inputs=read_runtime_inputs,
2112
2075
  telemetry_logs=_TELEMETRY_LOG_RUNTIME.tool,
2076
+ submit_input=runtime_input_gateway().submit_stream_input,
2113
2077
  ),
2114
2078
  )
2115
2079
 
@@ -2133,7 +2097,15 @@ def _first_param(params: dict[str, list[str]], name: str, default: str = "") ->
2133
2097
  def chat_http_controller() -> ChatHttpController:
2134
2098
  return ChatHttpController(
2135
2099
  router_base=ROUTER_BASE,
2136
- reads=ChatHttpReadServices(read_chat_messages, read_chat_messages_before, _CHAT_CONDITION, _safe_segment, CHAT_FILES_DIR),
2100
+ reads=ChatHttpReadServices(
2101
+ read_chat_messages,
2102
+ read_chat_messages_before,
2103
+ _CHAT_CONDITION,
2104
+ _safe_segment,
2105
+ CHAT_FILES_DIR,
2106
+ _RUNTIME_INPUT_STATUS_REPOSITORY.get,
2107
+ _RUNTIME_INPUT_STATUS_REPOSITORY.list_latest,
2108
+ ),
2137
2109
  writes=ChatHttpWriteServices(
2138
2110
  write_json,
2139
2111
  append_chat_message,
@@ -2141,6 +2113,7 @@ def chat_http_controller() -> ChatHttpController:
2141
2113
  runtime_input_gateway().submit_web_chat,
2142
2114
  runtime_input_gateway().submit_notification,
2143
2115
  runtime_input_gateway().submit_tty,
2116
+ _default_channel_input_transport,
2144
2117
  ),
2145
2118
  )
2146
2119
 
@@ -2990,6 +2963,22 @@ def _router_server_context() -> RouterServerContext:
2990
2963
  external_event_receiver_service().start(), _TELEMETRY_LOG_RUNTIME.start(), usage_services.start()
2991
2964
  def stop_router_services() -> None:
2992
2965
  usage_services.stop(), _TELEMETRY_LOG_RUNTIME.stop(), external_event_receiver_service().stop()
2966
+ provider_files = ProviderFilesProxy(
2967
+ ProviderFilesProxyPorts(
2968
+ current_provider=get_current_provider,
2969
+ bridge_enabled=_REMOTE_BRIDGE.enabled,
2970
+ bridge_is_request=lambda handler, cfg: _ROUTER_ACCESS_POLICY.remote_bridge_request(handler, cfg, remote_bridge_access_token),
2971
+ bridge_resolve=_REMOTE_BRIDGE.resolve,
2972
+ upstream_base=provider_upstream_request_base,
2973
+ join_url=join_url,
2974
+ headers=provider_headers,
2975
+ urlopen=provider_urlopen,
2976
+ timeout_seconds=provider_request_timeout_seconds,
2977
+ copy_response_headers=_copy_upstream_response_headers,
2978
+ write_json=write_json,
2979
+ log=router_log,
2980
+ )
2981
+ )
2993
2982
  http_services = RouterHttpServices(
2994
2983
  core=RouterHttpCore(load_config, reject_external_router_request, get_current_provider, parse_json_body, is_client_disconnect_error, router_log, observe_tui_runtime_response, router_request_body_policy(), RouterHttpRemoteBridge(_REMOTE_BRIDGE.enabled, _REMOTE_BRIDGE.resolve, _REMOTE_BRIDGE.status_payload, lambda handler, cfg: _ROUTER_ACCESS_POLICY.remote_bridge_request(handler, cfg, remote_bridge_access_token))),
2995
2984
  get=RouterHttpGetEndpoints(handle_tui_observation_get, handle_observability_get, handle_llm_config_get, lambda _handler, _path: False, handle_web_get,
@@ -2999,6 +2988,7 @@ def _router_server_context() -> RouterServerContext:
2999
2988
  handle_plan_post, route_runtime_post, handle_external_event_raw_post, handle_external_event_config_post, handle_usage_post, telemetry_raw=_TELEMETRY_LOG_RUNTIME.http.post),
3000
2989
  presentation=RouterHttpPresentation(render_router_home_html, router_health_payload, write_text_response, write_json, list_model_objects_for_request, resolve_requested_model, model_object, _REMOTE_BRIDGE.model_objects),
3001
2990
  errors=RouterHttpErrors(write_openai_responses_error, try_write_json),
2991
+ files=RouterHttpFileEndpoints(provider_files.get, provider_files.post, provider_files.delete),
3002
2992
  )
3003
2993
  server_runtime = router_server_runtime.RouterServerRuntime(
3004
2994
  router_server_runtime.RouterServerConfig(ROUTER_INSTANCE_DIR, PID_PATH, ROUTER_PORT, ROUTER_BASE, LOG_LEVEL_PATH, LOG_LEVEL_NAMES, RouterHandler),
@@ -3160,7 +3150,7 @@ portable_language_menu = _CONFIGURATION_CLI_API.portable_language_menu
3160
3150
 
3161
3151
  def credential_cli_controller() -> CredentialCliController:
3162
3152
  return CredentialCliController(
3163
- policy=CredentialCliPolicy(frozenset({"anthropic", "ollama-cloud", "deepseek", "opencode", "opencode-go", "kimi", "nvidia-hosted", "openrouter", "fireworks", "zai", "zai-api", "zai-coding-plan", "zai-start-plan"})),
3153
+ policy=CredentialCliPolicy(frozenset({"anthropic", "ollama-cloud", "deepseek", "opencode", "opencode-go", "kimi", "meta", "nvidia-hosted", "openrouter", "fireworks", "zai", "zai-api", "zai-coding-plan", "zai-start-plan"})),
3164
3154
  ports=CredentialCliPorts(normalize_provider, load_config, provider_api_key_count, provider_primary_api_key, mask_secret, secret_fingerprint,
3165
3155
  api_key_clear_requested, clear_api_key_config, store_api_key_input_config, store_api_keys_config),
3166
3156
  io=CredentialCliIO(sys.stdin.isatty, getpass.getpass, print),
@@ -3238,7 +3228,7 @@ def cmd_ollama_native(args: argparse.Namespace) -> None: provider_option_cli_con
3238
3228
  def provider_option_policy() -> ProviderOptionPolicy: return ProviderOptionPolicy(normalize_claude_code_supported_capabilities, normalize_ip_family, normalize_model_id, normalize_opencode_endpoint_kind, parse_bool, parse_config_value, positive_int, ProviderSamplingPolicy())
3239
3229
  def apply_ollama_option(pcfg: dict[str, Any], token: str) -> None: mutate_ollama_option(pcfg, token, policy=provider_option_policy())
3240
3230
  def cmd_ollama_options(args: argparse.Namespace) -> None: provider_option_cli_controller().ollama_options(args)
3241
- PROVIDER_OPTION_PROVIDERS = ("anthropic", "agy", "codex", "vllm", "lm-studio", "nvidia-hosted", "self-hosted-nim", "ollama", "ollama-cloud", "deepseek", "opencode", "opencode-go", "kimi", "openrouter", "fireworks", "zai", "zai-api", "zai-coding-plan", "zai-start-plan")
3231
+ PROVIDER_OPTION_PROVIDERS = ("anthropic", "agy", "codex", "vllm", "lm-studio", "nvidia-hosted", "self-hosted-nim", "ollama", "ollama-cloud", "deepseek", "opencode", "opencode-go", "kimi", "meta", "openrouter", "fireworks", "zai", "zai-api", "zai-coding-plan", "zai-start-plan")
3242
3232
  PROVIDER_SAMPLING_OPTION_PROVIDERS = ("vllm", "lm-studio", "nvidia-hosted", "self-hosted-nim", "openrouter")
3243
3233
  PROVIDER_SAMPLING_OPTIONS = ("temperature", "top_p", "top_k")
3244
3234
  def sampling_option_key(key: str) -> str | None: return ProviderSamplingPolicy().option_key(key)
@@ -4023,6 +4013,27 @@ _ZCODE_RUNTIME_API = ZcodeRuntimeCompatibilityApi(zcode_runtime_context)
4023
4013
  def install_zcode_if_missing() -> str: return _ZCODE_RUNTIME_API.install_if_missing()
4024
4014
  def launch_zcode(passthrough: list[str] | None = None, **_kwargs: Any) -> int: return _ZCODE_RUNTIME_API.launch(list(passthrough or []))
4025
4015
  launch_zcode = SynchronizedLaunch(launch_zcode, sync_remote_launch_assets, "zcode")
4016
+
4017
+ def muse_runtime_context() -> MuseRuntimeContext:
4018
+ return MuseRuntimeContext(
4019
+ process=MuseProcessPorts(find_executable, subprocess.run, subprocess.call, print, os.environ, path_with_ciel_runtime_user_dirs, os.name),
4020
+ config=MuseConfigurationPorts(load_config, get_current_provider),
4021
+ lifecycle=MuseLifecyclePorts(
4022
+ materialize_runtime_command,
4023
+ start_router_if_needed,
4024
+ run_with_router_lifetime,
4025
+ subprocess_call_with_channel_wake_proxy,
4026
+ channel_delivery_mode,
4027
+ runtime_launch.web_backend_start_requested,
4028
+ lambda provider, model: record_launch_state_for_cwd(current_launch_cwd_key(), provider, "muse-native-subscription", model),
4029
+ _set_channel_transcript_scope,
4030
+ ),
4031
+ )
4032
+
4033
+ _MUSE_RUNTIME_API = MuseRuntimeCompatibilityApi(muse_runtime_context)
4034
+ def install_muse_if_missing(): return _MUSE_RUNTIME_API.install_if_missing()
4035
+ def launch_muse(passthrough: list[str] | None = None, **_kwargs: Any) -> int: return _MUSE_RUNTIME_API.launch(list(passthrough or []))
4036
+ launch_muse = SynchronizedLaunch(launch_muse, sync_remote_launch_assets, "muse")
4026
4037
  enable_ansi = enable_terminal_ansi
4027
4038
  ansi = render_ansi
4028
4039
  animated_ansi_text = render_animated_ansi_text
@@ -4135,7 +4146,7 @@ def portable_prelaunch_menu(passthrough: list[str] | None = None) -> int:
4135
4146
  config=prelaunch.PrelaunchConfig(clear_model_cache, current_provider_panel_choice, default_base_url, get_current_provider, load_config, preflight_lines,
4136
4147
  provider_menu_label, save_config, settings_ready_except_api_key, read_model_list_cache),
4137
4148
  launch_policy=prelaunch.PrelaunchLaunchPolicy(agy_launch_enabled_for_provider, claude_launch_enabled_for_provider, codex_launch_enabled_for_provider,
4138
- launch_blockers_require_api_key, launch_readiness_errors, launch_kimi, launch_grok, launch_zcode),
4149
+ launch_blockers_require_api_key, launch_readiness_errors, launch_kimi, launch_grok, launch_zcode, launch_muse),
4139
4150
  panel_rows=prelaunch.PrelaunchPanelRows(advisor_model_panel_rows, api_key_panel_rows, base_url_panel_rows, context_setup_panel_rows, language_panel_rows,
4140
4151
  llm_option_panel_rows, llm_preset_panel_rows, log_level_panel_rows, model_panel_rows, provider_panel_rows),
4141
4152
  mutations=prelaunch.PrelaunchMutations(apply_context_setup_config, apply_llm_preset_config, apply_timeout_profile_to_provider,
@@ -4342,6 +4353,8 @@ def should_use_channel_stdin_proxy(use_router_mode: bool, passthrough: list[str]
4342
4353
  return False
4343
4354
  claude_config = cfg.get("claude_code") if isinstance(cfg, dict) else {}
4344
4355
  return not (isinstance(claude_config, dict) and claude_config.get("web_chat_session_bridge") is False)
4356
+ _CLAUDE_SESSION_SOCKET = ClaudeSessionSocketClient(HOME, router_log)
4357
+ def _default_channel_input_transport() -> str: return "session_socket"
4345
4358
  def _channel_pending_scan_limit() -> int: return channel_runtime_environment_policy().pending_scan_limit()
4346
4359
  def _channel_stdin_wake_batch_limit() -> int: return channel_runtime_environment_policy().wake_batch_limit()
4347
4360
  _CHANNEL_LLM_TOOL_CONTEXT_LOCK = threading.Lock()
@@ -4417,9 +4430,9 @@ def channel_wake_context() -> ChannelWakeContext:
4417
4430
  _channel_superseded_message_ids, _channel_message_is_web_chat_request, _channel_llm_message_skip_reason, _channel_message_event_identity_key,
4418
4431
  _channel_stdin_wake_state_for_message, _channel_stdin_wake_queued_is_stale_for_message),
4419
4432
  pending_delivery=ChannelPendingDeliveryPorts(format_channel_llm_delivery_wake_prompt, format_channel_visible_llm_delivery_wake_prompt, format_channel_web_chat_wake_batch_prompt, format_channel_wake_batch_prompt, _channel_enter_label,
4420
- _channel_wake_store_release_stale, _CHANNEL_WAKE_DELIVERY_REPOSITORY.mark_delivered, _channel_wake_store_record_prompts,
4421
- _channel_wake_store_rollback, _commit_channel_llm_cursor_if_newer),
4422
- pending_io=ChannelPendingIoPorts(_CHANNEL_STDIN_INJECT_LOCK, read_runtime_inputs, _write_channel_wake_prompt, _read_channel_compact_request, _clear_channel_compact_request, _runtime_input_storage_path(), router_log),
4433
+ _channel_wake_store_release_stale, _CHANNEL_WAKE_DELIVERY_REPOSITORY,
4434
+ _commit_channel_llm_cursor_if_newer),
4435
+ pending_io=ChannelPendingIoPorts(_CHANNEL_STDIN_INJECT_LOCK, read_runtime_inputs, _write_channel_wake_prompt, _read_channel_compact_request, _clear_channel_compact_request, _runtime_input_storage_path(), router_log, _CLAUDE_SESSION_SOCKET.send),
4423
4436
  pending_policy=ChannelPendingPolicyPorts(_channel_stdin_wake_batch_limit, time.time, lambda: channel_runtime_environment_policy().web_chat_replay_ttl_seconds(),
4424
4437
  lambda message: runtime_input_repository().timestamp_seconds(message), _channel_message_is_web_chat_request),
4425
4438
  )
@@ -4428,7 +4441,6 @@ def channel_wake_claim_repository() -> ChannelWakeClaimRepository: return channe
4428
4441
  def _channel_stdin_wake_claim_prompt(message_id: int) -> str: return channel_wake_context().claim_prompt(message_id)
4429
4442
  def _channel_stdin_claim_wake_prompt(message_id: int, prompt: str) -> bool: return channel_wake_context().claim_wake_prompt(message_id, prompt)
4430
4443
  def _channel_stdin_clear_wake_claim(message_id: int) -> None: channel_wake_context().clear_wake_claim(message_id)
4431
- def _channel_stdin_mark_body_fallback(message_id: int, reason: str) -> None: channel_wake_context().mark_wake_body_fallback(message_id, reason)
4432
4444
  def _channel_prompt_references_message_id(text: str, message_id: int, prompt_texts: list[str] | tuple[str, ...] | None = None) -> bool: return channel_wake_context().prompt_references_message_id(text, message_id, prompt_texts)
4433
4445
  def _channel_message_ids_already_in_request(body: dict[str, Any]) -> set[int]: return channel_wake_context().message_ids_already_in_request(body)
4434
4446
  def _channel_llm_commit_cursor_locked(last_id: int) -> None: channel_wake_context().commit_cursor(last_id)
@@ -4445,9 +4457,6 @@ def _windows_channel_startup_grace_seconds() -> float:
4445
4457
  """Allow an interactive Windows TUI to begin reading console input."""
4446
4458
  return channel_runtime_environment_policy().windows_startup_grace_seconds()
4447
4459
 
4448
- def _windows_channel_wake_max_attempts() -> int:
4449
- return channel_runtime_environment_policy().windows_wake_max_attempts()
4450
-
4451
4460
  def _write_channel_wake_prompt( master_fd: int, prompt: str, enter_bytes: bytes | None = None, *, submit_retry_count: int = 1, confirm_submit: bool = False, bracketed_paste: bool = False, submit_delay_seconds: float | None = None, ) -> bool:
4452
4461
  return channel_wake_context().write_prompt(
4453
4462
  master_fd, prompt, enter_bytes, submit_retry_count=submit_retry_count,
@@ -4459,12 +4468,12 @@ def _write_channel_wake_prompt( master_fd: int, prompt: str, enter_bytes: bytes
4459
4468
  _CHANNEL_TRANSCRIPT_CACHE: dict[str, Any] = {"checked_at": 0.0, "path": None}
4460
4469
  _CHANNEL_TRANSCRIPT_SCOPE: dict[str, Any] = {
4461
4470
  'runtime': '', 'started_at': 0.0, 'codex_home': None, 'cwd': None,
4462
- 'session_id': '', 'bound_path': None,
4471
+ 'muse_home': None, 'session_id': '', 'bound_path': None,
4463
4472
  }
4464
4473
  _CHANNEL_STDIN_RECOVERY_CACHE: dict[str, Any] = {'checked_at': 0.0, 'last_id': None, 'marker': None, 'recovered_last_id': None}
4465
- _TRANSCRIPT_DELIVERY_SERVICE = TranscriptDeltaDeliveryService(WORKSPACE_STATE_DIR / "transcript-event-cursors.json", ROUTER_WORKSPACE_ID, TranscriptDeliveryPorts(load_config, lambda: _latest_claude_transcript_path(ttl_seconds=0.5), lambda: dict(_CHANNEL_TRANSCRIPT_SCOPE), router_log))
4474
+ _TRANSCRIPT_DELIVERY_SERVICE = TranscriptDeltaDeliveryService(WORKSPACE_STATE_DIR / "transcript-event-cursors.json", ROUTER_WORKSPACE_ID, TranscriptDeliveryPorts(load_config, lambda: _latest_claude_transcript_path(ttl_seconds=0.5), lambda: dict(_CHANNEL_TRANSCRIPT_SCOPE), router_log, event_publish=EVENT_BUS.publish, event_recent=EVENT_BUS.recent))
4466
4475
  def channel_transcript_repository() -> ChannelTranscriptRepository: return channel_wake_context().transcript_repository()
4467
- def _set_channel_transcript_scope(runtime: str, *, started_at: float | None = None, codex_home: Path | None = None, cwd: Path | None = None, session_id: str | None = None) -> None: return (channel_wake_context().set_transcript_scope(runtime, started_at=started_at, codex_home=codex_home, cwd=cwd, session_id=session_id), _TRANSCRIPT_DELIVERY_SERVICE.start())[1]
4476
+ def _set_channel_transcript_scope(runtime: str, *, started_at: float | None = None, codex_home: Path | None = None, muse_home: Path | None = None, cwd: Path | None = None, session_id: str | None = None) -> None: return (channel_wake_context().set_transcript_scope(runtime, started_at=started_at, codex_home=codex_home, muse_home=muse_home, cwd=cwd, session_id=session_id), _TRANSCRIPT_DELIVERY_SERVICE.start())[1]
4468
4477
  def _channel_transcript_roots() -> tuple[tuple[Path, str], ...]: return channel_wake_context().transcript_roots()
4469
4478
  def _latest_claude_transcript_path(ttl_seconds: float = 2.0) -> Path | None: return channel_wake_context().latest_transcript_path(ttl_seconds)
4470
4479
  _read_file_tail_text = ChannelTranscriptRepository.read_tail_text
@@ -4592,34 +4601,19 @@ def _open_windows_conpty(
4592
4601
  return None
4593
4602
  return WindowsConPtySession(cmd, env, log=log)
4594
4603
 
4595
- def _write_windows_channel_body_fallback(writer: Any, message_id: int, enter_bytes: bytes) -> None:
4596
- prompt = f"[ciel-runtime pending request-body input] id={int(message_id)}"
4597
- channel_wake_context().write_prompt(
4598
- writer,
4599
- prompt,
4600
- enter_bytes,
4601
- submit_retry_count=1,
4602
- confirm_submit=False,
4603
- bracketed_paste=False,
4604
- submit_delay_seconds=_channel_wake_submit_delay_seconds(),
4605
- write_all=_write_fd_all,
4606
- snapshot=_channel_current_tmux_pane_text,
4607
- )
4608
-
4609
4604
  def channel_terminal_context() -> ChannelTerminalContext:
4610
4605
  return ChannelTerminalContext(
4611
4606
  process=ChannelTerminalProcessPorts(subprocess.Popen, _write_codex_child_process_record, _terminate_recorded_child_process, _release_codex_child_process_record),
4612
4607
  policy=ChannelTerminalPolicyPorts(ensure_channel_llm_delivery_cursor_initialized, _channel_wake_enter_bytes, _channel_enter_label,
4613
- _channel_wake_enter_env_is_fixed, _channel_stdin_unseen_retry_seconds, _channel_stdin_inflight_is_stale, router_log,
4614
- _windows_channel_wake_max_attempts),
4608
+ _channel_wake_enter_env_is_fixed, _channel_stdin_unseen_retry_seconds, _channel_stdin_inflight_is_stale, router_log),
4615
4609
  polling=ChannelTerminalPollingPorts(_inject_pending_compact_request, _chat_messages_file_marker, _channel_stdin_should_check_pending,
4616
4610
  _channel_stdin_active_tool_call, _channel_stdin_active_turn, _inject_pending_channel_messages, _channel_stdin_wake_state, channel_inflight_effects,
4617
- _channel_stdin_mark_body_fallback, runtime_interactions.read),
4611
+ runtime_interactions.read),
4618
4612
  io=ChannelTerminalIoPorts(_terminal_winsize_from_fd, _apply_pty_winsize, _write_fd_all, _TerminalMouseInputFilter,
4619
4613
  _channel_synthetic_enter_bytes_from_user_input, _write_terminal_input_mode_reset),
4620
4614
  windows=ChannelTerminalWindowsPorts(run_windows_channel_terminal_proxy, _reset_windows_terminal_input_modes,
4621
4615
  _WindowsConsoleMouseInputGuard, _WindowsConsoleInputWriter, _windows_channel_startup_grace_seconds,
4622
- _terminal_input_mode_reset_interval_seconds, _channel_stdin_active_turn, _write_windows_channel_body_fallback, time.sleep,
4616
+ _terminal_input_mode_reset_interval_seconds, _channel_stdin_active_turn, time.sleep,
4623
4617
  _open_windows_conpty),
4624
4618
  dispatch_ports=ChannelTerminalDispatchPorts(os.name, sys.stdin.isatty, sys.stdout.isatty, subprocess.call,
4625
4619
  lambda *args, **kwargs: subprocess_call_with_windows_console_wake_proxy(*args, **kwargs),
@@ -4738,6 +4732,8 @@ def claude_launch_services() -> runtime_launch.ClaudeLaunchServices:
4738
4732
  _codex_channel_wake_submit_delay_seconds,
4739
4733
  _codex_channel_wake_submit_retries,
4740
4734
  _set_channel_transcript_scope,
4735
+ prepared_socket_path,
4736
+ _CLAUDE_SESSION_SOCKET.configure,
4741
4737
  ),
4742
4738
  mcp_config=assembly.ClaudeLaunchMcpConfigPorts(
4743
4739
  write_duckduckgo_mcp_config,
@@ -4938,7 +4934,7 @@ def cli_services() -> cli_dispatch.CliServices:
4938
4934
  core=cli_dispatch.CliCore(VERSION, cli_usage, find_executable, get_current_provider, load_config, pop_headless_env_file_args,
4939
4935
  portable_provider_menu, run_external_menu, run_quiet_upgrade_and_exit),
4940
4936
  runtime=cli_dispatch.CliRuntime(agy_passthrough_has_command, codex_passthrough_has_command, last_launch_runtime, launch_agy, launch_claude,
4941
- launch_codex, launch_codex_app_server, native_agy_enabled, native_codex_enabled, launch_grok, launch_zcode),
4937
+ launch_codex, launch_codex_app_server, native_agy_enabled, native_codex_enabled, launch_grok, launch_zcode, launch_muse),
4942
4938
  provider_commands=cli_dispatch.CliProviderCommands(cmd_advisor_model, cmd_api_key, cmd_base_url, cmd_language, cmd_log_level, cmd_model,
4943
4939
  cmd_models, cmd_provider, cmd_provider_options, cmd_set_api_key),
4944
4940
  special_commands=cli_dispatch.CliSpecialCommands(cmd_ollama_catalog, cmd_ollama_native, cmd_ollama_options, cmd_web_fetch, cmd_web_search),
@@ -4948,7 +4944,7 @@ def cli_services() -> cli_dispatch.CliServices:
4948
4944
  ).services()
4949
4945
  def cli_parser_services() -> cli_parser.CliParserServices:
4950
4946
  return cli_assembly.CliParserAssembly(
4951
- launch=cli_parser.CliParserLaunch(cmd_cli, cmd_launch, cmd_launch_codex, cmd_launch_codex_app_server, cmd_launch_agy, serve, cmd_remote_bridge, cmd_launch_grok, cmd_launch_zcode),
4947
+ launch=cli_parser.CliParserLaunch(cmd_cli, cmd_launch, cmd_launch_codex, cmd_launch_codex_app_server, cmd_launch_agy, serve, cmd_remote_bridge, cmd_launch_grok, cmd_launch_zcode, cmd_launch_muse),
4952
4948
  runtime=cli_parser.CliParserRuntime(cmd_version, cmd_status, cmd_env, cmd_stop, cmd_test),
4953
4949
  settings=cli_parser.CliParserSettings(cmd_language, cmd_web_search, cmd_web_fetch, cmd_log_level, *event_settings_cli.handlers(event_settings_cli.EventSettingsCliPorts(load_config, save_config, external_event_receiver_service, lambda: set_remote_instruction_config('sync', ''), sync_all_remote_memories, print, lambda: USAGE_API_KEYS))),
4954
4950
  provider=cli_parser.CliParserProvider(cmd_ollama_native, cmd_ollama_options, cmd_provider_options, cmd_ollama_catalog, cmd_provider,
@@ -4959,7 +4955,8 @@ def cli_parser_services() -> cli_parser.CliParserServices:
4959
4955
  def cli_application_context() -> CliApplicationContext:
4960
4956
  return CliApplicationContext(
4961
4957
  dispatch=CliApplicationDispatchPorts(dispatch_cli, cli_services, launch_claude, launch_codex, launch_codex_app_server,
4962
- launch_agy, launch_kimi, run_kimi_oauth_login, launch_grok, launch_zcode),
4958
+ launch_agy, launch_kimi, run_kimi_oauth_login,
4959
+ {"grok": launch_grok, "zcode": launch_zcode, "muse": launch_muse}),
4963
4960
  presentation=CliApplicationPresentationPorts(build_cli_parser, cli_parser_services, VERSION, print, lambda: sys.argv),
4964
4961
  )
4965
4962
 
@@ -4973,6 +4970,7 @@ cmd_launch_codex_app_server = _CLI_APPLICATION_API.cmd_launch_codex_app_server
4973
4970
  cmd_launch_agy = _CLI_APPLICATION_API.cmd_launch_agy
4974
4971
  cmd_launch_grok = _CLI_APPLICATION_API.cmd_launch_grok
4975
4972
  cmd_launch_zcode = _CLI_APPLICATION_API.cmd_launch_zcode
4973
+ cmd_launch_muse = _CLI_APPLICATION_API.cmd_launch_muse
4976
4974
  cmd_version = _CLI_APPLICATION_API.cmd_version
4977
4975
  main = _CLI_APPLICATION_API.main
4978
4976
 
@@ -18,15 +18,32 @@ SUPPORTED_CAPABILITIES = (
18
18
 
19
19
 
20
20
  def model_family(model_id: str) -> str:
21
- model = (model_id or "").strip().lower()
21
+ model = re.sub(r"\[1m\]$", "", (model_id or "").strip().lower())
22
22
  for family in ("fable", "mythos", "opus", "sonnet", "haiku"):
23
23
  if re.search(rf"(?:^|-)claude-(?:\d+(?:-\d+){{0,2}}-)?{family}(?:-|$)", model) or f"-{family}-" in model:
24
24
  return family
25
25
  return "claude"
26
26
 
27
27
 
28
+ def defaults_to_one_million_context(model_id: str) -> bool:
29
+ """Return whether Anthropic documents 1M as this model's default context."""
30
+
31
+ model = re.sub(r"\[1m\]$", "", (model_id or "").strip().lower())
32
+ return bool(
33
+ re.search(
34
+ r"(?:^|-)(?:"
35
+ r"fable-5(?:-1)?|"
36
+ r"mythos-(?:5(?:-1)?|preview)|"
37
+ r"opus-(?:5|4-[678])|"
38
+ r"sonnet-(?:5|4-6)"
39
+ r")(?:-|$)",
40
+ model,
41
+ )
42
+ )
43
+
44
+
28
45
  def limit_hints(model_id: str) -> dict[str, Any]:
29
- model = (model_id or "").strip().lower()
46
+ model = re.sub(r"\[1m\]$", "", (model_id or "").strip().lower())
30
47
  family = model_family(model)
31
48
  if family in ("fable", "mythos") or (
32
49
  family == "opus" and re.search(r"(?:^|-)opus-(?:5|4-[678])(?:-|$)", model)
@@ -58,7 +75,7 @@ def limit_hints(model_id: str) -> dict[str, Any]:
58
75
 
59
76
 
60
77
  def runtime_hints(model_id: str) -> dict[str, Any]:
61
- model = (model_id or "").strip().lower()
78
+ model = re.sub(r"\[1m\]$", "", (model_id or "").strip().lower())
62
79
  if model_family(model) in ("fable", "mythos"):
63
80
  return {
64
81
  "claude_code_default_effort": "high",
@@ -510,6 +510,11 @@ class ProviderAdapter(ABC):
510
510
  del model_id
511
511
  return False
512
512
 
513
+ def preserves_claude_context_suffix_in_alias(self) -> bool:
514
+ """Whether ``[1m]`` remains a Claude-facing suffix after aliasing."""
515
+
516
+ return False
517
+
513
518
  def display_model_name(self, model_id: str, provider_label: str) -> str:
514
519
  """Project a provider model id into the shared human-readable label."""
515
520