Skip to content

agui://

Expose a Helix agent to a frontend via the CopilotKit AG-UI (Agent-User Interaction) protocol. The consumer stands up an HTTP POST endpoint that accepts a JSON RunAgentInput, runs the agent through the route's pipeline, and streams TEXT_MESSAGE_* events back as Server-Sent Events. Use agui:// when you want a chat-style streaming endpoint that drops into CopilotKit / Vercel AI SDK / any AG-UI-compatible client.

For richer declarative UI (cards, columns, forms), see a2ui://. For the more powerful peer-to-peer protocol, see a2a-server://.

Consumer-only — CreateProducer returns an error.

URI shape

agui://<host:port>/<path>?<params>
  • <host:port> — listen address. If port is missing, 4100 is used.
  • <path> — HTTP path (default /).

Parameters

Param Type Default Producer/Consumer/Both Description
(path) host string — Consumer Host:port to listen on.
(path) path string / Consumer HTTP path.
name string helix-agui Consumer Server identity (informational).
native boolean false Consumer When true, the route's own processor pipeline handles the request directly. When false (discovery mode), the server scans every direct:// / seda:// workflow and routes calls to the first one found.
corsOrigin string * Consumer Access-Control-Allow-Origin value. Set to a specific origin in production.

HTTP surface

POST <path>

Body: AG-UI RunAgentInput JSON. The server:

  1. Extracts the last user message (text + any multimodal parts: images, audio, files).
  2. If only attachments are present (no text), auto-generates a prompt based on the dominant content type ("Analyze this image and describe what you see.", etc.).
  3. For non-image binary files (PDF, CSV, JSON, YAML, plain text, ...), inlines the content as text:
  4. text/* and JSON/XML/YAML → embedded verbatim.
  5. PDFs → built-in text extraction; falls back to OCR (configurable via helix.ocr.{backend,endpoint,api_key} config / HELIX_OCR_* env, default backend docling on http://localhost:5001). Output is truncated to 100 K chars to fit LLM context.
  6. other binaries → stub text noting the upload.
  7. Materializes an exchange and runs it through the pipeline (or, in discovery mode, hands it to the first invocable producer).
  8. Streams responses back as AG-UI events.

Request bodies are capped at 10 MB. CORS preflight (OPTIONS) is supported.

Event flow

For every request the server emits:

RUN_STARTED { threadID, runID }
TEXT_MESSAGE_START { messageID, role: "assistant" }
TEXT_MESSAGE_CONTENT { messageID, delta }
...
TEXT_MESSAGE_END { messageID }
RUN_FINISHED { threadID, runID }

threadID is taken from the input (or generated). The same threadID is used as the session key when a session store is configured.

Per-call exchange shape

Header Description
HelixStream "true" — downstream producers use streaming.
HelixAGUIThreadID The AG-UI thread (== session id when session store is on).
HelixAGUIRunID The AG-UI run id.
HelixAGUIState JSON of the input's state field (if any).
HelixAGUITools JSON of the input's tools field (if any).

Body: the user text, or — when files / images / audio are attached — a multipart body (exchange.SetMultipartBody). The pipeline can return:

Body type Effect
*llm.StreamReader Each non-empty chunk becomes a TEXT_MESSAGE_CONTENT event.
chan string / <-chan string Same — driven by channel.
anything else The full body as one TEXT_MESSAGE_CONTENT event.

After the stream finishes, the assembled assistant text is appended to the session's conversation history, and a helix.response.content exchange property is set for tracer / audit downstream.

Examples

Single-agent chat endpoint for CopilotKit:

agents:
  - id: helper
    type: react
    model: { provider: openai, model: gpt-4o }
    system-prompt: "You are a helpful assistant."

workflows:
  - id: chat
    trigger:
      uri: agui://0.0.0.0:4100/?corsOrigin=https://app.example.com
    steps:
      - target: agent://helper

CopilotKit config (frontend):

import { CopilotKit } from "@copilotkit/react-core";

<CopilotKit runtimeUrl="http://helix.local:4100/">
  <ChatUI />
</CopilotKit>

Multiple workflows on different paths:

workflows:
  - id: agui-research
    trigger: { uri: agui://0.0.0.0:4100/research?native=true }
    steps:
      - target: agent://researcher

  - id: agui-translate
    trigger: { uri: agui://0.0.0.0:4100/translate?native=true }
    steps:
      - target: agent://translator

(With native=true the route's own pipeline handles the request — no auto-discovery scan; one AG-UI server per workflow.)

Discovery mode — point at an existing direct:// workflow:

workflows:
  - id: ask
    trigger: { uri: direct://ask }
    steps:
      - target: agent://helper

  - id: agui-server
    trigger: { uri: agui://0.0.0.0:4100/ }   # discovers the 'ask' route
    steps: []

Behavior notes

  • Two modes — discovery (default) scans direct:// / seda:// workflows; native (native=true) uses the route's own pipeline. Discovery is convenient when a single AG-UI server fronts many internal workflows; native gives you per-endpoint configuration.
  • PDF handling — when a PDF is uploaded, the server tries pkg/rag/ingest.NewPDFReader first (fast text extraction). If that returns < 50 chars, OCR fallback runs. Embedded base64 image data URIs are stripped from the OCR output (sanitizePDFContent) to keep context windows sane.
  • Truncation — extracted document text is capped at 100 000 chars before reaching the LLM.
  • Session history — when a session store is configured, the user's prompt and the streamed assistant response are appended to sess.ConversationHistory.
  • CORS exposure — Content-Type and X-Helix-Session are listed in Access-Control-Expose-Headers so the frontend can read them.

Source

pkg/component/agui/server.go

See also