ai-functions 2.1.3 → 2.4.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 -1
- package/CHANGELOG.md +90 -1
- package/README.md +38 -0
- package/dist/ai-promise.d.ts +3 -3
- package/dist/ai-promise.d.ts.map +1 -1
- package/dist/ai-promise.js +135 -64
- 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 +51 -858
- 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.map +1 -1
- package/dist/budget.js +27 -14
- package/dist/budget.js.map +1 -1
- package/dist/cache.d.ts +23 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +36 -15
- package/dist/cache.js.map +1 -1
- package/dist/context.d.ts +26 -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 +8 -0
- 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 +176 -0
- package/dist/function-registry.d.ts.map +1 -0
- package/dist/function-registry.js +685 -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 -18
- package/dist/generate.js.map +1 -1
- package/dist/index.d.ts +18 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -18
- 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 +66 -1
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +115 -8
- package/dist/retry.js.map +1 -1
- package/dist/sandbox.d.ts +36 -0
- package/dist/sandbox.d.ts.map +1 -0
- package/dist/sandbox.js +44 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/schema.js +2 -2
- 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 +66 -4
- package/dist/tool-orchestration.d.ts.map +1 -1
- package/dist/tool-orchestration.js +123 -23
- package/dist/tool-orchestration.js.map +1 -1
- 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 +155 -19
- 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 +29 -25
- package/src/ai-promise.ts +226 -140
- package/src/ai-schemas.ts +122 -0
- package/src/ai.ts +71 -1176
- 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 +31 -18
- package/src/cache.ts +45 -17
- package/src/context.ts +106 -77
- package/src/digital-objects-registry.ts +750 -0
- package/src/errors.ts +37 -0
- package/src/eval/runner.ts +60 -36
- 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 +874 -0
- package/src/generate.ts +33 -28
- package/src/index.ts +122 -21
- 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 +144 -18
- package/src/sandbox.ts +52 -0
- package/src/schema.ts +8 -8
- package/src/telemetry.ts +403 -0
- package/src/template.ts +8 -4
- package/src/tool-orchestration.ts +213 -48
- package/src/type-guards.ts +31 -0
- package/src/types.ts +186 -27
- 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/batch-autosubmit-errors.test.ts +49 -37
- package/test/batch-blog-posts.test.ts +87 -129
- 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/fill-template.test.ts +89 -0
- package/test/generate-core.test.ts +140 -229
- package/test/implicit-batch.test.ts +22 -65
- package/test/retry-policy-integration.test.ts +117 -0
- package/test/sandbox-execution.test.ts +155 -0
- package/test/schema.test.ts +55 -19
- package/test/template.test.ts +1164 -0
- package/test/tool-orchestration.test.ts +270 -0
- package/test/wrap-for-v3.test.ts +612 -0
- package/vitest.config.js +6 -0
- package/vitest.config.ts +20 -0
- package/LICENSE +0 -21
- 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,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
|
+
})
|