Browse documentation

Start

One-off agent

Compile a Git-tracked prompt and run one provider call without Durable Objects or a Cloudflare account.

Use this path for a request that does not need a conversation to survive a disconnect. It is useful for a CLI command, a form submission, a build step, or a small background task.

The one-off path still gives you typed prompt inputs, model selection, thinking level, tool declarations, limits, provider normalization, and Zod validation. Add a durable thread when the caller needs reconnectable streaming or multi-turn state.

Create the prompt

---
name: answer-support-question
description: Answer one support question from approved product facts.
model: inherit
thinking: medium
tools:
  - docs.search
input:
  customer.name: string
  question: string
limits:
  steps: 8
  tools: 12
---

You are a support agent.

Use docs.search for product facts. Do not invent policy.
Answer {{customer.name}} clearly and briefly.

Question:
{{question}}

The file path becomes its stable slug:

prompts/support/answer.prompt.md → support/answer

Keep this file in Git. A changed prompt creates a new source hash when you compile it or publish it through a host control plane.

Compile and call an adapter

Flary’s provider adapters use one normalized request shape. The adapter can complete a request or return normalized stream events.

import { readFile } from "node:fs/promises";
import { compilePrompt } from "flary/prompts";
import {
  OpenAICompatibleAdapter,
  ProviderAdapterRegistry,
} from "flary/providers";

const source = {
  path: "prompts/support/answer.prompt.md",
  content: await readFile(
    "prompts/support/answer.prompt.md",
    "utf8",
  ),
};

const prompt = await compilePrompt(source, {
  callerModel: "openai/gpt-5.6",
  values: {
    customer: { name: "Ada" },
    question: "How do I change my plan?",
  },
});

if (!prompt.resolvedModel) {
  throw new Error("Select a model with callerModel or prompt front matter");
}

const providers = new ProviderAdapterRegistry({
  adapters: [
    new OpenAICompatibleAdapter({
      id: "openai",
      baseUrl: "https://api.openai.com/v1",
      apiKey: process.env.OPENAI_API_KEY,
    }),
  ],
});

const adapter = providers.resolve(prompt.resolvedModel.provider);
const response = await adapter.complete({
  model: prompt.resolvedModel.model,
  messages: [{ role: "user", content: prompt.rendered }],
  reasoningEffort: prompt.thinking === "inherit" ? undefined : prompt.thinking,
});

console.log(response.content);

The adapter never receives a prompt file path or a secret-like input value. Your application resolves credentials in server code and passes them to the adapter constructor or a Flary provider resolver.

Stream a one-off call

for await (const event of adapter.stream({
  model: prompt.resolvedModel.model,
  messages: [{ role: "user", content: prompt.rendered }],
})) {
  if (event.type === "text_delta") process.stdout.write(event.delta);
  if (event.type === "finish") console.log("\n", event.response.usage);
  if (event.type === "error") console.error(event.error);
}

Use the durable run API when a stream must resume after the browser, request, or Worker isolate ends. A one-off stream cannot restore an interrupted tool write.

Add Zod output validation

The normalized provider request supports JSON output. Validate the result in the application boundary:

import { z } from "zod";

const answer = z.object({
  message: z.string(),
  citations: z.array(z.string()),
});

const response = await adapter.complete({
  model: prompt.resolvedModel.model,
  messages: [{ role: "user", content: prompt.rendered }],
  responseFormat: {
    type: "json_object",
    schema: z.toJSONSchema(answer),
  },
});

const value = answer.parse(JSON.parse(response.content));

When to move to a thread

Use a durable thread if any of these are true:

  • The user can leave and return while work continues.
  • The agent needs more than one turn.
  • A tool can wait for approval or user input.
  • The agent edits a workspace or runs a build.
  • The product needs event replay, usage records, or Recall.

Continue with Durable threads and Self-hosting.