Skip to content

Commit 00c463e

Browse files
committed
codex_sdk: fix ollama exec routing and example hangs
1 parent a8b985f commit 00c463e

12 files changed

Lines changed: 50 additions & 24 deletions

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,14 @@ That causes the shared core registry to:
190190
- validate the local model id
191191
- keep `gpt-oss:20b` as the default validated OSS model when no explicit model
192192
is supplied
193-
- return a payload that renders `--oss --local-provider ollama --model llama3.2`
193+
- return a payload that renders exec/app-server startup through config-driven
194+
model-provider routing such as `--config 'model_provider="ollama"' --config
195+
'model="llama3.2"'`
194196

195197
The SDK does not infer those flags on its own.
196-
- CLI argument rendering only emits `--model` from a non-empty resolved value
198+
- exec-mode startup also closes stdin on start for one-shot argv-prompt runs so
199+
the upstream Codex CLI does not wait for EOF after printing
200+
`Reading additional input from stdin...`
197201

198202
If `ollama_base_url:` is supplied, that endpoint is carried inside the
199203
payload-owned env overrides as `CODEX_OSS_BASE_URL`. Raw Ollama roots are

examples/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ Supported SSH flags for CLI/app-server examples:
7070
- `--ssh-port <port>`
7171
- `--ssh-identity-file <path>`
7272

73+
Example SSH runs are intentionally noninteractive. The shared execution surface
74+
adds `BatchMode=yes` and `ConnectTimeout=10` so unattended example runs fail
75+
fast instead of hanging on password or connection prompts.
76+
7377
`--cwd` is optional for the exec-backed examples. In SSH mode it becomes
7478
required for app-server thread demos and raw prompt-mode CLI sessions, because
7579
those upstream surfaces do not expose `--skip-git-repo-check`. Point it at a
@@ -110,6 +114,8 @@ can behave less reliably under the full Codex agent prompt/tool stack.
110114
In `--ollama` mode, the runner:
111115

112116
- executes the full CLI-backed example suite against the local Ollama-backed Codex route
117+
- uses the same config-driven `model_provider="ollama"` / `model="..."` route
118+
that current upstream Codex expects for exec/app-server local-model startup
113119
- keeps app-server examples enabled by configuring `codex app-server` with supported
114120
`--config` overrides instead of unsupported OSS argv flags
115121
- uses deterministic local fallbacks where upstream features are not reliable on the

examples/live_config_overrides.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ alias CodexExamples.Support
66

77
Support.init!()
88

9-
alias Codex.{Options, Thread}
9+
alias Codex.Thread
1010
alias Codex.Config.LayerStack
1111

1212
defmodule LiveConfigOverrides do

examples/live_rate_limits.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ alias CodexExamples.Support
66

77
Support.init!()
88

9-
alias Codex.{Error, Events, Items, Options, RunResultStreaming, Thread, TransportError}
9+
alias Codex.{Error, Events, Items, RunResultStreaming, Thread, TransportError}
1010
alias Codex.Protocol.RateLimit, as: RateLimitSnapshot
1111

1212
defmodule LiveRateLimits do

examples/live_telemetry_stream.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ alias CodexExamples.Support
66

77
Support.init!()
88

9-
alias Codex.{Error, Models, Options, RunResultStreaming, Thread, TransportError}
9+
alias Codex.{Error, Models, RunResultStreaming, Thread, TransportError}
1010
alias Codex.ExamplesSupport
1111

1212
defmodule LiveTelemetryStream do

examples/live_tooling_stream.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ alias CodexExamples.Support
66

77
Support.init!()
88

9-
alias Codex.{Events, Items, Options, RunResultStreaming, Thread}
9+
alias Codex.{Events, Items, RunResultStreaming, Thread}
1010

1111
defmodule CodexExamples.LiveToolingStream do
1212
@moduledoc false

examples/live_usage_and_compaction.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ alias CodexExamples.Support
66

77
Support.init!()
88

9-
alias Codex.{Error, Events, Items, Models, Options, RunResultStreaming, Thread, TransportError}
9+
alias Codex.{Error, Events, Items, Models, RunResultStreaming, Thread, TransportError}
1010
alias Codex.ExamplesSupport
1111

1212
defmodule LiveUsageAndCompaction do

examples/run_all.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ echo
149149
if [[ "$ollama_enabled" == true ]]; then
150150
echo "CLI backend: Ollama via Codex OSS"
151151
echo "CLI model: ${CODEX_MODEL}"
152-
echo "CLI route: codex --oss --local-provider ollama --model ${CODEX_MODEL}"
152+
echo "CLI route: codex exec --json --config model_provider=\"ollama\" --config model=\"${CODEX_MODEL}\""
153153
echo "Direct API examples: skipped in --ollama mode because they are OpenAI-only"
154154
EXAMPLE_TIMEOUT_SECONDS="${CODEX_EXAMPLES_TIMEOUT_SECONDS:-120}"
155155
echo "Per-example timeout: ${EXAMPLE_TIMEOUT_SECONDS}s"

