The SDK returns tuples for execution outcomes and uses a single structured error envelope: %AmpSdk.Error{}.

run/2 Return Values

AmpSdk.run/2 returns {:ok, result} or {:error, %AmpSdk.Error{}}:

case AmpSdk.run("do something") do
  {:ok, result} ->
    IO.puts(result)

  {:error, %AmpSdk.Error{kind: :no_result}} ->
    IO.puts("No result received")

  {:error, %AmpSdk.Error{kind: kind, message: message}} ->
    IO.puts("#{kind}: #{message}")
end

Common kind values include :cli_not_found, :command_timeout, :task_timeout, :command_failed, :execution_failed, and :invalid_configuration.

Exception Types

AmpSdk.Error can be raised in explicit bang APIs or direct constructor usage:

Use tuple returns where possible and pattern-match on %AmpSdk.Error{} in application code.

Shared-Core Transport Errors

The SDK no longer exposes a separate Amp-owned raw transport wrapper. Shared core transport failures still normalize into tagged tuples or exceptions under the hood:

{:error, {:transport, reason}}

Normalize these when you need the unified envelope:

error = AmpSdk.Error.normalize({:transport, :timeout}, kind: :transport_error)

Streaming Errors

When using AmpSdk.execute/2, errors are delivered inline as ErrorResultMessage structs rather than raising exceptions:

AmpSdk.execute("prompt")
|> Enum.each(fn
  %AmpSdk.Types.ErrorResultMessage{error: error, permission_denials: denials} ->
    IO.puts("Error: #{error}")
    if denials, do: IO.puts("Denied tools: #{inspect(denials)}")

  %AmpSdk.Types.ResultMessage{result: result} ->
    IO.puts("Success: #{result}")

  _ -> :ok
end)

Timeout Handling

Use Options.stream_timeout_ms for stream receive timeout control:

alias AmpSdk.Types.Options

AmpSdk.execute("slow task", %Options{stream_timeout_ms: 30_000})
|> Enum.to_list()

You can still wrap long-running calls in a Task if you need outer cancellation:

task = Task.async(fn -> AmpSdk.run("slow task") end)

case Task.yield(task, 30_000) || Task.shutdown(task) do
  {:ok, {:ok, result}} -> IO.puts(result)
  {:ok, {:error, %AmpSdk.Error{message: msg}}} -> IO.puts("Error: #{msg}")
  nil -> IO.puts("Timed out after 30s")
end