@oneciel-ai/ciel-runtime 0.1.1 → 0.2.0
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/README.md +132 -0
- package/ciel-runtime-menu.py +56 -6
- package/ciel_runtime.py +9379 -35909
- package/ciel_runtime_support/advisor_client.py +193 -0
- package/ciel_runtime_support/advisor_policy.py +320 -0
- package/ciel_runtime_support/advisor_refinement.py +160 -0
- package/ciel_runtime_support/advisor_request_builder.py +261 -0
- package/ciel_runtime_support/agy_installer.py +169 -0
- package/ciel_runtime_support/agy_mcp_restore.py +182 -0
- package/ciel_runtime_support/anthropic_model_policy.py +186 -0
- package/ciel_runtime_support/anthropic_response_writer.py +255 -0
- package/ciel_runtime_support/anthropic_tool_turns.py +130 -0
- package/ciel_runtime_support/api_key_cooldown.py +159 -0
- package/ciel_runtime_support/architecture.py +488 -1
- package/ciel_runtime_support/architecture_budget.py +42 -0
- package/ciel_runtime_support/channel_backlog.py +90 -0
- package/ciel_runtime_support/channel_cli.py +119 -0
- package/ciel_runtime_support/channel_compact_injection.py +82 -0
- package/ciel_runtime_support/channel_compact_poll.py +67 -0
- package/ciel_runtime_support/channel_compact_request_repository.py +113 -0
- package/ciel_runtime_support/channel_config_service.py +281 -0
- package/ciel_runtime_support/channel_connection_lifecycle.py +180 -0
- package/ciel_runtime_support/channel_connection_registry.py +128 -0
- package/ciel_runtime_support/channel_connection_worker.py +284 -0
- package/ciel_runtime_support/channel_cursor_recovery.py +92 -0
- package/ciel_runtime_support/channel_cursor_repository.py +89 -0
- package/ciel_runtime_support/channel_cursor_service.py +178 -0
- package/ciel_runtime_support/channel_event_identity.py +212 -0
- package/ciel_runtime_support/channel_event_projection.py +315 -0
- package/ciel_runtime_support/channel_inflight.py +127 -0
- package/ciel_runtime_support/channel_injection.py +115 -0
- package/ciel_runtime_support/channel_launch_guard_repository.py +58 -0
- package/ciel_runtime_support/channel_launch_policy.py +180 -0
- package/ciel_runtime_support/channel_llm_context.py +156 -0
- package/ciel_runtime_support/channel_mcp_discovery.py +186 -0
- package/ciel_runtime_support/channel_mcp_http_controller.py +239 -0
- package/ciel_runtime_support/channel_mcp_ownership.py +148 -0
- package/ciel_runtime_support/channel_mcp_tools.py +240 -0
- package/ciel_runtime_support/channel_mcp_transport.py +394 -0
- package/ciel_runtime_support/channel_message_dedupe.py +65 -0
- package/ciel_runtime_support/channel_message_policy.py +256 -0
- package/ciel_runtime_support/channel_message_prompt.py +305 -0
- package/ciel_runtime_support/channel_message_repository.py +234 -0
- package/ciel_runtime_support/channel_notification_projection.py +217 -0
- package/ciel_runtime_support/channel_panel.py +162 -0
- package/ciel_runtime_support/channel_pending_injection.py +209 -0
- package/ciel_runtime_support/channel_pending_poll.py +109 -0
- package/ciel_runtime_support/channel_probe_cache.py +433 -0
- package/ciel_runtime_support/channel_probe_report.py +101 -0
- package/ciel_runtime_support/channel_runtime_environment.py +181 -0
- package/ciel_runtime_support/channel_session_lifecycle.py +114 -0
- package/ciel_runtime_support/channel_session_repository.py +90 -0
- package/ciel_runtime_support/channel_terminal_dispatch.py +115 -0
- package/ciel_runtime_support/channel_terminal_input.py +277 -0
- package/ciel_runtime_support/channel_terminal_proxy.py +447 -0
- package/ciel_runtime_support/channel_tool_context.py +166 -0
- package/ciel_runtime_support/channel_transcript.py +414 -0
- package/ciel_runtime_support/channel_transcript_repository.py +96 -0
- package/ciel_runtime_support/channel_wake_claim_repository.py +126 -0
- package/ciel_runtime_support/channel_wake_delivery_repository.py +88 -0
- package/ciel_runtime_support/chat_files.py +138 -0
- package/ciel_runtime_support/chat_http_controller.py +235 -0
- package/ciel_runtime_support/claude_environment.py +375 -0
- package/ciel_runtime_support/claude_router.py +247 -193
- package/ciel_runtime_support/cli_dispatch.py +792 -0
- package/ciel_runtime_support/cli_parser.py +165 -0
- package/ciel_runtime_support/cli_usage.py +100 -0
- package/ciel_runtime_support/codex_app_server.py +20 -5
- package/ciel_runtime_support/codex_channel_sse_launch.py +87 -0
- package/ciel_runtime_support/codex_cli.py +42 -6
- package/ciel_runtime_support/codex_config.py +323 -0
- package/ciel_runtime_support/codex_launch_configuration.py +240 -0
- package/ciel_runtime_support/codex_launch_policy.py +66 -0
- package/ciel_runtime_support/codex_mcp_integration.py +195 -0
- package/ciel_runtime_support/codex_mcp_restore.py +304 -0
- package/ciel_runtime_support/codex_model_catalog.py +133 -0
- package/ciel_runtime_support/codex_process_lifecycle.py +271 -0
- package/ciel_runtime_support/codex_router.py +147 -1
- package/ciel_runtime_support/codex_session_repository.py +115 -0
- package/ciel_runtime_support/codex_session_selection.py +114 -0
- package/ciel_runtime_support/command_asset_installer.py +103 -0
- package/ciel_runtime_support/compatibility_probe.py +295 -0
- package/ciel_runtime_support/compatibility_protocol.py +251 -0
- package/ciel_runtime_support/compatibility_runtime.py +166 -0
- package/ciel_runtime_support/compatibility_test.py +370 -0
- package/ciel_runtime_support/config_migrations.py +307 -0
- package/ciel_runtime_support/config_repository.py +175 -0
- package/ciel_runtime_support/config_value_codec.py +64 -0
- package/ciel_runtime_support/configuration_cli.py +374 -0
- package/ciel_runtime_support/context_compaction.py +280 -0
- package/ciel_runtime_support/context_setup.py +208 -0
- package/ciel_runtime_support/context_summary_policy.py +392 -0
- package/ciel_runtime_support/credential_cli.py +104 -0
- package/ciel_runtime_support/credential_management.py +261 -0
- package/ciel_runtime_support/credentials.py +269 -0
- package/ciel_runtime_support/executable_discovery.py +141 -0
- package/ciel_runtime_support/github_copilot_oauth.py +335 -0
- package/ciel_runtime_support/github_copilot_oauth_runtime.py +213 -0
- package/ciel_runtime_support/header_forwarding.py +73 -0
- package/ciel_runtime_support/headless_config.py +221 -0
- package/ciel_runtime_support/http_response.py +129 -0
- package/ciel_runtime_support/install_diagnostics.py +149 -0
- package/ciel_runtime_support/kimi_identity.py +123 -0
- package/ciel_runtime_support/launch_diagnostics.py +204 -0
- package/ciel_runtime_support/launch_state.py +127 -0
- package/ciel_runtime_support/live_api_key_controller.py +58 -0
- package/ciel_runtime_support/llm_config_http.py +148 -0
- package/ciel_runtime_support/llm_option_config.py +259 -0
- package/ciel_runtime_support/llm_presentation_data.py +447 -0
- package/ciel_runtime_support/llm_presets.py +773 -0
- package/ciel_runtime_support/lm_studio_runtime.py +401 -0
- package/ciel_runtime_support/managed_mcp_config.py +144 -0
- package/ciel_runtime_support/managed_mcp_discovery.py +151 -0
- package/ciel_runtime_support/managed_service_cleanup.py +89 -0
- package/ciel_runtime_support/mcp_config_reader.py +230 -0
- package/ciel_runtime_support/mcp_http_proxy.py +607 -0
- package/ciel_runtime_support/mcp_inventory.py +59 -0
- package/ciel_runtime_support/mcp_notification_wait_policy.py +159 -0
- package/ciel_runtime_support/mcp_probe_codec.py +136 -0
- package/ciel_runtime_support/mcp_probe_transport.py +328 -0
- package/ciel_runtime_support/mcp_proxy_codec.py +345 -0
- package/ciel_runtime_support/mcp_proxy_config.py +107 -0
- package/ciel_runtime_support/mcp_proxy_notifications.py +261 -0
- package/ciel_runtime_support/mcp_proxy_process.py +560 -0
- package/ciel_runtime_support/mcp_split_proxy_http.py +165 -0
- package/ciel_runtime_support/mcp_stdio_probe.py +240 -0
- package/ciel_runtime_support/mcp_transport.py +146 -0
- package/ciel_runtime_support/model_cache_lifecycle.py +78 -0
- package/ciel_runtime_support/model_catalog_projection.py +61 -0
- package/ciel_runtime_support/model_context_hints.py +109 -0
- package/ciel_runtime_support/model_panel.py +147 -0
- package/ciel_runtime_support/model_registry_repository.py +231 -0
- package/ciel_runtime_support/npm_runtime.py +191 -0
- package/ciel_runtime_support/ollama_catalog.py +462 -0
- package/ciel_runtime_support/ollama_catalog_cli.py +41 -0
- package/ciel_runtime_support/ollama_catalog_repository.py +75 -0
- package/ciel_runtime_support/ollama_context_sync.py +87 -0
- package/ciel_runtime_support/ollama_forwarding.py +449 -0
- package/ciel_runtime_support/openai_chat_passthrough.py +67 -0
- package/ciel_runtime_support/openai_chat_router.py +64 -0
- package/ciel_runtime_support/openai_forwarding.py +194 -0
- package/ciel_runtime_support/openai_responses_router.py +291 -0
- package/ciel_runtime_support/openai_responses_stream.py +135 -0
- package/ciel_runtime_support/output_budget.py +89 -0
- package/ciel_runtime_support/package_lifecycle.py +217 -0
- package/ciel_runtime_support/plan_artifact_controller.py +104 -0
- package/ciel_runtime_support/prelaunch.py +959 -0
- package/ciel_runtime_support/prelaunch_launch_preference.py +75 -0
- package/ciel_runtime_support/prelaunch_panel_projection.py +396 -0
- package/ciel_runtime_support/prelaunch_terminal.py +764 -0
- package/ciel_runtime_support/process_control.py +708 -0
- package/ciel_runtime_support/prompt_compaction.py +322 -0
- package/ciel_runtime_support/prompt_injection.py +176 -0
- package/ciel_runtime_support/protocols/__init__.py +24 -0
- package/ciel_runtime_support/protocols/anthropic_content.py +29 -0
- package/ciel_runtime_support/protocols/anthropic_thinking_policy.py +336 -0
- package/ciel_runtime_support/protocols/chat_projection.py +315 -0
- package/ciel_runtime_support/protocols/conversation_policy.py +217 -0
- package/ciel_runtime_support/protocols/conversation_turn_policy.py +972 -0
- package/ciel_runtime_support/protocols/ollama_chat.py +111 -0
- package/ciel_runtime_support/protocols/ollama_response.py +231 -0
- package/ciel_runtime_support/protocols/openai_reasoning.py +75 -0
- package/ciel_runtime_support/protocols/openai_responses.py +271 -0
- package/ciel_runtime_support/protocols/pseudo_tool_history.py +248 -0
- package/ciel_runtime_support/protocols/tool_result_projection.py +112 -0
- package/ciel_runtime_support/provider_adapters.py +160 -0
- package/ciel_runtime_support/provider_catalog_sources.py +316 -0
- package/ciel_runtime_support/provider_choice.py +201 -0
- package/ciel_runtime_support/provider_compatibility.py +165 -0
- package/ciel_runtime_support/provider_config_mutations.py +361 -0
- package/ciel_runtime_support/provider_configuration_service.py +162 -0
- package/ciel_runtime_support/provider_context.py +308 -0
- package/ciel_runtime_support/provider_contract_projection.py +73 -0
- package/ciel_runtime_support/provider_descriptor.py +82 -0
- package/ciel_runtime_support/provider_endpoint_policy.py +130 -0
- package/ciel_runtime_support/provider_endpoint_probe.py +165 -0
- package/ciel_runtime_support/provider_launch_endpoint.py +109 -0
- package/ciel_runtime_support/provider_limits.py +457 -0
- package/ciel_runtime_support/provider_model_identity.py +139 -0
- package/ciel_runtime_support/provider_model_selection.py +431 -0
- package/ciel_runtime_support/provider_model_specs.py +142 -0
- package/ciel_runtime_support/provider_models.py +263 -0
- package/ciel_runtime_support/provider_network.py +176 -0
- package/ciel_runtime_support/provider_option_cli.py +238 -0
- package/ciel_runtime_support/provider_option_panel.py +275 -0
- package/ciel_runtime_support/provider_option_status.py +192 -0
- package/ciel_runtime_support/provider_policy.py +101 -0
- package/ciel_runtime_support/provider_query_policy.py +67 -0
- package/ciel_runtime_support/provider_readiness.py +112 -0
- package/ciel_runtime_support/provider_request_access.py +131 -0
- package/ciel_runtime_support/provider_request_builder.py +250 -0
- package/ciel_runtime_support/provider_responses_passthrough.py +81 -0
- package/ciel_runtime_support/provider_runtime_info.py +113 -0
- package/ciel_runtime_support/provider_runtime_modes.py +150 -0
- package/ciel_runtime_support/provider_sampling_policy.py +46 -0
- package/ciel_runtime_support/provider_status.py +145 -0
- package/ciel_runtime_support/provider_timeout_policy.py +184 -0
- package/ciel_runtime_support/provider_tool_policy.py +145 -0
- package/ciel_runtime_support/providers/__init__.py +65 -0
- package/ciel_runtime_support/providers/anthropic.py +160 -0
- package/ciel_runtime_support/providers/anthropic_catalog.py +119 -0
- package/ciel_runtime_support/providers/base.py +232 -0
- package/ciel_runtime_support/providers/catalog.py +326 -0
- package/ciel_runtime_support/providers/cloud.py +194 -0
- package/ciel_runtime_support/providers/constants.py +54 -0
- package/ciel_runtime_support/providers/deepseek.py +115 -0
- package/ciel_runtime_support/providers/fireworks.py +158 -0
- package/ciel_runtime_support/providers/github_copilot_oauth.py +199 -0
- package/ciel_runtime_support/providers/kimi.py +297 -0
- package/ciel_runtime_support/providers/lm_studio.py +76 -0
- package/ciel_runtime_support/providers/meta.py +257 -0
- package/ciel_runtime_support/providers/native.py +194 -0
- package/ciel_runtime_support/providers/nim.py +69 -0
- package/ciel_runtime_support/providers/nvidia.py +158 -0
- package/ciel_runtime_support/providers/nvidia_runtime.py +285 -0
- package/ciel_runtime_support/providers/ollama.py +181 -0
- package/ciel_runtime_support/providers/ollama_context.py +195 -0
- package/ciel_runtime_support/providers/ollama_runtime.py +213 -0
- package/ciel_runtime_support/providers/opencode.py +220 -0
- package/ciel_runtime_support/providers/opencode_go.py +37 -0
- package/ciel_runtime_support/providers/openrouter.py +57 -0
- package/ciel_runtime_support/providers/vllm.py +65 -0
- package/ciel_runtime_support/providers/zai.py +119 -0
- package/ciel_runtime_support/pseudo_tool_parser.py +115 -0
- package/ciel_runtime_support/rate_limit_policy.py +117 -0
- package/ciel_runtime_support/rate_limit_repository.py +154 -0
- package/ciel_runtime_support/registry.py +46 -0
- package/ciel_runtime_support/request_shortcuts.py +253 -0
- package/ciel_runtime_support/request_trace.py +323 -0
- package/ciel_runtime_support/response_collection.py +209 -0
- package/ciel_runtime_support/router_access.py +238 -0
- package/ciel_runtime_support/router_client_lifecycle.py +366 -0
- package/ciel_runtime_support/router_health_policy.py +101 -0
- package/ciel_runtime_support/router_http.py +513 -0
- package/ciel_runtime_support/router_process_lifecycle.py +401 -0
- package/ciel_runtime_support/router_rate_limit_service.py +285 -0
- package/ciel_runtime_support/router_server_runtime.py +103 -0
- package/ciel_runtime_support/router_shortcuts.py +201 -0
- package/ciel_runtime_support/routing_fallback.py +73 -0
- package/ciel_runtime_support/runtime_activity_repository.py +143 -0
- package/ciel_runtime_support/runtime_adapters.py +104 -0
- package/ciel_runtime_support/runtime_command_factory.py +73 -0
- package/ciel_runtime_support/runtime_compatibility.py +50 -0
- package/ciel_runtime_support/runtime_constants.py +178 -0
- package/ciel_runtime_support/runtime_launch.py +1602 -0
- package/ciel_runtime_support/runtime_llm_options.py +312 -0
- package/ciel_runtime_support/runtime_logging.py +161 -0
- package/ciel_runtime_support/runtime_paths.py +157 -0
- package/ciel_runtime_support/runtime_restart.py +84 -0
- package/ciel_runtime_support/runtime_upgrade.py +149 -0
- package/ciel_runtime_support/secure_json_repository.py +55 -0
- package/ciel_runtime_support/session_import.py +356 -0
- package/ciel_runtime_support/settings_repository.py +8 -0
- package/ciel_runtime_support/slash_command_assets.py +211 -0
- package/ciel_runtime_support/sse_stream.py +57 -0
- package/ciel_runtime_support/sse_trace.py +225 -0
- package/ciel_runtime_support/statusline_script.py +593 -0
- package/ciel_runtime_support/statusline_settings.py +53 -0
- package/ciel_runtime_support/stream_chunk_policy.py +18 -0
- package/ciel_runtime_support/streaming_anthropic.py +1955 -0
- package/ciel_runtime_support/synthetic_tool_policy.py +105 -0
- package/ciel_runtime_support/terminal_platform_io.py +127 -0
- package/ciel_runtime_support/timeout_profile.py +196 -0
- package/ciel_runtime_support/tool_dialects.py +85 -0
- package/ciel_runtime_support/tool_exposure_policy.py +63 -0
- package/ciel_runtime_support/tool_guard_hooks.py +218 -0
- package/ciel_runtime_support/tool_request_projection.py +96 -0
- package/ciel_runtime_support/tool_schema.py +483 -0
- package/ciel_runtime_support/tool_side_effect_dedupe.py +95 -0
- package/ciel_runtime_support/ui_text.py +266 -0
- package/ciel_runtime_support/upstream_error_policy.py +104 -0
- package/ciel_runtime_support/upstream_retry.py +419 -0
- package/ciel_runtime_support/upstream_stream_io.py +106 -0
- package/ciel_runtime_support/usage_events.py +96 -0
- package/ciel_runtime_support/visible_stream_filters.py +130 -0
- package/ciel_runtime_support/web_endpoints.py +447 -0
- package/ciel_runtime_support/web_ui.py +915 -0
- package/ciel_runtime_support/web_ui_controller.py +189 -0
- package/ciel_runtime_support/windows_console_input.py +137 -0
- package/ciel_runtime_support/windows_console_mode.py +112 -0
- package/docs/Architecture.md +54 -0
- package/docs/Configuration.md +17 -0
- package/docs/Module-Map.md +1093 -26
- package/docs/Providers.md +46 -1
- package/docs/adr/0001-runtime-bounded-contexts.md +295 -0
- package/npm-bin/run-ciel-runtime.js +22 -2
- package/package.json +9 -2
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"""Codex configuration discovery and TOML projection policies."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
from collections.abc import Callable
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def toml_string(value: str) -> str:
|
|
14
|
+
return json.dumps(str(value))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def codex_config_override_keys(passthrough: list[str]) -> set[str]:
|
|
18
|
+
keys: set[str] = set()
|
|
19
|
+
index = 0
|
|
20
|
+
while index < len(passthrough):
|
|
21
|
+
argument = str(passthrough[index])
|
|
22
|
+
value = ""
|
|
23
|
+
if argument in ("-c", "--config") and index + 1 < len(passthrough):
|
|
24
|
+
value = str(passthrough[index + 1])
|
|
25
|
+
index += 2
|
|
26
|
+
elif argument.startswith("--config="):
|
|
27
|
+
value = argument.split("=", 1)[1]
|
|
28
|
+
index += 1
|
|
29
|
+
else:
|
|
30
|
+
index += 1
|
|
31
|
+
continue
|
|
32
|
+
if "=" in value:
|
|
33
|
+
keys.add(value.split("=", 1)[0].strip())
|
|
34
|
+
return keys
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def toml_scalar_without_comment(raw: str) -> str:
|
|
38
|
+
in_single = False
|
|
39
|
+
in_double = False
|
|
40
|
+
escaped = False
|
|
41
|
+
out: list[str] = []
|
|
42
|
+
for character in raw:
|
|
43
|
+
if escaped:
|
|
44
|
+
out.append(character)
|
|
45
|
+
escaped = False
|
|
46
|
+
continue
|
|
47
|
+
if character == "\\" and in_double:
|
|
48
|
+
out.append(character)
|
|
49
|
+
escaped = True
|
|
50
|
+
continue
|
|
51
|
+
if character == '"' and not in_single:
|
|
52
|
+
in_double = not in_double
|
|
53
|
+
elif character == "'" and not in_double:
|
|
54
|
+
in_single = not in_single
|
|
55
|
+
elif character == "#" and not in_single and not in_double:
|
|
56
|
+
break
|
|
57
|
+
out.append(character)
|
|
58
|
+
return "".join(out).strip()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def unquote_toml_string(raw: str) -> str:
|
|
62
|
+
value = raw.strip()
|
|
63
|
+
if len(value) >= 2 and value[0] == value[-1] and value[0] in ("'", '"'):
|
|
64
|
+
return value[1:-1].strip()
|
|
65
|
+
return value
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def codex_alternate_screen_value_from_config_text(text: str) -> str | None:
|
|
69
|
+
table = ""
|
|
70
|
+
for line in text.splitlines():
|
|
71
|
+
stripped = toml_scalar_without_comment(line)
|
|
72
|
+
if not stripped:
|
|
73
|
+
continue
|
|
74
|
+
table_match = re.fullmatch(r"\[([A-Za-z0-9_.-]+)\]", stripped)
|
|
75
|
+
if table_match:
|
|
76
|
+
table = table_match.group(1).strip()
|
|
77
|
+
continue
|
|
78
|
+
match = re.match(r"alternate_screen\s*=\s*(.+)$", stripped) if table == "tui" else None
|
|
79
|
+
if match is None:
|
|
80
|
+
match = re.match(r"tui\.alternate_screen\s*=\s*(.+)$", stripped)
|
|
81
|
+
if match is None:
|
|
82
|
+
continue
|
|
83
|
+
value = unquote_toml_string(match.group(1)).casefold()
|
|
84
|
+
if value in ("false", "0", "off", "no", "disabled", "disable"):
|
|
85
|
+
return "never"
|
|
86
|
+
if value in ("true", "1", "on", "yes", "enabled", "enable"):
|
|
87
|
+
return "always"
|
|
88
|
+
if value in ("auto", "always", "never"):
|
|
89
|
+
return None
|
|
90
|
+
return "auto"
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def codex_config_paths_for_launch(
|
|
95
|
+
passthrough: list[str],
|
|
96
|
+
env: dict[str, str] | None = None,
|
|
97
|
+
cwd: Path | None = None,
|
|
98
|
+
) -> list[Path]:
|
|
99
|
+
env = env or os.environ
|
|
100
|
+
configured_home = str(env.get("CODEX_HOME") or "").strip()
|
|
101
|
+
default_home = Path.home() / ".codex"
|
|
102
|
+
home = Path(configured_home or default_home).expanduser()
|
|
103
|
+
paths = [home / "config.toml"]
|
|
104
|
+
profiles: list[str] = []
|
|
105
|
+
index = 0
|
|
106
|
+
while index < len(passthrough):
|
|
107
|
+
argument = str(passthrough[index])
|
|
108
|
+
if argument in ("-p", "--profile") and index + 1 < len(passthrough):
|
|
109
|
+
profiles.append(str(passthrough[index + 1]))
|
|
110
|
+
index += 2
|
|
111
|
+
continue
|
|
112
|
+
if argument.startswith("--profile="):
|
|
113
|
+
profiles.append(argument.split("=", 1)[1])
|
|
114
|
+
index += 1
|
|
115
|
+
for profile in profiles:
|
|
116
|
+
if re.fullmatch(r"[A-Za-z0-9_-]+", profile or ""):
|
|
117
|
+
paths.append(home / f"{profile}.config.toml")
|
|
118
|
+
current = (cwd or Path.cwd()).resolve()
|
|
119
|
+
for parent in (current, *current.parents):
|
|
120
|
+
path = parent / ".codex" / "config.toml"
|
|
121
|
+
# An explicit CODEX_HOME is an isolation boundary. When cwd happens
|
|
122
|
+
# to live below the OS home directory, parent discovery must not pull
|
|
123
|
+
# the default ~/.codex/config.toml back into that isolated config.
|
|
124
|
+
if configured_home and path.resolve() == (default_home / "config.toml").resolve():
|
|
125
|
+
continue
|
|
126
|
+
if path not in paths:
|
|
127
|
+
paths.append(path)
|
|
128
|
+
return paths
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def normalize_codex_mcp_server(
|
|
132
|
+
raw_name: Any, raw_server: Any
|
|
133
|
+
) -> tuple[str, dict[str, Any]] | None:
|
|
134
|
+
name = str(raw_name or "").strip()
|
|
135
|
+
if not name or not isinstance(raw_server, dict):
|
|
136
|
+
return None
|
|
137
|
+
url = str(raw_server.get("url") or raw_server.get("endpoint") or "").strip()
|
|
138
|
+
if not url.startswith(("http://", "https://")):
|
|
139
|
+
return None
|
|
140
|
+
explicit_type = raw_server.get("type") is not None or raw_server.get("transport") is not None
|
|
141
|
+
server_type = str(raw_server.get("type") or raw_server.get("transport") or "http").strip().lower()
|
|
142
|
+
if server_type in {"streamable-http", "streamable_http"}:
|
|
143
|
+
server_type = "http"
|
|
144
|
+
if server_type not in {"http", "sse"}:
|
|
145
|
+
server_type = "http"
|
|
146
|
+
out: dict[str, Any] = {"type": server_type, "url": url}
|
|
147
|
+
if explicit_type:
|
|
148
|
+
out["_ciel_runtime_explicit_type"] = True
|
|
149
|
+
for key in (
|
|
150
|
+
"headers",
|
|
151
|
+
"env_http_headers",
|
|
152
|
+
"bearer_token_env_var",
|
|
153
|
+
"token_env_var",
|
|
154
|
+
"bearer_token",
|
|
155
|
+
"token",
|
|
156
|
+
"streamable_requires_session",
|
|
157
|
+
"require_session",
|
|
158
|
+
"mcp_session_required",
|
|
159
|
+
"mcp_protocol_version",
|
|
160
|
+
"protocolVersion",
|
|
161
|
+
"protocol_version",
|
|
162
|
+
"mcp_timeout_seconds",
|
|
163
|
+
"timeout",
|
|
164
|
+
):
|
|
165
|
+
value = raw_server.get(key)
|
|
166
|
+
if value is not None:
|
|
167
|
+
out[key] = value
|
|
168
|
+
return name, out
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def codex_mcp_servers_from_toml_data(data: Any) -> dict[str, dict[str, Any]]:
|
|
172
|
+
if not isinstance(data, dict) or not isinstance(data.get("mcp_servers"), dict):
|
|
173
|
+
return {}
|
|
174
|
+
out: dict[str, dict[str, Any]] = {}
|
|
175
|
+
for raw_name, raw_server in data["mcp_servers"].items():
|
|
176
|
+
normalized = normalize_codex_mcp_server(raw_name, raw_server)
|
|
177
|
+
if normalized is not None:
|
|
178
|
+
name, server = normalized
|
|
179
|
+
out[name] = server
|
|
180
|
+
return out
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def toml_table_parts(raw: str) -> list[str]:
|
|
184
|
+
parts: list[str] = []
|
|
185
|
+
current: list[str] = []
|
|
186
|
+
quote = ""
|
|
187
|
+
escaped = False
|
|
188
|
+
for character in raw:
|
|
189
|
+
if escaped:
|
|
190
|
+
current.append(character)
|
|
191
|
+
escaped = False
|
|
192
|
+
continue
|
|
193
|
+
if character == "\\" and quote == '"':
|
|
194
|
+
current.append(character)
|
|
195
|
+
escaped = True
|
|
196
|
+
continue
|
|
197
|
+
if character in {"'", '"'}:
|
|
198
|
+
quote = "" if quote == character else character if not quote else quote
|
|
199
|
+
current.append(character)
|
|
200
|
+
continue
|
|
201
|
+
if character == "." and not quote:
|
|
202
|
+
part = unquote_toml_string("".join(current).strip())
|
|
203
|
+
if part:
|
|
204
|
+
parts.append(part)
|
|
205
|
+
current = []
|
|
206
|
+
continue
|
|
207
|
+
current.append(character)
|
|
208
|
+
part = unquote_toml_string("".join(current).strip())
|
|
209
|
+
if part:
|
|
210
|
+
parts.append(part)
|
|
211
|
+
return parts
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def parse_simple_toml_value(raw: str) -> Any:
|
|
215
|
+
value = toml_scalar_without_comment(raw).strip()
|
|
216
|
+
if not value:
|
|
217
|
+
return ""
|
|
218
|
+
if len(value) >= 2 and value[0] == value[-1] and value[0] in {"'", '"'}:
|
|
219
|
+
return unquote_toml_string(value)
|
|
220
|
+
low = value.lower()
|
|
221
|
+
if low in {"true", "false"}:
|
|
222
|
+
return low == "true"
|
|
223
|
+
if value.startswith("[") and value.endswith("]"):
|
|
224
|
+
items: list[str] = []
|
|
225
|
+
current: list[str] = []
|
|
226
|
+
quote = ""
|
|
227
|
+
escaped = False
|
|
228
|
+
for character in value[1:-1]:
|
|
229
|
+
if escaped:
|
|
230
|
+
current.append(character)
|
|
231
|
+
escaped = False
|
|
232
|
+
continue
|
|
233
|
+
if character == "\\" and quote == '"':
|
|
234
|
+
current.append(character)
|
|
235
|
+
escaped = True
|
|
236
|
+
continue
|
|
237
|
+
if character in {"'", '"'}:
|
|
238
|
+
quote = "" if quote == character else character if not quote else quote
|
|
239
|
+
current.append(character)
|
|
240
|
+
continue
|
|
241
|
+
if character == "," and not quote:
|
|
242
|
+
item = unquote_toml_string("".join(current).strip())
|
|
243
|
+
if item:
|
|
244
|
+
items.append(item)
|
|
245
|
+
current = []
|
|
246
|
+
continue
|
|
247
|
+
current.append(character)
|
|
248
|
+
item = unquote_toml_string("".join(current).strip())
|
|
249
|
+
if item:
|
|
250
|
+
items.append(item)
|
|
251
|
+
return items
|
|
252
|
+
try:
|
|
253
|
+
return int(value)
|
|
254
|
+
except ValueError:
|
|
255
|
+
return value
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def fallback_codex_mcp_servers_from_config_text(text: str) -> dict[str, dict[str, Any]]:
|
|
259
|
+
raw_servers: dict[str, dict[str, Any]] = {}
|
|
260
|
+
current_name = ""
|
|
261
|
+
current_subtable = ""
|
|
262
|
+
for line in text.splitlines():
|
|
263
|
+
stripped = toml_scalar_without_comment(line)
|
|
264
|
+
if not stripped:
|
|
265
|
+
continue
|
|
266
|
+
table_match = re.fullmatch(r"\[(.+)\]", stripped)
|
|
267
|
+
if table_match:
|
|
268
|
+
parts = toml_table_parts(table_match.group(1).strip())
|
|
269
|
+
current_name = ""
|
|
270
|
+
current_subtable = ""
|
|
271
|
+
if len(parts) >= 2 and parts[0] == "mcp_servers":
|
|
272
|
+
current_name = parts[1]
|
|
273
|
+
current_subtable = parts[2] if len(parts) >= 3 else ""
|
|
274
|
+
raw_servers.setdefault(current_name, {})
|
|
275
|
+
continue
|
|
276
|
+
if not current_name or "=" not in stripped:
|
|
277
|
+
continue
|
|
278
|
+
key, raw_value = stripped.split("=", 1)
|
|
279
|
+
value = parse_simple_toml_value(raw_value)
|
|
280
|
+
server = raw_servers.setdefault(current_name, {})
|
|
281
|
+
if current_subtable:
|
|
282
|
+
nested = server.setdefault(current_subtable, {})
|
|
283
|
+
if isinstance(nested, dict):
|
|
284
|
+
nested[key.strip()] = value
|
|
285
|
+
else:
|
|
286
|
+
server[key.strip()] = value
|
|
287
|
+
return codex_mcp_servers_from_toml_data({"mcp_servers": raw_servers})
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def codex_mcp_servers_from_config_text(text: str) -> dict[str, dict[str, Any]]:
|
|
291
|
+
try:
|
|
292
|
+
import tomllib
|
|
293
|
+
|
|
294
|
+
parsed = codex_mcp_servers_from_toml_data(tomllib.loads(text))
|
|
295
|
+
if parsed:
|
|
296
|
+
return parsed
|
|
297
|
+
except (ImportError, TypeError, ValueError):
|
|
298
|
+
pass
|
|
299
|
+
return fallback_codex_mcp_servers_from_config_text(text)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def discover_codex_mcp_servers(
|
|
303
|
+
passthrough: list[str] | None = None,
|
|
304
|
+
env: dict[str, str] | None = None,
|
|
305
|
+
cwd: Path | None = None,
|
|
306
|
+
*,
|
|
307
|
+
log: Callable[[str, str], None],
|
|
308
|
+
) -> dict[str, dict[str, Any]]:
|
|
309
|
+
servers: dict[str, dict[str, Any]] = {}
|
|
310
|
+
for path in codex_config_paths_for_launch(passthrough or [], env=env, cwd=cwd):
|
|
311
|
+
if not path.is_file():
|
|
312
|
+
continue
|
|
313
|
+
try:
|
|
314
|
+
parsed = codex_mcp_servers_from_config_text(path.read_text(encoding="utf-8"))
|
|
315
|
+
except (OSError, UnicodeError) as exc:
|
|
316
|
+
log(
|
|
317
|
+
"WARN",
|
|
318
|
+
f"codex_mcp_config_read_failed path={path} "
|
|
319
|
+
f"error={type(exc).__name__}: {exc}",
|
|
320
|
+
)
|
|
321
|
+
continue
|
|
322
|
+
servers.update(parsed)
|
|
323
|
+
return servers
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"""Codex launch configuration and routed model catalog orchestration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable, Mapping
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from ciel_runtime_support.codex_config import (
|
|
11
|
+
codex_alternate_screen_value_from_config_text,
|
|
12
|
+
codex_config_override_keys,
|
|
13
|
+
codex_config_paths_for_launch,
|
|
14
|
+
toml_string,
|
|
15
|
+
)
|
|
16
|
+
from ciel_runtime_support.codex_model_catalog import CodexModelCatalogSpec
|
|
17
|
+
from ciel_runtime_support.runtime_constants import (
|
|
18
|
+
CODEX_NATIVE_PROVIDER_ID_ENV,
|
|
19
|
+
CODEX_ROUTED_PROVIDER_ID,
|
|
20
|
+
CODEX_RUNTIME_API_KEY_ENV,
|
|
21
|
+
CODEX_RUNTIME_PROVIDER_ID,
|
|
22
|
+
CODEX_TUI_ALTERNATE_SCREEN_KEY,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass(frozen=True, slots=True)
|
|
27
|
+
class CodexLaunchConfigurationConstants:
|
|
28
|
+
runtime_provider_id: str
|
|
29
|
+
runtime_api_key_env: str
|
|
30
|
+
native_provider_id_env: str
|
|
31
|
+
routed_provider_id: str
|
|
32
|
+
alternate_screen_key: str
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass(frozen=True, slots=True)
|
|
36
|
+
class CodexLaunchPolicyPorts:
|
|
37
|
+
has_option: Callable[..., bool]
|
|
38
|
+
config_override_keys: Callable[[list[str]], set[str]]
|
|
39
|
+
config_paths: Callable[..., list[Path]]
|
|
40
|
+
alternate_screen_value: Callable[[str], str | None]
|
|
41
|
+
toml_string: Callable[[str], str]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def build_default_codex_launch_constants() -> CodexLaunchConfigurationConstants:
|
|
45
|
+
"""Build immutable routed Codex provider configuration constants."""
|
|
46
|
+
return CodexLaunchConfigurationConstants(
|
|
47
|
+
runtime_provider_id=CODEX_RUNTIME_PROVIDER_ID,
|
|
48
|
+
runtime_api_key_env=CODEX_RUNTIME_API_KEY_ENV,
|
|
49
|
+
native_provider_id_env=CODEX_NATIVE_PROVIDER_ID_ENV,
|
|
50
|
+
routed_provider_id=CODEX_ROUTED_PROVIDER_ID,
|
|
51
|
+
alternate_screen_key=CODEX_TUI_ALTERNATE_SCREEN_KEY,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def build_default_codex_launch_policy(
|
|
56
|
+
has_option: Callable[..., bool],
|
|
57
|
+
) -> CodexLaunchPolicyPorts:
|
|
58
|
+
"""Build the standard Codex config-file and CLI projection policy."""
|
|
59
|
+
return CodexLaunchPolicyPorts(
|
|
60
|
+
has_option=has_option,
|
|
61
|
+
config_override_keys=codex_config_override_keys,
|
|
62
|
+
config_paths=codex_config_paths_for_launch,
|
|
63
|
+
alternate_screen_value=codex_alternate_screen_value_from_config_text,
|
|
64
|
+
toml_string=toml_string,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass(frozen=True, slots=True)
|
|
69
|
+
class CodexLaunchModelPorts:
|
|
70
|
+
current_provider: Callable[[dict[str, Any]], tuple[str, dict[str, Any]]]
|
|
71
|
+
native_enabled: Callable[[str], bool]
|
|
72
|
+
current_alias: Callable[[dict[str, Any]], str]
|
|
73
|
+
context_limit: Callable[[str, dict[str, Any]], int | None]
|
|
74
|
+
context_capacity: Callable[[str, dict[str, Any]], int | None]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@dataclass(frozen=True, slots=True)
|
|
78
|
+
class CodexLaunchCatalogPorts:
|
|
79
|
+
write: Callable[[str, CodexModelCatalogSpec, dict[str, str]], Path | None]
|
|
80
|
+
provider_label: Callable[[str], str]
|
|
81
|
+
path_value: Callable[[dict[str, str]], str]
|
|
82
|
+
current_model_args: Callable[..., list[str]]
|
|
83
|
+
native_routed_args: Callable[..., list[str]]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@dataclass(frozen=True, slots=True)
|
|
87
|
+
class CodexLaunchConfigurationEffects:
|
|
88
|
+
environ: Callable[[], Mapping[str, str]]
|
|
89
|
+
router_base: Callable[[], str]
|
|
90
|
+
read_text: Callable[[Path], str]
|
|
91
|
+
log: Callable[[str, str], None]
|
|
92
|
+
output: Callable[[str], None]
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@dataclass(frozen=True, slots=True)
|
|
96
|
+
class CodexLaunchConfigurationService:
|
|
97
|
+
constants: CodexLaunchConfigurationConstants
|
|
98
|
+
policy: CodexLaunchPolicyPorts
|
|
99
|
+
model: CodexLaunchModelPorts
|
|
100
|
+
catalog: CodexLaunchCatalogPorts
|
|
101
|
+
effects: CodexLaunchConfigurationEffects
|
|
102
|
+
|
|
103
|
+
def alternate_screen_compat_args(
|
|
104
|
+
self,
|
|
105
|
+
passthrough: list[str],
|
|
106
|
+
env: dict[str, str] | None = None,
|
|
107
|
+
cwd: Path | None = None,
|
|
108
|
+
) -> list[str]:
|
|
109
|
+
key = self.constants.alternate_screen_key
|
|
110
|
+
if self.policy.has_option(passthrough, "--no-alt-screen"):
|
|
111
|
+
return []
|
|
112
|
+
if key in self.policy.config_override_keys(passthrough):
|
|
113
|
+
return []
|
|
114
|
+
for path in self.policy.config_paths(passthrough, env=env, cwd=cwd):
|
|
115
|
+
try:
|
|
116
|
+
text = self.effects.read_text(path)
|
|
117
|
+
except Exception:
|
|
118
|
+
continue
|
|
119
|
+
value = self.policy.alternate_screen_value(text)
|
|
120
|
+
if value:
|
|
121
|
+
self.effects.log(
|
|
122
|
+
"WARN",
|
|
123
|
+
f"codex_compat_alternate_screen_override path={path} value={value}",
|
|
124
|
+
)
|
|
125
|
+
self.effects.output(
|
|
126
|
+
"Ciel Runtime warning: applying Codex config compatibility "
|
|
127
|
+
f'override {key}="{value}".'
|
|
128
|
+
)
|
|
129
|
+
return ["-c", f"{key}={self.policy.toml_string(value)}"]
|
|
130
|
+
return []
|
|
131
|
+
|
|
132
|
+
def runtime_config_args(self, router_base: str | None = None) -> list[str]:
|
|
133
|
+
provider = self.constants.runtime_provider_id
|
|
134
|
+
configured_base = (
|
|
135
|
+
self.effects.router_base() if router_base is None else router_base
|
|
136
|
+
)
|
|
137
|
+
base = configured_base.rstrip("/") + "/v1"
|
|
138
|
+
toml = self.policy.toml_string
|
|
139
|
+
return [
|
|
140
|
+
"-c",
|
|
141
|
+
f"model_provider={toml(provider)}",
|
|
142
|
+
"-c",
|
|
143
|
+
f"model_providers.{provider}.name={toml('Ciel Runtime')}",
|
|
144
|
+
"-c",
|
|
145
|
+
f"model_providers.{provider}.base_url={toml(base)}",
|
|
146
|
+
"-c",
|
|
147
|
+
f"model_providers.{provider}.wire_api={toml('responses')}",
|
|
148
|
+
"-c",
|
|
149
|
+
f"model_providers.{provider}.env_key={toml(self.constants.runtime_api_key_env)}",
|
|
150
|
+
"-c",
|
|
151
|
+
f"model_providers.{provider}.request_max_retries=0",
|
|
152
|
+
"-c",
|
|
153
|
+
f"model_providers.{provider}.stream_max_retries=0",
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
def write_runtime_model_catalog(
|
|
157
|
+
self, codex: str, cfg: dict[str, Any]
|
|
158
|
+
) -> Path | None:
|
|
159
|
+
provider, provider_config = self.model.current_provider(cfg)
|
|
160
|
+
if self.model.native_enabled(provider):
|
|
161
|
+
return None
|
|
162
|
+
alias = self.model.current_alias(cfg)
|
|
163
|
+
if not alias:
|
|
164
|
+
return None
|
|
165
|
+
context_window = (
|
|
166
|
+
self.model.context_limit(provider, provider_config)
|
|
167
|
+
or self.model.context_capacity(provider, provider_config)
|
|
168
|
+
or 272000
|
|
169
|
+
)
|
|
170
|
+
catalog_env = dict(self.effects.environ())
|
|
171
|
+
catalog_env["PATH"] = self.catalog.path_value(catalog_env)
|
|
172
|
+
configured_auto_compact = provider_config.get(
|
|
173
|
+
"codex_auto_compact_window"
|
|
174
|
+
)
|
|
175
|
+
try:
|
|
176
|
+
auto_compact_token_limit = int(configured_auto_compact)
|
|
177
|
+
except (TypeError, ValueError):
|
|
178
|
+
auto_compact_token_limit = None
|
|
179
|
+
if auto_compact_token_limit is not None and auto_compact_token_limit <= 0:
|
|
180
|
+
auto_compact_token_limit = None
|
|
181
|
+
return self.catalog.write(
|
|
182
|
+
codex,
|
|
183
|
+
CodexModelCatalogSpec(
|
|
184
|
+
alias=alias,
|
|
185
|
+
provider_label=self.catalog.provider_label(provider),
|
|
186
|
+
context_window=context_window,
|
|
187
|
+
effort=str(provider_config.get("effort_level") or "").strip().lower(),
|
|
188
|
+
auto_compact_token_limit=auto_compact_token_limit,
|
|
189
|
+
),
|
|
190
|
+
catalog_env,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
def runtime_model_catalog_args(
|
|
194
|
+
self, codex: str, cfg: dict[str, Any]
|
|
195
|
+
) -> list[str]:
|
|
196
|
+
path = self.write_runtime_model_catalog(codex, cfg)
|
|
197
|
+
if path is None:
|
|
198
|
+
return []
|
|
199
|
+
value = self.policy.toml_string(str(path.resolve()))
|
|
200
|
+
return ["-c", f"model_catalog_json={value}"]
|
|
201
|
+
|
|
202
|
+
def native_routed_config_args(
|
|
203
|
+
self, router_base: str | None = None
|
|
204
|
+
) -> list[str]:
|
|
205
|
+
env = self.effects.environ()
|
|
206
|
+
provider = str(env.get(self.constants.native_provider_id_env) or "").strip()
|
|
207
|
+
provider = provider or self.constants.routed_provider_id
|
|
208
|
+
configured_base = (
|
|
209
|
+
self.effects.router_base() if router_base is None else router_base
|
|
210
|
+
)
|
|
211
|
+
return self.catalog.native_routed_args(
|
|
212
|
+
configured_base,
|
|
213
|
+
provider,
|
|
214
|
+
toml_string=self.policy.toml_string,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
def passthrough_has_model_override(self, passthrough: list[str]) -> bool:
|
|
218
|
+
return self.policy.has_option(
|
|
219
|
+
passthrough, "-m", "--model"
|
|
220
|
+
) or "model" in self.policy.config_override_keys(passthrough)
|
|
221
|
+
|
|
222
|
+
def current_model_cli_args(
|
|
223
|
+
self, provider_config: dict[str, Any], passthrough: list[str]
|
|
224
|
+
) -> list[str]:
|
|
225
|
+
return self.catalog.current_model_args(
|
|
226
|
+
provider_config,
|
|
227
|
+
passthrough,
|
|
228
|
+
overridden=self.passthrough_has_model_override,
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
def current_model_config_args(
|
|
232
|
+
self, provider_config: dict[str, Any], passthrough: list[str]
|
|
233
|
+
) -> list[str]:
|
|
234
|
+
return self.catalog.current_model_args(
|
|
235
|
+
provider_config,
|
|
236
|
+
passthrough,
|
|
237
|
+
overridden=self.passthrough_has_model_override,
|
|
238
|
+
config_style=True,
|
|
239
|
+
toml_string=self.policy.toml_string,
|
|
240
|
+
)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Pure Codex command-line launch argument policies."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def native_routed_config_args(
|
|
10
|
+
router_base: str,
|
|
11
|
+
provider: str,
|
|
12
|
+
*,
|
|
13
|
+
toml_string: Callable[[str], str],
|
|
14
|
+
) -> list[str]:
|
|
15
|
+
base = router_base.rstrip("/") + "/backend-api/codex"
|
|
16
|
+
if provider == "openai":
|
|
17
|
+
return ["-c", 'model_provider="openai"', "-c", f"openai_base_url={toml_string(base)}"]
|
|
18
|
+
return [
|
|
19
|
+
"-c",
|
|
20
|
+
f"model_provider={toml_string(provider)}",
|
|
21
|
+
"-c",
|
|
22
|
+
f"model_providers.{provider}.name={toml_string('Ciel Runtime Codex')}",
|
|
23
|
+
"-c",
|
|
24
|
+
f"model_providers.{provider}.base_url={toml_string(base)}",
|
|
25
|
+
"-c",
|
|
26
|
+
f"model_providers.{provider}.wire_api={toml_string('responses')}",
|
|
27
|
+
"-c",
|
|
28
|
+
f"model_providers.{provider}.requires_openai_auth=true",
|
|
29
|
+
"-c",
|
|
30
|
+
f"model_providers.{provider}.supports_websockets=false",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def passthrough_has_model_override(
|
|
35
|
+
passthrough: list[str],
|
|
36
|
+
*,
|
|
37
|
+
has_option: Callable[..., bool],
|
|
38
|
+
config_override_keys: Callable[[list[str]], set[str]],
|
|
39
|
+
) -> bool:
|
|
40
|
+
return has_option(passthrough, "-m", "--model") or "model" in config_override_keys(
|
|
41
|
+
passthrough
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def current_model_args(
|
|
46
|
+
config: dict[str, Any],
|
|
47
|
+
passthrough: list[str],
|
|
48
|
+
*,
|
|
49
|
+
overridden: Callable[[list[str]], bool],
|
|
50
|
+
config_style: bool = False,
|
|
51
|
+
toml_string: Callable[[str], str] = repr,
|
|
52
|
+
) -> list[str]:
|
|
53
|
+
model = str(config.get("current_model") or "").strip()
|
|
54
|
+
if not model or overridden(passthrough):
|
|
55
|
+
return []
|
|
56
|
+
return ["-c", f"model={toml_string(model)}"] if config_style else ["-m", model]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def help_requested(passthrough: list[str]) -> bool:
|
|
60
|
+
return any(argument in ("help", "--help", "-h") for argument in passthrough)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def yolo_launch_args(
|
|
64
|
+
passthrough: list[str], *, has_option: Callable[..., bool]
|
|
65
|
+
) -> list[str]:
|
|
66
|
+
return [] if has_option(passthrough, "--yolo") else ["--yolo"]
|