lib/codex/examples_support.ex

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ defmodule Codex.ExamplesSupport do
3434
end
3535

3636
@context_key {__MODULE__, :ssh_context}
37+
@example_ssh_options %{
38+
"BatchMode" => "yes",
39+
"ConnectTimeout" => 10
40+
}
3741
@ssh_switches [
3842
cwd: :string,
3943
danger_full_access: :boolean,
@@ -415,6 +419,7 @@ defmodule Codex.ExamplesSupport do
415419
|> maybe_put_kw(:ssh_user, effective_user)
416420
|> maybe_put_kw(:port, ssh_port)
417421
|> maybe_put_kw(:identity_file, identity_file)
422+
|> Keyword.put(:ssh_options, @example_ssh_options)
418423
) do
419424
{:ok,
420425
%SSHContext{

lib/codex/runtime/exec/profile.ex

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ defmodule Codex.Runtime.Exec.Profile do
1818
args =
1919
["exec", "--json"]
2020
|> Shared.maybe_add_pair("--profile", Keyword.get(opts, :cli_profile))
21-
|> Shared.maybe_add_flag("--oss", oss_enabled?(opts))
22-
|> Shared.maybe_add_pair("--local-provider", local_provider_value(opts))
2321
|> Shared.maybe_add_flag("--full-auto", Keyword.get(opts, :full_auto))
2422
|> Shared.maybe_add_flag(
2523
"--dangerously-bypass-approvals-and-sandbox",
@@ -32,12 +30,12 @@ defmodule Codex.Runtime.Exec.Profile do
3230
|> Shared.maybe_add_pair("--cd", Keyword.get(opts, :working_directory))
3331
|> Shared.maybe_add_repeat("--add-dir", Keyword.get(opts, :additional_directories, []))
3432
|> Shared.maybe_add_flag("--skip-git-repo-check", Keyword.get(opts, :skip_git_repo_check))
33+
|> Shared.maybe_add_repeat("--config", config_values(opts))
3534
|> Kernel.++(normalize_string_list(Keyword.get(opts, :subcommand_args, [])))
3635
|> Shared.maybe_add_pair("--continuation-token", Keyword.get(opts, :continuation_token))
3736
|> Shared.maybe_add_pair("--cancellation-token", Keyword.get(opts, :cancellation_token))
3837
|> Shared.maybe_add_repeat("--image", Keyword.get(opts, :images, []))
3938
|> maybe_add_output_schema(Keyword.get(opts, :output_schema))
40-
|> Shared.maybe_add_repeat("--config", config_values(opts))
4139
|> maybe_add_prompt(Keyword.get(opts, :prompt))
4240

4341
{:ok,
@@ -87,12 +85,11 @@ defmodule Codex.Runtime.Exec.Profile do
8785
defp normalize_string_list(_values), do: []
8886

8987
defp model_value(opts) do
90-
Keyword.get(opts, :model) || model_payload_value(opts, :resolved_model)
91-
end
92-
93-
defp oss_enabled?(opts) do
94-
payload_backend = model_payload_value(opts, :provider_backend)
95-
payload_backend in [:oss, "oss"] || Keyword.get(opts, :oss) == true
88+
if local_provider_value(opts) do
89+
nil
90+
else
91+
Keyword.get(opts, :model) || model_payload_value(opts, :resolved_model)
92+
end
9693
end
9794

9895
defp local_provider_value(opts) do
@@ -107,10 +104,25 @@ defmodule Codex.Runtime.Exec.Profile do
107104
|> List.wrap()
108105
|> Enum.filter(&(is_binary(&1) and &1 != ""))
109106

110-
(Keyword.get(opts, :config_values, []) ++ payload_values)
107+
(local_model_provider_config_values(opts) ++
108+
Keyword.get(opts, :config_values, []) ++
109+
payload_values)
111110
|> Enum.uniq()
112111
end
113112

113+
defp local_model_provider_config_values(opts) do
114+
model = Keyword.get(opts, :model) || model_payload_value(opts, :resolved_model)
115+
116+
case {local_provider_value(opts), model} do
117+
{provider, model}
118+
when is_binary(provider) and provider != "" and is_binary(model) and model != "" ->
119+
[~s(model_provider="#{provider}"), ~s(model="#{model}")]
120+
121+
_other ->
122+
[]
123+
end
124+
end
125+
114126
defp model_payload_backend_metadata(opts) do
115127
opts
116128
|> Keyword.get(:model_payload, %{})

0 commit comments

Comments
 (0)