OrkaJS
Orka.JS

Agents Durables

Exécution d'agents persistante et reprennable

Construisez des agents tolérants aux pannes qui survivent aux crashes, supportent pause/reprise, et persistent l'état entre les redémarrages. Parfait pour workflows longs, tâches planifiées et opérations critiques.

Installation

npm install @orka-js/durable
# or
pnpm add @orka-js/durable
 
# Optional: for Redis storage
npm install redis
 
# Optional: for cron scheduling
npm install node-cron

Fonctionnalités Clés

Récupération Crash

Les agents reprennent depuis le dernier checkpoint après crash

Pause/Reprise

Mettez en pause l'exécution et reprenez plus tard

Persistance Jobs

Stockez l'état des jobs en mémoire ou Redis

Logique Retry

Retries automatiques avec backoff exponentiel

Jobs Planifiés

Planification cron pour tâches récurrentes

Support Streaming

Streamez les événements tout en persistant

Utilisation Basique

Enveloppez n'importe quel agent avec DurableAgent pour la persistence.

durable-agent.ts
import { DurableAgent, MemoryStore } from '@orka-js/durable';
import { StreamingToolAgent } from '@orka-js/agent';
import { OpenAIAdapter } from '@orka-js/openai';
 
const llm = new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! });
 
const agent = new StreamingToolAgent({
goal: 'Process customer support tickets',
tools: [ticketTool, emailTool],
}, llm);
 
// Wrap with DurableAgent
const store = new MemoryStore();
const durableAgent = new DurableAgent(agent, store, {
maxRetries: 3,
retryDelayMs: 2000,
metadata: { team: 'support' },
});
 
// Run a job
const job = await durableAgent.run('job_123', 'Handle ticket #456');
console.log(job.status); // "completed"
console.log(job.result); // Agent output
 
// Check job status later
const status = await durableAgent.status('job_123');
console.log(status?.completedAt);

# Backends de Stockage

Choisissez entre stockage en mémoire ou Redis.

stores.ts
// ─── In-Memory Store (default) ───────────────────────────────────────────────
import { MemoryStore } from '@orka-js/durable';
 
const memoryStore = new MemoryStore();
// Jobs are lost on restart — good for development
 
// ─── Redis Store (production) ─────────────────────────────────────────────────
import { RedisStore } from '@orka-js/durable';
import { createClient } from 'redis';
 
const redis = createClient({ url: 'redis://localhost:6379' });
await redis.connect();
 
const redisStore = new RedisStore(redis, {
keyPrefix: 'orka:jobs:',
ttlSeconds: 86400, // Jobs expire after 24h
});
 
const durableAgent = new DurableAgent(agent, redisStore);
 
// Jobs persist across restarts
const job = await durableAgent.run('job_456', 'Long-running task');
 
// Later, even after server restart:
const recovered = await durableAgent.status('job_456');
console.log(recovered?.status); // "completed"

# Pause & Reprise

Mettez en pause les jobs longs et reprenez-les plus tard.

pause-resume.ts
import { DurableAgent, MemoryStore } from '@orka-js/durable';
 
const durableAgent = new DurableAgent(agent, new MemoryStore());
 
// Start a job
const job = await durableAgent.run('job_789', 'Analyze large dataset');
 
// User requests to pause
await durableAgent.pause('job_789');
console.log('Job paused — state saved');
 
// Later, resume with optional new input
const resumed = await durableAgent.resume('job_789', 'Continue with updated params');
console.log(resumed.status); // "completed"
 
// Cancel a job
await durableAgent.cancel('job_789');
 
// List all jobs
const allJobs = await durableAgent.list();
const pending = await durableAgent.list({ status: 'pending' });
const failed = await durableAgent.list({ status: 'failed' });

# Jobs Planifiés

Exécutez des agents sur un planning cron.

scheduling.ts
import { DurableAgent, MemoryStore } from '@orka-js/durable';
import cron from 'node-cron';
 
const durableAgent = new DurableAgent(agent, new MemoryStore(), {
schedule: '0 9 * * MON', // Every Monday at 9 AM
onSchedule: async () => {
// Generate input for the scheduled run
const tickets = await db.getUnresolvedTickets();
return `Process ${tickets.length} pending tickets`;
},
});
 
// Start the scheduler
durableAgent.startScheduler();
console.log('Scheduler started — agent runs every Monday at 9 AM');
 
// Stop the scheduler
durableAgent.stopScheduler();

# Streaming avec Persistence

Streamez les événements tout en sauvegardant l'état du job.

streaming.ts
import { DurableAgent, RedisStore } from '@orka-js/durable';
 
const durableAgent = new DurableAgent(agent, redisStore);
 
// Stream events while persisting job state
for await (const event of durableAgent.runStream('job_999', 'Process invoice')) {
if (event.type === 'job_status') {
console.log('Job status:', event.job.status);
// job_status events are emitted at start, end, and on errors
} else if (event.type === 'token') {
process.stdout.write(event.token); // LLM streaming
} else if (event.type === 'tool_call') {
console.log(`Tool called: ${event.name}`);
} else if (event.type === 'done') {
console.log('\nAgent finished:', event.content);
}
}
 
// Job state is saved even if the process crashes mid-stream
// Resume from last checkpoint:
const recovered = await durableAgent.status('job_999');
if (recovered?.status === 'failed') {
await durableAgent.run('job_999', recovered.input); // Retry
}

# Retry Logic

retry.ts
import { DurableAgent, MemoryStore } from '@orka-js/durable';
 
const durableAgent = new DurableAgent(agent, new MemoryStore(), {
maxRetries: 5, // Retry up to 5 times
retryDelayMs: 1000, // Wait 1s between retries
});
 
// If the agent throws an error, it will retry automatically
const job = await durableAgent.run('job_retry', 'Flaky API call');
 
console.log(job.attempts); // Number of attempts made
console.log(job.status); // "completed" or "failed"
console.log(job.error); // Error message if failed

# Architecture

architecture.ts
// ─── Job Lifecycle ────────────────────────────────────────────────────────────
 
// 1. pending → Job created, not started yet
// 2. running → Agent is executing
// 3. paused → User paused execution
// 4. completed → Agent finished successfully
// 5. failed → Agent failed after max retries
// 6. cancelled → User cancelled the job
 
// ─── Job Schema ───────────────────────────────────────────────────────────────
 
interface DurableJob {
id: string;
input: string;
status: 'pending' | 'running' | 'paused' | 'completed' | 'failed' | 'cancelled';
result?: string;
error?: string;
attempts: number;
metadata?: Record<string, unknown>;
createdAt: Date;
updatedAt: Date;
completedAt?: Date;
}

Bonnes Pratiques Production

  • Utilisez RedisStore en production — MemoryStore est pour le dev uniquement
  • Définissez un TTL sur les jobs Redis pour éviter la croissance infinie du stockage
  • Surveillez les jobs échoués et configurez des alertes
  • Utilisez metadata pour taguer les jobs par équipe, priorité ou catégorie
  • Implémentez des agents idempotents — les retries doivent être sûrs