/** * Engram Team Research (orchestrated) * * Same research pipeline as research-team.ts, but driven by the orchestrator * via `runTeam()` with `EngramMemoryStore` plugged in as the team's * `sharedMemoryStore`. This means the orchestrator's built-in shared-memory * plumbing (task-result injection, coordinator summaries) flows through * Engram automatically — no manual engram_commit/engram_query calls needed * for inter-task context. * * The Engram toolkit tools are still registered so agents can query or audit * conflicts when they choose to. * * Works with every provider the framework supports. Set the provider and model * via environment variables: * * AGENT_PROVIDER — anthropic | openai | gemini | grok | copilot | deepseek | minimax | azure-openai * AGENT_MODEL — model name for the chosen provider * * Defaults to anthropic / claude-sonnet-4-6 when unset. * * Run: * npx tsx examples/integrations/with-engram/team-research.ts * * Prerequisites: * - API key env var for your chosen provider * - Engram server running at http://localhost:7474 * - ENGRAM_INVITE_KEY env var */ import { OpenMultiAgent } from '../../../src/index.js' import type { AgentConfig, OrchestratorEvent, SupportedProvider, } from '../../../src/index.js' import { EngramMemoryStore } from './engram-store.js' import { EngramToolkit } from './engram-toolkit.js' // --------------------------------------------------------------------------- // Provider / model configuration // --------------------------------------------------------------------------- const PROVIDER = (process.env.AGENT_PROVIDER ?? 'anthropic') as SupportedProvider const MODEL = process.env.AGENT_MODEL ?? 'claude-sonnet-4-6' const PROVIDER_ENV_KEYS: Record = { anthropic: 'ANTHROPIC_API_KEY', openai: 'OPENAI_API_KEY', gemini: 'GEMINI_API_KEY', grok: 'XAI_API_KEY', copilot: 'GITHUB_TOKEN', deepseek: 'DEEPSEEK_API_KEY', minimax: 'MINIMAX_API_KEY', 'azure-openai': 'AZURE_OPENAI_API_KEY', } const envKey = PROVIDER_ENV_KEYS[PROVIDER] if (envKey && !process.env[envKey]?.trim()) { console.error(`Missing ${envKey}: required for provider "${PROVIDER}".`) process.exit(1) } if (!process.env.ENGRAM_INVITE_KEY?.trim()) { console.error('Missing ENGRAM_INVITE_KEY: set your Engram workspace invite key in the environment.') process.exit(1) } // --------------------------------------------------------------------------- // Engram-backed shared memory store // --------------------------------------------------------------------------- const engramStore = new EngramMemoryStore() // --------------------------------------------------------------------------- // Engram tools via customTools so the orchestrator's per-agent registry // picks them up (runTeam builds its own registry per agent from built-ins // plus AgentConfig.customTools — an outer ToolRegistry is never seen). // --------------------------------------------------------------------------- const engramTools = new EngramToolkit().getTools() // --------------------------------------------------------------------------- // Agent configs // --------------------------------------------------------------------------- const TOPIC = 'the current state of AI agent memory systems' const researcher: AgentConfig = { name: 'researcher', model: MODEL, provider: PROVIDER, systemPrompt: `You are a research agent investigating: "${TOPIC}". Your job: 1. Think through the key dimensions of this topic (architectures, open problems, leading projects, recent breakthroughs). 2. For each finding, use engram_commit to record it as a shared fact with scope="research" and an appropriate confidence level. 3. Commit at least 5 distinct facts covering different aspects. Be specific and cite concrete systems or papers where possible.`, customTools: engramTools, maxTurns: 10, } const factChecker: AgentConfig = { name: 'fact-checker', model: MODEL, provider: PROVIDER, systemPrompt: `You are a fact-checking agent. Your job: 1. Use engram_query with topic="${TOPIC}" to retrieve what the researcher committed. 2. Evaluate each fact for accuracy and completeness. 3. If a fact is wrong or misleading, use engram_commit with operation="update" to commit a corrected version in the same scope. 4. After committing corrections, call engram_conflicts to review any auto-resolved conflicts. You are auditing the resolutions — do NOT manually resolve them unless an auto-resolution is clearly wrong. 5. Summarize your findings at the end.`, customTools: engramTools, maxTurns: 10, } const writer: AgentConfig = { name: 'writer', model: MODEL, provider: PROVIDER, systemPrompt: `You are a technical writer. Your job: 1. Use engram_query with topic="${TOPIC}" to retrieve all settled facts. 2. Synthesize the facts into a concise executive briefing (300-500 words). 3. Structure the briefing with clear sections: Overview, Key Systems, Open Challenges, and Outlook. 4. Only include claims that are grounded in the queried facts — do not fabricate or speculate beyond what the team has verified. 5. Output the briefing as your final response.`, customTools: engramTools, maxTurns: 6, } // --------------------------------------------------------------------------- // Progress tracking // --------------------------------------------------------------------------- function handleProgress(event: OrchestratorEvent): void { const ts = new Date().toISOString().slice(11, 23) switch (event.type) { case 'agent_start': console.log(`[${ts}] AGENT START → ${event.agent}`) break case 'agent_complete': console.log(`[${ts}] AGENT DONE ← ${event.agent}`) break case 'task_start': console.log(`[${ts}] TASK START ↓ ${event.task}`) break case 'task_complete': console.log(`[${ts}] TASK DONE ↑ ${event.task}`) break case 'error': console.error(`[${ts}] ERROR ✗ agent=${event.agent} task=${event.task}`) break } } // --------------------------------------------------------------------------- // Orchestrate // --------------------------------------------------------------------------- console.log('Engram Team Research (orchestrated)') console.log('='.repeat(60)) console.log(`Provider: ${PROVIDER}`) console.log(`Model: ${MODEL}`) console.log(`Topic: ${TOPIC}`) console.log(`Store: EngramMemoryStore → http://localhost:7474\n`) const orchestrator = new OpenMultiAgent({ defaultModel: MODEL, defaultProvider: PROVIDER, maxConcurrency: 1, onProgress: handleProgress, }) const team = orchestrator.createTeam('engram-research', { name: 'engram-research', agents: [researcher, factChecker, writer], sharedMemory: true, sharedMemoryStore: engramStore, maxConcurrency: 1, }) const result = await orchestrator.runTeam( team, `Research "${TOPIC}". The researcher explores and commits facts, the fact-checker ` + `verifies and corrects them (auditing any auto-resolved conflicts), and the writer ` + `produces an executive briefing from the settled facts.`, ) // --------------------------------------------------------------------------- // Output // --------------------------------------------------------------------------- console.log('\n' + '='.repeat(60)) console.log('RESULTS') console.log('='.repeat(60)) console.log(`\nSuccess: ${result.success}`) console.log('\nPer-agent results:') for (const [name, agentResult] of result.agentResults) { const status = agentResult.success ? 'OK' : 'FAILED' const tools = agentResult.toolCalls.length console.log(` ${name.padEnd(14)} [${status}] tool_calls=${tools}`) } // Print the writer's briefing if available const writerResult = result.agentResults.get('writer') if (writerResult?.success) { console.log('\n' + '='.repeat(60)) console.log('EXECUTIVE BRIEFING') console.log('='.repeat(60)) console.log() console.log(writerResult.output) } // Token summary console.log('\n' + '-'.repeat(60)) console.log('Token Usage:') console.log(` Total — input: ${result.totalTokenUsage.input_tokens}, output: ${result.totalTokenUsage.output_tokens}`) console.log(`\nView shared memory and conflicts: http://localhost:7474/dashboard`)