signalwire-agents 0.1.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/CLAUDE.md +112 -0
- package/README.md +417 -0
- package/dist/AgentBase.d.ts +481 -0
- package/dist/AgentBase.js +1155 -0
- package/dist/AgentBase.js.map +1 -0
- package/dist/AgentServer.d.ts +60 -0
- package/dist/AgentServer.js +128 -0
- package/dist/AgentServer.js.map +1 -0
- package/dist/AuthHandler.d.ts +56 -0
- package/dist/AuthHandler.js +119 -0
- package/dist/AuthHandler.js.map +1 -0
- package/dist/ConfigLoader.d.ts +68 -0
- package/dist/ConfigLoader.js +150 -0
- package/dist/ConfigLoader.js.map +1 -0
- package/dist/ContextBuilder.d.ts +431 -0
- package/dist/ContextBuilder.js +751 -0
- package/dist/ContextBuilder.js.map +1 -0
- package/dist/DataMap.d.ts +179 -0
- package/dist/DataMap.js +321 -0
- package/dist/DataMap.js.map +1 -0
- package/dist/Logger.d.ts +91 -0
- package/dist/Logger.js +191 -0
- package/dist/Logger.js.map +1 -0
- package/dist/PomBuilder.d.ts +144 -0
- package/dist/PomBuilder.js +249 -0
- package/dist/PomBuilder.js.map +1 -0
- package/dist/PromptManager.d.ts +85 -0
- package/dist/PromptManager.js +108 -0
- package/dist/PromptManager.js.map +1 -0
- package/dist/SchemaUtils.d.ts +42 -0
- package/dist/SchemaUtils.js +148 -0
- package/dist/SchemaUtils.js.map +1 -0
- package/dist/ServerlessAdapter.d.ts +100 -0
- package/dist/ServerlessAdapter.js +166 -0
- package/dist/ServerlessAdapter.js.map +1 -0
- package/dist/SessionManager.d.ts +86 -0
- package/dist/SessionManager.js +155 -0
- package/dist/SessionManager.js.map +1 -0
- package/dist/SslConfig.d.ts +77 -0
- package/dist/SslConfig.js +100 -0
- package/dist/SslConfig.js.map +1 -0
- package/dist/SwaigFunction.d.ts +88 -0
- package/dist/SwaigFunction.js +125 -0
- package/dist/SwaigFunction.js.map +1 -0
- package/dist/SwaigFunctionResult.d.ts +442 -0
- package/dist/SwaigFunctionResult.js +735 -0
- package/dist/SwaigFunctionResult.js.map +1 -0
- package/dist/SwmlBuilder.d.ts +37 -0
- package/dist/SwmlBuilder.js +55 -0
- package/dist/SwmlBuilder.js.map +1 -0
- package/dist/cli/agent-loader.d.ts +22 -0
- package/dist/cli/agent-loader.js +106 -0
- package/dist/cli/agent-loader.js.map +1 -0
- package/dist/cli/mock-data.d.ts +37 -0
- package/dist/cli/mock-data.js +79 -0
- package/dist/cli/mock-data.js.map +1 -0
- package/dist/cli/swaig-test.d.ts +32 -0
- package/dist/cli/swaig-test.js +405 -0
- package/dist/cli/swaig-test.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/prefabs/ConciergeAgent.d.ts +64 -0
- package/dist/prefabs/ConciergeAgent.js +188 -0
- package/dist/prefabs/ConciergeAgent.js.map +1 -0
- package/dist/prefabs/FAQBotAgent.d.ts +68 -0
- package/dist/prefabs/FAQBotAgent.js +206 -0
- package/dist/prefabs/FAQBotAgent.js.map +1 -0
- package/dist/prefabs/InfoGathererAgent.d.ts +73 -0
- package/dist/prefabs/InfoGathererAgent.js +202 -0
- package/dist/prefabs/InfoGathererAgent.js.map +1 -0
- package/dist/prefabs/ReceptionistAgent.d.ts +65 -0
- package/dist/prefabs/ReceptionistAgent.js +205 -0
- package/dist/prefabs/ReceptionistAgent.js.map +1 -0
- package/dist/prefabs/SurveyAgent.d.ts +84 -0
- package/dist/prefabs/SurveyAgent.js +324 -0
- package/dist/prefabs/SurveyAgent.js.map +1 -0
- package/dist/prefabs/index.d.ts +13 -0
- package/dist/prefabs/index.js +14 -0
- package/dist/prefabs/index.js.map +1 -0
- package/dist/skills/SkillBase.d.ts +134 -0
- package/dist/skills/SkillBase.js +105 -0
- package/dist/skills/SkillBase.js.map +1 -0
- package/dist/skills/SkillManager.d.ts +83 -0
- package/dist/skills/SkillManager.js +159 -0
- package/dist/skills/SkillManager.js.map +1 -0
- package/dist/skills/SkillRegistry.d.ts +105 -0
- package/dist/skills/SkillRegistry.js +195 -0
- package/dist/skills/SkillRegistry.js.map +1 -0
- package/dist/skills/builtin/api_ninjas_trivia.d.ts +35 -0
- package/dist/skills/builtin/api_ninjas_trivia.js +161 -0
- package/dist/skills/builtin/api_ninjas_trivia.js.map +1 -0
- package/dist/skills/builtin/claude_skills.d.ts +34 -0
- package/dist/skills/builtin/claude_skills.js +156 -0
- package/dist/skills/builtin/claude_skills.js.map +1 -0
- package/dist/skills/builtin/custom_skills.d.ts +59 -0
- package/dist/skills/builtin/custom_skills.js +231 -0
- package/dist/skills/builtin/custom_skills.js.map +1 -0
- package/dist/skills/builtin/datasphere.d.ts +34 -0
- package/dist/skills/builtin/datasphere.js +163 -0
- package/dist/skills/builtin/datasphere.js.map +1 -0
- package/dist/skills/builtin/datasphere_serverless.d.ts +54 -0
- package/dist/skills/builtin/datasphere_serverless.js +155 -0
- package/dist/skills/builtin/datasphere_serverless.js.map +1 -0
- package/dist/skills/builtin/datetime.d.ts +31 -0
- package/dist/skills/builtin/datetime.js +95 -0
- package/dist/skills/builtin/datetime.js.map +1 -0
- package/dist/skills/builtin/google_maps.d.ts +33 -0
- package/dist/skills/builtin/google_maps.js +233 -0
- package/dist/skills/builtin/google_maps.js.map +1 -0
- package/dist/skills/builtin/index.d.ts +28 -0
- package/dist/skills/builtin/index.js +75 -0
- package/dist/skills/builtin/index.js.map +1 -0
- package/dist/skills/builtin/info_gatherer.d.ts +52 -0
- package/dist/skills/builtin/info_gatherer.js +237 -0
- package/dist/skills/builtin/info_gatherer.js.map +1 -0
- package/dist/skills/builtin/joke.d.ts +32 -0
- package/dist/skills/builtin/joke.js +142 -0
- package/dist/skills/builtin/joke.js.map +1 -0
- package/dist/skills/builtin/math.d.ts +33 -0
- package/dist/skills/builtin/math.js +120 -0
- package/dist/skills/builtin/math.js.map +1 -0
- package/dist/skills/builtin/mcp_gateway.d.ts +35 -0
- package/dist/skills/builtin/mcp_gateway.js +85 -0
- package/dist/skills/builtin/mcp_gateway.js.map +1 -0
- package/dist/skills/builtin/native_vector_search.d.ts +44 -0
- package/dist/skills/builtin/native_vector_search.js +248 -0
- package/dist/skills/builtin/native_vector_search.js.map +1 -0
- package/dist/skills/builtin/play_background_file.d.ts +34 -0
- package/dist/skills/builtin/play_background_file.js +135 -0
- package/dist/skills/builtin/play_background_file.js.map +1 -0
- package/dist/skills/builtin/spider.d.ts +34 -0
- package/dist/skills/builtin/spider.js +164 -0
- package/dist/skills/builtin/spider.js.map +1 -0
- package/dist/skills/builtin/swml_transfer.d.ts +44 -0
- package/dist/skills/builtin/swml_transfer.js +204 -0
- package/dist/skills/builtin/swml_transfer.js.map +1 -0
- package/dist/skills/builtin/weather_api.d.ts +34 -0
- package/dist/skills/builtin/weather_api.js +136 -0
- package/dist/skills/builtin/weather_api.js.map +1 -0
- package/dist/skills/builtin/web_search.d.ts +34 -0
- package/dist/skills/builtin/web_search.js +141 -0
- package/dist/skills/builtin/web_search.js.map +1 -0
- package/dist/skills/builtin/wikipedia_search.d.ts +34 -0
- package/dist/skills/builtin/wikipedia_search.js +166 -0
- package/dist/skills/builtin/wikipedia_search.js.map +1 -0
- package/dist/skills/index.d.ts +11 -0
- package/dist/skills/index.js +10 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/docs/agent-guide.md +869 -0
- package/docs/api-reference.md +2419 -0
- package/docs/architecture.md +843 -0
- package/docs/cli-guide.md +579 -0
- package/docs/configuration.md +422 -0
- package/docs/contexts-guide.md +787 -0
- package/docs/datamap-guide.md +1141 -0
- package/docs/prefabs-guide.md +830 -0
- package/docs/security.md +436 -0
- package/docs/serverless-guide.md +513 -0
- package/docs/skills-guide.md +845 -0
- package/docs/swaig-reference.md +1627 -0
- package/examples/call-flow.ts +60 -0
- package/examples/contexts-steps.ts +62 -0
- package/examples/datamap-tools.ts +52 -0
- package/examples/dynamic-config.ts +51 -0
- package/examples/multi-agent.ts +67 -0
- package/examples/pom-prompt.ts +68 -0
- package/examples/simple-agent.ts +33 -0
- package/package.json +35 -0
- package/src/AgentBase.ts +1279 -0
- package/src/AgentServer.ts +149 -0
- package/src/AuthHandler.ts +141 -0
- package/src/ConfigLoader.ts +165 -0
- package/src/ContextBuilder.ts +796 -0
- package/src/DataMap.ts +365 -0
- package/src/Logger.ts +197 -0
- package/src/PomBuilder.ts +298 -0
- package/src/PromptManager.ts +133 -0
- package/src/SchemaUtils.ts +170 -0
- package/src/ServerlessAdapter.ts +218 -0
- package/src/SessionManager.ts +161 -0
- package/src/SslConfig.ts +118 -0
- package/src/SwaigFunction.ts +168 -0
- package/src/SwaigFunctionResult.ts +864 -0
- package/src/SwmlBuilder.ts +62 -0
- package/src/cli/agent-loader.ts +122 -0
- package/src/cli/mock-data.ts +110 -0
- package/src/cli/swaig-test.ts +440 -0
- package/src/index.ts +99 -0
- package/src/prefabs/ConciergeAgent.ts +251 -0
- package/src/prefabs/FAQBotAgent.ts +263 -0
- package/src/prefabs/InfoGathererAgent.ts +276 -0
- package/src/prefabs/ReceptionistAgent.ts +277 -0
- package/src/prefabs/SurveyAgent.ts +413 -0
- package/src/prefabs/index.ts +23 -0
- package/src/skills/SkillBase.ts +184 -0
- package/src/skills/SkillManager.ts +177 -0
- package/src/skills/SkillRegistry.ts +231 -0
- package/src/skills/builtin/api_ninjas_trivia.ts +230 -0
- package/src/skills/builtin/claude_skills.ts +239 -0
- package/src/skills/builtin/custom_skills.ts +326 -0
- package/src/skills/builtin/datasphere.ts +225 -0
- package/src/skills/builtin/datasphere_serverless.ts +194 -0
- package/src/skills/builtin/datetime.ts +115 -0
- package/src/skills/builtin/google_maps.ts +347 -0
- package/src/skills/builtin/index.ts +79 -0
- package/src/skills/builtin/info_gatherer.ts +331 -0
- package/src/skills/builtin/joke.ts +180 -0
- package/src/skills/builtin/math.ts +150 -0
- package/src/skills/builtin/mcp_gateway.ts +99 -0
- package/src/skills/builtin/native_vector_search.ts +327 -0
- package/src/skills/builtin/play_background_file.ts +189 -0
- package/src/skills/builtin/spider.ts +232 -0
- package/src/skills/builtin/swml_transfer.ts +285 -0
- package/src/skills/builtin/weather_api.ts +193 -0
- package/src/skills/builtin/web_search.ts +212 -0
- package/src/skills/builtin/wikipedia_search.ts +248 -0
- package/src/skills/index.ts +12 -0
- package/src/types.ts +99 -0
- package/tests/AgentBase.test.ts +693 -0
- package/tests/AgentServer.test.ts +102 -0
- package/tests/AuthHandler.test.ts +121 -0
- package/tests/ConfigLoader.test.ts +121 -0
- package/tests/DataMap.test.ts +286 -0
- package/tests/Logger.test.ts +218 -0
- package/tests/PomBuilder.test.ts +164 -0
- package/tests/ProxyDetection.test.ts +185 -0
- package/tests/SchemaUtils.test.ts +106 -0
- package/tests/ServerlessAdapter.test.ts +200 -0
- package/tests/SessionManager.test.ts +139 -0
- package/tests/SslConfig.test.ts +97 -0
- package/tests/SwaigFunctionResult.test.ts +298 -0
- package/tests/cli/mock-data.test.ts +94 -0
- package/tests/cli/swaig-test.test.ts +96 -0
- package/tests/prefabs/prefabs.test.ts +854 -0
- package/tests/setup.ts +6 -0
- package/tests/skills/SkillBase.test.ts +118 -0
- package/tests/skills/SkillManager.test.ts +164 -0
- package/tests/skills/SkillRegistry.test.ts +124 -0
- package/tests/skills/builtin.test.ts +924 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
# Serverless Deployment Guide
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- [Overview](#overview)
|
|
6
|
+
- [ServerlessAdapter](#serverlessadapter)
|
|
7
|
+
- [AWS Lambda](#aws-lambda)
|
|
8
|
+
- [Google Cloud Functions](#google-cloud-functions)
|
|
9
|
+
- [Azure Functions](#azure-functions)
|
|
10
|
+
- [CGI Mode](#cgi-mode)
|
|
11
|
+
- [Platform Detection](#platform-detection)
|
|
12
|
+
- [URL Generation](#url-generation)
|
|
13
|
+
- [CLI Testing](#cli-testing)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Overview
|
|
18
|
+
|
|
19
|
+
The SignalWire AI Agents TypeScript SDK can be deployed to serverless platforms using the `ServerlessAdapter` class (`src/ServerlessAdapter.ts`). The adapter converts platform-specific event formats into standard `Request` objects, routes them through the Hono application, and returns normalized responses.
|
|
20
|
+
|
|
21
|
+
Supported platforms:
|
|
22
|
+
|
|
23
|
+
| Platform | Identifier | Factory Method |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| AWS Lambda | `lambda` | `ServerlessAdapter.createLambdaHandler()` |
|
|
26
|
+
| Google Cloud Functions | `gcf` | `ServerlessAdapter.createGcfHandler()` |
|
|
27
|
+
| Azure Functions | `azure` | `ServerlessAdapter.createAzureHandler()` |
|
|
28
|
+
| CGI | `cgi` | Manual via `handleRequest()` |
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## ServerlessAdapter
|
|
33
|
+
|
|
34
|
+
### Constructor
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { ServerlessAdapter } from '@anthropic/signalwire-agents';
|
|
38
|
+
|
|
39
|
+
// Auto-detect platform from environment variables
|
|
40
|
+
const adapter = new ServerlessAdapter();
|
|
41
|
+
// or: new ServerlessAdapter('auto')
|
|
42
|
+
|
|
43
|
+
// Explicit platform selection
|
|
44
|
+
const lambdaAdapter = new ServerlessAdapter('lambda');
|
|
45
|
+
const gcfAdapter = new ServerlessAdapter('gcf');
|
|
46
|
+
const azureAdapter = new ServerlessAdapter('azure');
|
|
47
|
+
const cgiAdapter = new ServerlessAdapter('cgi');
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The `platform` parameter accepts `'lambda' | 'gcf' | 'azure' | 'cgi' | 'auto'`. When set to `'auto'` (the default), the platform is detected from environment variables (see [Platform Detection](#platform-detection)).
|
|
51
|
+
|
|
52
|
+
### Core Types
|
|
53
|
+
|
|
54
|
+
**`ServerlessEvent`** -- Normalized incoming event:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
interface ServerlessEvent {
|
|
58
|
+
httpMethod?: string; // HTTP method (AWS Lambda style)
|
|
59
|
+
method?: string; // HTTP method (GCF/Azure style)
|
|
60
|
+
headers?: Record<string, string>; // Request headers
|
|
61
|
+
body?: string | Record<string, unknown>; // Raw or parsed request body
|
|
62
|
+
path?: string; // Request path
|
|
63
|
+
rawPath?: string; // Raw path (AWS API Gateway v2)
|
|
64
|
+
queryStringParameters?: Record<string, string>; // Query parameters
|
|
65
|
+
requestContext?: Record<string, unknown>; // Platform-specific context
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**`ServerlessResponse`** -- Normalized outgoing response:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
interface ServerlessResponse {
|
|
73
|
+
statusCode: number; // HTTP status code
|
|
74
|
+
headers: Record<string, string>; // Response headers
|
|
75
|
+
body: string; // Response body as string
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### handleRequest()
|
|
80
|
+
|
|
81
|
+
The core method that processes any serverless event through a Hono app:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
const adapter = new ServerlessAdapter('lambda');
|
|
85
|
+
const agent = new AgentBase({ name: 'my-agent' });
|
|
86
|
+
const app = agent.getApp();
|
|
87
|
+
|
|
88
|
+
const response = await adapter.handleRequest(app, event);
|
|
89
|
+
// response: { statusCode: 200, headers: {...}, body: '...' }
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Processing steps:**
|
|
93
|
+
|
|
94
|
+
1. Extract HTTP method from `event.httpMethod` (Lambda) or `event.method` (GCF/Azure), defaulting to `POST`.
|
|
95
|
+
2. Extract path from `event.rawPath` (API Gateway v2) or `event.path`, defaulting to `/`.
|
|
96
|
+
3. Build a full URL from the `host` and `x-forwarded-proto` headers.
|
|
97
|
+
4. Append query string parameters if present.
|
|
98
|
+
5. Create a standard `Request` object and route it through `app.fetch()`.
|
|
99
|
+
6. Convert the `Response` back into a `ServerlessResponse`.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## AWS Lambda
|
|
104
|
+
|
|
105
|
+
Use `ServerlessAdapter.createLambdaHandler()` to create a Lambda-compatible handler function.
|
|
106
|
+
|
|
107
|
+
### Example: Lambda Handler
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// handler.ts
|
|
111
|
+
import { AgentBase, ServerlessAdapter } from '@anthropic/signalwire-agents';
|
|
112
|
+
|
|
113
|
+
const agent = new AgentBase({
|
|
114
|
+
name: 'lambda-agent',
|
|
115
|
+
basicAuth: ['admin', process.env.AGENT_PASSWORD!],
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
agent.setPromptText('You are a helpful assistant deployed on AWS Lambda.');
|
|
119
|
+
|
|
120
|
+
agent.defineTool({
|
|
121
|
+
name: 'get_status',
|
|
122
|
+
description: 'Get the current system status',
|
|
123
|
+
parameters: {
|
|
124
|
+
type: 'object',
|
|
125
|
+
properties: {
|
|
126
|
+
system: { type: 'string', description: 'System name' },
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
handler: async (args) => {
|
|
130
|
+
const { SwaigFunctionResult } = await import('@anthropic/signalwire-agents');
|
|
131
|
+
const result = new SwaigFunctionResult();
|
|
132
|
+
result.setResponse(`System ${args.system} is operational.`);
|
|
133
|
+
return result;
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const app = agent.getApp();
|
|
138
|
+
|
|
139
|
+
// Export the Lambda handler
|
|
140
|
+
export const handler = ServerlessAdapter.createLambdaHandler(app);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### How It Works
|
|
144
|
+
|
|
145
|
+
`createLambdaHandler()` creates a new `ServerlessAdapter` instance with `platform: 'lambda'` and returns a function with the signature:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
(event: ServerlessEvent) => Promise<ServerlessResponse>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
This matches the AWS Lambda handler contract. The event object maps directly to API Gateway proxy integration events (both v1 and v2):
|
|
152
|
+
|
|
153
|
+
- `event.httpMethod` -- HTTP method (v1)
|
|
154
|
+
- `event.rawPath` -- Request path (v2, preferred)
|
|
155
|
+
- `event.path` -- Request path (v1 fallback)
|
|
156
|
+
- `event.headers` -- Request headers
|
|
157
|
+
- `event.body` -- Request body (string)
|
|
158
|
+
- `event.queryStringParameters` -- Query parameters
|
|
159
|
+
|
|
160
|
+
### Deployment
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# Build and package
|
|
164
|
+
npm run build
|
|
165
|
+
zip -r function.zip dist/ node_modules/ package.json
|
|
166
|
+
|
|
167
|
+
# Deploy via AWS CLI
|
|
168
|
+
aws lambda create-function \
|
|
169
|
+
--function-name my-agent \
|
|
170
|
+
--runtime nodejs20.x \
|
|
171
|
+
--handler dist/handler.handler \
|
|
172
|
+
--zip-file fileb://function.zip \
|
|
173
|
+
--environment "Variables={AGENT_PASSWORD=s3cret}"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Google Cloud Functions
|
|
179
|
+
|
|
180
|
+
Use `ServerlessAdapter.createGcfHandler()` to create a GCF-compatible handler.
|
|
181
|
+
|
|
182
|
+
### Example: Cloud Function Handler
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
// index.ts
|
|
186
|
+
import { AgentBase, ServerlessAdapter } from '@anthropic/signalwire-agents';
|
|
187
|
+
|
|
188
|
+
const agent = new AgentBase({
|
|
189
|
+
name: 'gcf-agent',
|
|
190
|
+
basicAuth: ['admin', process.env.AGENT_PASSWORD!],
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
agent.setPromptText('You are a helpful assistant on Google Cloud Functions.');
|
|
194
|
+
|
|
195
|
+
const app = agent.getApp();
|
|
196
|
+
|
|
197
|
+
// Export the GCF handler
|
|
198
|
+
export const agentHandler = ServerlessAdapter.createGcfHandler(app);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### How It Works
|
|
202
|
+
|
|
203
|
+
`createGcfHandler()` returns a function with the signature:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
(req: any, res: any) => Promise<void>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
This matches the Google Cloud Functions HTTP function contract. The adapter:
|
|
210
|
+
|
|
211
|
+
1. Constructs a `ServerlessEvent` from the GCF `req` object:
|
|
212
|
+
- `req.method` -- HTTP method
|
|
213
|
+
- `req.headers` -- Request headers
|
|
214
|
+
- `req.body` -- Request body (already parsed by GCF)
|
|
215
|
+
- `req.path` or `req.url` -- Request path
|
|
216
|
+
2. Routes through the Hono app via `handleRequest()`.
|
|
217
|
+
3. Writes the response to `res` using `res.status()`, `res.set()`, and `res.send()`.
|
|
218
|
+
|
|
219
|
+
### Deployment
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# Deploy via gcloud CLI
|
|
223
|
+
gcloud functions deploy agentHandler \
|
|
224
|
+
--runtime nodejs20 \
|
|
225
|
+
--trigger-http \
|
|
226
|
+
--entry-point agentHandler \
|
|
227
|
+
--set-env-vars AGENT_PASSWORD=s3cret \
|
|
228
|
+
--allow-unauthenticated
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Azure Functions
|
|
234
|
+
|
|
235
|
+
Use `ServerlessAdapter.createAzureHandler()` to create an Azure Functions-compatible handler.
|
|
236
|
+
|
|
237
|
+
### Example: Azure Function Handler
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// index.ts
|
|
241
|
+
import { AgentBase, ServerlessAdapter } from '@anthropic/signalwire-agents';
|
|
242
|
+
|
|
243
|
+
const agent = new AgentBase({
|
|
244
|
+
name: 'azure-agent',
|
|
245
|
+
basicAuth: ['admin', process.env.AGENT_PASSWORD!],
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
agent.setPromptText('You are a helpful assistant on Azure Functions.');
|
|
249
|
+
|
|
250
|
+
const app = agent.getApp();
|
|
251
|
+
|
|
252
|
+
// Export the Azure handler
|
|
253
|
+
const azureHandler = ServerlessAdapter.createAzureHandler(app);
|
|
254
|
+
export default azureHandler;
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### How It Works
|
|
258
|
+
|
|
259
|
+
`createAzureHandler()` returns a function with the signature:
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
(context: any, req: any) => Promise<void>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
This matches the Azure Functions HTTP trigger contract. The adapter:
|
|
266
|
+
|
|
267
|
+
1. Constructs a `ServerlessEvent` from the Azure `req` object:
|
|
268
|
+
- `req.method` -- HTTP method
|
|
269
|
+
- `req.headers` -- Request headers
|
|
270
|
+
- `req.body` -- Request body
|
|
271
|
+
- `req.url` -- Request path
|
|
272
|
+
2. Routes through the Hono app via `handleRequest()`.
|
|
273
|
+
3. Sets `context.res` with `status`, `headers`, and `body`.
|
|
274
|
+
|
|
275
|
+
### Deployment
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
# Deploy via Azure CLI
|
|
279
|
+
func azure functionapp publish my-agent-app \
|
|
280
|
+
--typescript
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### function.json
|
|
284
|
+
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"bindings": [
|
|
288
|
+
{
|
|
289
|
+
"authLevel": "anonymous",
|
|
290
|
+
"type": "httpTrigger",
|
|
291
|
+
"direction": "in",
|
|
292
|
+
"name": "req",
|
|
293
|
+
"methods": ["get", "post"]
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"type": "http",
|
|
297
|
+
"direction": "out",
|
|
298
|
+
"name": "res"
|
|
299
|
+
}
|
|
300
|
+
]
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## CGI Mode
|
|
307
|
+
|
|
308
|
+
For traditional CGI environments, use the `ServerlessAdapter` with `platform: 'cgi'`:
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
import { AgentBase, ServerlessAdapter } from '@anthropic/signalwire-agents';
|
|
312
|
+
|
|
313
|
+
const agent = new AgentBase({ name: 'cgi-agent' });
|
|
314
|
+
agent.setPromptText('You are a CGI-deployed assistant.');
|
|
315
|
+
|
|
316
|
+
const adapter = new ServerlessAdapter('cgi');
|
|
317
|
+
const app = agent.getApp();
|
|
318
|
+
|
|
319
|
+
// Read CGI environment and stdin to build a ServerlessEvent
|
|
320
|
+
const event = {
|
|
321
|
+
method: process.env.REQUEST_METHOD ?? 'GET',
|
|
322
|
+
headers: {
|
|
323
|
+
'content-type': process.env.CONTENT_TYPE ?? 'application/json',
|
|
324
|
+
host: process.env.HTTP_HOST ?? 'localhost',
|
|
325
|
+
authorization: process.env.HTTP_AUTHORIZATION ?? '',
|
|
326
|
+
},
|
|
327
|
+
path: process.env.PATH_INFO ?? '/',
|
|
328
|
+
body: await readStdin(),
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
const response = await adapter.handleRequest(app, event);
|
|
332
|
+
|
|
333
|
+
// Write CGI response
|
|
334
|
+
process.stdout.write(`Status: ${response.statusCode}\r\n`);
|
|
335
|
+
for (const [key, value] of Object.entries(response.headers)) {
|
|
336
|
+
process.stdout.write(`${key}: ${value}\r\n`);
|
|
337
|
+
}
|
|
338
|
+
process.stdout.write('\r\n');
|
|
339
|
+
process.stdout.write(response.body);
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
CGI mode is auto-detected when the `GATEWAY_INTERFACE` environment variable is present (e.g., `GATEWAY_INTERFACE=CGI/1.1`).
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## Platform Detection
|
|
347
|
+
|
|
348
|
+
When the `ServerlessAdapter` is created with `platform: 'auto'` (the default), the platform is detected by checking for well-known environment variables in the following order:
|
|
349
|
+
|
|
350
|
+
| Order | Environment Variables Checked | Detected Platform |
|
|
351
|
+
|---|---|---|
|
|
352
|
+
| 1 | `AWS_LAMBDA_FUNCTION_NAME` or `_HANDLER` | `lambda` |
|
|
353
|
+
| 2 | `FUNCTION_TARGET` or `K_SERVICE` | `gcf` |
|
|
354
|
+
| 3 | `FUNCTIONS_WORKER_RUNTIME` or `AZURE_FUNCTIONS_ENVIRONMENT` | `azure` |
|
|
355
|
+
| 4 | `GATEWAY_INTERFACE` | `cgi` |
|
|
356
|
+
| 5 | *(none matched)* | `lambda` (default fallback) |
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
const adapter = new ServerlessAdapter('auto');
|
|
360
|
+
console.log(adapter.getPlatform());
|
|
361
|
+
// 'lambda', 'gcf', 'azure', or 'cgi'
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
The `detectPlatform()` method can also be called explicitly:
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
const adapter = new ServerlessAdapter('auto');
|
|
368
|
+
const platform = adapter.detectPlatform();
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## URL Generation
|
|
374
|
+
|
|
375
|
+
The `generateUrl()` method constructs the expected invocation URL for a deployed function on each platform:
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
const adapter = new ServerlessAdapter('lambda');
|
|
379
|
+
const url = adapter.generateUrl({
|
|
380
|
+
region: 'us-west-2',
|
|
381
|
+
apiId: 'abc123xyz',
|
|
382
|
+
stage: 'prod',
|
|
383
|
+
});
|
|
384
|
+
// "https://abc123xyz.execute-api.us-west-2.amazonaws.com/prod"
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### URL Formats by Platform
|
|
388
|
+
|
|
389
|
+
**AWS Lambda (API Gateway)**
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
const adapter = new ServerlessAdapter('lambda');
|
|
393
|
+
adapter.generateUrl({
|
|
394
|
+
region: 'us-east-1', // default: AWS_REGION env or 'us-east-1'
|
|
395
|
+
apiId: 'abc123', // default: 'API_ID'
|
|
396
|
+
stage: 'prod', // default: 'prod'
|
|
397
|
+
});
|
|
398
|
+
// "https://abc123.execute-api.us-east-1.amazonaws.com/prod"
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**Google Cloud Functions**
|
|
402
|
+
|
|
403
|
+
```typescript
|
|
404
|
+
const adapter = new ServerlessAdapter('gcf');
|
|
405
|
+
adapter.generateUrl({
|
|
406
|
+
projectId: 'my-project', // default: GCLOUD_PROJECT env or 'PROJECT'
|
|
407
|
+
region: 'us-central1', // default: FUNCTION_REGION env or 'us-central1'
|
|
408
|
+
functionName: 'agent', // default: AWS_LAMBDA_FUNCTION_NAME env or 'agent'
|
|
409
|
+
});
|
|
410
|
+
// "https://us-central1-my-project.cloudfunctions.net/agent"
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
**Azure Functions**
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
const adapter = new ServerlessAdapter('azure');
|
|
417
|
+
adapter.generateUrl({
|
|
418
|
+
functionName: 'my-agent', // default: 'agent'
|
|
419
|
+
});
|
|
420
|
+
// "https://my-agent.azurewebsites.net/api/my-agent"
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
**CGI**
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
const adapter = new ServerlessAdapter('cgi');
|
|
427
|
+
adapter.generateUrl({
|
|
428
|
+
functionName: 'my-agent',
|
|
429
|
+
});
|
|
430
|
+
// "http://localhost/cgi-bin/my-agent"
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### generateUrl() Options
|
|
434
|
+
|
|
435
|
+
| Option | Type | Default | Description |
|
|
436
|
+
|---|---|---|---|
|
|
437
|
+
| `region` | `string` | Platform-specific env var or default | Cloud region for the function. |
|
|
438
|
+
| `projectId` | `string` | `GCLOUD_PROJECT` env or `"PROJECT"` | GCP project ID (GCF only). |
|
|
439
|
+
| `functionName` | `string` | `AWS_LAMBDA_FUNCTION_NAME` env or `"agent"` | Name of the deployed function. |
|
|
440
|
+
| `stage` | `string` | `"prod"` | API Gateway stage (Lambda only). |
|
|
441
|
+
| `apiId` | `string` | `"API_ID"` | API Gateway ID (Lambda only). |
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## CLI Testing
|
|
446
|
+
|
|
447
|
+
You can test serverless deployments locally using the `swaig-test` CLI tool. While there is no dedicated `--simulate-serverless` flag, you can test agent functionality locally before deploying:
|
|
448
|
+
|
|
449
|
+
### Testing Tools Locally
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
# List all registered tools
|
|
453
|
+
npx swaig-test --file handler.ts --list-tools
|
|
454
|
+
|
|
455
|
+
# Dump the SWML document the agent generates
|
|
456
|
+
npx swaig-test --file handler.ts --dump-swml
|
|
457
|
+
|
|
458
|
+
# Execute a specific tool with arguments
|
|
459
|
+
npx swaig-test --file handler.ts --exec get_status --args '{"system": "production"}'
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### Local Development Pattern
|
|
463
|
+
|
|
464
|
+
For local development and testing before deploying to a serverless platform, run the agent as a standard HTTP server:
|
|
465
|
+
|
|
466
|
+
```typescript
|
|
467
|
+
// local-dev.ts
|
|
468
|
+
import { AgentBase } from '@anthropic/signalwire-agents';
|
|
469
|
+
|
|
470
|
+
const agent = new AgentBase({
|
|
471
|
+
name: 'my-agent',
|
|
472
|
+
port: 3000,
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
agent.setPromptText('You are a helpful assistant.');
|
|
476
|
+
|
|
477
|
+
// In development, run as an HTTP server
|
|
478
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
479
|
+
agent.serve();
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Export the app for serverless deployment
|
|
483
|
+
export const app = agent.getApp();
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### Simulating Serverless Events
|
|
487
|
+
|
|
488
|
+
You can manually test the `ServerlessAdapter` with constructed events:
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
import { AgentBase, ServerlessAdapter } from '@anthropic/signalwire-agents';
|
|
492
|
+
|
|
493
|
+
const agent = new AgentBase({ name: 'test-agent', basicAuth: ['admin', 'test'] });
|
|
494
|
+
agent.setPromptText('Hello!');
|
|
495
|
+
|
|
496
|
+
const adapter = new ServerlessAdapter('lambda');
|
|
497
|
+
const app = agent.getApp();
|
|
498
|
+
|
|
499
|
+
// Simulate a Lambda event
|
|
500
|
+
const event = {
|
|
501
|
+
httpMethod: 'POST',
|
|
502
|
+
path: '/',
|
|
503
|
+
headers: {
|
|
504
|
+
'content-type': 'application/json',
|
|
505
|
+
authorization: 'Basic ' + Buffer.from('admin:test').toString('base64'),
|
|
506
|
+
},
|
|
507
|
+
body: JSON.stringify({ call_id: 'test-call-123' }),
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
const response = await adapter.handleRequest(app, event);
|
|
511
|
+
console.log('Status:', response.statusCode);
|
|
512
|
+
console.log('Body:', response.body);
|
|
513
|
+
```
|