@oneciel-ai/ciel-runtime 0.2.37 → 0.2.39
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 +85 -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 +81 -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 +35 -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/fixes/codex/native-web-transport.okf +39 -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/docs/journal/2026/09/07/release/stable/0.2.39.okf +10 -0
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ from dataclasses import dataclass
|
|
|
6
6
|
from typing import Any, Callable, Literal
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
InflightAction = Literal["none", "completed", "
|
|
9
|
+
InflightAction = Literal["none", "completed", "failed", "waiting"]
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
@dataclass(frozen=True, slots=True)
|
|
@@ -71,9 +71,9 @@ def advance_channel_inflight(
|
|
|
71
71
|
effects.release_wake(message_id)
|
|
72
72
|
effects.log(
|
|
73
73
|
"WARN",
|
|
74
|
-
f"{policy.log_namespace}
|
|
74
|
+
f"{policy.log_namespace}_unseen_failed message_id={message_id} age={age:.1f}s",
|
|
75
75
|
)
|
|
76
|
-
return _reset("
|
|
76
|
+
return _reset("failed", snapshot, last_id=effects.ensure_cursor(), logged_at=snapshot.now)
|
|
77
77
|
if policy.is_stale(state, snapshot.started_at, snapshot.now):
|
|
78
78
|
if policy.commit_cursor_on_stale and snapshot.cursor is not None:
|
|
79
79
|
effects.commit_cursor(snapshot.cursor)
|
|
@@ -83,7 +83,7 @@ def advance_channel_inflight(
|
|
|
83
83
|
f"{policy.log_namespace}_{policy.stale_event} message_id={message_id} state={state} "
|
|
84
84
|
f"age={age:.1f}s cursor={snapshot.cursor or '-'}",
|
|
85
85
|
)
|
|
86
|
-
return _reset("
|
|
86
|
+
return _reset("failed", snapshot, last_id=effects.ensure_cursor(), logged_at=snapshot.now)
|
|
87
87
|
if snapshot.now - snapshot.logged_at >= policy.waiting_log_interval:
|
|
88
88
|
effects.log(
|
|
89
89
|
"INFO",
|
|
@@ -33,6 +33,13 @@ class InputTransport(Protocol):
|
|
|
33
33
|
expected_prompt: str | None = None,
|
|
34
34
|
) -> bool | None: ...
|
|
35
35
|
|
|
36
|
+
def clear_unsubmitted_prompt(
|
|
37
|
+
self,
|
|
38
|
+
clear_input: bytes,
|
|
39
|
+
expected_prompt: str,
|
|
40
|
+
timeout_seconds: float = 2.0,
|
|
41
|
+
) -> bool: ...
|
|
42
|
+
|
|
36
43
|
|
|
37
44
|
@dataclass(frozen=True)
|
|
38
45
|
class RuntimeInjectionPolicy:
|
|
@@ -139,9 +146,16 @@ class ChannelPromptInjector:
|
|
|
139
146
|
policy,
|
|
140
147
|
)
|
|
141
148
|
if prompt_ready is False:
|
|
149
|
+
cleared = self._clear_unsubmitted_prompt(
|
|
150
|
+
transport,
|
|
151
|
+
policy.clear_input,
|
|
152
|
+
prompt_text,
|
|
153
|
+
policy.input_drain_timeout_seconds,
|
|
154
|
+
)
|
|
142
155
|
self._log(
|
|
143
156
|
"WARN",
|
|
144
|
-
"
|
|
157
|
+
"channel_input_submit_failed reason=prompt_render_timeout "
|
|
158
|
+
f"draft_clear={'confirmed' if cleared else 'unverified'} retry=disabled",
|
|
145
159
|
)
|
|
146
160
|
return False
|
|
147
161
|
|
|
@@ -178,6 +192,36 @@ class ChannelPromptInjector:
|
|
|
178
192
|
)
|
|
179
193
|
return False
|
|
180
194
|
|
|
195
|
+
def _clear_unsubmitted_prompt(
|
|
196
|
+
self,
|
|
197
|
+
transport: InputTransport,
|
|
198
|
+
clear_input: bytes,
|
|
199
|
+
prompt: str,
|
|
200
|
+
timeout_seconds: float,
|
|
201
|
+
) -> bool:
|
|
202
|
+
clear = getattr(transport, "clear_unsubmitted_prompt", None)
|
|
203
|
+
if not callable(clear):
|
|
204
|
+
self._log(
|
|
205
|
+
"WARN",
|
|
206
|
+
"channel_input_draft_clear result=unavailable retry=disabled",
|
|
207
|
+
)
|
|
208
|
+
return False
|
|
209
|
+
try:
|
|
210
|
+
cleared = bool(clear(clear_input, prompt, timeout_seconds))
|
|
211
|
+
except Exception as exc:
|
|
212
|
+
self._log(
|
|
213
|
+
"ERROR",
|
|
214
|
+
"channel_input_draft_clear result=error retry=disabled "
|
|
215
|
+
f"error={type(exc).__name__}: {exc}",
|
|
216
|
+
)
|
|
217
|
+
return False
|
|
218
|
+
self._log(
|
|
219
|
+
"INFO" if cleared else "WARN",
|
|
220
|
+
"channel_input_draft_clear "
|
|
221
|
+
f"result={'confirmed' if cleared else 'unverified'} retry=disabled",
|
|
222
|
+
)
|
|
223
|
+
return cleared
|
|
224
|
+
|
|
181
225
|
def _submission_snapshot(self, transport: InputTransport) -> str | None:
|
|
182
226
|
"""Use the host snapshot when available, then the transport's own view."""
|
|
183
227
|
|
|
@@ -334,6 +378,17 @@ class CallableInputTransport:
|
|
|
334
378
|
)
|
|
335
379
|
)
|
|
336
380
|
|
|
381
|
+
def clear_unsubmitted_prompt(
|
|
382
|
+
self,
|
|
383
|
+
clear_input: bytes,
|
|
384
|
+
expected_prompt: str,
|
|
385
|
+
timeout_seconds: float = 2.0,
|
|
386
|
+
) -> bool:
|
|
387
|
+
clear = getattr(self._target, "clear_unsubmitted_prompt", None)
|
|
388
|
+
if not callable(clear):
|
|
389
|
+
return False
|
|
390
|
+
return bool(clear(clear_input, expected_prompt, timeout_seconds))
|
|
391
|
+
|
|
337
392
|
|
|
338
393
|
__all__ = [
|
|
339
394
|
"CallableInputTransport",
|
|
@@ -20,10 +20,37 @@ class ChannelMcpToolServices:
|
|
|
20
20
|
handle_llm_options: Callable[[str, str], tuple[list[str], bool]]
|
|
21
21
|
read_runtime_inputs: Callable[..., list[dict[str, Any]]] | None = None
|
|
22
22
|
telemetry_logs: Callable[[str, dict[str, Any]], dict[str, Any]] | None = None
|
|
23
|
+
submit_input: Callable[[dict[str, Any]], dict[str, Any]] | None = None
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
def channel_mcp_tool_schemas() -> list[dict[str, Any]]:
|
|
26
27
|
return [
|
|
28
|
+
{
|
|
29
|
+
"name": "submit_input",
|
|
30
|
+
"description": (
|
|
31
|
+
"Submit an external message to the active Ciel Runtime session. "
|
|
32
|
+
"Claude sessions use their authenticated session socket by default; "
|
|
33
|
+
"callers may explicitly select session_socket, tty, or router."
|
|
34
|
+
),
|
|
35
|
+
"inputSchema": {
|
|
36
|
+
"type": "object",
|
|
37
|
+
"properties": {
|
|
38
|
+
"message": {"type": "string"},
|
|
39
|
+
"channel": {"type": "string"},
|
|
40
|
+
"sender_id": {"type": "string"},
|
|
41
|
+
"thread_id": {"type": "string"},
|
|
42
|
+
"input_transport": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"enum": ["session_socket", "tty", "router"],
|
|
45
|
+
},
|
|
46
|
+
"response_mode": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"enum": ["web_chat", "tty", "mcp"],
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
"required": ["message"],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
27
54
|
{
|
|
28
55
|
"name": "compact_session",
|
|
29
56
|
"description": (
|
|
@@ -213,6 +240,13 @@ def dispatch_channel_mcp_tool(
|
|
|
213
240
|
"expires_at": request.get("expires_at"),
|
|
214
241
|
},
|
|
215
242
|
)
|
|
243
|
+
if name == "submit_input":
|
|
244
|
+
if services.submit_input is None:
|
|
245
|
+
return channel_mcp_tool_response(request_id, "runtime input submission is unavailable", True)
|
|
246
|
+
if not str(args.get("message") or args.get("content") or args.get("text") or "").strip():
|
|
247
|
+
return channel_mcp_tool_response(request_id, "submit_input requires message", True)
|
|
248
|
+
saved = services.submit_input(args)
|
|
249
|
+
return _json_response(request_id, {"ok": True, "message": saved})
|
|
216
250
|
if name == "send_message":
|
|
217
251
|
return _send_message(request_id, args, services)
|
|
218
252
|
if name == "send_file":
|
|
@@ -125,13 +125,21 @@ def web_chat_input_mode(message: dict[str, Any]) -> str:
|
|
|
125
125
|
return "voice" if value == "voice" else "text"
|
|
126
126
|
|
|
127
127
|
|
|
128
|
+
def message_raw_injection(message: dict[str, Any]) -> bool:
|
|
129
|
+
"""Return whether only the exact admitted message text may reach the model."""
|
|
130
|
+
|
|
131
|
+
return _metadata(message).get("raw_injection") is True
|
|
132
|
+
|
|
133
|
+
|
|
128
134
|
def message_input_transport(message: dict[str, Any]) -> str:
|
|
129
135
|
"""Return the per-request path used to enter the active model turn."""
|
|
130
136
|
|
|
131
137
|
# Messages admitted before input_transport existed followed the router
|
|
132
138
|
# delivery policy selected at launch. Preserve that persisted compatibility;
|
|
133
|
-
#
|
|
139
|
+
# current input APIs always stamp their runtime-selected transport.
|
|
134
140
|
value = str(_metadata(message).get("input_transport") or "router").strip().lower().replace("-", "_")
|
|
141
|
+
if value in {"session_socket", "socket", "claude_socket", "messaging_socket"}:
|
|
142
|
+
return "session_socket"
|
|
135
143
|
if value in {"router", "llm", "context", "inband", "in_band"}:
|
|
136
144
|
return "router"
|
|
137
145
|
return "tty"
|
|
@@ -14,6 +14,7 @@ from ciel_runtime_support.channel_message_policy import (
|
|
|
14
14
|
message_is_web_chat_request,
|
|
15
15
|
message_is_external_event,
|
|
16
16
|
message_meta_sources,
|
|
17
|
+
message_raw_injection,
|
|
17
18
|
message_response_mcp,
|
|
18
19
|
message_response_mode,
|
|
19
20
|
string_list,
|
|
@@ -172,6 +173,8 @@ def _web_chat_reply_routes(
|
|
|
172
173
|
routes: list[dict[str, str]] = []
|
|
173
174
|
seen: set[tuple[str, str, str]] = set()
|
|
174
175
|
for message in messages:
|
|
176
|
+
if message_raw_injection(message):
|
|
177
|
+
continue
|
|
175
178
|
if not message_is_web_chat_request(message):
|
|
176
179
|
continue
|
|
177
180
|
if message_response_mode(message) != "web_chat":
|
|
@@ -257,6 +260,8 @@ def _mcp_reply_instruction(messages: list[dict[str, Any]]) -> str:
|
|
|
257
260
|
instructions: list[str] = []
|
|
258
261
|
seen: set[tuple[str, str, str]] = set()
|
|
259
262
|
for message in messages:
|
|
263
|
+
if message_raw_injection(message):
|
|
264
|
+
continue
|
|
260
265
|
if message_response_mode(message) != "mcp":
|
|
261
266
|
continue
|
|
262
267
|
hint = message_response_mcp(message)
|
|
@@ -321,6 +326,12 @@ def _format_cielarvis_internal_prompt(messages: list[dict[str, Any]]) -> str | N
|
|
|
321
326
|
|
|
322
327
|
|
|
323
328
|
def format_web_chat_wake_batch_prompt(messages: list[dict[str, Any]]) -> str:
|
|
329
|
+
if len(messages) == 1 and message_raw_injection(messages[0]):
|
|
330
|
+
return str(
|
|
331
|
+
messages[0].get("message")
|
|
332
|
+
if messages[0].get("message") is not None
|
|
333
|
+
else ""
|
|
334
|
+
)
|
|
324
335
|
if compact := _format_cielarvis_internal_prompt(messages):
|
|
325
336
|
return compact
|
|
326
337
|
if messages and all(
|
|
@@ -406,6 +417,12 @@ def wake_message_is_noise(message: dict[str, Any]) -> bool:
|
|
|
406
417
|
|
|
407
418
|
|
|
408
419
|
def format_wake_batch_prompt(messages: list[dict[str, Any]]) -> str:
|
|
420
|
+
if len(messages) == 1 and message_raw_injection(messages[0]):
|
|
421
|
+
return str(
|
|
422
|
+
messages[0].get("message")
|
|
423
|
+
if messages[0].get("message") is not None
|
|
424
|
+
else ""
|
|
425
|
+
)
|
|
409
426
|
if len(messages) == 1:
|
|
410
427
|
return format_wake_prompt(messages[0])
|
|
411
428
|
parts: list[str] = []
|
|
@@ -493,6 +510,12 @@ def message_llm_display_text(message: dict[str, Any]) -> str:
|
|
|
493
510
|
|
|
494
511
|
|
|
495
512
|
def format_llm_batch_prompt(messages: list[dict[str, Any]]) -> str:
|
|
513
|
+
if len(messages) == 1 and message_raw_injection(messages[0]):
|
|
514
|
+
return str(
|
|
515
|
+
messages[0].get("message")
|
|
516
|
+
if messages[0].get("message") is not None
|
|
517
|
+
else ""
|
|
518
|
+
)
|
|
496
519
|
prompt = "\n\n".join(message_llm_display_text(message) for message in messages)
|
|
497
520
|
instruction = _response_instruction(messages)
|
|
498
521
|
return f"{prompt}\n\n{instruction}" if instruction else prompt
|
|
@@ -10,6 +10,7 @@ from ciel_runtime_support.channel_message_policy import (
|
|
|
10
10
|
message_is_external_event,
|
|
11
11
|
message_response_mcp,
|
|
12
12
|
message_response_mode,
|
|
13
|
+
message_raw_injection,
|
|
13
14
|
web_chat_input_mode,
|
|
14
15
|
)
|
|
15
16
|
|
|
@@ -44,11 +45,8 @@ class ChannelInjectionWakeStore:
|
|
|
44
45
|
claim_prompt: Callable[[int, str], bool]
|
|
45
46
|
clear_claim: Callable[[int], Any]
|
|
46
47
|
release_stale: Callable[[int, bool], Any]
|
|
47
|
-
|
|
48
|
-
record_prompts: Callable[[list[dict[str, Any]], str], Any]
|
|
49
|
-
rollback: Callable[[list[dict[str, Any]], list[int]], Any]
|
|
48
|
+
lifecycle: Any
|
|
50
49
|
commit_cursor: Callable[[int], Any]
|
|
51
|
-
body_fallback: Callable[[int], bool] = lambda _message_id: False
|
|
52
50
|
|
|
53
51
|
|
|
54
52
|
@dataclass(frozen=True, slots=True)
|
|
@@ -57,6 +55,7 @@ class ChannelInjectionIO:
|
|
|
57
55
|
read_messages: Callable[..., list[dict[str, Any]]]
|
|
58
56
|
write_prompt: Callable[..., Any]
|
|
59
57
|
log: Callable[[str, str], Any]
|
|
58
|
+
write_session_socket: Callable[[str, list[dict[str, Any]]], bool] | None = None
|
|
60
59
|
|
|
61
60
|
|
|
62
61
|
@dataclass(frozen=True, slots=True)
|
|
@@ -103,12 +102,8 @@ def inject_pending_channel_messages(
|
|
|
103
102
|
wake_store = services.wake_store
|
|
104
103
|
io = services.io
|
|
105
104
|
with io.inject_lock:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return last_id
|
|
109
|
-
if state.active_turn():
|
|
110
|
-
io.log("INFO", f"channel_stdin_proxy_deferred cursor={last_id} reason=active_turn")
|
|
111
|
-
return last_id
|
|
105
|
+
active_tool_call = state.active_tool_call()
|
|
106
|
+
active_turn = state.active_turn()
|
|
112
107
|
if not web_chat_only:
|
|
113
108
|
last_id = state.recover_cursor(last_id)
|
|
114
109
|
pending: list[dict[str, Any]] = []
|
|
@@ -118,6 +113,7 @@ def inject_pending_channel_messages(
|
|
|
118
113
|
batch_limit = services.policy.wake_batch_limit() if wake_for_llm_delivery else 1
|
|
119
114
|
pending_batch_key: tuple[str, str, str] | None = None
|
|
120
115
|
pending_uses_router = False
|
|
116
|
+
pending_uses_session_socket = False
|
|
121
117
|
seen_event_keys: set[tuple[str, ...]] = set()
|
|
122
118
|
for message in candidates:
|
|
123
119
|
previous_last_id = last_id
|
|
@@ -126,6 +122,17 @@ def inject_pending_channel_messages(
|
|
|
126
122
|
continue
|
|
127
123
|
last_id = max(last_id, message_id)
|
|
128
124
|
channel = message.get("channel")
|
|
125
|
+
failure_reason = wake_store.lifecycle.failure_reason(message_id)
|
|
126
|
+
if failure_reason:
|
|
127
|
+
io.log(
|
|
128
|
+
"ERROR",
|
|
129
|
+
"channel_stdin_proxy_blocked "
|
|
130
|
+
f"cursor={previous_last_id} message_id={message_id} "
|
|
131
|
+
f"reason=prior_submission_failed detail={failure_reason}",
|
|
132
|
+
)
|
|
133
|
+
if pending:
|
|
134
|
+
break
|
|
135
|
+
return previous_last_id
|
|
129
136
|
if web_chat_only and not state.message_is_web_chat(message):
|
|
130
137
|
io.log("INFO", f"channel_stdin_proxy_skipped_noise message_id={message_id} channel={channel} reason=not_web_chat")
|
|
131
138
|
continue
|
|
@@ -138,11 +145,28 @@ def inject_pending_channel_messages(
|
|
|
138
145
|
)
|
|
139
146
|
continue
|
|
140
147
|
metadata = message.get("meta") if isinstance(message.get("meta"), dict) else {}
|
|
148
|
+
input_transport = message_input_transport(message)
|
|
149
|
+
requested_session_socket = input_transport == "session_socket"
|
|
141
150
|
requested_router = (
|
|
142
|
-
|
|
151
|
+
input_transport == "router"
|
|
143
152
|
if "input_transport" in metadata
|
|
144
153
|
else wake_for_llm_delivery
|
|
145
154
|
)
|
|
155
|
+
if requested_session_socket and io.write_session_socket is None:
|
|
156
|
+
io.log(
|
|
157
|
+
"WARN",
|
|
158
|
+
f"channel_stdin_proxy_transport_fallback cursor={previous_last_id} "
|
|
159
|
+
f"message_id={message_id} channel={channel} "
|
|
160
|
+
"requested=session_socket fallback=tty "
|
|
161
|
+
"reason=session_socket_transport_unavailable",
|
|
162
|
+
)
|
|
163
|
+
requested_session_socket = False
|
|
164
|
+
if not requested_session_socket and (active_tool_call or active_turn):
|
|
165
|
+
reason = "active_tool_call" if active_tool_call else "active_turn"
|
|
166
|
+
io.log("INFO", f"channel_stdin_proxy_deferred cursor={previous_last_id} reason={reason}")
|
|
167
|
+
if pending:
|
|
168
|
+
break
|
|
169
|
+
return previous_last_id
|
|
146
170
|
if requested_router and not wake_for_llm_delivery:
|
|
147
171
|
io.log(
|
|
148
172
|
"WARN",
|
|
@@ -153,13 +177,6 @@ def inject_pending_channel_messages(
|
|
|
153
177
|
break
|
|
154
178
|
return previous_last_id
|
|
155
179
|
candidate_uses_router = requested_router
|
|
156
|
-
if candidate_uses_router and wake_store.body_fallback(message_id):
|
|
157
|
-
io.log(
|
|
158
|
-
"INFO",
|
|
159
|
-
f"channel_stdin_proxy_skipped_noise message_id={message_id} "
|
|
160
|
-
f"channel={channel} reason=stdin_wake_body_fallback",
|
|
161
|
-
)
|
|
162
|
-
continue
|
|
163
180
|
skip_reason = state.message_skip_reason(message)
|
|
164
181
|
if skip_reason:
|
|
165
182
|
io.log("INFO", f"channel_stdin_proxy_skipped_noise message_id={message_id} channel={channel} reason={skip_reason}")
|
|
@@ -213,21 +230,30 @@ def inject_pending_channel_messages(
|
|
|
213
230
|
+ ":".join(response_mcp.get(key, "") for key in ("server", "tool", "hint"))
|
|
214
231
|
)
|
|
215
232
|
batch_key_base = (
|
|
233
|
+
("raw", str(message_id))
|
|
234
|
+
if message_raw_injection(message)
|
|
235
|
+
else
|
|
216
236
|
("web_chat", web_chat_input_mode(message) + ":" + response_key)
|
|
217
237
|
if state.message_is_web_chat(message)
|
|
218
238
|
else ("external_event", str((message.get("meta") or {}).get("receiver_id") or ""))
|
|
219
239
|
if message_is_external_event(message)
|
|
220
240
|
else ("channel", "")
|
|
221
241
|
)
|
|
222
|
-
|
|
242
|
+
transport_key = (
|
|
243
|
+
"session_socket"
|
|
244
|
+
if requested_session_socket
|
|
245
|
+
else "router" if candidate_uses_router else "tty"
|
|
246
|
+
)
|
|
247
|
+
batch_key = (batch_key_base[0], batch_key_base[1], transport_key)
|
|
223
248
|
if pending and pending_batch_key != batch_key:
|
|
224
249
|
break
|
|
225
|
-
if not candidate_uses_router and not wake_store.mark_delivered(message_id):
|
|
250
|
+
if not candidate_uses_router and not wake_store.lifecycle.mark_delivered(message_id):
|
|
226
251
|
io.log("INFO", f"channel_stdin_proxy_skipped_noise message_id={message_id} channel={channel} reason=stdin_wake_delivered")
|
|
227
252
|
continue
|
|
228
253
|
pending.append(message)
|
|
229
254
|
pending_batch_key = batch_key
|
|
230
255
|
pending_uses_router = candidate_uses_router
|
|
256
|
+
pending_uses_session_socket = requested_session_socket
|
|
231
257
|
if event_key:
|
|
232
258
|
seen_event_keys.add(event_key)
|
|
233
259
|
if candidate_uses_router and len(pending) == 1:
|
|
@@ -235,6 +261,11 @@ def inject_pending_channel_messages(
|
|
|
235
261
|
last_id = message_id
|
|
236
262
|
if len(pending) >= batch_limit:
|
|
237
263
|
break
|
|
264
|
+
if not candidate_uses_router:
|
|
265
|
+
# A TUI/session-socket draft carries exactly one request. This
|
|
266
|
+
# prevents a later request from being appended to an earlier,
|
|
267
|
+
# not-yet-confirmed draft.
|
|
268
|
+
break
|
|
238
269
|
if not pending:
|
|
239
270
|
return last_id
|
|
240
271
|
if pending_uses_router:
|
|
@@ -262,17 +293,39 @@ def inject_pending_channel_messages(
|
|
|
262
293
|
claimed_ids.append(claim_id)
|
|
263
294
|
submit_bytes = prompts.enter_bytes(enter_bytes)
|
|
264
295
|
try:
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
296
|
+
if pending_uses_session_socket:
|
|
297
|
+
submitted = bool(io.write_session_socket and io.write_session_socket(prompt, pending))
|
|
298
|
+
if submitted is False and not (active_tool_call or active_turn):
|
|
299
|
+
ids = ",".join(str(message.get("id") or "") for message in pending)
|
|
300
|
+
io.log(
|
|
301
|
+
"WARN",
|
|
302
|
+
"channel_stdin_proxy_transport_fallback "
|
|
303
|
+
f"message_ids={ids} requested=session_socket fallback=tty "
|
|
304
|
+
"reason=session_socket_submit_failed",
|
|
305
|
+
)
|
|
306
|
+
submitted = io.write_prompt(
|
|
307
|
+
master_fd,
|
|
308
|
+
prompt,
|
|
309
|
+
submit_bytes,
|
|
310
|
+
submit_retry_count=submit_retry_count,
|
|
311
|
+
confirm_submit=confirm_submit,
|
|
312
|
+
bracketed_paste=bracketed_paste,
|
|
313
|
+
submit_delay_seconds=submit_delay_seconds,
|
|
314
|
+
)
|
|
315
|
+
if submitted is not False:
|
|
316
|
+
pending_uses_session_socket = False
|
|
317
|
+
else:
|
|
318
|
+
submitted = io.write_prompt(
|
|
319
|
+
master_fd,
|
|
320
|
+
prompt,
|
|
321
|
+
submit_bytes,
|
|
322
|
+
submit_retry_count=submit_retry_count,
|
|
323
|
+
confirm_submit=confirm_submit,
|
|
324
|
+
bracketed_paste=bracketed_paste,
|
|
325
|
+
submit_delay_seconds=submit_delay_seconds,
|
|
326
|
+
)
|
|
274
327
|
if submitted is False:
|
|
275
|
-
wake_store.
|
|
328
|
+
wake_store.lifecycle.fail(pending, claimed_ids, "prompt_not_submitted")
|
|
276
329
|
ids = ",".join(str(message.get("id") or "") for message in pending)
|
|
277
330
|
io.log(
|
|
278
331
|
"WARN",
|
|
@@ -280,9 +333,9 @@ def inject_pending_channel_messages(
|
|
|
280
333
|
f"message_ids={ids} reason=prompt_not_submitted",
|
|
281
334
|
)
|
|
282
335
|
return return_last_id if pending_uses_router else previous_last_id
|
|
283
|
-
wake_store.record_prompts(pending, prompt)
|
|
336
|
+
wake_store.lifecycle.record_prompts(pending, prompt)
|
|
284
337
|
except Exception:
|
|
285
|
-
wake_store.
|
|
338
|
+
wake_store.lifecycle.fail(pending, claimed_ids, "submission_exception")
|
|
286
339
|
raise
|
|
287
340
|
if not web_chat_only:
|
|
288
341
|
if commit_cursor:
|
|
@@ -295,6 +348,7 @@ def inject_pending_channel_messages(
|
|
|
295
348
|
"INFO",
|
|
296
349
|
f"channel_stdin_proxy_injected count={len(pending)} message_ids={ids} "
|
|
297
350
|
f"channels={channels} enter={prompts.enter_label(submit_bytes)} "
|
|
351
|
+
f"transport={'session_socket' if pending_uses_session_socket else 'router' if pending_uses_router else 'tty'} "
|
|
298
352
|
f"commit_cursor={commit_cursor} "
|
|
299
353
|
f"display_body={bool(pending_uses_router and display_llm_delivery_body)}",
|
|
300
354
|
)
|
|
@@ -140,7 +140,11 @@ def poll_pending_channel_messages(
|
|
|
140
140
|
web_chat_only=options.web_chat_only,
|
|
141
141
|
wake_for_llm_delivery=options.wake_for_llm_delivery,
|
|
142
142
|
display_llm_delivery_body=options.display_llm_delivery_body,
|
|
143
|
-
|
|
143
|
+
# A runtime without transcript confirmation (for example Muse Code)
|
|
144
|
+
# uses a single fire-and-forget TTY write. Persist its cursor in that
|
|
145
|
+
# same operation; otherwise the generic inflight verifier sees every
|
|
146
|
+
# successful delivery as "missing" and replays it.
|
|
147
|
+
commit_cursor=not options.confirm_submit,
|
|
144
148
|
injected_message_ids=injected_ids,
|
|
145
149
|
submit_retry_count=options.submit_retry_count,
|
|
146
150
|
confirm_submit=options.confirm_submit,
|
|
@@ -148,7 +152,7 @@ def poll_pending_channel_messages(
|
|
|
148
152
|
submit_delay_seconds=options.submit_delay_seconds,
|
|
149
153
|
skip_blocking_wake_states=state.inflight_message_id is not None,
|
|
150
154
|
)
|
|
151
|
-
if injected_ids:
|
|
155
|
+
if injected_ids and options.confirm_submit:
|
|
152
156
|
state.inflight_message_id = injected_ids[-1]
|
|
153
157
|
state.inflight.attempts += 1
|
|
154
158
|
# The injector deliberately returns the cursor preceding an LLM-delivery
|
|
@@ -113,17 +113,6 @@ class ChannelRuntimeEnvironmentPolicy:
|
|
|
113
113
|
maximum=60.0,
|
|
114
114
|
)
|
|
115
115
|
|
|
116
|
-
def windows_wake_max_attempts(self) -> int:
|
|
117
|
-
"""Bound full-prompt attempts before switching to request-body delivery."""
|
|
118
|
-
return self._bounded_int(
|
|
119
|
-
self.environment.get(
|
|
120
|
-
"CIEL_RUNTIME_WINDOWS_CHANNEL_WAKE_MAX_ATTEMPTS"
|
|
121
|
-
),
|
|
122
|
-
default=2,
|
|
123
|
-
minimum=1,
|
|
124
|
-
maximum=4,
|
|
125
|
-
)
|
|
126
|
-
|
|
127
116
|
@staticmethod
|
|
128
117
|
def inflight_is_stale(
|
|
129
118
|
state: str,
|
|
@@ -42,7 +42,6 @@ class ChannelTerminalPolicyPorts:
|
|
|
42
42
|
unseen_retry_seconds: Callable[[], float]
|
|
43
43
|
inflight_is_stale: Callable[..., bool]
|
|
44
44
|
log: Callable[[str, str], None]
|
|
45
|
-
windows_wake_max_attempts: Callable[[], int]
|
|
46
45
|
|
|
47
46
|
|
|
48
47
|
@dataclass(frozen=True, slots=True)
|
|
@@ -55,7 +54,6 @@ class ChannelTerminalPollingPorts:
|
|
|
55
54
|
inject_pending: Callable[..., Any]
|
|
56
55
|
wake_state: Callable[[int], Any]
|
|
57
56
|
inflight_effects: Callable[[], Any]
|
|
58
|
-
mark_body_fallback: Callable[[int, str], None]
|
|
59
57
|
runtime_interaction: Callable[[], RuntimeInteractionEvent | None] = lambda: None
|
|
60
58
|
|
|
61
59
|
|
|
@@ -78,7 +76,6 @@ class ChannelTerminalWindowsPorts:
|
|
|
78
76
|
startup_grace_seconds: Callable[[], float]
|
|
79
77
|
reset_interval_seconds: Callable[[float], float]
|
|
80
78
|
active_turn: Callable[[], bool]
|
|
81
|
-
write_body_fallback: Callable[[Any, int, bytes], None]
|
|
82
79
|
sleep: Callable[[float], None]
|
|
83
80
|
open_conpty: Callable[[list[str], dict[str, str], Callable[[str, str], None]], Any | None]
|
|
84
81
|
|
|
@@ -121,7 +118,6 @@ class ChannelTerminalContext:
|
|
|
121
118
|
unseen_retry_seconds=self.policy.unseen_retry_seconds,
|
|
122
119
|
inflight_is_stale=self.policy.inflight_is_stale,
|
|
123
120
|
log=self.policy.log,
|
|
124
|
-
windows_wake_max_attempts=self.policy.windows_wake_max_attempts,
|
|
125
121
|
)
|
|
126
122
|
|
|
127
123
|
def polling_services(self) -> ChannelTerminalPolling:
|
|
@@ -134,7 +130,6 @@ class ChannelTerminalContext:
|
|
|
134
130
|
inject_pending=self.polling.inject_pending,
|
|
135
131
|
wake_state=self.polling.wake_state,
|
|
136
132
|
inflight_effects=self.polling.inflight_effects,
|
|
137
|
-
mark_body_fallback=self.polling.mark_body_fallback,
|
|
138
133
|
runtime_interaction=self.polling.runtime_interaction,
|
|
139
134
|
)
|
|
140
135
|
|
|
@@ -165,7 +160,6 @@ class ChannelTerminalContext:
|
|
|
165
160
|
startup_grace_seconds=self.windows.startup_grace_seconds,
|
|
166
161
|
reset_interval_seconds=self.windows.reset_interval_seconds,
|
|
167
162
|
active_turn=self.windows.active_turn,
|
|
168
|
-
write_body_fallback=self.windows.write_body_fallback,
|
|
169
163
|
sleep=self.windows.sleep,
|
|
170
164
|
open_conpty=self.windows.open_conpty,
|
|
171
165
|
),
|
|
@@ -62,7 +62,6 @@ class ChannelTerminalPolicy:
|
|
|
62
62
|
unseen_retry_seconds: Callable[[], float]
|
|
63
63
|
inflight_is_stale: Callable[..., bool]
|
|
64
64
|
log: Callable[[str, str], None]
|
|
65
|
-
windows_wake_max_attempts: Callable[[], int]
|
|
66
65
|
|
|
67
66
|
|
|
68
67
|
@dataclass(frozen=True)
|
|
@@ -75,7 +74,6 @@ class ChannelTerminalPolling:
|
|
|
75
74
|
inject_pending: Callable[..., Any]
|
|
76
75
|
wake_state: Callable[[int], Any]
|
|
77
76
|
inflight_effects: Callable[[], Any]
|
|
78
|
-
mark_body_fallback: Callable[[int, str], None]
|
|
79
77
|
runtime_interaction: Callable[[], RuntimeInteractionEvent | None] = lambda: None
|
|
80
78
|
|
|
81
79
|
def input_busy(self) -> bool:
|
|
@@ -100,7 +98,6 @@ class ChannelWindowsConsole:
|
|
|
100
98
|
startup_grace_seconds: Callable[[], float]
|
|
101
99
|
reset_interval_seconds: Callable[[float], float]
|
|
102
100
|
active_turn: Callable[[], bool]
|
|
103
|
-
write_body_fallback: Callable[[Any, int, bytes], None]
|
|
104
101
|
sleep: Callable[[float], None]
|
|
105
102
|
open_conpty: Callable[[list[str], dict[str, str], Callable[[str, str], None]], Any | None]
|
|
106
103
|
|
|
@@ -113,15 +110,6 @@ class ChannelWindowsServices:
|
|
|
113
110
|
console: ChannelWindowsConsole
|
|
114
111
|
|
|
115
112
|
|
|
116
|
-
def windows_wake_requires_body_fallback(
|
|
117
|
-
action: str, attempts: int, maximum_attempts: int
|
|
118
|
-
) -> bool:
|
|
119
|
-
return bool(
|
|
120
|
-
action in {"unseen_retry", "stale"}
|
|
121
|
-
and attempts >= max(1, int(maximum_attempts))
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
|
|
125
113
|
def resolve_posix_child_exit_status(
|
|
126
114
|
proc: Any,
|
|
127
115
|
log: Callable[[str, str], None],
|
|
@@ -400,35 +388,8 @@ def run_windows_channel_terminal_proxy(
|
|
|
400
388
|
pending_poll_state.last_id = inflight_update.last_id
|
|
401
389
|
if inflight_update.action == "completed":
|
|
402
390
|
pending_poll_state.inflight.attempts = 0
|
|
403
|
-
elif inflight_update.action
|
|
404
|
-
|
|
405
|
-
if windows_wake_requires_body_fallback(
|
|
406
|
-
inflight_update.action,
|
|
407
|
-
attempts,
|
|
408
|
-
policy.windows_wake_max_attempts(),
|
|
409
|
-
):
|
|
410
|
-
polling.mark_body_fallback(
|
|
411
|
-
inflight_message_id,
|
|
412
|
-
f"windows_console_{inflight_update.action}",
|
|
413
|
-
)
|
|
414
|
-
pending_poll_state.inflight.attempts = 0
|
|
415
|
-
policy.log(
|
|
416
|
-
"ERROR",
|
|
417
|
-
"channel_windows_console_body_fallback "
|
|
418
|
-
f"message_id={inflight_message_id} attempts={attempts} "
|
|
419
|
-
f"reason={inflight_update.action}",
|
|
420
|
-
)
|
|
421
|
-
try:
|
|
422
|
-
console.write_body_fallback(
|
|
423
|
-
writer, inflight_message_id, channel_enter_bytes
|
|
424
|
-
)
|
|
425
|
-
except Exception as exc:
|
|
426
|
-
policy.log(
|
|
427
|
-
"ERROR",
|
|
428
|
-
"channel_windows_console_body_fallback_wake_failed "
|
|
429
|
-
f"message_id={inflight_message_id} "
|
|
430
|
-
f"error={type(exc).__name__}: {exc}",
|
|
431
|
-
)
|
|
391
|
+
elif inflight_update.action == "failed":
|
|
392
|
+
pending_poll_state.inflight.attempts = 0
|
|
432
393
|
compact_poll_state = poll_pending_compaction(
|
|
433
394
|
now,
|
|
434
395
|
writer,
|
|
@@ -620,7 +581,7 @@ def run_posix_channel_terminal_proxy(
|
|
|
620
581
|
unseen_retry_seconds=policy.unseen_retry_seconds(),
|
|
621
582
|
waiting_log_interval=30.0,
|
|
622
583
|
is_stale=policy.inflight_is_stale,
|
|
623
|
-
commit_cursor_on_stale=
|
|
584
|
+
commit_cursor_on_stale=False,
|
|
624
585
|
log_namespace="channel_stdin_proxy",
|
|
625
586
|
stale_event="stale_inflight_skipped",
|
|
626
587
|
),
|