Build AI-powered applications with Solo for structured outputs, Agent for tool-enabled workflows, and Gig for orchestrating multi-step AI operations. Supports AWS Bedrock, OpenAI, and multiple LLM providers with type-safe outputs and event streaming.
Build sophisticated AI-powered applications using the @flatfile/improv TypeScript library. This skill helps you implement three complementary APIs: Solo for structured LLM outputs, Agent for complex tool-enabled workflows, and Gig for orchestrating multi-step AI operations.
First, install the required dependencies:
```bash
npm install @flatfile/improv zod
```
For AWS Bedrock integration:
```bash
npm install @aws-sdk/client-bedrock-runtime
```
**Use Solo when:**
**Use Agent when:**
**Use Gig when:**
Create a Solo instance for simple structured LLM calls:
```typescript
import { Solo, BedrockThreadDriver } from '@flatfile/improv';
import { z } from 'zod';
// Initialize driver
const driver = new BedrockThreadDriver({
model: 'anthropic.claude-3-haiku-20240307-v1:0',
temperature: 0.7,
});
// Define output schema
const sentimentSchema = z.object({
sentiment: z.enum(["positive", "negative", "neutral"]),
confidence: z.number().min(0).max(1),
keywords: z.array(z.string())
});
// Create Solo instance
const solo = new Solo({
driver,
outputSchema: sentimentSchema,
temperature: 0.1, // Lower temp for consistent classification
maxRetries: 3,
fallbackDriver: fallbackDriver // Optional backup driver
});
// Make a request
const result = await solo.ask("Analyze: 'This product exceeded my expectations!'");
// result.output is fully typed: { sentiment: "positive", confidence: 0.95, keywords: [...] }
```
**Solo Features:**
Create an Agent with custom tools and knowledge:
```typescript
import { Agent, Tool, Message } from '@flatfile/improv';
import { z } from 'zod';
// Define a custom tool
const searchTool = new Tool({
name: 'search_knowledge',
description: 'Search the knowledge base for relevant information',
parameters: z.object({
query: z.string().describe('The search query'),
category: z.enum(['technical', 'billing', 'general']).optional()
}),
followUpMessage: 'Review the search results and provide a comprehensive answer.',
executeFn: async (args) => {
const { query, category } = args;
// Implement your search logic
return {
results: [
{ title: 'Article 1', content: '...', relevance: 0.95 },
{ title: 'Article 2', content: '...', relevance: 0.87 }
]
};
}
});
// Create agent with knowledge and instructions
const agent = new Agent({
driver,
knowledge: [
{
fact: 'The system supports multiple payment methods.',
source: 'payment_docs.md',
timestamp: new Date()
},
{
fact: 'Technical support is available 24/7.',
source: 'support_policy.md'
}
],
instructions: [
{
instruction: 'Always search the knowledge base before answering.',
priority: 1
},
{
instruction: 'Provide specific references when citing information.',
priority: 2
}
],
tools: [searchTool],
systemPrompt: 'You are a helpful customer support assistant.'
});
// Create and use a thread
const thread = agent.createThread({
prompt: 'What payment methods are supported?',
onResponse: async (message) => {
console.log('Response:', message.content);
},
onToolExecution: async ({ tool, args, result }) => {
console.log(`Tool ${tool.name} executed:`, result);
}
});
await thread.send();
```
**Agent Features:**
Create complex workflows with dependencies:
```typescript
import { Gig, PieceDefinition } from '@flatfile/improv';
import { z } from 'zod';
// Create a Gig
const supportWorkflow = new Gig({
label: 'Customer Support Workflow',
driver,
onError: (error, pieceName) => {
console.error(`Error in ${pieceName}:`, error);
}
});
// Add pieces sequentially (default)
supportWorkflow
.add('classify', groove => {
const request = groove.feelVibe('request');
return `Classify this support request: "${request}"`;
}, {
outputSchema: z.enum(['technical', 'billing', 'general']),
temperature: 0.1
})
.add('sentiment', groove => {
const request = groove.feelVibe('request');
return `Analyze sentiment: "${request}"`;
}, {
outputSchema: z.enum(['positive', 'negative', 'neutral']),
temperature: 0.1
})
// Access previous results
.add('research', groove => {
const category = groove.recall('classify');
const request = groove.feelVibe('request');
return `Research solutions for ${category} issue: "${request}"`;
}, {
tools: [searchTool],
driver: cheaperModel // Override driver for cost savings
})
// Explicit parallel execution when needed
.parallel([
['check_status', 'Check current system status'],
['find_similar', 'Find similar resolved issues']
])
.add('respond', groove => {
const sentiment = groove.recall('sentiment');
const research = groove.recall('research');
const category = groove.recall('classify');
return `Generate a ${sentiment} tone response for a ${category} issue using: ${research}`;
});
// Execute the workflow
const results = await supportWorkflow.perform({
request: 'My invoice is incorrect and I need it fixed urgently!'
});
// Access individual results
console.log('Category:', results.recordings.get('classify'));
console.log('Sentiment:', results.recordings.get('sentiment'));
console.log('Final response:', results.recordings.get('respond'));
```
**Gig Features:**
Build modular components that can be shared:
```typescript
import { PieceDefinition } from '@flatfile/improv';
import { z } from 'zod';
// Define a reusable piece
export const sentimentAnalysis: PieceDefinition<"positive" | "negative" | "neutral"> = {
name: 'sentiment',
play: (groove) => {
const text = groove.feelVibe('text');
return `Analyze the emotional tone of: "${text}"`;
},
config: {
outputSchema: z.enum(['positive', 'negative', 'neutral']),
temperature: 0.1,
maxRetries: 2
},
meta: {
version: '1.0.0',
description: 'Analyzes emotional tone of text input',
author: 'Support Team'
}
};
// Use in any Gig
const workflow = new Gig({ label: 'Analysis', driver });
workflow.add(sentimentAnalysis);
// Or with custom configuration
workflow.add('custom_sentiment', sentimentAnalysis.play, {
...sentimentAnalysis.config,
temperature: 0.3 // Override default
});
```
**Organize pieces with evaluations:**
```
src/
pieces/
sentiment/
index.ts # Piece definition (production)
eval.ts # Evaluation data (dev only)
classification/
index.ts
eval.ts
```
Use the event system for observability:
```typescript
// Agent-level events
agent.on('agent.thread-added', ({ agent, thread }) => {
console.log('New thread created:', thread.id);
});
agent.on('agent.knowledge-added', ({ agent, knowledge }) => {
console.log('Knowledge added:', knowledge.fact);
});
// Thread-level events
thread.on('thread.response', ({ thread, message }) => {
console.log('Response received:', message.content);
});
thread.on('thread.max_steps_reached', ({ thread, steps }) => {
console.warn('Max steps reached:', steps);
});
// Tool-level events
tool.on('tool.execution.started', ({ tool, name, args }) => {
console.log(`Tool ${name} starting:`, args);
});
tool.on('tool.execution.completed', ({ tool, name, result }) => {
console.log(`Tool ${name} completed:`, result);
});
tool.on('tool.execution.failed', ({ tool, name, error }) => {
console.error(`Tool ${name} failed:`, error);
});
// Gig-level events
gig.on('gig.piece.started', ({ pieceName }) => {
console.log(`Starting piece: ${pieceName}`);
});
gig.on('gig.piece.completed', ({ pieceName, result }) => {
console.log(`Completed piece: ${pieceName}`, result);
});
```
Enable real-time streaming:
```typescript
// Solo streaming
const stream = await solo.stream('Analyze this long document...');
for await (const text of stream) {
process.stdout.write(text);
}
// Agent thread streaming
const thread = agent.createThread({ prompt: 'Explain quantum computing' });
const stream = await thread.stream();
for await (const chunk of stream) {
process.stdout.write(chunk);
}
```
Configure AWS credentials and Bedrock:
```typescript
import { BedrockThreadDriver } from '@flatfile/improv';
const driver = new BedrockThreadDriver({
model: 'anthropic.claude-3-sonnet-20240229-v1:0',
temperature: 0.7,
maxTokens: 4096,
// AWS credentials (optional - uses default AWS SDK chain)
region: 'us-east-1',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
}
});
```
**Available Bedrock models:**
Enable step-by-step reasoning for complex problems:
```typescript
const driver = new BedrockThreadDriver({
model: 'anthropic.claude-3-7-sonnet-20250219-v1:0',
temperature: 1,
reasoning_config: {
budget_tokens: 1024,
type: 'enabled'
}
});
const agent = new Agent({ driver });
const thread = agent.createThread({
systemPrompt: 'You are a helpful assistant that reasons through problems.',
prompt: 'How many people will live in the world in 2040?'
});
const result = await thread.send();
console.log(result.last()); // Includes reasoning steps
```
1. **Choose the appropriate API based on task complexity**
- Solo: Simple classification, extraction, structured output
- Agent: Tool usage, multi-step reasoning
- Gig: Multi-operation workflows with dependencies
2. **Design focused, single-purpose pieces**
- Keep pieces atomic and reusable
- Use descriptive names indicating purpose
- Override drivers for cost optimization
3. **Implement robust error handling**
- Configure retry logic with backoff
- Set up fallback drivers for critical operations
- Monitor events for debugging
4. **Leverage type safety**
- Define Zod schemas for all structured outputs
- Use `PieceDefinition<T>` for type-safe pieces
- Validate tool parameters with Zod
5. **Optimize workflow execution**
- Default to sequential for predictable flow
- Use `parallel()` only for independent operations
- Monitor token usage and costs
6. **Organize code effectively**
- Separate evaluation data into `eval.ts` files
- Create reusable pieces for common operations
- Use TypeScript for full type inference
```typescript
import { Gig, Agent, Tool, Solo } from '@flatfile/improv';
import { z } from 'zod';
// Define tools
const ticketSearchTool = new Tool({
name: 'search_tickets',
description: 'Search historical support tickets',
parameters: z.object({
query: z.string(),
category: z.string().optional()
}),
executeFn: async ({ query, category }) => {
// Search implementation
return { tickets: [...] };
}
});
// Create support workflow
const supportGig = new Gig({
label: 'Support Ticket Processing',
driver: bedrockDriver
});
supportGig
.add('extract_info', groove => {
const ticket = groove.feelVibe('ticket');
return `Extract structured information from: ${ticket}`;
}, {
outputSchema: z.object({
customer: z.string(),
issue: z.string(),
urgency: z.enum(['low', 'medium', 'high'])
})
})
.add('classify', groove => {
const info = groove.recall('extract_info');
return `Classify issue type: ${info.issue}`;
}, {
outputSchema: z.enum(['technical', 'billing', 'account'])
})
.add('research', groove => {
const classification = groove.recall('classify');
const info = groove.recall('extract_info');
return `Research solutions for ${classification} issue: ${info.issue}`;
}, {
tools: [ticketSearchTool]
})
.add('generate_response', groove => {
const info = groove.recall('extract_info');
const research = groove.recall('research');
return `Generate professional response based on: ${research}`;
});
// Execute
const results = await supportGig.perform({
ticket: 'Customer email content...'
});
```
This skill enables you to build sophisticated AI applications with type safety, event monitoring, and flexible orchestration using the @flatfile/improv library.
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/flatfileimprov-ai-agent-builder/raw