# `A2UIAgent.Express.Parser`
[🔗](https://github.com/a2ui-elixir/a2ui/blob/v0.1.1/umbrella/apps/a2ui_agent/lib/a2ui_agent/express/parser.ex#L1)

Reads model output written in Express: conversational text with
Express blocks between `<a2ui>` and `</a2ui>` tags.

    {:ok, parser} = A2UIAgent.Express.Parser.new(catalogs, surface_id: "main")

    {:ok, parts} =
      A2UIAgent.Express.Parser.parse_response(parser, """
      Here it is.
      <a2ui>
      root = Text("Hello")
      </a2ui>
      """)

    parts
    #=> [{:text, "Here it is."}, {:a2ui, [%{"version" => "v1.0", "createSurface" => ...}]}]

Blocks are found with `A2UIAgent.BlockLexer` (a closing tag inside a
string or comment does not close a block) and compiled with
`A2UIAgent.Express.Compiler`. Express is not read incrementally: a
response is parsed once it is complete.

Parts are `{:text, text}` and `{:a2ui, messages}`. `unwrap/1` returns
raw parts, `{:text, text}` and `{:a2ui_raw, block, final?}`.

# `part`
*since 0.1.0* 

```elixir
@type part() :: {:text, String.t()} | {:a2ui, [map()]}
```

A part of a parsed response.

# `t`
*since 0.1.0* 

```elixir
@type t() :: %A2UIAgent.Express.Parser{
  catalogs: A2UIAgent.Express.Catalogs.t(),
  surface_id: String.t()
}
```

# `compile`
*since 0.1.0* 

```elixir
@spec compile(t(), String.t(), keyword()) ::
  {:ok, [map()]} | {:error, A2UICore.Error.t()}
```

Compiles one block (see `A2UIAgent.Express.Compiler.compile/3`). With
`final: false`, the statements before the block's first syntax error
compile.

# `decompile`
*since 0.1.0* 

```elixir
@spec decompile(t(), [map()] | map(), keyword()) ::
  {:ok, String.t()} | {:error, A2UICore.Error.t()}
```

Writes messages back as Express; see `A2UIAgent.Express.Decompiler.decompile/3`
for the options.

# `has_format_content?`
*since 0.1.0* 

```elixir
@spec has_format_content?(String.t(), keyword()) :: boolean()
```

Whether `content` holds an `<a2ui>` block; with `complete: true`, a
block whose closing tag has arrived.

# `new`
*since 0.1.0* 

```elixir
@spec new([A2UICore.Catalog.t()], keyword()) ::
  {:ok, t()} | {:error, A2UICore.Error.t()}
```

Creates a parser for `catalogs`. Options: `:surface_id`, the surface
of statements before any `surface` line (default `"main"`), and
`:version`, the protocol version to write (default: the catalogs').

# `parse_response`
*since 0.1.0* 

```elixir
@spec parse_response(t(), String.t(), keyword()) ::
  {:ok, [part()]} | {:error, A2UICore.Error.t()}
```

Parses a complete model response into parts.

With `wrapped: false` the whole response is one block. Otherwise each
block is compiled in turn (a block whose closing tag never came as not
final) and the first failure is returned.

# `supports_streaming?`
*since 0.1.0* 

```elixir
@spec supports_streaming?() :: false
```

Express is read once a response is complete, never chunk by chunk.

# `unwrap`
*since 0.1.0* 

```elixir
@spec unwrap(String.t()) :: [A2UIAgent.BlockLexer.raw_part()]
```

Splits model output into text and raw Express blocks.

# `wrap`
*since 0.1.0* 

```elixir
@spec wrap([A2UIAgent.BlockLexer.raw_part() | {:a2ui_raw, String.t()}]) :: String.t()
```

Writes parts out as model output, joined by newlines: text as it is,
each block between tags.

# `wrap_decompiled_blocks`
*since 0.1.0* 

```elixir
@spec wrap_decompiled_blocks([String.t()]) :: String.t()
```

Encloses decompiled blocks in one pair of tags.

---

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