# `Snodo.Result`
[🔗](https://github.com/joshrotenberg/snodo/blob/v0.2.0/lib/snodo/result.ex#L1)

A protocol-neutral handler result shaped later by the selected dialect.

`error/2` builds a *successful* `tools/call` response carrying
`isError: true`. That is what a failed upstream call, a rejected domain
precondition, or any other outcome the tool itself understands should
return. It is not the same as returning `{:error, %Snodo.Error{}}` from a
handler, which makes the whole JSON-RPC request fail. See `Snodo.Tool` for
which to reach for.

Values handed to `structured/2` and to the content builders must be JSON
values, meaning string keys and no atoms. `Snodo.JSONValue.encodable!/1`
converts an atom-keyed domain value into one.

# `kind`

```elixir
@type kind() ::
  :text
  | :structured
  | :content
  | :tools
  | :resources
  | :resource_templates
  | :resource_read
  | :prompts
  | :prompt_get
  | :completion
  | :subscription
  | :input_required
  | :error
  | :raw
  | :wire
```

# `t`

```elixir
@type t() :: %Snodo.Result{kind: kind(), metadata: map(), value: term()}
```

# `completion`

```elixir
@spec completion([String.t()], keyword()) :: t()
```

Builds a ranked completion result with optional cardinality hints.

# `content`

```elixir
@spec content(map() | [map()], keyword()) :: t()
```

Builds a `tools/call` result from content blocks.

`contents` is one content block map, such as an `"image"` or embedded
`"resource"` block, or a list of them. It becomes the result's `"content"`
unchanged, with `"isError" => false`.

Options:

  * `:metadata` - as for `text/2`.

# `error`

```elixir
@spec error(String.t(), keyword()) :: t()
```

Builds a `tools/call` result that reports a failure.

`message` becomes one `"text"` content block and `"isError"` is `true`. The
JSON-RPC request itself succeeds. Output schema validation is skipped.

Options:

  * `:metadata` - as for `text/2`.

# `input_required`

```elixir
@spec input_required(keyword()) :: t()
```

Requests another round trip from an ordinary tool, resource, or prompt.

Provide `:input_requests` (a map of server-assigned IDs to bare input
requests), `:request_state` (an opaque string), or both. For example:

    Result.input_required(input_requests: %{"approval" => request})

The current request ends when this result is sent. The client may retry with
a fresh ID and new `Snodo.Context.input_responses` / `request_state` values, or
never retry. Keep side effects explicit and defer them until inputs are ready.
Use `Snodo.MRTR.State` when state influences business logic; a plain string is
not integrity protection. The dialect validates placement and peer support.

Prefer a nonempty input map or a state-only continuation. The pinned official
TypeScript client rejects an empty `inputRequests` without state, even though
the protocol schema permits that field to be an empty map.

# `normalize`

```elixir
@spec normalize(t() | term()) :: t()
```

Converts a tool's `{:ok, value}` payload into a result.

A `Snodo.Result` is returned unchanged, a binary becomes `text/1`, and any
other value becomes `structured/1`.

# `prompt_get`

```elixir
@spec prompt_get([map()] | map(), keyword()) :: t()
```

Builds a `prompts/get` result.

`messages` is one message or a list of them, built with
`Snodo.Prompt.message/2`.

Options:

  * `:description` - a string sent as the result's `"description"`.
  * `:metadata` - as for `text/2`.

# `prompts`

```elixir
@spec prompts([term()]) :: t()
```

Builds a `prompts/list` result from `Snodo.Prompt.Definition` structs.

`Snodo.Router.dispatch/5` returns this for `:prompts_list`.

# `raw`

```elixir
@spec raw(term()) :: t()
```

Wraps a map that is already in wire shape.

As a `tools/call` result, the map is sent as the result, with `"content"`
defaulting to `[]` and `"isError"` to `false`. When the tool declares an
output schema, the map must carry `"structuredContent"`, which is validated.
Extensions also return `raw/1` from `c:Snodo.Extension.dispatch/3` and shape
the value in `c:Snodo.Extension.shape_result/3`.

# `resource_read`

```elixir
@spec resource_read([map()] | map(), keyword()) :: t()
```

Builds a `resources/read` result.

`contents` is one resource-content map or a list of them, built with
`Snodo.Resource.text/3`, `Snodo.Resource.json/3`, or `Snodo.Resource.blob/3`.

Options:

  * `:metadata` - a map. String keys are added to the result's `"_meta"`.
    The atom keys `:ttl_ms` (a non-negative integer) and `:cache_scope`
    (`"public"` or `"private"`) override the runtime's `resources_cache`
    policy for this read.

# `resource_templates`

```elixir
@spec resource_templates([term()]) :: t()
```

Builds a `resources/templates/list` result from `Snodo.Resource.Definition`
structs.

`Snodo.Router.dispatch/5` returns this for `:resource_templates_list`.

# `resources`

```elixir
@spec resources([term()]) :: t()
```

Builds a `resources/list` result from `Snodo.Resource.Definition` structs.

`Snodo.Router.dispatch/5` returns this for `:resources_list`.

# `structured`

```elixir
@spec structured(term(), keyword()) :: t()
```

Builds a structured result from a JSON value.

As a `tools/call` result, `value` becomes `"structuredContent"` and is also
encoded as JSON into one `"text"` content block. When the tool declares an
output schema, the runtime's schema validator checks `value` against it.

Options:

  * `:metadata` - as for `text/2`.

# `text`

```elixir
@spec text(String.t(), keyword()) :: t()
```

Builds a text result.

As a `tools/call` result it becomes one `"text"` content block with
`"isError" => false`.

Options:

  * `:metadata` - a map. String keys are added to the result's `"_meta"`;
    atom keys are not sent.

# `tools`

```elixir
@spec tools([map()]) :: t()
```

Builds a `tools/list` result from `Snodo.Tool.Definition` structs.

`Snodo.Router.dispatch/5` returns this for `:tools_list`. The server then
pages it and adds cache hints.

# `wire`

```elixir
@spec wire(map(), keyword()) :: t()
```

Marks a JSON object as an already dialect-shaped result.

This escape hatch is intended for protocol dialects and negotiated extensions
that add a polymorphic result shape to an existing core method. The selected
dialect still stamps response metadata and the server still validates that the
final JSON-RPC response is JSON-compatible.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
