Skip to content
Development
Skill

/output-dev-agent-class

Use the Agent class for multi-step tool loops, conversation history, streaming progress, and reusable LLM agents. Use when building agents with skills, structured output, stateful conversations, or streaming callbacks.

From plugin
output
43753 skills11 agents1 command
Install
$ npx -y skills add growthxai/output --skill output-dev-agent-class --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/output-dev-agent-class

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use the Agent class for multi-step tool loops, conversation history, streaming progress, and reusable LLM agents. Use when building agents with skills, structured output, stateful conversations, or streaming callbacks.

SKILL.md

output-dev-agent-class.SKILL.md
name: output-dev-agent-class
description: Use the Agent class for multi-step tool loops, conversation history, streaming progress, and reusable LLM agents. Use when building agents with skills, structured output, stateful conversations, or streaming callbacks.
allowed-tools: [Read, Write, Edit]

Using the Agent Class

Overview

The `Agent` class uses an internal AI SDK `ToolLoopAgent` through composition with Output prompt files and the skills system. It does not inherit from `ToolLoopAgent`. Use it when you need multi-step tool execution, conversation history, or a reusable agent instance. For single-shot LLM calls without tools, `generateText` is simpler.

When to Use This Skill

  • Building multi-step agents that call tools in a loop
  • Using skills (lazy-loaded instructions) with an agent
  • Creating agents with structured output via `aiSdk.Output.object()`
  • Implementing stateful conversations with `messageStore`
  • Streaming Agent progress with `onChunk`
  • Deciding between `Agent` and `generateText`

Import Pattern

import { Agent, aiSdk } from '@outputai/llm';
import type { MessageStore } from '@outputai/llm';
import { z } from '@outputai/core';

`Agent` comes from `@outputai/llm`. Use `aiSdk.Output` for structured output. Import `z` from `@outputai/core` (never from `zod` directly). `MessageStore` is the type for a pluggable `getMessages` / `addMessages` store; implement it yourself.

Construction

The prompt file is loaded and rendered at construction time. Variables and tools are fixed at construction. Skills and `maxSteps` come from the prompt file. The agent is ready to call `generate()`, `generateWithStreaming()`, or `stream()` immediately.

const agent = new Agent( {
  prompt: 'writing_assistant@v1',
  variables: {
    content_type: input.contentType,
    focus: input.focus,
    content: input.content
  },
  output: aiSdk.Output.object( { schema: reviewSchema } )
} );

Constructor Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | `prompt` | `string` | *(required)* | Prompt file name (e.g. `'writing_assistant@v1'`) | | `promptDir` | `string` | - | Override the stack-resolved prompt directory | | `variables` | `PromptVariables` | - | Template variables rendered at construction | | `tools` | AI SDK tools | - | Caller tools; merged with prompt YAML tools (`load_skill` last) | | `stopWhen` | function or function[] | - | Custom stop condition (overrides prompt `maxSteps` when tools exist) | | `output` | `aiSdk.Output` | - | Structured output spec (e.g. `aiSdk.Output.object({ schema })`) | | `messageStore` | `MessageStore` | - | Pluggable store for multi-turn history |

generate()

Run the agent and return when complete:

const result = await agent.generate();
console.log( result.text );   // Generated text
console.log( result.output ); // Structured output (when using aiSdk.Output.object)
console.log( result.usage );  // Token counts

The result has the same shape as `generateText`: `text`, `result` (alias for `text`), `output`, `usage`, `finishReason`, `toolCalls`, etc.

Passing Additional Messages

Extend the conversation with extra messages:

const result = await agent.generate( {
  messages: [ { role: 'user', content: 'Focus on the introduction section.' } ]
} );

Messages are appended after the initial prompt messages (and any message-store history). You can also pass `abortSignal` and `toolChoice`.

generateWithStreaming()

Use `generateWithStreaming()` when you need progress callbacks and a complete result:

const result = await agent.generateWithStreaming( {
  onChunk( { chunk } ) {
    if ( chunk.type === 'text-delta' ) {
      process.stdout.write( chunk.text );
    }
  }
} );

The method behaves like `generate()` while using streaming internally. It returns the complete response, rejects on stream errors, and automatically appends messages to the configured message store. It accepts the same `messages`, `abortSignal`, and `toolChoice` as `generate()`, plus `onChunk`. Prefer it over `stream()` in Temporal activity steps unless direct access to the stream result is required.

stream()

Use `stream()` when direct control over `textStream` or `stream` is required. It accepts the same `messages`, `abortSignal`, and `toolChoice` as `generate()`, plus `onChunk`, `onEnd`, and `onError`:

const stream = await agent.stream();

for await ( const chunk of stream.textStream ) {
  process.stdout.write( chunk );
}

Like `streamText`, the stream result provides `textStream` and `stream` iterables, plus promise-based properties (`text`, `usage`, `finishReason`) that resolve on completion.

`stream()` appends messages to the message store in its wrapped `onEnd` when `finishReason` is not `'error'`. See `output-dev-llm-streaming` for streaming and error-handling guidance.

Structured Output

Use `aiSdk.Output.object()` to get typed responses:

const reviewSchema = z.object( {
  issues: z.array( z.string() ).describe( 'List of issues found' ),
  suggestions: z.array( z.string() ).describe( 'Actionable suggestions' ),
  score: z.number().describe( 'Quality score 0-100' ),
  summary: z.string().describe( 'Brief overall assessment' )
} );

const agent = new Agent( {
  prompt: 'writing_assistant@v1',
  variables: { content_type: 'documentation', focus: 'clarity', content: markdownContent },
  output: aiSdk.Output.object( { schema: reviewSchema } )
} );

const { output } = await agent.generate();
// output: { issues: string[], suggestions: string[], score: number, summary: string }

Use `.describe()` on schema fields instead of `.min()/.max()` for number constraints. Anthropic does not support `minimum`/`maximum` JSON Schema constraints in tool definitions.

Message Store

By default, Agent is stateless. Each `generate()` call starts fresh with only the initial prompt messages. Pass a

Read more
Ships withoutput

The open-source TypeScript framework for building AI workflows and agents. Designed for Claude Code — describe what you want, Claude builds it, with all the best practices already in place. One framework.

Get the whole plugin

Other skills on output.