@oneciel-ai/ciel-runtime 0.2.46 → 0.2.47

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 CHANGED
@@ -5,6 +5,16 @@ capability, followed by the complete commit ledger merged into each release.
5
5
 
6
6
  ## Unreleased
7
7
 
8
+ ## 0.2.47 — 2026-09-12
9
+
10
+ - Report non-native upstream authentication failures on Responses routes as
11
+ HTTP 424 dependency failures, preserving the provider, upstream HTTP 401,
12
+ error type and message. Prevent Codex from hiding these failures behind an
13
+ unrelated ChatGPT token refresh. Native OpenAI and router access authentication
14
+ retain their original HTTP semantics.
15
+
16
+ ## Earlier unreleased changes
17
+
8
18
  - Allow complete transcript records larger than the batch target (separate
9
19
  max_record_bytes memory bound, default 16 MiB, configurable up to 64 MiB).
10
20
  - Forward structured runtime errors to the shared event stream and display
@@ -261,6 +261,7 @@ def handle_openai_responses_request(
261
261
  stream=stream,
262
262
  status=exc.code,
263
263
  error_type=_responses_error_type(exc.code),
264
+ **({"upstream_provider": provider} if exc.code == 401 else {}),
264
265
  )
265
266
  except UpstreamFailure as exc:
266
267
  # The upstream status, type and message were all read before this was
@@ -273,6 +274,7 @@ def handle_openai_responses_request(
273
274
  stream=stream,
274
275
  status=exc.status_code,
275
276
  error_type=exc.anthropic_error_type,
277
+ **({"upstream_provider": provider} if exc.status_code == 401 else {}),
276
278
  )
277
279
  except UpstreamStreamReadError as exc:
278
280
  core.event_bus.publish(
@@ -467,6 +469,7 @@ def _handle_provider_responses_route(
467
469
  stream=bool(body.get("stream", True)),
468
470
  status=exc.code,
469
471
  error_type=_responses_error_type(exc.code),
472
+ **({"upstream_provider": provider} if exc.code == 401 else {}),
470
473
  )
471
474
  except UpstreamFailure as exc:
472
475
  delivery.mark_failed(
@@ -478,6 +481,7 @@ def _handle_provider_responses_route(
478
481
  stream=bool(body.get("stream", True)),
479
482
  status=exc.status_code,
480
483
  error_type=exc.anthropic_error_type,
484
+ **({"upstream_provider": provider} if exc.status_code == 401 else {}),
481
485
  response_started=exc.output_started,
482
486
  response_id=exc.response_id,
483
487
  )
@@ -51,26 +51,37 @@ def write_openai_responses_error(
51
51
  error_type: str = "api_error",
52
52
  response_started: bool = False,
53
53
  response_id: str | None = None,
54
+ upstream_provider: str | None = None,
54
55
  services: OpenAIResponsesStreamServices,
55
56
  ) -> None:
57
+ error = {"type": error_type, "message": message}
58
+ if upstream_provider is not None and status == 401:
59
+ # The client authenticated to this router; a different credential at
60
+ # the upstream dependency failed. HTTP 401 here makes Codex refresh
61
+ # its unrelated OpenAI login, hiding the actual provider failure.
62
+ error.update(
63
+ code="upstream_authentication_error",
64
+ upstream_status=status,
65
+ upstream_provider=upstream_provider,
66
+ message=f"Upstream provider {upstream_provider} rejected authentication (HTTP {status}): {message}",
67
+ )
68
+ status = 424
69
+ if not response_started:
70
+ stream = False
56
71
  if response_started:
57
72
  failed = {
58
73
  "type": "response.failed",
59
74
  "response": {
60
75
  "id": str(response_id or "resp_ciel_upstream_failure"),
61
76
  "status": "failed",
62
- "error": {
63
- "type": error_type,
64
- "code": error_type,
65
- "message": message,
66
- },
77
+ "error": {"code": error_type, **error},
67
78
  },
68
79
  }
69
80
  handler.wfile.write(b"\n\n")
70
81
  _emit(handler, "response.failed", failed)
71
82
  handler.wfile.flush()
72
83
  return
73
- payload = {"type": "error", "error": {"type": error_type, "message": message}}
84
+ payload = {"type": "error", "error": error}
74
85
  if not stream:
75
86
  services.write_json(handler, payload, status)
76
87
  return
@@ -423,6 +423,7 @@ class ResponseStreamContext:
423
423
  error_type: str = "api_error",
424
424
  response_started: bool = False,
425
425
  response_id: str | None = None,
426
+ upstream_provider: str | None = None,
426
427
  ) -> None:
427
428
  self.algorithms.write_openai_error(
428
429
  handler,
@@ -432,6 +433,7 @@ class ResponseStreamContext:
432
433
  error_type=error_type,
433
434
  response_started=response_started,
434
435
  response_id=response_id,
436
+ **({"upstream_provider": upstream_provider} if upstream_provider is not None else {}),
435
437
  services=self.openai_responses_stream_services(),
436
438
  )
437
439
 
@@ -97,7 +97,7 @@ OPENCODE_ENDPOINT_ALIASES = {
97
97
  }
98
98
 
99
99
  APP_NAME = "Ciel Runtime"
100
- VERSION = "0.2.46"
100
+ VERSION = "0.2.47"
101
101
  CREDITS = "Credits: One Ciel LLC"
102
102
  PRELAUNCH_CANCEL = 10
103
103
  PRELAUNCH_LAUNCH_CODEX = 11
@@ -0,0 +1,16 @@
1
+ title: Responses upstream authentication isolation, 0.2.47
2
+ scope: Non-native upstream HTTP 401 only; native OpenAI and router access policy unchanged.
3
+ implementation:
4
+ transport: Upstream failure projected to HTTP 424 with JSON even for requested streaming when headers are not sent. Already-started streams emit response.failed without new headers.
5
+ metadata: error.upstream_status=401, upstream_provider, code=upstream_authentication_error, original error type and original message retained within prefixed message.
6
+ routes: Translated Responses and provider-native Responses, HTTPError and structured UpstreamFailure. Native Codex route deliberately excluded.
7
+ verification:
8
+ unit: python -m unittest discover -s tests -p test_openai_responses_stream.py; 9 tests passed.
9
+ boundary: python -m unittest discover -s tests -p test_responses_provider_auth_boundary.py; native/non-native and raw/structured matrix passed.
10
+ runtime_binary: codex-cli 0.154.0
11
+ runtime_harness: Isolated CODEX_HOME, synthetic provider and ChatGPT credentials, loopback server and refresh endpoint; actual production write_openai_responses_error used by server.
12
+ before: Two /v1/responses attempts followed by /oauth/token; user-visible refresh token revoked error.
13
+ after: One /v1/responses request with correct synthetic provider key, no /oauth/token; turn.failed displays unexpected status 424 Failed Dependency: Upstream provider diagnostic-provider rejected authentication (HTTP 401): invalid credentials.
14
+ assertions: Original message present, unrelated refresh message absent, no retry, no OAuth request; PASS.
15
+ static: Modified-source Ruff checks and documentation metadata checks passed.
16
+ limitations: Does not make an invalid upstream API key valid. Remote Ollama account identity check rejected currently stored key with HTTP 401 invalid credentials. No remote credentials or processes changed.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oneciel-ai/ciel-runtime",
3
- "version": "0.2.46",
3
+ "version": "0.2.47",
4
4
  "description": "Universal AI coding-agent runtime and model-routing layer for Claude, Codex, AGY, ZCode, and compatible runtimes.",
5
5
  "license": "MIT",
6
6
  "author": "One Ciel LLC",