@oneciel-ai/ciel-runtime 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/ciel_runtime.py +2553 -9635
  2. package/ciel_runtime_support/advisor_request_builder.py +8 -21
  3. package/ciel_runtime_support/anthropic_tool_turns.py +13 -8
  4. package/ciel_runtime_support/architecture.py +68 -0
  5. package/ciel_runtime_support/architecture_budget.py +1 -1
  6. package/ciel_runtime_support/channel_connection_context.py +233 -0
  7. package/ciel_runtime_support/channel_delivery_context.py +332 -0
  8. package/ciel_runtime_support/channel_mcp_context.py +313 -0
  9. package/ciel_runtime_support/channel_mcp_discovery.py +47 -0
  10. package/ciel_runtime_support/channel_mcp_transport.py +5 -1
  11. package/ciel_runtime_support/channel_message_context.py +212 -0
  12. package/ciel_runtime_support/channel_message_repository.py +14 -3
  13. package/ciel_runtime_support/channel_pending_injection.py +9 -0
  14. package/ciel_runtime_support/channel_probe_launch_context.py +213 -0
  15. package/ciel_runtime_support/channel_replay_policy.py +38 -0
  16. package/ciel_runtime_support/channel_runtime_environment.py +8 -0
  17. package/ciel_runtime_support/channel_session_context.py +236 -0
  18. package/ciel_runtime_support/channel_terminal_context.py +350 -0
  19. package/ciel_runtime_support/channel_wake_context.py +532 -0
  20. package/ciel_runtime_support/claude_environment.py +60 -0
  21. package/ciel_runtime_support/claude_launch_assembly.py +249 -0
  22. package/ciel_runtime_support/claude_router.py +62 -12
  23. package/ciel_runtime_support/cli_application_context.py +132 -0
  24. package/ciel_runtime_support/cli_assembly.py +50 -0
  25. package/ciel_runtime_support/codex_backend_context.py +363 -0
  26. package/ciel_runtime_support/codex_config.py +13 -1
  27. package/ciel_runtime_support/codex_launch_assembly.py +213 -0
  28. package/ciel_runtime_support/codex_launch_configuration.py +30 -1
  29. package/ciel_runtime_support/codex_mcp_integration.py +90 -8
  30. package/ciel_runtime_support/codex_model_catalog.py +4 -1
  31. package/ciel_runtime_support/codex_reasoning_rejects.py +225 -0
  32. package/ciel_runtime_support/codex_router.py +38 -8
  33. package/ciel_runtime_support/codex_turn_recovery.py +154 -0
  34. package/ciel_runtime_support/config_migrations.py +103 -0
  35. package/ciel_runtime_support/configuration_cli.py +38 -0
  36. package/ciel_runtime_support/context_compaction.py +9 -4
  37. package/ciel_runtime_support/credential_management.py +12 -0
  38. package/ciel_runtime_support/credentials.py +12 -0
  39. package/ciel_runtime_support/github_copilot_oauth.py +2 -2
  40. package/ciel_runtime_support/hosted_formula_tools.py +216 -0
  41. package/ciel_runtime_support/kimi_runtime_context.py +208 -0
  42. package/ciel_runtime_support/llm_preset_context.py +338 -0
  43. package/ciel_runtime_support/managed_mcp_config.py +8 -4
  44. package/ciel_runtime_support/mcp_configuration_context.py +291 -0
  45. package/ciel_runtime_support/mcp_http_proxy.py +14 -8
  46. package/ciel_runtime_support/mcp_probe_transport.py +47 -15
  47. package/ciel_runtime_support/mcp_transport.py +14 -1
  48. package/ciel_runtime_support/native_context_recovery.py +72 -0
  49. package/ciel_runtime_support/ollama_catalog_context.py +213 -0
  50. package/ciel_runtime_support/ollama_stream_collection.py +103 -0
  51. package/ciel_runtime_support/ollama_thinking.py +6 -1
  52. package/ciel_runtime_support/ollama_wire_projection.py +157 -0
  53. package/ciel_runtime_support/openai_forwarding.py +32 -10
  54. package/ciel_runtime_support/openai_responses_router.py +12 -0
  55. package/ciel_runtime_support/package_lifecycle.py +39 -0
  56. package/ciel_runtime_support/prelaunch_assembly.py +37 -0
  57. package/ciel_runtime_support/prelaunch_panel_context.py +418 -0
  58. package/ciel_runtime_support/prelaunch_shell_context.py +394 -0
  59. package/ciel_runtime_support/prompt_compaction.py +144 -0
  60. package/ciel_runtime_support/prompt_injection.py +45 -0
  61. package/ciel_runtime_support/protocols/anthropic_thinking_policy.py +1 -1
  62. package/ciel_runtime_support/protocols/chat_projection.py +85 -5
  63. package/ciel_runtime_support/protocols/conversation_turn_policy.py +43 -0
  64. package/ciel_runtime_support/protocols/ollama_chat.py +31 -0
  65. package/ciel_runtime_support/protocols/ollama_response.py +57 -5
  66. package/ciel_runtime_support/protocols/openai_reasoning.py +5 -2
  67. package/ciel_runtime_support/protocols/openai_responses.py +61 -15
  68. package/ciel_runtime_support/provider_adapters.py +26 -0
  69. package/ciel_runtime_support/provider_administration_context.py +207 -0
  70. package/ciel_runtime_support/provider_config_mutations.py +3 -0
  71. package/ciel_runtime_support/provider_model_catalog_context.py +137 -0
  72. package/ciel_runtime_support/provider_model_context.py +107 -0
  73. package/ciel_runtime_support/provider_model_metadata_context.py +197 -0
  74. package/ciel_runtime_support/provider_model_selection.py +10 -3
  75. package/ciel_runtime_support/provider_models.py +45 -2
  76. package/ciel_runtime_support/provider_option_cli.py +19 -0
  77. package/ciel_runtime_support/provider_policy.py +1 -1
  78. package/ciel_runtime_support/provider_readiness_context.py +189 -0
  79. package/ciel_runtime_support/provider_request_builder.py +64 -28
  80. package/ciel_runtime_support/provider_responses_passthrough.py +21 -2
  81. package/ciel_runtime_support/provider_timeout_policy.py +54 -0
  82. package/ciel_runtime_support/provider_tool_policy.py +9 -1
  83. package/ciel_runtime_support/providers/__init__.py +6 -0
  84. package/ciel_runtime_support/providers/alibaba.py +634 -0
  85. package/ciel_runtime_support/providers/catalog.py +24 -16
  86. package/ciel_runtime_support/providers/deepseek.py +73 -0
  87. package/ciel_runtime_support/providers/github_copilot_oauth.py +22 -1
  88. package/ciel_runtime_support/providers/kimi.py +69 -9
  89. package/ciel_runtime_support/providers/ollama.py +8 -0
  90. package/ciel_runtime_support/providers/ollama_context.py +21 -2
  91. package/ciel_runtime_support/providers/vllm.py +7 -1
  92. package/ciel_runtime_support/response_collection.py +68 -18
  93. package/ciel_runtime_support/response_collection_context.py +391 -0
  94. package/ciel_runtime_support/response_stream_context.py +555 -0
  95. package/ciel_runtime_support/responses_input_compatibility.py +121 -0
  96. package/ciel_runtime_support/responses_usage_observer.py +83 -0
  97. package/ciel_runtime_support/router_client_lifecycle.py +1 -0
  98. package/ciel_runtime_support/router_http.py +239 -3
  99. package/ciel_runtime_support/router_observability_context.py +251 -0
  100. package/ciel_runtime_support/router_process_context.py +200 -0
  101. package/ciel_runtime_support/router_process_lifecycle.py +2 -0
  102. package/ciel_runtime_support/router_request_assembly.py +399 -0
  103. package/ciel_runtime_support/router_request_context.py +215 -0
  104. package/ciel_runtime_support/router_server_context.py +82 -0
  105. package/ciel_runtime_support/runaway_output_guard.py +488 -0
  106. package/ciel_runtime_support/runtime_asset_assembly.py +147 -0
  107. package/ciel_runtime_support/runtime_asset_context.py +297 -0
  108. package/ciel_runtime_support/runtime_constants.py +16 -1
  109. package/ciel_runtime_support/runtime_launch.py +9 -5
  110. package/ciel_runtime_support/runtime_launch_context.py +130 -0
  111. package/ciel_runtime_support/runtime_maintenance_assembly.py +60 -0
  112. package/ciel_runtime_support/runtime_maintenance_context.py +309 -0
  113. package/ciel_runtime_support/runtime_maintenance_services.py +265 -0
  114. package/ciel_runtime_support/runtime_paths.py +60 -40
  115. package/ciel_runtime_support/runtime_primitives.py +78 -0
  116. package/ciel_runtime_support/sse_stream_collection.py +236 -0
  117. package/ciel_runtime_support/statusline_script.py +57 -8
  118. package/ciel_runtime_support/streaming_anthropic.py +361 -24
  119. package/ciel_runtime_support/tool_schema.py +40 -2
  120. package/ciel_runtime_support/tool_side_effect_dedupe.py +117 -12
  121. package/ciel_runtime_support/upstream_dump.py +68 -0
  122. package/ciel_runtime_support/upstream_retry_context.py +259 -0
  123. package/ciel_runtime_support/workspace_router_selection.py +86 -0
  124. package/docs/Configuration.md +50 -0
  125. package/docs/Test-Suite.md +1 -0
  126. package/package.json +1 -1
