226 lines
8.0 KiB
TypeScript
226 lines
8.0 KiB
TypeScript
/**
|
|
* Engram Research Team
|
|
*
|
|
* Three agents collaborate on a research topic using Engram shared memory:
|
|
*
|
|
* 1. **Researcher** — explores the topic and commits findings as facts
|
|
* 2. **Fact-checker** — verifies claims, commits corrections, and audits
|
|
* any auto-resolved conflicts
|
|
* 3. **Writer** — queries settled facts and produces a briefing document
|
|
*
|
|
* 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/research-team.ts
|
|
*
|
|
* Examples:
|
|
* # Anthropic (default)
|
|
* ANTHROPIC_API_KEY=sk-... ENGRAM_INVITE_KEY=ek_live_... npx tsx examples/integrations/with-engram/research-team.ts
|
|
*
|
|
* # OpenAI
|
|
* AGENT_PROVIDER=openai AGENT_MODEL=gpt-4o OPENAI_API_KEY=sk-... ENGRAM_INVITE_KEY=ek_live_... npx tsx examples/integrations/with-engram/research-team.ts
|
|
*
|
|
* # Gemini
|
|
* AGENT_PROVIDER=gemini AGENT_MODEL=gemini-2.5-flash GEMINI_API_KEY=... ENGRAM_INVITE_KEY=ek_live_... npx tsx examples/integrations/with-engram/research-team.ts
|
|
*
|
|
* # Grok
|
|
* AGENT_PROVIDER=grok AGENT_MODEL=grok-3 XAI_API_KEY=... ENGRAM_INVITE_KEY=ek_live_... npx tsx examples/integrations/with-engram/research-team.ts
|
|
*
|
|
* # DeepSeek
|
|
* AGENT_PROVIDER=deepseek AGENT_MODEL=deepseek-chat DEEPSEEK_API_KEY=... ENGRAM_INVITE_KEY=ek_live_... npx tsx examples/integrations/with-engram/research-team.ts
|
|
*
|
|
* Prerequisites:
|
|
* - API key env var for your chosen provider
|
|
* - Engram server running at http://localhost:7474
|
|
* - ENGRAM_INVITE_KEY env var
|
|
*/
|
|
|
|
import {
|
|
Agent,
|
|
ToolExecutor,
|
|
ToolRegistry,
|
|
registerBuiltInTools,
|
|
} from '../../../src/index.js'
|
|
import type { SupportedProvider } from '../../../src/index.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<string, string> = {
|
|
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)
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Shared setup
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const TOPIC = 'the current state of AI agent memory systems'
|
|
|
|
const engramTools = ['engram_commit', 'engram_query', 'engram_conflicts', 'engram_resolve']
|
|
|
|
function buildAgent(config: {
|
|
name: string
|
|
systemPrompt: string
|
|
}): Agent {
|
|
const registry = new ToolRegistry()
|
|
registerBuiltInTools(registry)
|
|
new EngramToolkit().registerAll(registry)
|
|
const executor = new ToolExecutor(registry)
|
|
|
|
return new Agent(
|
|
{
|
|
name: config.name,
|
|
model: MODEL,
|
|
provider: PROVIDER,
|
|
tools: engramTools,
|
|
systemPrompt: config.systemPrompt,
|
|
},
|
|
registry,
|
|
executor,
|
|
)
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Agents
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const researcher = buildAgent({
|
|
name: 'researcher',
|
|
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.`,
|
|
})
|
|
|
|
const factChecker = buildAgent({
|
|
name: 'fact-checker',
|
|
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.`,
|
|
})
|
|
|
|
const writer = buildAgent({
|
|
name: 'writer',
|
|
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.`,
|
|
})
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Sequential execution
|
|
// ---------------------------------------------------------------------------
|
|
|
|
console.log('Engram Research Team')
|
|
console.log('='.repeat(60))
|
|
console.log(`Provider: ${PROVIDER}`)
|
|
console.log(`Model: ${MODEL}`)
|
|
console.log(`Topic: ${TOPIC}\n`)
|
|
|
|
// Step 1: Research
|
|
console.log('[1/3] Researcher is exploring the topic...')
|
|
const researchResult = await researcher.run(
|
|
`Research "${TOPIC}" and commit your findings to Engram shared memory.`,
|
|
)
|
|
console.log(` Done — ${researchResult.toolCalls.length} tool calls, ` +
|
|
`${researchResult.tokenUsage.output_tokens} output tokens\n`)
|
|
|
|
// Step 2: Fact-check
|
|
console.log('[2/3] Fact-checker is verifying claims...')
|
|
const checkResult = await factChecker.run(
|
|
`Review and fact-check the research on "${TOPIC}" in Engram shared memory. ` +
|
|
`Commit corrections and audit any auto-resolved conflicts.`,
|
|
)
|
|
console.log(` Done — ${checkResult.toolCalls.length} tool calls, ` +
|
|
`${checkResult.tokenUsage.output_tokens} output tokens\n`)
|
|
|
|
// Step 3: Write briefing
|
|
console.log('[3/3] Writer is producing the briefing...')
|
|
const writeResult = await writer.run(
|
|
`Query Engram for settled facts on "${TOPIC}" and write an executive briefing.`,
|
|
)
|
|
console.log(` Done — ${writeResult.toolCalls.length} tool calls, ` +
|
|
`${writeResult.tokenUsage.output_tokens} output tokens\n`)
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Output
|
|
// ---------------------------------------------------------------------------
|
|
|
|
console.log('='.repeat(60))
|
|
console.log('EXECUTIVE BRIEFING')
|
|
console.log('='.repeat(60))
|
|
console.log()
|
|
console.log(writeResult.output)
|
|
console.log()
|
|
console.log('-'.repeat(60))
|
|
|
|
// Token summary
|
|
const agents = [
|
|
{ name: 'researcher', result: researchResult },
|
|
{ name: 'fact-checker', result: checkResult },
|
|
{ name: 'writer', result: writeResult },
|
|
]
|
|
|
|
let totalInput = 0
|
|
let totalOutput = 0
|
|
|
|
console.log('\nToken Usage:')
|
|
for (const { name, result } of agents) {
|
|
totalInput += result.tokenUsage.input_tokens
|
|
totalOutput += result.tokenUsage.output_tokens
|
|
console.log(
|
|
` ${name.padEnd(14)} — input: ${result.tokenUsage.input_tokens}, output: ${result.tokenUsage.output_tokens}`,
|
|
)
|
|
}
|
|
console.log('-'.repeat(60))
|
|
console.log(` ${'TOTAL'.padEnd(14)} — input: ${totalInput}, output: ${totalOutput}`)
|
|
|
|
console.log(`\nView shared memory and conflicts: http://localhost:7474/dashboard`)
|