Current section

Files

Jump to
codex_sdk examples live_app_server_streaming.exs
Raw

examples/live_app_server_streaming.exs

Mix.Task.run("app.start")
Code.require_file(Path.expand("support/example_helper.exs", __DIR__))
alias CodexExamples.Support
Support.init!()
alias Codex.RunResultStreaming
alias Codex.Events
alias Codex.Items
defmodule CodexExamples.LiveAppServerStreaming do
@moduledoc false
@default_prompt "Reply with exactly ok and nothing else."
def main(argv) do
prompt =
case argv do
[] -> @default_prompt
values -> Enum.join(values, " ")
end
case Support.ensure_remote_working_directory() do
:ok ->
:ok
{:skip, reason} ->
IO.puts("SKIPPED: #{reason}")
System.halt(0)
end
codex_opts = Support.codex_options!()
:ok = Support.ensure_app_server_supported(codex_opts)
{:ok, conn} = Codex.AppServer.connect(codex_opts, init_timeout_ms: 30_000)
try do
{:ok, thread} =
Codex.start_thread(
codex_opts,
Support.thread_opts!(%{
transport: {:app_server, conn},
working_directory: Support.example_working_directory()
})
)
IO.puts("""
Streaming over app-server.
prompt: #{prompt}
""")
case Codex.Thread.run_streamed(thread, prompt, %{timeout_ms: 120_000}) do
{:ok, stream} ->
stream
|> RunResultStreaming.raw_events()
|> Enum.each(&print_event/1)
IO.puts("\nusage: #{inspect(RunResultStreaming.usage(stream))}")
{:error, reason} ->
Mix.raise("Streaming run failed: #{inspect(reason)}")
end
after
:ok = Codex.AppServer.disconnect(conn)
end
end
defp print_event(%Events.ItemAgentMessageDelta{item: %{"text" => delta}})
when is_binary(delta) do
IO.write(delta)
end
defp print_event(%Events.ItemCompleted{item: %Items.AgentMessage{text: text}}) do
if is_binary(text) and String.trim(text) != "" do
IO.puts("\n\n[agent_message.completed]\n#{text}\n")
end
end
defp print_event(%Events.TurnCompleted{} = event) do
IO.puts("""
[turn.completed]
status: #{inspect(event.status)}
started_at: #{optional_field(event.started_at)}
completed_at: #{optional_field(event.completed_at)}
duration_ms: #{optional_field(Events.turn_duration_ms(event))}
time_to_first_token_ms: #{optional_field(event.time_to_first_token_ms)}
terminal_error: #{optional_error(event.error)}
""")
end
defp print_event(_other), do: :ok
defp optional_field(nil), do: "not emitted by this CLI/lane"
defp optional_field(value), do: inspect(value)
defp optional_error(nil), do: "none"
defp optional_error(error), do: inspect(error)
end
CodexExamples.LiveAppServerStreaming.main(System.argv())