@@ -0,0 +1,157 @@
1
+ """Project provider-owned Ollama request settings onto wire payloads.
2
+
3
+ The application uses several Ollama request paths (interactive forwarding,
4
+ Advisor, and optional LLM compaction). This policy is their single boundary
5
+ for optional model/runtime settings. It deliberately distinguishes required
6
+ protocol fields from explicit operator overrides so persisted adapter defaults
7
+ do not silently become upstream request parameters.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from dataclasses import dataclass
13
+ from typing import Any, Callable, Mapping
14
+
15
+
16
+ @dataclass(frozen=True, slots=True)
17
+ class OllamaWireProjectionPorts:
18
+ think_value: Callable[
19
+ [str, str | None, dict[str, Any], Mapping[str, Any]], bool | str | None
20
+ ]
21
+ positive_int: Callable[[Any], int | None]
22
+
23
+
24
+ @dataclass(frozen=True, slots=True)
25
+ class OllamaWireProjection:
26
+ ports: OllamaWireProjectionPorts
27
+ legacy_keep_alive_default: str = "5m"
28
+
29
+ @staticmethod
30
+ def _marked_keys(config: Mapping[str, Any], name: str) -> set[str]:
31
+ raw = config.get(name)
32
+ if not isinstance(raw, (list, tuple, set)):
33
+ return set()
34
+ return {str(item) for item in raw if str(item).strip()}
35
+
36
+ def explicit_options(self, config: Mapping[str, Any]) -> dict[str, Any]:
37
+ raw = config.get("ollama_options")
38
+ if not isinstance(raw, Mapping):
39
+ return {}
40
+ allowed = self._marked_keys(
41
+ config, "ollama_explicit_options"
42
+ ) | self._marked_keys(config, "ollama_transient_options")
43
+ return {
44
+ str(key): value
45
+ for key, value in raw.items()
46
+ if str(key) in allowed and value is not None
47
+ }
48
+
49
+ def keep_alive(self, config: Mapping[str, Any]) -> str | None:
50
+ value = config.get("keep_alive")
51
+ if value is None or str(value).strip() == "":
52
+ return None
53
+ if config.get("keep_alive_explicit"):
54
+ return str(value)
55
+ # Before provenance markers existed, any non-default persisted value
56
+ # could only have come from an operator edit. Preserve that intent.
57
+ if str(value) != self.legacy_keep_alive_default:
58
+ return str(value)
59
+ return None
60
+
61
+ def options(
62
+ self,
63
+ config: Mapping[str, Any],
64
+ *,
65
+ output_limit: int | None = None,
66
+ ) -> dict[str, Any]:
67
+ options = self.explicit_options(config)
68
+ raw_num_ctx = config.get("num_ctx", "auto")
69
+ if not (
70
+ isinstance(raw_num_ctx, str)
71
+ and raw_num_ctx.strip().lower() in {"", "auto", "dynamic"}
72
+ ):
73
+ num_ctx = self.ports.positive_int(raw_num_ctx)
74
+ if num_ctx:
75
+ options["num_ctx"] = num_ctx
76
+
77
+ output_is_explicit = bool(config.get("output_tokens_explicit")) or (
78
+ "num_predict"
79
+ in self._marked_keys(config, "ollama_transient_options")
80
+ )
81
+ if output_is_explicit:
82
+ configured = self.ports.positive_int(
83
+ options.get("num_predict")
84
+ or config.get("max_output_tokens")
85
+ )
86
+ limit = self.ports.positive_int(output_limit)
87
+ if configured and limit:
88
+ options["num_predict"] = min(configured, limit)
89
+ elif configured:
90
+ options["num_predict"] = configured
91
+ elif limit:
92
+ options["num_predict"] = limit
93
+ else:
94
+ options.pop("num_predict", None)
95
+ return options
96
+
97
+ def apply(
98
+ self,
99
+ request: dict[str, Any],
100
+ provider: str,
101
+ model: str | None,
102
+ config: dict[str, Any],
103
+ source_request: Mapping[str, Any] | None = None,
104
+ *,
105
+ output_limit: int | None = None,
106
+ ) -> dict[str, Any]:
107
+ projected = dict(request)
108
+ think = self.ports.think_value(
109
+ provider, model, config, source_request or {}
110
+ )
111
+ if think is not None:
112
+ projected["think"] = think
113
+ keep_alive = self.keep_alive(config)
114
+ if keep_alive is not None:
115
+ projected["keep_alive"] = keep_alive
116
+ options = self.options(config, output_limit=output_limit)
117
+ if options:
118
+ projected["options"] = options
119
+ return projected
120
+
121
+
122
+ @dataclass(frozen=True, slots=True)
123
+ class OllamaWireCompatibilityApi:
124
+ """Stable facade adapter backed by typed projection dependencies."""
125
+
126
+ think_value: Callable[
127
+ [str, str | None, dict[str, Any], Mapping[str, Any]], bool | str | None
128
+ ]
129
+ positive_int: Callable[[Any], int | None]
130
+
131
+ def apply(
132
+ self,
133
+ request: dict[str, Any],
134
+ provider: str,
135
+ model: str | None,
136
+ config: dict[str, Any],
137
+ source_request: Mapping[str, Any] | None = None,
138
+ *,
139
+ output_limit: int | None = None,
140
+ ) -> dict[str, Any]:
141
+ return OllamaWireProjection(
142
+ OllamaWireProjectionPorts(self.think_value, self.positive_int)
143
+ ).apply(
144
+ request,
145
+ provider,
146
+ model,
147
+ config,
148
+ source_request,
149
+ output_limit=output_limit,
150
+ )
151
+
152
+
153
+ __all__ = [
154
+ "OllamaWireCompatibilityApi",
155
+ "OllamaWireProjection",
156
+ "OllamaWireProjectionPorts",
157
+ ]
@@ -73,6 +73,7 @@ class OpenAIForwardServices:
73
73
  advisor: OpenAIForwardAdvisor
74
74
  streaming: OpenAIForwardStreaming
75
75
  response: OpenAIForwardResponse
76
+ hosted_tools: Any
76
77
  log: Callable[[str, str], Any]
77
78
 
78
79
 
@@ -100,10 +101,19 @@ def forward_openai_compatible_chat(
100
101
  original_body = body
101
102
  upstream_body = request.body_with_advisor_tool(body, pcfg) if request.advisor_provider_supported(provider) else body
102
103
  url = request.join_url(request.upstream_request_base(provider, pcfg), "/v1/chat/completions")
104
+ timeout = rate_limit.request_timeout_seconds(pcfg)
105
+ headers = request.provider_headers(provider, pcfg, handler.headers, "openai_chat")
103
106
  waited, rpm_used, rpm_limit = rate_limit.apply(provider, pcfg, model)
104
107
  compatibility_test = str(handler.headers.get(policy.compatibility_test_header) or "").strip().lower() in ("1", "true", "yes", "on")
105
108
  stream_enabled = bool(pcfg.get("stream_enabled", True))
106
109
  stream = policy.provider_requires_streaming(provider, pcfg) or (bool(body.get("stream", stream_enabled)) and stream_enabled)
110
+ collected_request = request.build_chat_request(provider, model, upstream_body, pcfg, stream=False)
111
+ collected_request, hosted_state = services.hosted_tools.prepare(
112
+ provider, pcfg, collected_request, headers, timeout
113
+ )
114
+ if hosted_state.enabled and stream:
115
+ stream = False
116
+ services.log("INFO", f"provider-hosted tools enabled for {provider}; collecting tool rounds internally")
107
117
  if stream and advisor.model_enabled(pcfg) and request.advisor_provider_supported(provider):
108
118
  stream = False
109
119
  services.log("INFO", f"advisor tool enabled for {provider}; collecting this turn so advisor tool calls can be resolved internally")
@@ -128,10 +138,8 @@ def forward_openai_compatible_chat(
128
138
  upstream_response = streaming.open_with_retry(
129
139
  url,
130
140
  req_body,
131
- request.provider_headers(
132
- provider, pcfg, handler.headers, "openai_chat"
133
- ),
134
- rate_limit.request_timeout_seconds(pcfg),
141
+ headers,
142
+ timeout,
135
143
  provider,
136
144
  pcfg,
137
145
  model,
@@ -151,7 +159,6 @@ def forward_openai_compatible_chat(
151
159
  )
152
160
  if stream_ok:
153
161
  response.mark_delivery_success(handler, "openai_stream_message_stop")
154
- response.write_activity("success", provider, model, tokens=req_tokens, bytes=req_bytes, stream=True)
155
162
  else:
156
163
  response.mark_delivery_failed(handler, "openai_stream_error")
157
164
  except RuntimeError as exc:
@@ -168,21 +175,36 @@ def forward_openai_compatible_chat(
168
175
  return
169
176
  return
170
177
 
171
- req_body = request.build_chat_request(provider, model, upstream_body, pcfg, stream=False)
178
+ req_body = collected_request
172
179
  try:
173
180
  data = streaming.post_json_with_retry(
174
181
  url,
175
182
  req_body,
176
- request.provider_headers(
177
- provider, pcfg, handler.headers, "openai_chat"
178
- ),
179
- rate_limit.request_timeout_seconds(pcfg),
183
+ headers,
184
+ timeout,
180
185
  provider,
181
186
  pcfg,
182
187
  model,
183
188
  None,
184
189
  retry_rate_limits=not compatibility_test,
185
190
  )
191
+ data = services.hosted_tools.resolve(
192
+ hosted_state,
193
+ req_body,
194
+ data,
195
+ lambda next_body: streaming.post_json_with_retry(
196
+ url,
197
+ next_body,
198
+ headers,
199
+ timeout,
200
+ provider,
201
+ pcfg,
202
+ model,
203
+ None,
204
+ retry_rate_limits=not compatibility_test,
205
+ ),
206
+ timeout,
207
+ )
186
208
  except RuntimeError as exc:
187
209
  response.write_json(handler, {"type": "error", "error": {"type": "upstream_error", "message": str(exc)}}, 500)
188
210
  return
@@ -41,6 +41,10 @@ class OpenAIResponsesRouting:
41
41
  dump_request: Callable[..., Any]
42
42
  normalize_provider_wire: Callable[..., dict[str, Any]]
43
43
  collect_message: Callable[..., dict[str, Any]]
44
+ # Both belong here rather than with the conversions: each one's behaviour is
45
+ # decided by the routed-vs-native split this group already owns.
46
+ apply_codex_compat_instructions: Callable[..., dict[str, Any]]
47
+ recover_preamble_only_turn: Callable[..., dict[str, Any]]
44
48
 
45
49
 
46
50
  @dataclass(frozen=True, slots=True)
@@ -82,6 +86,11 @@ def handle_openai_responses_request(
82
86
  routing = services.routing
83
87
  delivery = services.delivery
84
88
  output = services.output
89
+ # Codex cannot receive --append-system-prompt, so the routed compatibility
90
+ # instruction has to ride along in the request itself. Do this before the
91
+ # conversion so it reaches both the translated path and a native Responses
92
+ # provider; the native Codex backend is excluded inside the port.
93
+ body = routing.apply_codex_compat_instructions(cfg, provider, pcfg, body)
85
94
  anthropic_body = conversion.to_anthropic(body, conversion.current_alias(cfg))
86
95
  if routing.maybe_import_session(
87
96
  handler,
@@ -146,6 +155,9 @@ def handle_openai_responses_request(
146
155
  )
147
156
  try:
148
157
  message = routing.collect_message(handler, provider, pcfg, anthropic_body)
158
+ message = routing.recover_preamble_only_turn(
159
+ handler, provider, pcfg, anthropic_body, message
160
+ )
149
161
  output.write_response(handler, message, source_body=body, stream=stream)
150
162
  delivery.mark_success(handler, "responses_json")
151
163
  delivery.commit(anthropic_body, handler)
@@ -3,12 +3,41 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from dataclasses import dataclass
6
+ import ntpath
6
7
  import os
7
8
  from pathlib import Path
8
9
  import subprocess
9
10
  from typing import Callable
10
11
 
11
12
 
13
+ def windows_executable_image_running(executable_name: str) -> bool:
14
+ """Return whether Windows currently has the executable image loaded.
15
+
16
+ npm replaces native package binaries in place. Windows rejects that copy
17
+ with EBUSY while any process is using the image, so the update must be
18
+ deferred instead of starting an install that cannot complete.
19
+ """
20
+
21
+ if os.name != "nt":
22
+ return False
23
+ image_name = ntpath.basename(executable_name)
24
+ if not image_name.casefold().endswith(".exe"):
25
+ image_name += ".exe"
26
+ try:
27
+ result = subprocess.run(
28
+ ["tasklist", "/FI", f"IMAGENAME eq {image_name}", "/FO", "CSV", "/NH"],
29
+ stdout=subprocess.PIPE,
30
+ stderr=subprocess.DEVNULL,
31
+ text=True,
32
+ timeout=5,
33
+ check=False,
34
+ )
35
+ except (OSError, subprocess.SubprocessError):
36
+ return False
37
+ expected = f'"{image_name}"'.casefold()
38
+ return any(line.strip().casefold().startswith(expected) for line in result.stdout.splitlines())
39
+
40
+
12
41
  @dataclass(frozen=True, slots=True)
13
42
  class NpmPackageLifecyclePorts:
14
43
  find_executable: Callable[[str], str | None]
@@ -98,6 +127,15 @@ class NpmPackageLifecycle:
98
127
  if current and not self._ports.version_newer(latest, current):
99
128
  self._print(f"{label} is up to date ({current}).")
100
129
  return executable
130
+ if executable_name.casefold() == "codex" and windows_executable_image_running(
131
+ executable_name
132
+ ):
133
+ self._print(
134
+ f"{label} update deferred: {executable_name}.exe is currently running and "
135
+ "Windows has locked the executable. Continuing with the current version; "
136
+ "the update will be retried on a later launch."
137
+ )
138
+ return executable
101
139
  self._print(f"{label} update available: {current or 'unknown'} -> {latest}; upgrading automatically.")
102
140
  prefix = self._ports.install_prefix()
103
141
  if prefix is not None:
@@ -214,4 +252,5 @@ __all__ = [
214
252
  "NpmPackageLifecyclePorts",
215
253
  "SelfUpdateLifecycle",
216
254
  "SelfUpdatePorts",
255
+ "windows_executable_image_running",
217
256
  ]
@@ -0,0 +1,37 @@
1
+ """Compose the prelaunch application service from bounded UI port groups."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+ from . import prelaunch
8
+
9
+
10
+ @dataclass(frozen=True, slots=True)
11
+ class PrelaunchAssembly:
12
+ terminal: prelaunch.PrelaunchTerminal
13
+ config: prelaunch.PrelaunchConfig
14
+ launch_policy: prelaunch.PrelaunchLaunchPolicy
15
+ panel_rows: prelaunch.PrelaunchPanelRows
16
+ channel_query: prelaunch.PrelaunchChannelQuery
17
+ channel_commands: prelaunch.PrelaunchChannelCommands
18
+ mutations: prelaunch.PrelaunchMutations
19
+ secrets: prelaunch.PrelaunchSecrets
20
+ options: prelaunch.PrelaunchOptions
21
+
22
+ def services(self) -> prelaunch.PrelaunchServices:
23
+ return prelaunch.PrelaunchServices(
24
+ constants=prelaunch.build_default_prelaunch_constants(),
25
+ terminal=self.terminal,
26
+ config=self.config,
27
+ launch_policy=self.launch_policy,
28
+ panel_rows=self.panel_rows,
29
+ channel_query=self.channel_query,
30
+ channel_commands=self.channel_commands,
31
+ mutations=self.mutations,
32
+ secrets=self.secrets,
33
+ options=self.options,
34
+ )
35
+
36
+
37
+ __all__ = ["PrelaunchAssembly"]