ai-functions 2.1.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -4
- package/CHANGELOG.md +68 -1
- package/README.md +397 -157
- package/dist/ai-promise.d.ts +50 -3
- package/dist/ai-promise.d.ts.map +1 -1
- package/dist/ai-promise.js +410 -51
- package/dist/ai-promise.js.map +1 -1
- package/dist/ai-schemas.d.ts +56 -0
- package/dist/ai-schemas.d.ts.map +1 -0
- package/dist/ai-schemas.js +53 -0
- package/dist/ai-schemas.js.map +1 -0
- package/dist/ai.d.ts +16 -242
- package/dist/ai.d.ts.map +1 -1
- package/dist/ai.js +54 -837
- package/dist/ai.js.map +1 -1
- package/dist/batch/anthropic.d.ts +6 -4
- package/dist/batch/anthropic.d.ts.map +1 -1
- package/dist/batch/anthropic.js +83 -145
- package/dist/batch/anthropic.js.map +1 -1
- package/dist/batch/bedrock.d.ts +8 -30
- package/dist/batch/bedrock.d.ts.map +1 -1
- package/dist/batch/bedrock.js +155 -338
- package/dist/batch/bedrock.js.map +1 -1
- package/dist/batch/cloudflare.d.ts +8 -20
- package/dist/batch/cloudflare.d.ts.map +1 -1
- package/dist/batch/cloudflare.js +68 -189
- package/dist/batch/cloudflare.js.map +1 -1
- package/dist/batch/google.d.ts +6 -20
- package/dist/batch/google.d.ts.map +1 -1
- package/dist/batch/google.js +70 -238
- package/dist/batch/google.js.map +1 -1
- package/dist/batch/index.d.ts +4 -1
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js +4 -1
- package/dist/batch/index.js.map +1 -1
- package/dist/batch/memory.d.ts +1 -1
- package/dist/batch/memory.d.ts.map +1 -1
- package/dist/batch/memory.js +14 -10
- package/dist/batch/memory.js.map +1 -1
- package/dist/batch/openai.d.ts +11 -14
- package/dist/batch/openai.d.ts.map +1 -1
- package/dist/batch/openai.js +52 -156
- package/dist/batch/openai.js.map +1 -1
- package/dist/batch/provider.d.ts +111 -0
- package/dist/batch/provider.d.ts.map +1 -0
- package/dist/batch/provider.js +233 -0
- package/dist/batch/provider.js.map +1 -0
- package/dist/batch-map.d.ts.map +1 -1
- package/dist/batch-map.js +23 -17
- package/dist/batch-map.js.map +1 -1
- package/dist/batch-queue.d.ts +65 -0
- package/dist/batch-queue.d.ts.map +1 -1
- package/dist/batch-queue.js +169 -14
- package/dist/batch-queue.js.map +1 -1
- package/dist/budget.d.ts +272 -0
- package/dist/budget.d.ts.map +1 -0
- package/dist/budget.js +513 -0
- package/dist/budget.js.map +1 -0
- package/dist/cache.d.ts +295 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +433 -0
- package/dist/cache.js.map +1 -0
- package/dist/context.d.ts +42 -8
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +64 -62
- package/dist/context.js.map +1 -1
- package/dist/digital-objects-registry.d.ts +229 -0
- package/dist/digital-objects-registry.d.ts.map +1 -0
- package/dist/digital-objects-registry.js +617 -0
- package/dist/digital-objects-registry.js.map +1 -0
- package/dist/embeddings.d.ts +2 -2
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +35 -0
- package/dist/errors.js.map +1 -0
- package/dist/eval/runner.d.ts +10 -1
- package/dist/eval/runner.d.ts.map +1 -1
- package/dist/eval/runner.js +41 -35
- package/dist/eval/runner.js.map +1 -1
- package/dist/eval-log/in-memory.d.ts +34 -0
- package/dist/eval-log/in-memory.d.ts.map +1 -0
- package/dist/eval-log/in-memory.js +84 -0
- package/dist/eval-log/in-memory.js.map +1 -0
- package/dist/eval-log/index.d.ts +29 -0
- package/dist/eval-log/index.d.ts.map +1 -0
- package/dist/eval-log/index.js +39 -0
- package/dist/eval-log/index.js.map +1 -0
- package/dist/eval-log/types.d.ts +101 -0
- package/dist/eval-log/types.d.ts.map +1 -0
- package/dist/eval-log/types.js +16 -0
- package/dist/eval-log/types.js.map +1 -0
- package/dist/function-registry.d.ts +116 -0
- package/dist/function-registry.d.ts.map +1 -0
- package/dist/function-registry.js +546 -0
- package/dist/function-registry.js.map +1 -0
- package/dist/generate.d.ts +9 -3
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +18 -22
- package/dist/generate.js.map +1 -1
- package/dist/index.d.ts +35 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +89 -42
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +118 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +187 -0
- package/dist/logger.js.map +1 -0
- package/dist/middleware/budget.d.ts +84 -0
- package/dist/middleware/budget.d.ts.map +1 -0
- package/dist/middleware/budget.js +110 -0
- package/dist/middleware/budget.js.map +1 -0
- package/dist/middleware/cache.d.ts +103 -0
- package/dist/middleware/cache.d.ts.map +1 -0
- package/dist/middleware/cache.js +228 -0
- package/dist/middleware/cache.js.map +1 -0
- package/dist/middleware/embed-cache.d.ts +99 -0
- package/dist/middleware/embed-cache.d.ts.map +1 -0
- package/dist/middleware/embed-cache.js +128 -0
- package/dist/middleware/embed-cache.js.map +1 -0
- package/dist/middleware/index.d.ts +11 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +11 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/trace.d.ts +103 -0
- package/dist/middleware/trace.d.ts.map +1 -0
- package/dist/middleware/trace.js +176 -0
- package/dist/middleware/trace.js.map +1 -0
- package/dist/primitives.d.ts +120 -1
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +398 -26
- package/dist/primitives.js.map +1 -1
- package/dist/retry.d.ts +368 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +646 -0
- package/dist/retry.js.map +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +2 -10
- package/dist/schema.js.map +1 -1
- package/dist/telemetry.d.ts +128 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +285 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/template.d.ts.map +1 -1
- package/dist/template.js +6 -1
- package/dist/template.js.map +1 -1
- package/dist/tool-orchestration.d.ts +453 -0
- package/dist/tool-orchestration.d.ts.map +1 -0
- package/dist/tool-orchestration.js +763 -0
- package/dist/tool-orchestration.js.map +1 -0
- package/dist/type-guards.d.ts +28 -0
- package/dist/type-guards.d.ts.map +1 -0
- package/dist/type-guards.js +29 -0
- package/dist/type-guards.js.map +1 -0
- package/dist/types.d.ts +135 -17
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +36 -1
- package/dist/types.js.map +1 -1
- package/dist/wrap-for-v3.d.ts +80 -0
- package/dist/wrap-for-v3.d.ts.map +1 -0
- package/dist/wrap-for-v3.js +89 -0
- package/dist/wrap-for-v3.js.map +1 -0
- package/examples/00-quickstart.ts +232 -0
- package/examples/01-rag-chatbot.ts +212 -0
- package/examples/02-multi-agent-research.ts +290 -0
- package/examples/03-email-classification.ts +379 -0
- package/examples/04-content-moderation.ts +400 -0
- package/examples/05-document-extraction.ts +455 -0
- package/examples/06-streaming-chat-nextjs.ts +437 -0
- package/examples/07-cloudflare-worker.ts +483 -0
- package/examples/08-batch-processing.ts +491 -0
- package/examples/09-budget-constrained.ts +527 -0
- package/examples/10-tool-orchestration.ts +565 -0
- package/examples/11-retry-resilience.ts +403 -0
- package/examples/12-caching-strategies.ts +422 -0
- package/examples/README.md +145 -0
- package/package.json +10 -6
- package/src/ai-promise.ts +528 -99
- package/src/ai-schemas.ts +122 -0
- package/src/ai.ts +69 -1153
- package/src/batch/anthropic.ts +96 -161
- package/src/batch/bedrock.ts +203 -454
- package/src/batch/cloudflare.ts +99 -282
- package/src/batch/google.ts +91 -297
- package/src/batch/index.ts +4 -1
- package/src/batch/memory.ts +15 -10
- package/src/batch/openai.ts +65 -193
- package/src/batch/provider.ts +336 -0
- package/src/batch-map.ts +29 -24
- package/src/batch-queue.ts +200 -11
- package/src/budget.ts +740 -0
- package/src/cache.ts +681 -0
- package/src/context.ts +122 -76
- package/src/digital-objects-registry.ts +750 -0
- package/src/errors.ts +37 -0
- package/src/eval/runner.ts +63 -38
- package/src/eval-log/in-memory.ts +90 -0
- package/src/eval-log/index.ts +46 -0
- package/src/eval-log/types.ts +110 -0
- package/src/function-registry.ts +671 -0
- package/src/generate.ts +33 -33
- package/src/index.ts +325 -49
- package/src/logger.ts +232 -0
- package/src/middleware/budget.ts +171 -0
- package/src/middleware/cache.ts +299 -0
- package/src/middleware/embed-cache.ts +195 -0
- package/src/middleware/index.ts +23 -0
- package/src/middleware/trace.ts +248 -0
- package/src/primitives.ts +589 -62
- package/src/retry.ts +902 -0
- package/src/schema.ts +8 -17
- package/src/telemetry.ts +403 -0
- package/src/template.ts +8 -4
- package/src/tool-orchestration.ts +1173 -0
- package/src/type-guards.ts +31 -0
- package/src/types.ts +164 -25
- package/src/wrap-for-v3.ts +105 -0
- package/test/ai-promise.test.ts +1080 -0
- package/test/ai-proxy.test.ts +1 -1
- package/test/backward-compat.test.ts +147 -0
- package/test/batch-autosubmit-errors.test.ts +610 -0
- package/test/batch-blog-posts.test.ts +87 -129
- package/test/budget-tracking.test.ts +800 -0
- package/test/cache.test.ts +712 -0
- package/test/context-isolation.test.ts +687 -0
- package/test/core-functions.test.ts +183 -579
- package/test/decide.test.ts +154 -322
- package/test/define.test.ts +211 -8
- package/test/digital-objects-registry.test.ts +760 -0
- package/test/embedding-cache-middleware.test.ts +140 -0
- package/test/evals/deterministic.eval.test.ts +376 -0
- package/test/generate-core.test.ts +140 -229
- package/test/implicit-batch.test.ts +22 -65
- package/test/json-parse-error-handling.test.ts +463 -0
- package/test/retry-policy-integration.test.ts +117 -0
- package/test/retry.test.ts +1016 -0
- package/test/schema.test.ts +55 -19
- package/test/streaming.test.ts +316 -0
- package/test/template.test.ts +1164 -0
- package/test/tool-orchestration.test.ts +1040 -0
- package/test/wrap-for-v3.test.ts +612 -0
- package/vitest.config.js +6 -0
- package/vitest.config.ts +20 -0
- package/dist/rpc/auth.d.ts +0 -69
- package/dist/rpc/auth.d.ts.map +0 -1
- package/dist/rpc/auth.js +0 -136
- package/dist/rpc/auth.js.map +0 -1
- package/dist/rpc/client.d.ts +0 -62
- package/dist/rpc/client.d.ts.map +0 -1
- package/dist/rpc/client.js +0 -103
- package/dist/rpc/client.js.map +0 -1
- package/dist/rpc/deferred.d.ts +0 -60
- package/dist/rpc/deferred.d.ts.map +0 -1
- package/dist/rpc/deferred.js +0 -96
- package/dist/rpc/deferred.js.map +0 -1
- package/dist/rpc/index.d.ts +0 -22
- package/dist/rpc/index.d.ts.map +0 -1
- package/dist/rpc/index.js +0 -38
- package/dist/rpc/index.js.map +0 -1
- package/dist/rpc/local.d.ts +0 -42
- package/dist/rpc/local.d.ts.map +0 -1
- package/dist/rpc/local.js +0 -50
- package/dist/rpc/local.js.map +0 -1
- package/dist/rpc/server.d.ts +0 -165
- package/dist/rpc/server.d.ts.map +0 -1
- package/dist/rpc/server.js +0 -405
- package/dist/rpc/server.js.map +0 -1
- package/dist/rpc/session.d.ts +0 -32
- package/dist/rpc/session.d.ts.map +0 -1
- package/dist/rpc/session.js +0 -43
- package/dist/rpc/session.js.map +0 -1
- package/dist/rpc/transport.d.ts +0 -306
- package/dist/rpc/transport.d.ts.map +0 -1
- package/dist/rpc/transport.js +0 -731
- package/dist/rpc/transport.js.map +0 -1
- package/src/batch/anthropic.js +0 -256
- package/src/batch/bedrock.js +0 -584
- package/src/batch/cloudflare.js +0 -287
- package/src/batch/google.js +0 -359
- package/src/batch/index.js +0 -30
- package/src/batch/memory.js +0 -187
- package/src/batch/openai.js +0 -402
- package/src/eval/index.js +0 -7
- package/src/eval/models.js +0 -119
- package/src/eval/runner.js +0 -147
- package/test/schema.test.js +0 -96
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Agent Research Workflow Example
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates a multi-agent research workflow where different
|
|
5
|
+
* specialized agents collaborate to research a topic. It shows how to:
|
|
6
|
+
* - Define specialized agents with different roles
|
|
7
|
+
* - Coordinate agent interactions
|
|
8
|
+
* - Aggregate and synthesize results
|
|
9
|
+
* - Use tool orchestration for complex workflows
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```bash
|
|
13
|
+
* ANTHROPIC_API_KEY=sk-... npx tsx examples/02-multi-agent-research.ts
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
ai,
|
|
19
|
+
write,
|
|
20
|
+
list,
|
|
21
|
+
is,
|
|
22
|
+
configure,
|
|
23
|
+
AgenticLoop,
|
|
24
|
+
createTool,
|
|
25
|
+
createToolset,
|
|
26
|
+
type Tool,
|
|
27
|
+
} from '../src/index.js'
|
|
28
|
+
import { z } from 'zod'
|
|
29
|
+
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Agent Definitions
|
|
32
|
+
// ============================================================================
|
|
33
|
+
|
|
34
|
+
interface AgentResult {
|
|
35
|
+
agent: string
|
|
36
|
+
findings: string[]
|
|
37
|
+
confidence: number
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Research Planner Agent - Creates a research plan
|
|
42
|
+
*/
|
|
43
|
+
async function plannerAgent(topic: string): Promise<string[]> {
|
|
44
|
+
console.log('\n[Planner Agent] Creating research plan...')
|
|
45
|
+
|
|
46
|
+
const questions = await list`5 key research questions to thoroughly investigate: "${topic}"
|
|
47
|
+
|
|
48
|
+
Consider:
|
|
49
|
+
- Background and context
|
|
50
|
+
- Current state and trends
|
|
51
|
+
- Key players and stakeholders
|
|
52
|
+
- Challenges and opportunities
|
|
53
|
+
- Future implications`
|
|
54
|
+
|
|
55
|
+
console.log('[Planner Agent] Research questions:')
|
|
56
|
+
questions.forEach((q, i) => console.log(` ${i + 1}. ${q}`))
|
|
57
|
+
|
|
58
|
+
return questions
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Fact Finder Agent - Gathers factual information
|
|
63
|
+
*/
|
|
64
|
+
async function factFinderAgent(question: string): Promise<AgentResult> {
|
|
65
|
+
console.log(`\n[Fact Finder] Researching: ${question.substring(0, 50)}...`)
|
|
66
|
+
|
|
67
|
+
const { facts, sources, confidence } =
|
|
68
|
+
await ai`Research this question and provide factual information:
|
|
69
|
+
"${question}"
|
|
70
|
+
|
|
71
|
+
Provide your response with:
|
|
72
|
+
- facts: array of factual findings (3-5 key facts)
|
|
73
|
+
- sources: where this information typically comes from
|
|
74
|
+
- confidence: your confidence level 0-1 in these facts`
|
|
75
|
+
|
|
76
|
+
const result: AgentResult = {
|
|
77
|
+
agent: 'FactFinder',
|
|
78
|
+
findings: facts as string[],
|
|
79
|
+
confidence: (confidence as number) || 0.7,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log(
|
|
83
|
+
`[Fact Finder] Found ${result.findings.length} facts (confidence: ${result.confidence})`
|
|
84
|
+
)
|
|
85
|
+
return result
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Critical Analyst Agent - Analyzes and critiques
|
|
90
|
+
*/
|
|
91
|
+
async function analystAgent(findings: string[]): Promise<AgentResult> {
|
|
92
|
+
console.log('\n[Analyst Agent] Analyzing findings...')
|
|
93
|
+
|
|
94
|
+
const { analysis, gaps, confidence } = await ai`Critically analyze these research findings:
|
|
95
|
+
${findings.map((f, i) => `${i + 1}. ${f}`).join('\n')}
|
|
96
|
+
|
|
97
|
+
Provide:
|
|
98
|
+
- analysis: array of analytical insights (3-4 insights)
|
|
99
|
+
- gaps: any gaps or areas needing more research
|
|
100
|
+
- confidence: confidence in the analysis 0-1`
|
|
101
|
+
|
|
102
|
+
const result: AgentResult = {
|
|
103
|
+
agent: 'Analyst',
|
|
104
|
+
findings: analysis as string[],
|
|
105
|
+
confidence: (confidence as number) || 0.6,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
console.log(`[Analyst Agent] Generated ${result.findings.length} insights`)
|
|
109
|
+
return result
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Synthesizer Agent - Creates final summary
|
|
114
|
+
*/
|
|
115
|
+
async function synthesizerAgent(allResults: AgentResult[]): Promise<string> {
|
|
116
|
+
console.log('\n[Synthesizer Agent] Creating final synthesis...')
|
|
117
|
+
|
|
118
|
+
const allFindings = allResults.flatMap((r) => r.findings)
|
|
119
|
+
|
|
120
|
+
const synthesis = await write`Create a comprehensive research summary from these findings:
|
|
121
|
+
|
|
122
|
+
${allFindings.map((f, i) => `- ${f}`).join('\n')}
|
|
123
|
+
|
|
124
|
+
Structure the summary with:
|
|
125
|
+
1. Executive Summary (2-3 sentences)
|
|
126
|
+
2. Key Findings (bullet points)
|
|
127
|
+
3. Analysis & Insights
|
|
128
|
+
4. Recommendations
|
|
129
|
+
5. Areas for Further Research`
|
|
130
|
+
|
|
131
|
+
return synthesis
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ============================================================================
|
|
135
|
+
// Coordinator - Orchestrates the Multi-Agent Workflow
|
|
136
|
+
// ============================================================================
|
|
137
|
+
|
|
138
|
+
class ResearchCoordinator {
|
|
139
|
+
private topic: string
|
|
140
|
+
private results: AgentResult[] = []
|
|
141
|
+
|
|
142
|
+
constructor(topic: string) {
|
|
143
|
+
this.topic = topic
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async run(): Promise<string> {
|
|
147
|
+
console.log(`\n${'='.repeat(60)}`)
|
|
148
|
+
console.log(`Research Topic: ${this.topic}`)
|
|
149
|
+
console.log('='.repeat(60))
|
|
150
|
+
|
|
151
|
+
// Phase 1: Planning
|
|
152
|
+
const questions = await plannerAgent(this.topic)
|
|
153
|
+
|
|
154
|
+
// Phase 2: Parallel Research
|
|
155
|
+
console.log('\n[Coordinator] Starting parallel research phase...')
|
|
156
|
+
const researchPromises = questions.slice(0, 3).map((q) => factFinderAgent(q))
|
|
157
|
+
const researchResults = await Promise.all(researchPromises)
|
|
158
|
+
this.results.push(...researchResults)
|
|
159
|
+
|
|
160
|
+
// Phase 3: Analysis
|
|
161
|
+
const allFacts = researchResults.flatMap((r) => r.findings)
|
|
162
|
+
const analysisResult = await analystAgent(allFacts)
|
|
163
|
+
this.results.push(analysisResult)
|
|
164
|
+
|
|
165
|
+
// Phase 4: Synthesis
|
|
166
|
+
const finalReport = await synthesizerAgent(this.results)
|
|
167
|
+
|
|
168
|
+
// Phase 5: Quality Check
|
|
169
|
+
const isQualityOk =
|
|
170
|
+
await is`This research summary is well-structured and comprehensive: "${finalReport.substring(
|
|
171
|
+
0,
|
|
172
|
+
200
|
|
173
|
+
)}..."`
|
|
174
|
+
|
|
175
|
+
if (!isQualityOk) {
|
|
176
|
+
console.log('[Coordinator] Quality check failed, requesting revision...')
|
|
177
|
+
// In production, you might iterate on the summary
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return finalReport
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
getResults(): AgentResult[] {
|
|
184
|
+
return this.results
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ============================================================================
|
|
189
|
+
// Tool-Based Research Agent (Alternative Approach)
|
|
190
|
+
// ============================================================================
|
|
191
|
+
|
|
192
|
+
const searchTool = createTool({
|
|
193
|
+
name: 'search',
|
|
194
|
+
description: 'Search for information on a topic',
|
|
195
|
+
parameters: {
|
|
196
|
+
query: z.string().describe('Search query'),
|
|
197
|
+
},
|
|
198
|
+
execute: async ({ query }) => {
|
|
199
|
+
// Simulate search results
|
|
200
|
+
console.log(` [Tool] Searching: ${query}`)
|
|
201
|
+
return {
|
|
202
|
+
results: [
|
|
203
|
+
`Result 1 for "${query}": Found relevant information...`,
|
|
204
|
+
`Result 2 for "${query}": Additional context...`,
|
|
205
|
+
],
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
const analyzeTool = createTool({
|
|
211
|
+
name: 'analyze',
|
|
212
|
+
description: 'Analyze and synthesize information',
|
|
213
|
+
parameters: {
|
|
214
|
+
data: z.string().describe('Data to analyze'),
|
|
215
|
+
perspective: z.string().describe('Analysis perspective'),
|
|
216
|
+
},
|
|
217
|
+
execute: async ({ data, perspective }) => {
|
|
218
|
+
console.log(` [Tool] Analyzing from ${perspective} perspective...`)
|
|
219
|
+
return {
|
|
220
|
+
analysis: `Analysis of "${data.substring(
|
|
221
|
+
0,
|
|
222
|
+
30
|
|
223
|
+
)}..." from ${perspective} perspective: Key insights identified.`,
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
async function toolBasedResearch(topic: string): Promise<void> {
|
|
229
|
+
console.log('\n--- Tool-Based Research Agent ---')
|
|
230
|
+
|
|
231
|
+
const loop = new AgenticLoop({
|
|
232
|
+
tools: createToolset(searchTool, analyzeTool),
|
|
233
|
+
maxSteps: 5,
|
|
234
|
+
onStep: (step) => {
|
|
235
|
+
console.log(`[Step ${step.stepNumber}] Tool calls: ${step.toolCalls.length}`)
|
|
236
|
+
},
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
// This requires a model that supports tool calling
|
|
240
|
+
// For demonstration, we'll skip the actual execution
|
|
241
|
+
console.log('Tool-based agent configured with:', loop.getToolsForSDK())
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ============================================================================
|
|
245
|
+
// Main Example
|
|
246
|
+
// ============================================================================
|
|
247
|
+
|
|
248
|
+
async function main() {
|
|
249
|
+
console.log('\n=== Multi-Agent Research Workflow ===\n')
|
|
250
|
+
|
|
251
|
+
// Configure the AI provider
|
|
252
|
+
configure({
|
|
253
|
+
model: 'sonnet',
|
|
254
|
+
provider: 'anthropic',
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
// Run the research workflow
|
|
258
|
+
const coordinator = new ResearchCoordinator(
|
|
259
|
+
'The impact of Large Language Models on software development practices'
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
const report = await coordinator.run()
|
|
263
|
+
|
|
264
|
+
console.log('\n' + '='.repeat(60))
|
|
265
|
+
console.log('FINAL RESEARCH REPORT')
|
|
266
|
+
console.log('='.repeat(60))
|
|
267
|
+
console.log(report)
|
|
268
|
+
|
|
269
|
+
// Show agent statistics
|
|
270
|
+
console.log('\n--- Agent Statistics ---')
|
|
271
|
+
const results = coordinator.getResults()
|
|
272
|
+
for (const result of results) {
|
|
273
|
+
console.log(
|
|
274
|
+
`${result.agent}: ${result.findings.length} findings (confidence: ${result.confidence})`
|
|
275
|
+
)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Demonstrate tool-based approach
|
|
279
|
+
await toolBasedResearch('AI in healthcare')
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
main()
|
|
283
|
+
.then(() => {
|
|
284
|
+
console.log('\n=== Example Complete ===\n')
|
|
285
|
+
process.exit(0)
|
|
286
|
+
})
|
|
287
|
+
.catch((error) => {
|
|
288
|
+
console.error('\nError:', error.message)
|
|
289
|
+
process.exit(1)
|
|
290
|
+
})
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email Classification and Routing Example
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates building an email classification and routing system
|
|
5
|
+
* using ai-functions. It shows how to:
|
|
6
|
+
* - Classify emails into categories
|
|
7
|
+
* - Extract key information from emails
|
|
8
|
+
* - Route to appropriate handlers
|
|
9
|
+
* - Handle priority and urgency
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```bash
|
|
13
|
+
* ANTHROPIC_API_KEY=sk-... npx tsx examples/03-email-classification.ts
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { ai, is, list, extract, configure, decide } from '../src/index.js'
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Types
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
interface Email {
|
|
24
|
+
id: string
|
|
25
|
+
from: string
|
|
26
|
+
to: string
|
|
27
|
+
subject: string
|
|
28
|
+
body: string
|
|
29
|
+
timestamp: Date
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface ClassificationResult {
|
|
33
|
+
category: string
|
|
34
|
+
subcategory: string
|
|
35
|
+
priority: 'low' | 'medium' | 'high' | 'urgent'
|
|
36
|
+
sentiment: 'positive' | 'neutral' | 'negative'
|
|
37
|
+
requiresResponse: boolean
|
|
38
|
+
suggestedTeam: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface ExtractedInfo {
|
|
42
|
+
senderIntent: string
|
|
43
|
+
keyEntities: string[]
|
|
44
|
+
actionItems: string[]
|
|
45
|
+
deadlines: string[]
|
|
46
|
+
attachmentReferences: string[]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface RoutingDecision {
|
|
50
|
+
team: string
|
|
51
|
+
handler: string
|
|
52
|
+
autoResponse: boolean
|
|
53
|
+
escalate: boolean
|
|
54
|
+
suggestedResponse?: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ============================================================================
|
|
58
|
+
// Sample Emails
|
|
59
|
+
// ============================================================================
|
|
60
|
+
|
|
61
|
+
const sampleEmails: Email[] = [
|
|
62
|
+
{
|
|
63
|
+
id: 'email-1',
|
|
64
|
+
from: 'john.smith@bigcorp.com',
|
|
65
|
+
to: 'sales@ourcompany.com',
|
|
66
|
+
subject: 'Enterprise License Inquiry - 500 seats',
|
|
67
|
+
body: `Hi,
|
|
68
|
+
|
|
69
|
+
We are interested in your enterprise solution for our organization.
|
|
70
|
+
We have approximately 500 developers who would need access.
|
|
71
|
+
|
|
72
|
+
Could you please provide:
|
|
73
|
+
1. Enterprise pricing for 500 seats
|
|
74
|
+
2. Volume discount options
|
|
75
|
+
3. Security compliance certifications (SOC2, HIPAA)
|
|
76
|
+
4. On-premise deployment options
|
|
77
|
+
|
|
78
|
+
We're looking to make a decision within the next 2 weeks.
|
|
79
|
+
|
|
80
|
+
Best regards,
|
|
81
|
+
John Smith
|
|
82
|
+
VP of Engineering, BigCorp Inc.`,
|
|
83
|
+
timestamp: new Date(),
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: 'email-2',
|
|
87
|
+
from: 'frustrated.user@example.com',
|
|
88
|
+
to: 'support@ourcompany.com',
|
|
89
|
+
subject: 'URGENT: System down - Production blocked!',
|
|
90
|
+
body: `Our production system has been down for 3 hours!!!
|
|
91
|
+
|
|
92
|
+
Error: "Connection timeout to API endpoint"
|
|
93
|
+
|
|
94
|
+
We're losing thousands of dollars per hour. We need immediate assistance.
|
|
95
|
+
Our contract includes 24/7 premium support.
|
|
96
|
+
|
|
97
|
+
Account ID: ENT-12345
|
|
98
|
+
Contact: 555-123-4567
|
|
99
|
+
|
|
100
|
+
This needs to be fixed NOW.`,
|
|
101
|
+
timestamp: new Date(),
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
id: 'email-3',
|
|
105
|
+
from: 'newsletter@techblog.com',
|
|
106
|
+
to: 'team@ourcompany.com',
|
|
107
|
+
subject: 'Weekly AI Newsletter - Top Stories',
|
|
108
|
+
body: `This week in AI:
|
|
109
|
+
|
|
110
|
+
- GPT-5 rumors continue to swirl
|
|
111
|
+
- New open-source models released
|
|
112
|
+
- Industry adoption trends
|
|
113
|
+
|
|
114
|
+
Click to read more...
|
|
115
|
+
|
|
116
|
+
Unsubscribe: techblog.com/unsubscribe`,
|
|
117
|
+
timestamp: new Date(),
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: 'email-4',
|
|
121
|
+
from: 'hr@ourcompany.com',
|
|
122
|
+
to: 'team@ourcompany.com',
|
|
123
|
+
subject: 'Company All-Hands Meeting - Friday 3pm',
|
|
124
|
+
body: `Hi everyone,
|
|
125
|
+
|
|
126
|
+
Reminder: Our monthly all-hands meeting is this Friday at 3pm.
|
|
127
|
+
|
|
128
|
+
Agenda:
|
|
129
|
+
- Q4 Results Review
|
|
130
|
+
- 2025 Planning
|
|
131
|
+
- Team Awards
|
|
132
|
+
|
|
133
|
+
Please submit any questions beforehand.
|
|
134
|
+
|
|
135
|
+
Best,
|
|
136
|
+
HR Team`,
|
|
137
|
+
timestamp: new Date(),
|
|
138
|
+
},
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
// ============================================================================
|
|
142
|
+
// Email Classifier
|
|
143
|
+
// ============================================================================
|
|
144
|
+
|
|
145
|
+
async function classifyEmail(email: Email): Promise<ClassificationResult> {
|
|
146
|
+
console.log(`\nClassifying: "${email.subject}"`)
|
|
147
|
+
|
|
148
|
+
const { category, subcategory, priority, sentiment, requiresResponse, suggestedTeam } =
|
|
149
|
+
await ai`Classify this email:
|
|
150
|
+
|
|
151
|
+
From: ${email.from}
|
|
152
|
+
Subject: ${email.subject}
|
|
153
|
+
Body: ${email.body}
|
|
154
|
+
|
|
155
|
+
Provide:
|
|
156
|
+
- category: one of [sales, support, marketing, internal, spam, other]
|
|
157
|
+
- subcategory: more specific classification
|
|
158
|
+
- priority: one of [low, medium, high, urgent]
|
|
159
|
+
- sentiment: one of [positive, neutral, negative]
|
|
160
|
+
- requiresResponse: boolean - does this need a reply?
|
|
161
|
+
- suggestedTeam: which team should handle this`
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
category: category as string,
|
|
165
|
+
subcategory: subcategory as string,
|
|
166
|
+
priority: priority as 'low' | 'medium' | 'high' | 'urgent',
|
|
167
|
+
sentiment: sentiment as 'positive' | 'neutral' | 'negative',
|
|
168
|
+
requiresResponse: requiresResponse as boolean,
|
|
169
|
+
suggestedTeam: suggestedTeam as string,
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ============================================================================
|
|
174
|
+
// Information Extractor
|
|
175
|
+
// ============================================================================
|
|
176
|
+
|
|
177
|
+
async function extractInfo(email: Email): Promise<ExtractedInfo> {
|
|
178
|
+
console.log(` Extracting key information...`)
|
|
179
|
+
|
|
180
|
+
const { senderIntent, keyEntities, actionItems, deadlines, attachmentReferences } =
|
|
181
|
+
await ai`Extract key information from this email:
|
|
182
|
+
|
|
183
|
+
Subject: ${email.subject}
|
|
184
|
+
Body: ${email.body}
|
|
185
|
+
|
|
186
|
+
Provide:
|
|
187
|
+
- senderIntent: what the sender wants (1 sentence)
|
|
188
|
+
- keyEntities: array of important entities (names, companies, products, account IDs)
|
|
189
|
+
- actionItems: array of action items or requests
|
|
190
|
+
- deadlines: array of mentioned deadlines or timeframes
|
|
191
|
+
- attachmentReferences: any references to attachments or documents`
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
senderIntent: senderIntent as string,
|
|
195
|
+
keyEntities: keyEntities as string[],
|
|
196
|
+
actionItems: actionItems as string[],
|
|
197
|
+
deadlines: deadlines as string[],
|
|
198
|
+
attachmentReferences: attachmentReferences as string[],
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ============================================================================
|
|
203
|
+
// Router
|
|
204
|
+
// ============================================================================
|
|
205
|
+
|
|
206
|
+
async function routeEmail(
|
|
207
|
+
email: Email,
|
|
208
|
+
classification: ClassificationResult,
|
|
209
|
+
info: ExtractedInfo
|
|
210
|
+
): Promise<RoutingDecision> {
|
|
211
|
+
console.log(` Determining routing...`)
|
|
212
|
+
|
|
213
|
+
// Check if escalation is needed
|
|
214
|
+
const needsEscalation = await is`This email requires immediate escalation to management:
|
|
215
|
+
Category: ${classification.category}
|
|
216
|
+
Priority: ${classification.priority}
|
|
217
|
+
Sentiment: ${classification.sentiment}
|
|
218
|
+
Intent: ${info.senderIntent}`
|
|
219
|
+
|
|
220
|
+
// Determine if auto-response is appropriate
|
|
221
|
+
const canAutoRespond = await is`This email can be handled with an automated response:
|
|
222
|
+
Category: ${classification.category}
|
|
223
|
+
Intent: ${info.senderIntent}
|
|
224
|
+
Action Items: ${info.actionItems.join(', ')}`
|
|
225
|
+
|
|
226
|
+
// Route based on category
|
|
227
|
+
const routingMap: Record<string, { team: string; handler: string }> = {
|
|
228
|
+
sales: { team: 'Sales', handler: 'sales-queue' },
|
|
229
|
+
support: {
|
|
230
|
+
team: 'Support',
|
|
231
|
+
handler: classification.priority === 'urgent' ? 'urgent-queue' : 'support-queue',
|
|
232
|
+
},
|
|
233
|
+
marketing: { team: 'Marketing', handler: 'marketing-inbox' },
|
|
234
|
+
internal: { team: 'Internal', handler: 'internal-comms' },
|
|
235
|
+
spam: { team: 'None', handler: 'spam-filter' },
|
|
236
|
+
other: { team: 'Triage', handler: 'general-queue' },
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const route = routingMap[classification.category] || routingMap.other
|
|
240
|
+
|
|
241
|
+
let suggestedResponse: string | undefined
|
|
242
|
+
if (canAutoRespond) {
|
|
243
|
+
suggestedResponse = await generateAutoResponse(email, classification, info)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
team: route.team,
|
|
248
|
+
handler: route.handler,
|
|
249
|
+
autoResponse: canAutoRespond,
|
|
250
|
+
escalate: needsEscalation,
|
|
251
|
+
suggestedResponse,
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ============================================================================
|
|
256
|
+
// Auto-Response Generator
|
|
257
|
+
// ============================================================================
|
|
258
|
+
|
|
259
|
+
async function generateAutoResponse(
|
|
260
|
+
email: Email,
|
|
261
|
+
classification: ClassificationResult,
|
|
262
|
+
info: ExtractedInfo
|
|
263
|
+
): Promise<string> {
|
|
264
|
+
console.log(` Generating auto-response...`)
|
|
265
|
+
|
|
266
|
+
const response = await ai`Generate a brief, professional auto-response for this email:
|
|
267
|
+
|
|
268
|
+
Original Subject: ${email.subject}
|
|
269
|
+
Category: ${classification.category}
|
|
270
|
+
Sender Intent: ${info.senderIntent}
|
|
271
|
+
|
|
272
|
+
The response should:
|
|
273
|
+
- Acknowledge receipt
|
|
274
|
+
- Set expectations for response time
|
|
275
|
+
- Provide any immediately helpful information
|
|
276
|
+
- Be concise (3-4 sentences max)
|
|
277
|
+
|
|
278
|
+
Return just the response text.`
|
|
279
|
+
|
|
280
|
+
return response as string
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// ============================================================================
|
|
284
|
+
// Batch Classification
|
|
285
|
+
// ============================================================================
|
|
286
|
+
|
|
287
|
+
async function batchClassifyEmails(emails: Email[]): Promise<void> {
|
|
288
|
+
console.log(`\n${'='.repeat(60)}`)
|
|
289
|
+
console.log('Batch Email Classification Results')
|
|
290
|
+
console.log('='.repeat(60))
|
|
291
|
+
|
|
292
|
+
for (const email of emails) {
|
|
293
|
+
const classification = await classifyEmail(email)
|
|
294
|
+
const info = await extractInfo(email)
|
|
295
|
+
const routing = await routeEmail(email, classification, info)
|
|
296
|
+
|
|
297
|
+
console.log(`
|
|
298
|
+
ID: ${email.id}
|
|
299
|
+
Subject: ${email.subject}
|
|
300
|
+
---
|
|
301
|
+
Classification:
|
|
302
|
+
Category: ${classification.category} / ${classification.subcategory}
|
|
303
|
+
Priority: ${classification.priority}
|
|
304
|
+
Sentiment: ${classification.sentiment}
|
|
305
|
+
Requires Response: ${classification.requiresResponse}
|
|
306
|
+
|
|
307
|
+
Extracted Info:
|
|
308
|
+
Intent: ${info.senderIntent}
|
|
309
|
+
Entities: ${info.keyEntities.join(', ') || 'none'}
|
|
310
|
+
Action Items: ${info.actionItems.length}
|
|
311
|
+
Deadlines: ${info.deadlines.join(', ') || 'none'}
|
|
312
|
+
|
|
313
|
+
Routing:
|
|
314
|
+
Team: ${routing.team}
|
|
315
|
+
Handler: ${routing.handler}
|
|
316
|
+
Auto-Response: ${routing.autoResponse}
|
|
317
|
+
Escalate: ${routing.escalate}
|
|
318
|
+
${
|
|
319
|
+
routing.suggestedResponse
|
|
320
|
+
? `\nSuggested Response:\n "${routing.suggestedResponse.substring(0, 100)}..."`
|
|
321
|
+
: ''
|
|
322
|
+
}
|
|
323
|
+
${'='.repeat(60)}`)
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ============================================================================
|
|
328
|
+
// Priority Comparison
|
|
329
|
+
// ============================================================================
|
|
330
|
+
|
|
331
|
+
async function prioritizeEmails(emails: Email[]): Promise<Email[]> {
|
|
332
|
+
console.log('\n--- Prioritizing Emails ---')
|
|
333
|
+
|
|
334
|
+
// Use decide to compare email urgency
|
|
335
|
+
if (emails.length < 2) return emails
|
|
336
|
+
|
|
337
|
+
// For demo, just compare first two
|
|
338
|
+
const moreUrgent = await decide`which email is more urgent and should be handled first`(
|
|
339
|
+
{ subject: emails[0].subject, body: emails[0].body.substring(0, 100) },
|
|
340
|
+
{ subject: emails[1].subject, body: emails[1].body.substring(0, 100) }
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
console.log(`Most urgent: "${(moreUrgent as Email).subject}"`)
|
|
344
|
+
return emails
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// ============================================================================
|
|
348
|
+
// Main Example
|
|
349
|
+
// ============================================================================
|
|
350
|
+
|
|
351
|
+
async function main() {
|
|
352
|
+
console.log('\n=== Email Classification & Routing Example ===\n')
|
|
353
|
+
|
|
354
|
+
// Configure the AI provider
|
|
355
|
+
configure({
|
|
356
|
+
model: 'sonnet',
|
|
357
|
+
provider: 'anthropic',
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
// Process all sample emails
|
|
361
|
+
await batchClassifyEmails(sampleEmails)
|
|
362
|
+
|
|
363
|
+
// Prioritize emails
|
|
364
|
+
await prioritizeEmails(sampleEmails.slice(0, 2))
|
|
365
|
+
|
|
366
|
+
// Show statistics
|
|
367
|
+
console.log('\n--- Processing Statistics ---')
|
|
368
|
+
console.log(`Total emails processed: ${sampleEmails.length}`)
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
main()
|
|
372
|
+
.then(() => {
|
|
373
|
+
console.log('\n=== Example Complete ===\n')
|
|
374
|
+
process.exit(0)
|
|
375
|
+
})
|
|
376
|
+
.catch((error) => {
|
|
377
|
+
console.error('\nError:', error.message)
|
|
378
|
+
process.exit(1)
|
|
379
|
+
})
|