@oneciel-ai/ciel-runtime 0.2.22 → 0.2.23
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 +108 -0
- package/README.md +150 -57
- package/ciel-runtime-stop.cmd +1 -0
- package/ciel-runtime.cmd +1 -0
- package/ciel-runtimectl.cmd +1 -0
- package/ciel_runtime.py +56 -53
- package/ciel_runtime_support/anthropic_tool_turns.py +81 -0
- package/ciel_runtime_support/architecture.py +17 -0
- package/ciel_runtime_support/channel_injection.py +113 -3
- package/ciel_runtime_support/channel_message_prompt.py +15 -0
- package/ciel_runtime_support/channel_pending_injection.py +28 -4
- package/ciel_runtime_support/channel_pending_poll.py +2 -0
- package/ciel_runtime_support/channel_terminal_context.py +6 -0
- package/ciel_runtime_support/channel_terminal_dispatch.py +2 -0
- package/ciel_runtime_support/channel_terminal_proxy.py +8 -2
- package/ciel_runtime_support/channel_wake_claim_repository.py +7 -0
- package/ciel_runtime_support/channel_wake_context.py +7 -3
- package/ciel_runtime_support/cli_parser.py +6 -0
- package/ciel_runtime_support/codex_backend_context.py +4 -0
- package/ciel_runtime_support/codex_turn_recovery.py +75 -12
- package/ciel_runtime_support/config_migrations.py +102 -10
- package/ciel_runtime_support/config_repository.py +9 -0
- package/ciel_runtime_support/event_settings_cli.py +284 -2
- package/ciel_runtime_support/openai_chat_passthrough.py +2 -0
- package/ciel_runtime_support/protocols/openai_responses.py +22 -18
- package/ciel_runtime_support/provider_adapters.py +7 -0
- package/ciel_runtime_support/provider_policy.py +10 -1
- package/ciel_runtime_support/provider_request_builder.py +9 -2
- package/ciel_runtime_support/provider_responses_passthrough.py +4 -0
- package/ciel_runtime_support/providers/__init__.py +2 -0
- package/ciel_runtime_support/providers/alibaba.py +33 -10
- package/ciel_runtime_support/providers/constants.py +1 -0
- package/ciel_runtime_support/providers/opencode.py +25 -5
- package/ciel_runtime_support/providers/opencode_go.py +3 -3
- package/ciel_runtime_support/providers/openrouter.py +76 -3
- package/ciel_runtime_support/providers/tabitoken.py +130 -0
- package/ciel_runtime_support/remote_instructions.py +20 -6
- package/ciel_runtime_support/remote_memory.py +515 -55
- package/ciel_runtime_support/responses_input_compatibility.py +14 -0
- package/ciel_runtime_support/router_http.py +5 -0
- package/ciel_runtime_support/runtime_constants.py +1 -1
- package/ciel_runtime_support/runtime_launch.py +9 -2
- package/ciel_runtime_support/runtime_paths.py +2 -0
- package/ciel_runtime_support/tool_side_effect_dedupe.py +7 -4
- package/ciel_runtime_support/transcript_delta_delivery.py +333 -0
- package/ciel_runtime_support/usage_events.py +45 -3
- package/ciel_runtime_support/usage_service.py +871 -0
- package/ciel_runtime_support/windows_conpty.py +108 -2
- package/ciel_runtime_support/workspace_mcp.py +4 -0
- package/docs/CLI-Reference.md +11 -0
- package/docs/Configuration.md +7 -2
- package/docs/MCP-Channels.md +7 -3
- package/docs/Module-Map.md +4 -0
- package/docs/Providers.md +32 -0
- package/docs/Remote-Memory.md +29 -10
- package/docs/Test-Suite.md +1 -0
- package/docs/journal/2026/08/20/kevin-wake-orphan-tool-repair.md +161 -0
- package/docs/journal/2026/08/20/nightly-push-local-deployment.md +59 -2
- package/docs/journal/2026/08/20/wing-remote-memory-replication-verification.md +107 -0
- package/docs/journal/2026/08/21/alibaba-singapore-qwen38-official-alignment.md +64 -0
- package/docs/journal/2026/08/21/codex-visible-sse-wake-submit-regression.md +85 -0
- package/docs/journal/2026/08/21/external-sse-wake-only-change-analysis.md +131 -0
- package/docs/journal/2026/08/21/hyundai-invalid-replayed-tool-name-repair.okf +88 -0
- package/docs/journal/2026/08/21/local-stale-temporary-runtime-pin-repair.okf +118 -0
- package/docs/journal/2026/08/21/transcript-compaction-external-events.okf +131 -0
- package/docs/journal/2026/08/21/wing-ai-net-mcp-boundary-diagnosis.okf +129 -0
- package/docs/journal/2026/08/21/wing-cold-start-wake-submit-repair.okf +161 -0
- package/docs/journal/2026/08/21/wing-powershell-memory-runaway.okf +101 -0
- package/docs/journal/2026/08/21/wing-repeated-reasoning-tool-turn-repair.okf +112 -0
- package/docs/journal/2026/08/21/wing-repeated-tool-guard-finalization.okf +81 -0
- package/docs/journal/2026/08/21/wing-working-directory-memory-deployment.md +110 -0
- package/docs/journal/2026/08/21/wing-workspace-state-memory-prompt-injection.md +88 -0
- package/docs/journal/2026/08/22/alibaba-singapore-dual-endpoint-wire-alignment.okf +142 -0
- package/docs/journal/2026/08/22/delluhiold-claude-compaction-empty-tool-name.okf +168 -0
- package/docs/journal/2026/08/22/remote-memory-relative-prompt-paths.okf +79 -0
- package/docs/journal/2026/08/22/remote-memory-root-system-prompt.okf +121 -0
- package/docs/journal/2026/08/23/claude-web-chat-stateless-mcp-repair.okf +97 -0
- package/docs/journal/2026/08/23/cross-runtime-token-usage-interfaces-research.okf +378 -0
- package/docs/journal/2026/08/23/main-0.2.23-readme-release.okf +81 -0
- package/docs/journal/2026/08/23/mia-openrouter-ox-alpha-latency-diagnosis.okf +146 -0
- package/docs/journal/2026/08/23/openrouter-opencode-ox-alpha-support.okf +114 -0
- package/docs/journal/2026/08/23/tabitoken-provider-model-catalog.okf +97 -0
- package/docs/journal/2026/08/23/usage-stream-snapshot-implementation.okf +134 -0
- package/docs/usage-observability.md +141 -0
- package/install.ps1 +24 -3
- package/package.json +2 -1
|
@@ -7,6 +7,7 @@ import codecs
|
|
|
7
7
|
import subprocess
|
|
8
8
|
import sys
|
|
9
9
|
import threading
|
|
10
|
+
import time
|
|
10
11
|
from collections.abc import Mapping
|
|
11
12
|
from typing import Any, Callable
|
|
12
13
|
|
|
@@ -36,6 +37,10 @@ class WindowsConPtySession:
|
|
|
36
37
|
"""Own a Windows pseudo console and expose it as a byte input transport."""
|
|
37
38
|
|
|
38
39
|
separate_input_stages = False
|
|
40
|
+
supports_prompt_ready_wait = True
|
|
41
|
+
# Codex collapses long pastes to a placeholder, so the captured output tail
|
|
42
|
+
# cannot prove that the original prompt prefix is present. The snapshot is
|
|
43
|
+
# still usable for comparing output before and after a submit key.
|
|
39
44
|
supports_input_snapshot = False
|
|
40
45
|
|
|
41
46
|
def __init__(
|
|
@@ -61,6 +66,7 @@ class WindowsConPtySession:
|
|
|
61
66
|
self._write_lock = threading.Lock()
|
|
62
67
|
self._output_lock = threading.Lock()
|
|
63
68
|
self._output_tail = bytearray()
|
|
69
|
+
self._output_total_bytes = 0
|
|
64
70
|
self._closed = False
|
|
65
71
|
self._stop = threading.Event()
|
|
66
72
|
self._stdin_console_handle: Any = None
|
|
@@ -87,9 +93,108 @@ class WindowsConPtySession:
|
|
|
87
93
|
def normalize_prompt(prompt: str) -> str:
|
|
88
94
|
return " ".join(str(prompt or "").replace("\t", " ").splitlines()).strip()
|
|
89
95
|
|
|
96
|
+
def input_snapshot(self) -> str:
|
|
97
|
+
"""Return the captured child-output tail for submission confirmation."""
|
|
98
|
+
|
|
99
|
+
return self.output_tail().decode("utf-8", errors="replace")
|
|
100
|
+
|
|
101
|
+
def prompt_readiness_checkpoint(self) -> int:
|
|
102
|
+
"""Return an absolute child-output position for prompt render checks."""
|
|
103
|
+
|
|
104
|
+
with self._output_lock:
|
|
105
|
+
return int(self._output_total_bytes)
|
|
106
|
+
|
|
107
|
+
def wait_until_prompt_ready(
|
|
108
|
+
self,
|
|
109
|
+
previous_snapshot: object,
|
|
110
|
+
timeout_seconds: float = 2.0,
|
|
111
|
+
*,
|
|
112
|
+
expected_prompt: str | None = None,
|
|
113
|
+
) -> bool:
|
|
114
|
+
"""Wait for the child to render and settle after injected prompt input."""
|
|
115
|
+
|
|
116
|
+
if isinstance(previous_snapshot, int) and not isinstance(previous_snapshot, bool):
|
|
117
|
+
return self._wait_for_prompt_output(
|
|
118
|
+
previous_snapshot,
|
|
119
|
+
timeout_seconds,
|
|
120
|
+
expected_prompt,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
baseline = str(previous_snapshot or "")
|
|
124
|
+
last = baseline
|
|
125
|
+
rendered = False
|
|
126
|
+
stable_since: float | None = None
|
|
127
|
+
deadline = time.monotonic() + max(0.0, float(timeout_seconds))
|
|
128
|
+
while True:
|
|
129
|
+
now = time.monotonic()
|
|
130
|
+
current = self.input_snapshot()
|
|
131
|
+
if self._prompt_rendered_since(baseline, current, expected_prompt):
|
|
132
|
+
rendered = True
|
|
133
|
+
if rendered and current != last:
|
|
134
|
+
last = current
|
|
135
|
+
stable_since = now
|
|
136
|
+
elif rendered and stable_since is not None and now - stable_since >= 0.5:
|
|
137
|
+
return True
|
|
138
|
+
if now >= deadline:
|
|
139
|
+
return False
|
|
140
|
+
time.sleep(0.02)
|
|
141
|
+
|
|
142
|
+
def _wait_for_prompt_output(
|
|
143
|
+
self,
|
|
144
|
+
checkpoint: int,
|
|
145
|
+
timeout_seconds: float,
|
|
146
|
+
expected_prompt: str | None,
|
|
147
|
+
) -> bool:
|
|
148
|
+
"""Observe bytes emitted after input instead of comparing a rolling tail."""
|
|
149
|
+
|
|
150
|
+
cursor = max(0, int(checkpoint))
|
|
151
|
+
observed = bytearray()
|
|
152
|
+
deadline = time.monotonic() + max(0.0, float(timeout_seconds))
|
|
153
|
+
while True:
|
|
154
|
+
chunk, cursor = self._output_since(cursor)
|
|
155
|
+
if chunk:
|
|
156
|
+
observed.extend(chunk)
|
|
157
|
+
del observed[: max(0, len(observed) - 64 * 1024)]
|
|
158
|
+
if self._prompt_rendered_in_output(bytes(observed), expected_prompt):
|
|
159
|
+
return True
|
|
160
|
+
if time.monotonic() >= deadline:
|
|
161
|
+
return False
|
|
162
|
+
time.sleep(0.02)
|
|
163
|
+
|
|
164
|
+
def _output_since(self, checkpoint: int) -> tuple[bytes, int]:
|
|
165
|
+
with self._output_lock:
|
|
166
|
+
total = int(self._output_total_bytes)
|
|
167
|
+
base = total - len(self._output_tail)
|
|
168
|
+
start = max(base, min(total, int(checkpoint)))
|
|
169
|
+
return bytes(self._output_tail[start - base :]), total
|
|
170
|
+
|
|
90
171
|
@staticmethod
|
|
91
|
-
def
|
|
92
|
-
|
|
172
|
+
def _prompt_rendered_in_output(
|
|
173
|
+
output: bytes,
|
|
174
|
+
expected_prompt: str | None,
|
|
175
|
+
) -> bool:
|
|
176
|
+
prompt = WindowsConPtySession.normalize_prompt(str(expected_prompt or ""))
|
|
177
|
+
if not prompt:
|
|
178
|
+
return bool(output)
|
|
179
|
+
prefix = prompt[:48].encode("utf-8", errors="replace")
|
|
180
|
+
return bool(prefix and prefix in output) or b"[Pasted Content" in output
|
|
181
|
+
|
|
182
|
+
@staticmethod
|
|
183
|
+
def _prompt_rendered_since(
|
|
184
|
+
baseline: str,
|
|
185
|
+
current: str,
|
|
186
|
+
expected_prompt: str | None,
|
|
187
|
+
) -> bool:
|
|
188
|
+
if current == baseline:
|
|
189
|
+
return False
|
|
190
|
+
prompt = WindowsConPtySession.normalize_prompt(str(expected_prompt or ""))
|
|
191
|
+
prefix = prompt[:48]
|
|
192
|
+
if prefix and current.count(prefix) > baseline.count(prefix):
|
|
193
|
+
return True
|
|
194
|
+
paste_marker = "[Pasted Content"
|
|
195
|
+
if prompt and current.count(paste_marker) > baseline.count(paste_marker):
|
|
196
|
+
return True
|
|
197
|
+
return not prompt
|
|
93
198
|
|
|
94
199
|
@staticmethod
|
|
95
200
|
def pending_input_events() -> None:
|
|
@@ -560,6 +665,7 @@ class WindowsConPtySession:
|
|
|
560
665
|
break
|
|
561
666
|
with self._output_lock:
|
|
562
667
|
self._output_tail.extend(data)
|
|
668
|
+
self._output_total_bytes += len(data)
|
|
563
669
|
del self._output_tail[: max(0, len(self._output_tail) - 64 * 1024)]
|
|
564
670
|
if self._mirror_output:
|
|
565
671
|
self._mirror_bytes(data)
|
|
@@ -246,11 +246,15 @@ class WorkspaceMcpLaunchService:
|
|
|
246
246
|
runtime: str,
|
|
247
247
|
config: dict[str, Any],
|
|
248
248
|
environment: Mapping[str, str] | None = None,
|
|
249
|
+
injected_servers: Mapping[str, Any] | None = None,
|
|
249
250
|
) -> WorkspaceMcpLaunch:
|
|
250
251
|
if runtime not in _RUNTIMES:
|
|
251
252
|
raise ValueError(f"Unsupported workspace MCP runtime: {runtime}")
|
|
252
253
|
self.recover_stale()
|
|
253
254
|
servers = workspace_mcp_servers(config, runtime)
|
|
255
|
+
if injected_servers:
|
|
256
|
+
injected = {"workspace_mcp": {"servers": dict(injected_servers)}}
|
|
257
|
+
servers.update(workspace_mcp_servers(injected, runtime))
|
|
254
258
|
if not servers:
|
|
255
259
|
return WorkspaceMcpLaunch()
|
|
256
260
|
launch_id = uuid.uuid4().hex
|
package/docs/CLI-Reference.md
CHANGED
|
@@ -115,6 +115,17 @@ ciel-runtimectl api-keys [PROVIDER] [KEY1] [KEY2] ...
|
|
|
115
115
|
|
|
116
116
|
### Router 관리
|
|
117
117
|
|
|
118
|
+
#### `transcript-events`
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
ciel-runtimectl transcript-events enabled=true url=https://memory.example/v1/transcripts authorization='Bearer {MEMORY_TOKEN}'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
현재 런타임의 Claude/Codex JSONL 트랜스크립트를 등록한 HTTP(S) 주소로 증분
|
|
125
|
+
전송한다. URL과 트랜스크립트별 바이트 커서는 워크스페이스 상태에 저장되며 HTTP
|
|
126
|
+
2xx 이후에만 전진한다. `start_mode=tail`은 현재 실행 경계 이후만,
|
|
127
|
+
`start_mode=beginning`은 파일 처음부터 보낸다. 설정 확인은 인자 없이 실행한다.
|
|
128
|
+
|
|
118
129
|
#### `remote-memory`
|
|
119
130
|
|
|
120
131
|
```bash
|
package/docs/Configuration.md
CHANGED
|
@@ -273,8 +273,13 @@ ciel-runtimectl remote-memory enabled=true \
|
|
|
273
273
|
|
|
274
274
|
manifest는 인덱스 상대경로, 폴더 구조를 나타내는 파일 상대경로, 각 파일의 다운로드
|
|
275
275
|
URL과 포맷을 제공한다. 지원 포맷은 OKF, Markdown, JSON, YAML, TOML, 일반 텍스트다.
|
|
276
|
-
동기화 후 실제 메모리 내용
|
|
277
|
-
|
|
276
|
+
동기화 후 실제 메모리 내용 전체를 프롬프트에 넣지 않는다. 대신 내부적으로 검증된 메모리
|
|
277
|
+
루트와 인덱스의 워크스페이스 기준 상대경로, 그리고 인덱스부터 읽고 관련 메모리 파일을 참조하라는 지시를 최종
|
|
278
|
+
wire 시스템/개발자 문맥 하단의 관리 블록에 추가한다. 같은 블록을 원격으로 내려받은
|
|
279
|
+
`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`의 마지막에도 기록하여 라우터를 우회하는
|
|
280
|
+
네이티브 CLI 실행에서도 동일하게 참조할 수 있게 한다. Remote Instructions의 성공
|
|
281
|
+
상태와 해당 다운로드 파일이 확인된 경우에만 네이티브 파일을 갱신하며, Remote Memory
|
|
282
|
+
단독 설정으로 지시 파일을 새로 만들거나 확인되지 않은 사용자 파일을 변경하지 않는다.
|
|
278
283
|
|
|
279
284
|
계약, 제한, 예시는 [Remote Memory](Remote-Memory.md)를 참고한다.
|
|
280
285
|
|
package/docs/MCP-Channels.md
CHANGED
|
@@ -61,9 +61,13 @@ how a request enters the active TUI and how the answer should leave it:
|
|
|
61
61
|
active CLI terminal. `input_transport=router` keeps the full message in the
|
|
62
62
|
Runtime Input Gateway: while a model turn is already active, its next request
|
|
63
63
|
consumes the message without a console wake; while the CLI is idle, Ciel types
|
|
64
|
-
|
|
65
|
-
in the next request body.
|
|
66
|
-
|
|
64
|
+
a correlated wake turn and replaces that entire turn with the full pending
|
|
65
|
+
message in the next request body. Codex shows the wake marker followed by the
|
|
66
|
+
original projected message in its TUI; Claude and other CLI adapters retain the
|
|
67
|
+
short marker-only wake because their terminal turn behavior is different. In
|
|
68
|
+
both cases the model request receives the queued message exactly once. Router
|
|
69
|
+
transport therefore requires the active model session to use Ciel Router.
|
|
70
|
+
Aliases `llm`, `context`, and `inband` are accepted.
|
|
67
71
|
- `response_mode=web_chat` (alias `ai_net`, default) uses the normal correlated Web
|
|
68
72
|
Chat reply contract. `response_mode=tty` leaves the model's ordinary terminal
|
|
69
73
|
output as-is and does not require a Web Chat tool reply. `response_mode=mcp`
|
package/docs/Module-Map.md
CHANGED
|
@@ -577,6 +577,10 @@ Ollama model-context cache 일치, dynamic `num_ctx` bucket, preset cap, option/
|
|
|
577
577
|
|
|
578
578
|
OpenRouter 인증, OpenAI protocol capability와 hosted context 정책을 소유하는 독립 Adapter.
|
|
579
579
|
|
|
580
|
+
### `ciel_runtime_support/providers/tabitoken.py`
|
|
581
|
+
|
|
582
|
+
TaBiAI의 OpenAI Chat/Anthropic Messages 이중 endpoint, Bearer 인증, 공개 모델 fallback과 thinking 모델의 `reasoning_effort` 투영을 소유하는 독립 Adapter.
|
|
583
|
+
|
|
580
584
|
### `ciel_runtime_support/providers/lm_studio.py`
|
|
581
585
|
|
|
582
586
|
LM Studio catalog 경로, local capability, loaded-model readiness와 context/status 정책을 소유하는 독립 Adapter.
|
package/docs/Providers.md
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
| `nvidia-hosted` | Nvidia Hosted | OpenAI Chat | NVIDIA NIM Cloud |
|
|
22
22
|
| `self-hosted-nim` | Self Hosted NIM | OpenAI Chat | 로컬 NIM |
|
|
23
23
|
| `openrouter` | OpenRouter | OpenAI Chat | `https://openrouter.ai/api` |
|
|
24
|
+
| `tabitoken` | TaBiAI (Tabitoken.com) | Anthropic Messages / OpenAI Chat | `https://tabitoken.com` |
|
|
24
25
|
| `fireworks` | Fireworks.ai | OpenAI Chat | `https://api.fireworks.ai/inference` |
|
|
25
26
|
| `xai` | xAI | OpenAI Responses / Chat | `https://api.x.ai/v1` |
|
|
26
27
|
|
|
@@ -44,6 +45,25 @@ token은 Bearer header로 전송하며, 사용자 지정 `base_url`로 사설 ga
|
|
|
44
45
|
`base_url`로 명시해야 한다. “수동 OAuth token” 범주는 transport가 구현된 상태를
|
|
45
46
|
뜻하며, Ciel이 브라우저 로그인이나 refresh token을 대신 발급한다는 뜻은 아니다.
|
|
46
47
|
|
|
48
|
+
### Alibaba Model Studio Singapore
|
|
49
|
+
|
|
50
|
+
`alims-intl`의 기본 모델은 Singapore International scope의 `qwen3.8-max`다.
|
|
51
|
+
공식 한도에 맞춰 context window는 1,000,000, 최대 입력은 일반 모드 991,808,
|
|
52
|
+
thinking 모드 983,616, 최대 출력은 131,072로 취급한다. Codex에는 thinking 모드의
|
|
53
|
+
안전한 입력 상한인 983,616을 model catalog context로 제공한다.
|
|
54
|
+
|
|
55
|
+
신규 workspace endpoint는 계정별 Workspace ID가 필요하므로 Ciel이 이를 추측하지
|
|
56
|
+
않는다. Model Studio console에서 발급된 다음 OpenAI-compatible URL을 `base_url`에
|
|
57
|
+
입력한다.
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
이 URL을 사용하면 Claude용 native endpoint는 같은 workspace의
|
|
64
|
+
`/apps/anthropic`으로 파생된다. `alitoken`은 별도 구독·과금 계약의 Singapore Token
|
|
65
|
+
Plan endpoint를 계속 사용하므로 일반 `alims-intl` workspace URL과 혼용하지 않는다.
|
|
66
|
+
|
|
47
67
|
### Anthropic Messages 호환 제공자
|
|
48
68
|
|
|
49
69
|
`minimax`와 `minimax-cn`은 OpenAI 변환을 거치지 않고 Anthropic Messages 계약,
|
|
@@ -198,6 +218,18 @@ Anthropic thinking 객체나 문서로 확인되지 않은 GLM-5.2 effort 문자
|
|
|
198
218
|
- 단일 API로 다수 모델 접근.
|
|
199
219
|
- OpenAI Chat 호환.
|
|
200
220
|
|
|
221
|
+
## TaBiAI (Tabitoken.com)
|
|
222
|
+
|
|
223
|
+
- 내부 ID: `tabitoken` (`tabi`, `tabiai`, `tabi-token` 별칭 지원).
|
|
224
|
+
- 공식 공개 pricing catalog의 활성 모델 4개를 기본 catalog로 제공한다:
|
|
225
|
+
`claude-opus-4-8`, `claude-opus-4-8-thinking`, `claude-opus-5`,
|
|
226
|
+
`claude-opus-5-thinking`.
|
|
227
|
+
- Claude 요청은 `POST /v1/messages`, Codex/OpenAI 요청은
|
|
228
|
+
`POST /v1/chat/completions`로 보낸다.
|
|
229
|
+
- 모든 endpoint에 `Authorization: Bearer <TOKEN>`을 사용한다. 공식 API Detail에
|
|
230
|
+
표시된 `x-api-key`는 Anthropic 형식 endpoint가 추가로 허용하는 대체 인증이다.
|
|
231
|
+
- `-thinking` 모델의 OpenAI Chat 요청에만 `reasoning_effort`를 전달한다.
|
|
232
|
+
|
|
201
233
|
---
|
|
202
234
|
|
|
203
235
|
## Fireworks.ai
|
package/docs/Remote-Memory.md
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Remote Memory downloads a workspace-scoped memory tree from a separate HTTP
|
|
4
4
|
manifest endpoint before an interactive runtime starts. It does not place the
|
|
5
|
-
memory contents in the system prompt. Ciel
|
|
6
|
-
address
|
|
5
|
+
memory contents in the system prompt. Ciel appends the verified local memory
|
|
6
|
+
root, memory-index address, and an instruction to consult the relevant memory
|
|
7
|
+
files to the downloaded native instruction file and keeps the same managed
|
|
8
|
+
block at the end of routed system/developer prompt context.
|
|
7
9
|
|
|
8
10
|
## Configure and synchronize
|
|
9
11
|
|
|
@@ -15,11 +17,13 @@ ciel-runtimectl remote-memory `
|
|
|
15
17
|
sync
|
|
16
18
|
```
|
|
17
19
|
|
|
18
|
-
The default destination is `.ciel/memory` below the
|
|
19
|
-
|
|
20
|
+
The default destination is `.ciel/memory` below the runtime's actual launch
|
|
21
|
+
workspace. On Windows, launching from `C:\work\project` produces
|
|
22
|
+
`C:\work\project\.ciel\memory`. A custom destination must remain a portable
|
|
23
|
+
relative path inside that launch workspace:
|
|
20
24
|
|
|
21
25
|
```powershell
|
|
22
|
-
ciel-runtimectl remote-memory directory
|
|
26
|
+
ciel-runtimectl remote-memory directory=team-memory
|
|
23
27
|
```
|
|
24
28
|
|
|
25
29
|
Use `ciel-runtimectl remote-memory` without values to display the current
|
|
@@ -78,18 +82,33 @@ and optional SHA-256 values pass does Ciel replace the previous memory tree.
|
|
|
78
82
|
Files omitted by the new manifest therefore disappear. A failed synchronization
|
|
79
83
|
keeps the previous tree unchanged and logs `remote_memory_failed`.
|
|
80
84
|
|
|
81
|
-
|
|
82
|
-
|
|
85
|
+
The router's launch-workspace identity selects the destination. A machine with
|
|
86
|
+
no separate project checkout may use its user home as the launch workspace; in
|
|
87
|
+
that case Ciel creates `<home>/.ciel/memory`. Different launch workspaces receive
|
|
88
|
+
different trees. Ciel keeps only synchronization metadata in its workspace
|
|
89
|
+
state directory.
|
|
90
|
+
|
|
91
|
+
After a successful synchronization, routed OpenAI Responses, OpenAI Chat, and
|
|
92
|
+
Anthropic Messages requests receive a managed prompt block like this:
|
|
83
93
|
|
|
84
94
|
```markdown
|
|
85
95
|
<!-- ciel-runtime:remote-memory:begin -->
|
|
96
|
+
Memory root: .ciel/memory
|
|
86
97
|
Memory index: .ciel/memory/index.okf
|
|
98
|
+
Memory guidance: Resolve these paths from the current workspace root. Read the memory index first and use the relevant files under the memory root as context for your work.
|
|
87
99
|
<!-- ciel-runtime:remote-memory:end -->
|
|
88
100
|
```
|
|
89
101
|
|
|
90
|
-
The
|
|
91
|
-
|
|
92
|
-
|
|
102
|
+
The resolved absolute address is verified to remain below the current launch
|
|
103
|
+
workspace, but the projected prompt uses a portable workspace-relative path so
|
|
104
|
+
the workspace can be moved or replicated. When the matching Remote Instructions download has a verified
|
|
105
|
+
state and native file, Ciel appends the block idempotently to that downloaded
|
|
106
|
+
`CLAUDE.md`, `AGENTS.md`, or `GEMINI.md` and restores it after an instruction
|
|
107
|
+
refresh. Remote Memory by itself does not create a native instruction file or
|
|
108
|
+
modify an unverified user-owned file. Routed requests remove any earlier copy
|
|
109
|
+
and place one verified copy at the final system/developer prompt tail. Disabling
|
|
110
|
+
Remote Memory removes only the Ciel-managed block while preserving the rest of
|
|
111
|
+
the instruction file.
|
|
93
112
|
|
|
94
113
|
## Safety and limits
|
|
95
114
|
|
package/docs/Test-Suite.md
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
| `test_ollama_provider_options.py` | Ollama 옵션 처리 |
|
|
33
33
|
| `test_opencode_provider.py` | OpenCode 제공자 |
|
|
34
34
|
| `test_openrouter_provider.py` | OpenRouter 제공자 |
|
|
35
|
+
| `test_tabitoken_provider.py` | TaBiAI (Tabitoken.com) 제공자 |
|
|
35
36
|
| `test_vllm_provider.py` | vLLM 제공자 |
|
|
36
37
|
| `test_zai_provider.py` | Z.AI 제공자 |
|
|
37
38
|
|
|
@@ -77,3 +77,164 @@
|
|
|
77
77
|
Kevin-session restart followed by delivery of pending ID 3478 is still
|
|
78
78
|
required for live end-to-end confirmation. The task is not recorded as live
|
|
79
79
|
complete until that observation is obtained.
|
|
80
|
+
|
|
81
|
+
## 2026-08-20 queued-wake recurrence
|
|
82
|
+
|
|
83
|
+
- A Kevin-session screenshot shows Codex `Queued follow-up inputs` containing
|
|
84
|
+
message IDs 3636 through 3639.
|
|
85
|
+
- IDs 3637, 3638, and 3639 appear more than once; ID 3638 appears repeatedly
|
|
86
|
+
in consecutive queue entries. This is not a queue containing each pending
|
|
87
|
+
message exactly once.
|
|
88
|
+
- Queueing a new follow-up while a Codex turn is active is expected client
|
|
89
|
+
behavior. Repeated copies of the same `[ciel-wake] pending_ids=<id>` are not
|
|
90
|
+
evidence of distinct messages and are not treated as normal delivery.
|
|
91
|
+
- Source inspection rules out `submit_retries=4` alone as the explanation on
|
|
92
|
+
Windows ConPTY: confirmation retries require a tmux pane snapshot; without a
|
|
93
|
+
snapshot the injector stops after its first submit attempt.
|
|
94
|
+
- The screenshot does not identify whether duplicate entries originated from
|
|
95
|
+
repeated Ciel poll/claim injection or repeated input generation on Kevin's
|
|
96
|
+
host. Kevin's router log for IDs 3636-3639 is required to distinguish those
|
|
97
|
+
paths. No code change was made from this screenshot alone.
|
|
98
|
+
|
|
99
|
+
## 2026-08-20 live queued-wake root cause
|
|
100
|
+
|
|
101
|
+
### Kevin host evidence
|
|
102
|
+
|
|
103
|
+
- The Kevin host was reached as `kevin-codex@100.95.132.58`; hostname
|
|
104
|
+
`aap-pool-hera`.
|
|
105
|
+
- The affected process used Ciel Runtime
|
|
106
|
+
`0.2.21-nightly.20260821-003258.0ea4cce` and Codex CLI `0.149.0` on Linux.
|
|
107
|
+
- The persisted Codex session is
|
|
108
|
+
`01a00b77-e165-75a3-8255-17f55de2ebcf`.
|
|
109
|
+
- Its transcript records a turn from `2026-08-21T02:31:13.240Z` through
|
|
110
|
+
`2026-08-21T02:48:00.098Z`.
|
|
111
|
+
- Runtime input records 3636 through 3639 arrived while that turn was running
|
|
112
|
+
(the runtime-input file stores host-local times `21:40:34` through
|
|
113
|
+
`21:44:03`).
|
|
114
|
+
- The TUI screenshot shows those IDs in `Queued follow-up inputs`, including
|
|
115
|
+
repeated copies. Neither the Codex transcript nor `~/.codex/history.jsonl`
|
|
116
|
+
contains an executed/submitted record for IDs 3636 through 3639.
|
|
117
|
+
- The turn completed and the TUI then displayed
|
|
118
|
+
`No tool output found for custom tool call call_KjPlhUWIbFkQDJD6ywRc8ZCJ`;
|
|
119
|
+
the queued follow-ups remained stranded until the session was restarted.
|
|
120
|
+
- After restart, IDs 3648 and 3649 were submitted once and entered a new turn,
|
|
121
|
+
confirming that AI-Net receipt and Ciel runtime-input persistence were not
|
|
122
|
+
the blocked stage.
|
|
123
|
+
|
|
124
|
+
### Confirmed code defect
|
|
125
|
+
|
|
126
|
+
- The Windows terminal poller blocks injection when either a tool call or the
|
|
127
|
+
whole model turn is active.
|
|
128
|
+
- The POSIX terminal poller used only `active_tool_call`. It therefore injected
|
|
129
|
+
wake text during model execution between tool calls. Codex placed that text
|
|
130
|
+
in its internal follow-up queue instead of starting a turn.
|
|
131
|
+
- OpenAI Codex source defines queued follow-ups as input held until the current
|
|
132
|
+
turn finishes and drains them through `maybe_send_next_queued_input()`.
|
|
133
|
+
OpenAI issue 37974 documents a Codex failure path in which the TUI is ready
|
|
134
|
+
but queued follow-ups remain permanently stranded. The Kevin transcript does
|
|
135
|
+
not contain a prompt-edit failure record, so that particular Codex trigger is
|
|
136
|
+
not attributed to Kevin; only the observed stranded-queue state is used.
|
|
137
|
+
|
|
138
|
+
### Repair
|
|
139
|
+
|
|
140
|
+
- `ChannelTerminalPolling` now receives both `active_tool_call` and
|
|
141
|
+
`active_turn` signals and exposes `input_busy()` as their logical OR.
|
|
142
|
+
- The POSIX pending-message poller uses `input_busy()`, matching the existing
|
|
143
|
+
Windows safety boundary.
|
|
144
|
+
- This is transport-wide behavior for supported CLI runtimes; it contains no
|
|
145
|
+
Kevin, agent-ID, model, or provider exception.
|
|
146
|
+
|
|
147
|
+
### Verification
|
|
148
|
+
|
|
149
|
+
- Focused channel/transcript/architecture tests: 485 passed, 122 skipped.
|
|
150
|
+
- Full repository tests:
|
|
151
|
+
- unit: 1,105 passed, 44 skipped
|
|
152
|
+
- router: 902 passed
|
|
153
|
+
- channel: 370 passed, 80 skipped
|
|
154
|
+
- runtime: 244 passed, 12 skipped
|
|
155
|
+
- total: 2,621 passed, 136 skipped
|
|
156
|
+
|
|
157
|
+
## 2026-08-20 live validation correction
|
|
158
|
+
|
|
159
|
+
### Contradicting live result
|
|
160
|
+
|
|
161
|
+
- Commit `81fd842` and nightly
|
|
162
|
+
`0.2.21-nightly.20260821-031340.81fd842` were installed on Kevin.
|
|
163
|
+
- During an active turn, a local-only verification notification was admitted
|
|
164
|
+
as runtime input 3667. The input file advanced to 3667 while the delivery
|
|
165
|
+
cursor remained 3666.
|
|
166
|
+
- Contrary to the expected deferral, the Codex TUI displayed input 3667 under
|
|
167
|
+
`Messages to be submitted after next tool call`. The first repair was
|
|
168
|
+
therefore insufficient and was not treated as complete.
|
|
169
|
+
- After the turn ended, the verification input did run and produced the exact
|
|
170
|
+
requested marker once as an assistant response, but the active-turn
|
|
171
|
+
injection itself remained a confirmed defect.
|
|
172
|
+
|
|
173
|
+
### Confirmed second defect
|
|
174
|
+
|
|
175
|
+
- Kevin's resumed Codex transcript is 276,346,204 bytes.
|
|
176
|
+
- For the tested turn, `task_started` was at byte offset 275,665,220 and the
|
|
177
|
+
first verification-marker record was at offset 276,344,102: a distance of
|
|
178
|
+
678,882 bytes.
|
|
179
|
+
- `ChannelTranscriptRepository.read_tail_text` reads at most 524,288 bytes.
|
|
180
|
+
Thus the active-turn parser could no longer see the opening lifecycle event
|
|
181
|
+
once one turn emitted more than the diagnostic-tail limit, and it returned
|
|
182
|
+
inactive before the turn completed.
|
|
183
|
+
|
|
184
|
+
### Second repair
|
|
185
|
+
|
|
186
|
+
- Transcript scope initialization now records the exact end offset of an
|
|
187
|
+
existing resumed-session transcript before the CLI process starts.
|
|
188
|
+
- Active-turn detection incrementally reads complete JSONL records appended
|
|
189
|
+
after that boundary and persists the last lifecycle state between polls.
|
|
190
|
+
- The state closes only when a later lifecycle/assistant record closes the
|
|
191
|
+
turn. Output volume no longer determines whether the opening event remains
|
|
192
|
+
visible.
|
|
193
|
+
- The implementation is runtime/session scoped and contains no Kevin, agent,
|
|
194
|
+
provider, or model exception.
|
|
195
|
+
|
|
196
|
+
### Second-repair verification
|
|
197
|
+
|
|
198
|
+
- A regression test appends `task_started`, more than 600 KiB of reasoning,
|
|
199
|
+
and `task_complete` to a resumed transcript. The incremental reader retains
|
|
200
|
+
the start state beyond the old 512 KiB boundary and later observes the
|
|
201
|
+
completion.
|
|
202
|
+
- Focused transcript/channel/architecture tests: 497 passed, 122 skipped.
|
|
203
|
+
- Full repository tests:
|
|
204
|
+
- unit: 1,105 passed, 44 skipped
|
|
205
|
+
- router: 902 passed
|
|
206
|
+
- channel: 372 passed, 80 skipped
|
|
207
|
+
- runtime: 244 passed, 12 skipped
|
|
208
|
+
- total: 2,623 passed, 136 skipped
|
|
209
|
+
- Ruff and diff checks passed.
|
|
210
|
+
|
|
211
|
+
### Second-repair deployment and live result
|
|
212
|
+
|
|
213
|
+
- Commit `a6b8c58` was pushed to `nightly`.
|
|
214
|
+
- GitHub CI run `32443885914` succeeded.
|
|
215
|
+
- npm publish/tarball verification run `32443885966` succeeded.
|
|
216
|
+
- Published and installed Kevin version:
|
|
217
|
+
`0.2.21-nightly.20260821-033715.a6b8c58`; registry `gitHead` is
|
|
218
|
+
`a6b8c58c6a83f3208158bcac27f853797cf61df7`.
|
|
219
|
+
- After restart, runtime input 3674 was admitted during the active turn that
|
|
220
|
+
ran from `2026-08-21T03:43:32.213Z` to `03:43:56.729Z`.
|
|
221
|
+
- Six seconds after admission, the input file contained 3674, the delivery
|
|
222
|
+
cursor still read 3673, and the TUI contained zero matches for the marker,
|
|
223
|
+
`pending_ids=3674`, or `Messages to be submitted`.
|
|
224
|
+
- After the active turn completed, a new turn ran from `03:43:57.378Z` to
|
|
225
|
+
`03:44:01.320Z`. The assistant emitted the exact verification marker once,
|
|
226
|
+
the delivery cursor advanced to 3674, and the visible TUI contained zero
|
|
227
|
+
internal queue labels.
|
|
228
|
+
|
|
229
|
+
### Kevin MCP credential repair observed during deployment
|
|
230
|
+
|
|
231
|
+
- The restarted process contained `AINET_API_KEY`, and the same credential
|
|
232
|
+
returned HTTP 200 from `/api/v1/agents/me`; environment projection was not
|
|
233
|
+
missing.
|
|
234
|
+
- Kevin's pre-existing `ai-net-http` Codex entry contained a different static
|
|
235
|
+
bearer token, while the managed `ai-net` entry matched the current
|
|
236
|
+
credential. That static mismatch produced the observed 401.
|
|
237
|
+
- `ai-net-http` was replaced through `codex mcp` with
|
|
238
|
+
`bearer_token_env_var = "AINET_API_KEY"` and no static authorization header.
|
|
239
|
+
- After the final restart, the captured TUI contained zero `ai-net-http`
|
|
240
|
+
startup failures and zero `invalid agent API key` messages.
|
|
@@ -36,5 +36,62 @@
|
|
|
36
36
|
modules and task journals.
|
|
37
37
|
- Branch synchronization before commit: local `nightly` and `origin/nightly`
|
|
38
38
|
had zero commits of divergence.
|
|
39
|
-
-
|
|
40
|
-
|
|
39
|
+
- Commit: `0ea4cce` (`fix: harden runtime replay and MCP environment`).
|
|
40
|
+
- Published npm version:
|
|
41
|
+
`0.2.21-nightly.20260821-003258.0ea4cce`.
|
|
42
|
+
- Registry `gitHead`: `0ea4ccefce5955e3dbd37eff3b38cf8e122e0a75`.
|
|
43
|
+
- Publish workflow `32432946530`: success, including npm test, publish, and
|
|
44
|
+
published-tarball verification.
|
|
45
|
+
- CI workflow `32432946541`: success for minimum Python, unit, router,
|
|
46
|
+
channel, runtime, quality, documentation, and package checks.
|
|
47
|
+
- The exact registry version was installed globally on the local workstation.
|
|
48
|
+
Its package manifest reports the nightly version above.
|
|
49
|
+
- Source and installed SHA-256 values match for all three changed runtime
|
|
50
|
+
modules:
|
|
51
|
+
- `responses_input_compatibility.py`:
|
|
52
|
+
`A0B38961262AC7870317F99C892C4A1535525979C93EF632A177571C3C8DCDC2`
|
|
53
|
+
- `runtime_launch.py`:
|
|
54
|
+
`036E0323E6DD9FBF5B5DD3EC591017CB47FDCB2EE7CB6361C47143F734BDD609`
|
|
55
|
+
- `workspace_mcp.py`:
|
|
56
|
+
`C79DE505E5CA27DF0562DC006038CB68DAB1B2D1FA010D4E9160B1B38384AAAF`
|
|
57
|
+
- Installed-module runtime checks:
|
|
58
|
+
- the reported orphan custom call ID was removed while its following user
|
|
59
|
+
message remained;
|
|
60
|
+
- generic MCP projection produced `Authorization=Bearer test-token`,
|
|
61
|
+
`X-Env=projected`, and retained the static header;
|
|
62
|
+
- `ciel-runtime --version` exited successfully and printed the base runtime
|
|
63
|
+
compatibility version `0.2.21`; the nightly artifact identity is verified
|
|
64
|
+
separately from the installed package manifest and npm registry metadata.
|
|
65
|
+
|
|
66
|
+
## Remote memory and routed-turn recovery release
|
|
67
|
+
|
|
68
|
+
- Commits pushed to `nightly`:
|
|
69
|
+
- `c93e4b6` — remote workspace-memory manifest synchronization
|
|
70
|
+
- `fb1f871` — exact missing tool-output verdict repair
|
|
71
|
+
- `6d7ffb8` — bounded routed-Codex empty-end-turn recovery
|
|
72
|
+
- Published npm version:
|
|
73
|
+
`0.2.21-nightly.20260821-040635.6d7ffb8`.
|
|
74
|
+
- Registry `gitHead`:
|
|
75
|
+
`6d7ffb8a90a37a662d1721ae33476f5a545c130d`.
|
|
76
|
+
- CI workflow `32445593344`: success.
|
|
77
|
+
- Publish workflow `32445593325`: success, including npm test, publish, and
|
|
78
|
+
published-tarball verification.
|
|
79
|
+
- The published tarball contains `remote_memory.py`, `Remote-Memory.md`,
|
|
80
|
+
`codex_turn_recovery.py`, and `responses_input_compatibility.py`.
|
|
81
|
+
- The exact published version was installed globally on Wing through SSH port
|
|
82
|
+
1004. Installed and source SHA-256 values match:
|
|
83
|
+
- `remote_memory.py`:
|
|
84
|
+
`C00F72CD469436D597D8D9C286C714E65F6B890A06324AC63C811AB0192750A0`
|
|
85
|
+
- `codex_turn_recovery.py`:
|
|
86
|
+
`270D064CDBCEEB4E4D84351F8481620A5B9B219B80740DB81F4E9EBD22DE7F37`
|
|
87
|
+
- `responses_input_compatibility.py`:
|
|
88
|
+
`B69FB5690F0BC2AD0253F79689D6A7195A5AD95117874E8CEF3ACFE4B4289279`
|
|
89
|
+
- Wing's installed `ciel-runtimectl remote-memory` command exited 0 and
|
|
90
|
+
reported all manifest, destination, authorization, timeout, and size-limit
|
|
91
|
+
settings.
|
|
92
|
+
- An installed-module probe on Wing presented the exact runtime-generated
|
|
93
|
+
empty-end-turn notice. It performed exactly one retry, accepted the visible
|
|
94
|
+
retry result, and did not replay the synthetic notice into the retry request.
|
|
95
|
+
- No Python, Node, or Codex process remained active on Wing after installation,
|
|
96
|
+
so no stale in-memory runtime needs to be terminated; the next launch loads
|
|
97
|
+
the installed version.
|