AI Structured Output
Use ClaudeGenerateDocument to have the LLM generate structured data conforming to a Zod schema. The output is validated and stored as a typed document.
Define a Document
import { z } from 'zod';
import { Document } from '@loopstack/common';
export const FileDocumentSchema = z
.object({
filename: z.string(),
description: z.string(),
code: z.string(),
})
.strict();
export type FileDocumentType = z.infer<typeof FileDocumentSchema>;
@Document({
schema: FileDocumentSchema,
uiConfig: __dirname + '/file-document.yaml',
})
export class FileDocument {
filename: string;
description: string;
code: string;
}Workflow Example
import { ClaudeGenerateDocument, ClaudeMessageDocument } from '@loopstack/claude-module';
import { BaseWorkflow, DocumentEntity, Final, Initial, InjectTool, Transition, Workflow } from '@loopstack/common';
@Workflow({
uiConfig: __dirname + '/prompt-structured-output.ui.yaml',
schema: z.object({
language: z.enum(['python', 'javascript', 'java', 'cpp', 'ruby', 'go', 'php']).default('python'),
}),
})
export class PromptStructuredOutputWorkflow extends BaseWorkflow {
@InjectTool() claudeGenerateDocument: ClaudeGenerateDocument;
llmResult?: DocumentEntity<FileDocumentType>;
@Initial({ to: 'ready' })
async greeting() {
const args = this.ctx.args as { language: string };
await this.repository.save(
ClaudeMessageDocument,
{
role: 'assistant',
content: [{ type: 'text', text: `Creating a 'Hello, World!' script in ${args.language}...` }],
},
{ id: 'status' },
);
}
@Transition({ from: 'ready', to: 'prompt_executed' })
async prompt() {
const args = this.ctx.args as { language: string };
const result = await this.claudeGenerateDocument.call({
claude: { model: 'claude-sonnet-4-6' },
response: { document: FileDocument },
prompt: this.render(__dirname + '/templates/prompt.md', { language: args.language }),
});
this.llmResult = result.data as DocumentEntity<FileDocumentType>;
}
@Final({ from: 'prompt_executed' })
async respond() {
await this.repository.save(
ClaudeMessageDocument,
{
role: 'assistant',
content: [{ type: 'text', text: `Successfully generated: ${this.llmResult?.content?.description ?? ''}` }],
},
{ id: 'status' },
);
}
}How It Works
claudeGenerateDocumentcalls the LLM with a structured output schema derived from the document’s Zod schema- The LLM response is validated against the schema
- The result is returned as a
DocumentEntitywith typed content - The document is automatically saved and displayed in the UI
Key Parameters
await this.claudeGenerateDocument.call({
claude: { model: 'claude-sonnet-4-6' },
response: {
document: FileDocument, // Target document class
id: 'unique-id', // Optional: custom document ID
},
prompt: 'Generate a Hello World script.',
});Registry References
- prompt-structured-output-example-workflow — Generates structured code files with filename, description, and code fields using Claude
Last updated on