@polpo-ai/tools 0.2.4
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/dist/adapters/node-filesystem.d.ts +12 -0
- package/dist/adapters/node-filesystem.d.ts.map +1 -0
- package/dist/adapters/node-filesystem.js +46 -0
- package/dist/adapters/node-filesystem.js.map +1 -0
- package/dist/adapters/node-shell.d.ts +5 -0
- package/dist/adapters/node-shell.d.ts.map +1 -0
- package/dist/adapters/node-shell.js +34 -0
- package/dist/adapters/node-shell.js.map +1 -0
- package/dist/audio-tools.d.ts +42 -0
- package/dist/audio-tools.d.ts.map +1 -0
- package/dist/audio-tools.js +552 -0
- package/dist/audio-tools.js.map +1 -0
- package/dist/browser-tools.d.ts +36 -0
- package/dist/browser-tools.d.ts.map +1 -0
- package/dist/browser-tools.js +525 -0
- package/dist/browser-tools.js.map +1 -0
- package/dist/coding-tools.d.ts +99 -0
- package/dist/coding-tools.d.ts.map +1 -0
- package/dist/coding-tools.js +434 -0
- package/dist/coding-tools.js.map +1 -0
- package/dist/docx-tools.d.ts +22 -0
- package/dist/docx-tools.d.ts.map +1 -0
- package/dist/docx-tools.js +236 -0
- package/dist/docx-tools.js.map +1 -0
- package/dist/email-tools.d.ts +34 -0
- package/dist/email-tools.d.ts.map +1 -0
- package/dist/email-tools.js +787 -0
- package/dist/email-tools.js.map +1 -0
- package/dist/excel-tools.d.ts +25 -0
- package/dist/excel-tools.d.ts.map +1 -0
- package/dist/excel-tools.js +409 -0
- package/dist/excel-tools.js.map +1 -0
- package/dist/http-tools.d.ts +23 -0
- package/dist/http-tools.d.ts.map +1 -0
- package/dist/http-tools.js +214 -0
- package/dist/http-tools.js.map +1 -0
- package/dist/image-tools.d.ts +40 -0
- package/dist/image-tools.d.ts.map +1 -0
- package/dist/image-tools.js +522 -0
- package/dist/image-tools.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/memory-tools.d.ts +19 -0
- package/dist/memory-tools.d.ts.map +1 -0
- package/dist/memory-tools.js +104 -0
- package/dist/memory-tools.js.map +1 -0
- package/dist/outcome-tools.d.ts +25 -0
- package/dist/outcome-tools.d.ts.map +1 -0
- package/dist/outcome-tools.js +191 -0
- package/dist/outcome-tools.js.map +1 -0
- package/dist/path-sandbox.d.ts +28 -0
- package/dist/path-sandbox.d.ts.map +1 -0
- package/dist/path-sandbox.js +58 -0
- package/dist/path-sandbox.js.map +1 -0
- package/dist/pdf-tools.d.ts +25 -0
- package/dist/pdf-tools.d.ts.map +1 -0
- package/dist/pdf-tools.js +363 -0
- package/dist/pdf-tools.js.map +1 -0
- package/dist/phone-tools.d.ts +27 -0
- package/dist/phone-tools.d.ts.map +1 -0
- package/dist/phone-tools.js +577 -0
- package/dist/phone-tools.js.map +1 -0
- package/dist/safe-env.d.ts +26 -0
- package/dist/safe-env.d.ts.map +1 -0
- package/dist/safe-env.js +76 -0
- package/dist/safe-env.js.map +1 -0
- package/dist/search-tools.d.ts +22 -0
- package/dist/search-tools.d.ts.map +1 -0
- package/dist/search-tools.js +205 -0
- package/dist/search-tools.js.map +1 -0
- package/dist/ssrf-guard.d.ts +17 -0
- package/dist/ssrf-guard.d.ts.map +1 -0
- package/dist/ssrf-guard.js +95 -0
- package/dist/ssrf-guard.js.map +1 -0
- package/dist/types.d.ts +21 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/vault-tools.d.ts +26 -0
- package/dist/vault-tools.d.ts.map +1 -0
- package/dist/vault-tools.js +86 -0
- package/dist/vault-tools.js.map +1 -0
- package/dist/whatsapp-tools.d.ts +18 -0
- package/dist/whatsapp-tools.d.ts.map +1 -0
- package/dist/whatsapp-tools.js +206 -0
- package/dist/whatsapp-tools.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phone call tools powered by VAPI (vapi.ai).
|
|
3
|
+
*
|
|
4
|
+
* Provides AI-driven phone call capabilities: make outbound calls with
|
|
5
|
+
* natural language instructions, list recent calls, get call details
|
|
6
|
+
* (transcript, summary, recording), and hang up active calls.
|
|
7
|
+
*
|
|
8
|
+
* Requires VAPI_API_KEY and VAPI_PHONE_NUMBER_ID in vault or environment.
|
|
9
|
+
*
|
|
10
|
+
* Tools:
|
|
11
|
+
* - phone_call: Make an outbound phone call with AI assistant
|
|
12
|
+
* - phone_get_call: Get details of a specific call (transcript, summary, recording)
|
|
13
|
+
* - phone_list_calls: List recent phone calls with status
|
|
14
|
+
* - phone_hangup: Terminate an active phone call
|
|
15
|
+
*/
|
|
16
|
+
import { Type } from "@sinclair/typebox";
|
|
17
|
+
const VAPI_BASE = "https://api.vapi.ai";
|
|
18
|
+
const DEFAULT_MAX_DURATION = 600; // 10 minutes
|
|
19
|
+
const POLL_INTERVAL = 5000; // 5 seconds
|
|
20
|
+
const MAX_POLL_TIME = 15 * 60 * 1000; // 15 minutes
|
|
21
|
+
// ─── Helpers ───
|
|
22
|
+
function getVapiApiKey(vault) {
|
|
23
|
+
return vault?.getKey("vapi", "api_key") ?? process.env.VAPI_API_KEY;
|
|
24
|
+
}
|
|
25
|
+
function getVapiPhoneNumberId(vault) {
|
|
26
|
+
return vault?.getKey("vapi", "phone_number_id") ?? process.env.VAPI_PHONE_NUMBER_ID;
|
|
27
|
+
}
|
|
28
|
+
function ok(text, details) {
|
|
29
|
+
return { content: [{ type: "text", text }], details: details ?? {} };
|
|
30
|
+
}
|
|
31
|
+
function err(text) {
|
|
32
|
+
return { content: [{ type: "text", text }], details: { error: true } };
|
|
33
|
+
}
|
|
34
|
+
function sleep(ms) {
|
|
35
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
36
|
+
}
|
|
37
|
+
async function vapiRequest(method, path, apiKey, body, signal) {
|
|
38
|
+
const res = await fetch(`${VAPI_BASE}${path}`, {
|
|
39
|
+
method,
|
|
40
|
+
headers: {
|
|
41
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
42
|
+
"Content-Type": "application/json",
|
|
43
|
+
},
|
|
44
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
45
|
+
signal,
|
|
46
|
+
});
|
|
47
|
+
const data = await res.json().catch(() => ({}));
|
|
48
|
+
return { ok: res.ok, status: res.status, data };
|
|
49
|
+
}
|
|
50
|
+
function formatDuration(startedAt, endedAt) {
|
|
51
|
+
if (!startedAt || !endedAt)
|
|
52
|
+
return "unknown";
|
|
53
|
+
const ms = new Date(endedAt).getTime() - new Date(startedAt).getTime();
|
|
54
|
+
const secs = Math.round(ms / 1000);
|
|
55
|
+
if (secs < 60)
|
|
56
|
+
return `${secs}s`;
|
|
57
|
+
return `${Math.floor(secs / 60)}m ${secs % 60}s`;
|
|
58
|
+
}
|
|
59
|
+
function formatEndedReason(reason) {
|
|
60
|
+
if (!reason)
|
|
61
|
+
return "unknown";
|
|
62
|
+
const map = {
|
|
63
|
+
"customer-ended-call": "Customer hung up",
|
|
64
|
+
"assistant-ended-call": "Assistant ended the call",
|
|
65
|
+
"assistant-said-end-call-phrase": "End-call phrase triggered",
|
|
66
|
+
"customer-did-not-answer": "No answer",
|
|
67
|
+
"customer-busy": "Line busy",
|
|
68
|
+
"exceeded-max-duration": "Max duration exceeded",
|
|
69
|
+
"silence-timed-out": "Silence timeout",
|
|
70
|
+
"voicemail": "Went to voicemail",
|
|
71
|
+
"assistant-forwarded-call": "Call transferred",
|
|
72
|
+
"manually-canceled": "Manually canceled",
|
|
73
|
+
};
|
|
74
|
+
return map[reason] ?? reason;
|
|
75
|
+
}
|
|
76
|
+
function formatCallResult(call) {
|
|
77
|
+
const parts = [];
|
|
78
|
+
parts.push(`**Call ID:** ${call.id}`);
|
|
79
|
+
parts.push(`**Status:** ${call.status}`);
|
|
80
|
+
if (call.customer?.number) {
|
|
81
|
+
parts.push(`**Number:** ${call.customer.number}${call.customer.name ? ` (${call.customer.name})` : ""}`);
|
|
82
|
+
}
|
|
83
|
+
if (call.endedReason) {
|
|
84
|
+
parts.push(`**Ended:** ${formatEndedReason(call.endedReason)}`);
|
|
85
|
+
}
|
|
86
|
+
parts.push(`**Duration:** ${formatDuration(call.startedAt, call.endedAt)}`);
|
|
87
|
+
if (call.cost !== undefined) {
|
|
88
|
+
parts.push(`**Cost:** $${call.cost.toFixed(4)}`);
|
|
89
|
+
}
|
|
90
|
+
if (call.analysis?.summary) {
|
|
91
|
+
parts.push(`\n**Summary:**\n${call.analysis.summary}`);
|
|
92
|
+
}
|
|
93
|
+
if (call.artifact?.transcript) {
|
|
94
|
+
const transcript = call.artifact.transcript.length > 3000
|
|
95
|
+
? call.artifact.transcript.slice(0, 3000) + "\n... (truncated)"
|
|
96
|
+
: call.artifact.transcript;
|
|
97
|
+
parts.push(`\n**Transcript:**\n${transcript}`);
|
|
98
|
+
}
|
|
99
|
+
if (call.artifact?.recordingUrl) {
|
|
100
|
+
parts.push(`\n**Recording:** ${call.artifact.recordingUrl}`);
|
|
101
|
+
}
|
|
102
|
+
if (call.analysis?.successEvaluation) {
|
|
103
|
+
parts.push(`**Success:** ${call.analysis.successEvaluation}`);
|
|
104
|
+
}
|
|
105
|
+
return parts.join("\n");
|
|
106
|
+
}
|
|
107
|
+
// ─── phone_call ───
|
|
108
|
+
const PhoneCallSchema = Type.Object({
|
|
109
|
+
number: Type.String({ description: "Phone number to call (E.164 format with country code, e.g. '+14155551234' or '+393381234567')" }),
|
|
110
|
+
instructions: Type.String({ description: "Natural language instructions for the AI assistant — what to say, what to ask, what information to collect" }),
|
|
111
|
+
firstMessage: Type.Optional(Type.String({ description: "First message the assistant says when the call connects (e.g. 'Hi, this is Sara from Acme Corp.')" })),
|
|
112
|
+
customerName: Type.Optional(Type.String({ description: "Name of the person being called (for context)" })),
|
|
113
|
+
maxDuration: Type.Optional(Type.Number({ description: `Maximum call duration in seconds (default: ${DEFAULT_MAX_DURATION}, max: 1800)` })),
|
|
114
|
+
voice: Type.Optional(Type.String({ description: "Voice ID for TTS (default: VAPI default voice). Use provider:voiceId format (e.g. '11labs:sarah')" })),
|
|
115
|
+
record: Type.Optional(Type.Boolean({ description: "Record the call (default: true)" })),
|
|
116
|
+
wait: Type.Optional(Type.Boolean({ description: "Wait for the call to complete and return transcript (default: true). Set to false to return immediately with just the call ID." })),
|
|
117
|
+
});
|
|
118
|
+
function createPhoneCallTool(vault) {
|
|
119
|
+
return {
|
|
120
|
+
name: "phone_call",
|
|
121
|
+
label: "Make Phone Call",
|
|
122
|
+
description: "Make an outbound AI phone call. The AI assistant calls the specified number, follows your instructions, " +
|
|
123
|
+
"and returns a transcript and summary when done. Use this for scheduling, follow-ups, surveys, notifications, " +
|
|
124
|
+
"or any conversation that needs to happen over the phone. WARNING: This is an irreversible side effect — it will actually call the phone number.",
|
|
125
|
+
parameters: PhoneCallSchema,
|
|
126
|
+
async execute(_toolCallId, params, signal) {
|
|
127
|
+
const apiKey = getVapiApiKey(vault);
|
|
128
|
+
if (!apiKey) {
|
|
129
|
+
return err("Error: VAPI_API_KEY not found. Add it to vault (service: vapi, key: api_key) or set as environment variable.");
|
|
130
|
+
}
|
|
131
|
+
const phoneNumberId = getVapiPhoneNumberId(vault);
|
|
132
|
+
if (!phoneNumberId) {
|
|
133
|
+
return err("Error: VAPI_PHONE_NUMBER_ID not found. Add it to vault (service: vapi, key: phone_number_id) or set as environment variable. Buy a phone number at dashboard.vapi.ai first.");
|
|
134
|
+
}
|
|
135
|
+
const maxDuration = Math.min(params.maxDuration ?? DEFAULT_MAX_DURATION, 1800);
|
|
136
|
+
const shouldWait = params.wait !== false;
|
|
137
|
+
const shouldRecord = params.record !== false;
|
|
138
|
+
// Build voice config
|
|
139
|
+
let voiceConfig;
|
|
140
|
+
if (params.voice) {
|
|
141
|
+
const [provider, voiceId] = params.voice.includes(":")
|
|
142
|
+
? params.voice.split(":", 2)
|
|
143
|
+
: ["vapi", params.voice];
|
|
144
|
+
voiceConfig = { provider, voiceId };
|
|
145
|
+
}
|
|
146
|
+
// Build the call request with transient assistant
|
|
147
|
+
const callBody = {
|
|
148
|
+
phoneNumberId,
|
|
149
|
+
customer: {
|
|
150
|
+
number: params.number,
|
|
151
|
+
...(params.customerName ? { name: params.customerName } : {}),
|
|
152
|
+
},
|
|
153
|
+
assistant: {
|
|
154
|
+
model: {
|
|
155
|
+
provider: "openai",
|
|
156
|
+
model: "gpt-4o",
|
|
157
|
+
messages: [
|
|
158
|
+
{
|
|
159
|
+
role: "system",
|
|
160
|
+
content: params.instructions,
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
},
|
|
164
|
+
...(params.firstMessage ? { firstMessage: params.firstMessage } : {}),
|
|
165
|
+
...(voiceConfig ? { voice: voiceConfig } : {}),
|
|
166
|
+
maxDurationSeconds: maxDuration,
|
|
167
|
+
backgroundSound: "office",
|
|
168
|
+
voicemailDetection: {
|
|
169
|
+
provider: "google",
|
|
170
|
+
type: "audio",
|
|
171
|
+
beepMaxAwaitSeconds: 20,
|
|
172
|
+
},
|
|
173
|
+
analysisPlan: {
|
|
174
|
+
summaryPlan: { enabled: true },
|
|
175
|
+
successEvaluationPlan: { enabled: true },
|
|
176
|
+
},
|
|
177
|
+
artifactPlan: {
|
|
178
|
+
recordingEnabled: shouldRecord,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
try {
|
|
183
|
+
const { ok: isOk, status, data } = await vapiRequest("POST", "/call", apiKey, callBody, signal);
|
|
184
|
+
if (!isOk) {
|
|
185
|
+
return err(`Error: VAPI API returned ${status}: ${JSON.stringify(data)}`);
|
|
186
|
+
}
|
|
187
|
+
const callId = data.id;
|
|
188
|
+
if (!shouldWait) {
|
|
189
|
+
return ok(`Call initiated to ${params.number} (ID: ${callId}). Use phone_get_call to check status and get transcript.`, { callId, status: data.status });
|
|
190
|
+
}
|
|
191
|
+
// Poll until call ends
|
|
192
|
+
const pollStart = Date.now();
|
|
193
|
+
let lastStatus = data.status;
|
|
194
|
+
while (Date.now() - pollStart < MAX_POLL_TIME) {
|
|
195
|
+
if (signal?.aborted) {
|
|
196
|
+
return ok(`Call ${callId} still in progress (aborted by agent). Use phone_get_call to check later.\nLast status: ${lastStatus}`, { callId, status: lastStatus });
|
|
197
|
+
}
|
|
198
|
+
await sleep(POLL_INTERVAL);
|
|
199
|
+
const poll = await vapiRequest("GET", `/call/${callId}`, apiKey, undefined, signal);
|
|
200
|
+
if (!poll.ok)
|
|
201
|
+
continue;
|
|
202
|
+
const call = poll.data;
|
|
203
|
+
lastStatus = call.status;
|
|
204
|
+
if (call.status === "ended") {
|
|
205
|
+
return ok(formatCallResult(call), {
|
|
206
|
+
callId: call.id,
|
|
207
|
+
status: call.status,
|
|
208
|
+
endedReason: call.endedReason,
|
|
209
|
+
duration: formatDuration(call.startedAt, call.endedAt),
|
|
210
|
+
transcript: call.artifact?.transcript,
|
|
211
|
+
summary: call.analysis?.summary,
|
|
212
|
+
recordingUrl: call.artifact?.recordingUrl,
|
|
213
|
+
cost: call.cost,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Polling timed out
|
|
218
|
+
return ok(`Call ${callId} is still active after ${MAX_POLL_TIME / 60000} minutes. Use phone_get_call to check later.\nLast status: ${lastStatus}`, { callId, status: lastStatus, timedOut: true });
|
|
219
|
+
}
|
|
220
|
+
catch (e) {
|
|
221
|
+
return err(`Error making phone call: ${e.message}`);
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
// ─── phone_get_call ───
|
|
227
|
+
const PhoneGetCallSchema = Type.Object({
|
|
228
|
+
callId: Type.String({ description: "VAPI call ID to get details for" }),
|
|
229
|
+
});
|
|
230
|
+
function createPhoneGetCallTool(vault) {
|
|
231
|
+
return {
|
|
232
|
+
name: "phone_get_call",
|
|
233
|
+
label: "Get Call Details",
|
|
234
|
+
description: "Get details of a specific phone call including transcript, summary, recording URL, duration, and cost. " +
|
|
235
|
+
"Use this to check the result of a call initiated with phone_call (especially if wait was set to false).",
|
|
236
|
+
parameters: PhoneGetCallSchema,
|
|
237
|
+
async execute(_toolCallId, params, signal) {
|
|
238
|
+
const apiKey = getVapiApiKey(vault);
|
|
239
|
+
if (!apiKey) {
|
|
240
|
+
return err("Error: VAPI_API_KEY not found. Add it to vault (service: vapi, key: api_key) or set as environment variable.");
|
|
241
|
+
}
|
|
242
|
+
try {
|
|
243
|
+
const { ok: isOk, status, data } = await vapiRequest("GET", `/call/${params.callId}`, apiKey, undefined, signal);
|
|
244
|
+
if (!isOk) {
|
|
245
|
+
return err(`Error: VAPI API returned ${status}: ${JSON.stringify(data)}`);
|
|
246
|
+
}
|
|
247
|
+
return ok(formatCallResult(data), {
|
|
248
|
+
callId: data.id,
|
|
249
|
+
status: data.status,
|
|
250
|
+
endedReason: data.endedReason,
|
|
251
|
+
transcript: data.artifact?.transcript,
|
|
252
|
+
summary: data.analysis?.summary,
|
|
253
|
+
recordingUrl: data.artifact?.recordingUrl,
|
|
254
|
+
cost: data.cost,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
catch (e) {
|
|
258
|
+
return err(`Error getting call details: ${e.message}`);
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
// ─── phone_list_calls ───
|
|
264
|
+
const PhoneListCallsSchema = Type.Object({
|
|
265
|
+
limit: Type.Optional(Type.Number({ description: "Maximum number of calls to return (default: 10, max: 100)" })),
|
|
266
|
+
status: Type.Optional(Type.String({ description: "Filter by status: queued, ringing, in-progress, ended" })),
|
|
267
|
+
});
|
|
268
|
+
function createPhoneListCallsTool(vault) {
|
|
269
|
+
return {
|
|
270
|
+
name: "phone_list_calls",
|
|
271
|
+
label: "List Phone Calls",
|
|
272
|
+
description: "List recent phone calls with their status, duration, and summary. Use this to review call history or find specific call IDs.",
|
|
273
|
+
parameters: PhoneListCallsSchema,
|
|
274
|
+
async execute(_toolCallId, params, signal) {
|
|
275
|
+
const apiKey = getVapiApiKey(vault);
|
|
276
|
+
if (!apiKey) {
|
|
277
|
+
return err("Error: VAPI_API_KEY not found. Add it to vault (service: vapi, key: api_key) or set as environment variable.");
|
|
278
|
+
}
|
|
279
|
+
const limit = Math.min(params.limit ?? 10, 100);
|
|
280
|
+
try {
|
|
281
|
+
const { ok: isOk, status, data } = await vapiRequest("GET", `/call?limit=${limit}`, apiKey, undefined, signal);
|
|
282
|
+
if (!isOk) {
|
|
283
|
+
return err(`Error: VAPI API returned ${status}: ${JSON.stringify(data)}`);
|
|
284
|
+
}
|
|
285
|
+
let calls = (Array.isArray(data) ? data : data.calls ?? []);
|
|
286
|
+
if (params.status) {
|
|
287
|
+
calls = calls.filter((c) => c.status === params.status);
|
|
288
|
+
}
|
|
289
|
+
if (calls.length === 0) {
|
|
290
|
+
return ok("No phone calls found.");
|
|
291
|
+
}
|
|
292
|
+
const lines = calls.map((c) => {
|
|
293
|
+
const number = c.customer?.number ?? "unknown";
|
|
294
|
+
const duration = formatDuration(c.startedAt, c.endedAt);
|
|
295
|
+
const reason = c.endedReason ? ` — ${formatEndedReason(c.endedReason)}` : "";
|
|
296
|
+
const summary = c.analysis?.summary ? `\n Summary: ${c.analysis.summary.slice(0, 150)}` : "";
|
|
297
|
+
return `- **${c.id}** | ${c.status} | ${number} | ${duration}${reason}${summary}`;
|
|
298
|
+
});
|
|
299
|
+
return ok(`${calls.length} call(s):\n\n${lines.join("\n\n")}`, { count: calls.length });
|
|
300
|
+
}
|
|
301
|
+
catch (e) {
|
|
302
|
+
return err(`Error listing calls: ${e.message}`);
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
// ─── phone_hangup ───
|
|
308
|
+
const PhoneHangupSchema = Type.Object({
|
|
309
|
+
callId: Type.String({ description: "VAPI call ID to terminate" }),
|
|
310
|
+
});
|
|
311
|
+
function createPhoneHangupTool(vault) {
|
|
312
|
+
return {
|
|
313
|
+
name: "phone_hangup",
|
|
314
|
+
label: "Hang Up Call",
|
|
315
|
+
description: "Terminate an active phone call. Use this to end a call that is currently in progress. WARNING: This will immediately disconnect the call.",
|
|
316
|
+
parameters: PhoneHangupSchema,
|
|
317
|
+
async execute(_toolCallId, params, signal) {
|
|
318
|
+
const apiKey = getVapiApiKey(vault);
|
|
319
|
+
if (!apiKey) {
|
|
320
|
+
return err("Error: VAPI_API_KEY not found. Add it to vault (service: vapi, key: api_key) or set as environment variable.");
|
|
321
|
+
}
|
|
322
|
+
try {
|
|
323
|
+
const { ok: isOk, status, data } = await vapiRequest("DELETE", `/call/${params.callId}`, apiKey, undefined, signal);
|
|
324
|
+
if (!isOk) {
|
|
325
|
+
return err(`Error: VAPI API returned ${status}: ${JSON.stringify(data)}`);
|
|
326
|
+
}
|
|
327
|
+
return ok(`Call ${params.callId} terminated.`, { callId: params.callId });
|
|
328
|
+
}
|
|
329
|
+
catch (e) {
|
|
330
|
+
return err(`Error hanging up call: ${e.message}`);
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
// ─── phone_setup_inbound ───
|
|
336
|
+
const PhoneSetupInboundSchema = Type.Object({
|
|
337
|
+
instructions: Type.String({ description: "System prompt for the inbound assistant — how to greet callers, what to ask, how to handle different scenarios" }),
|
|
338
|
+
firstMessage: Type.Optional(Type.String({ description: "First message when answering (e.g. 'Hello, thank you for calling Acme Corp. How can I help you?')" })),
|
|
339
|
+
voice: Type.Optional(Type.String({ description: "Voice ID (e.g. '11labs:sarah'). Default: VAPI default voice" })),
|
|
340
|
+
maxDuration: Type.Optional(Type.Number({ description: "Maximum call duration in seconds (default: 600, max: 1800)" })),
|
|
341
|
+
record: Type.Optional(Type.Boolean({ description: "Record inbound calls (default: true)" })),
|
|
342
|
+
name: Type.Optional(Type.String({ description: "Name for the inbound assistant (default: 'Polpo Inbound Assistant')" })),
|
|
343
|
+
});
|
|
344
|
+
function createPhoneSetupInboundTool(vault) {
|
|
345
|
+
return {
|
|
346
|
+
name: "phone_setup_inbound",
|
|
347
|
+
label: "Setup Inbound Calls",
|
|
348
|
+
description: "Configure the AI assistant that answers incoming phone calls on your VAPI number. " +
|
|
349
|
+
"Creates a persistent assistant with your instructions and assigns it to the phone number. " +
|
|
350
|
+
"After setup, any call to your number will be answered by the AI. " +
|
|
351
|
+
"Call this again with different instructions to update the inbound behavior.",
|
|
352
|
+
parameters: PhoneSetupInboundSchema,
|
|
353
|
+
async execute(_toolCallId, params, signal) {
|
|
354
|
+
const apiKey = getVapiApiKey(vault);
|
|
355
|
+
if (!apiKey) {
|
|
356
|
+
return err("Error: VAPI_API_KEY not found. Add it to vault (service: vapi, key: api_key) or set as environment variable.");
|
|
357
|
+
}
|
|
358
|
+
const phoneNumberId = getVapiPhoneNumberId(vault);
|
|
359
|
+
if (!phoneNumberId) {
|
|
360
|
+
return err("Error: VAPI_PHONE_NUMBER_ID not found. Add it to vault (service: vapi, key: phone_number_id) or set as environment variable.");
|
|
361
|
+
}
|
|
362
|
+
const maxDuration = Math.min(params.maxDuration ?? DEFAULT_MAX_DURATION, 1800);
|
|
363
|
+
const shouldRecord = params.record !== false;
|
|
364
|
+
const assistantName = params.name ?? "Polpo Inbound Assistant";
|
|
365
|
+
let voiceConfig;
|
|
366
|
+
if (params.voice) {
|
|
367
|
+
const [provider, voiceId] = params.voice.includes(":")
|
|
368
|
+
? params.voice.split(":", 2)
|
|
369
|
+
: ["vapi", params.voice];
|
|
370
|
+
voiceConfig = { provider, voiceId };
|
|
371
|
+
}
|
|
372
|
+
try {
|
|
373
|
+
// Step 1: Check if there's already an assistant on the number
|
|
374
|
+
const phoneRes = await vapiRequest("GET", `/phone-number/${phoneNumberId}`, apiKey, undefined, signal);
|
|
375
|
+
if (!phoneRes.ok) {
|
|
376
|
+
return err(`Error fetching phone number: VAPI returned ${phoneRes.status}`);
|
|
377
|
+
}
|
|
378
|
+
const existingAssistantId = phoneRes.data.assistantId;
|
|
379
|
+
// Step 2: Create or update the assistant
|
|
380
|
+
const assistantBody = {
|
|
381
|
+
name: assistantName,
|
|
382
|
+
model: {
|
|
383
|
+
provider: "openai",
|
|
384
|
+
model: "gpt-4o",
|
|
385
|
+
messages: [{ role: "system", content: params.instructions }],
|
|
386
|
+
},
|
|
387
|
+
...(params.firstMessage ? { firstMessage: params.firstMessage } : { firstMessage: "Hello, how can I help you?" }),
|
|
388
|
+
...(voiceConfig ? { voice: voiceConfig } : {}),
|
|
389
|
+
firstMessageMode: "assistant-speaks-first",
|
|
390
|
+
maxDurationSeconds: maxDuration,
|
|
391
|
+
backgroundSound: "office",
|
|
392
|
+
voicemailDetection: "off",
|
|
393
|
+
analysisPlan: {
|
|
394
|
+
summaryPlan: { enabled: true },
|
|
395
|
+
successEvaluationPlan: { enabled: true },
|
|
396
|
+
},
|
|
397
|
+
artifactPlan: {
|
|
398
|
+
recordingEnabled: shouldRecord,
|
|
399
|
+
},
|
|
400
|
+
};
|
|
401
|
+
let assistantId;
|
|
402
|
+
if (existingAssistantId) {
|
|
403
|
+
// Update existing assistant
|
|
404
|
+
const updateRes = await vapiRequest("PATCH", `/assistant/${existingAssistantId}`, apiKey, assistantBody, signal);
|
|
405
|
+
if (!updateRes.ok) {
|
|
406
|
+
return err(`Error updating assistant: VAPI returned ${updateRes.status}: ${JSON.stringify(updateRes.data)}`);
|
|
407
|
+
}
|
|
408
|
+
assistantId = existingAssistantId;
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
// Create new assistant
|
|
412
|
+
const createRes = await vapiRequest("POST", "/assistant", apiKey, assistantBody, signal);
|
|
413
|
+
if (!createRes.ok) {
|
|
414
|
+
return err(`Error creating assistant: VAPI returned ${createRes.status}: ${JSON.stringify(createRes.data)}`);
|
|
415
|
+
}
|
|
416
|
+
assistantId = createRes.data.id;
|
|
417
|
+
// Step 3: Assign to phone number
|
|
418
|
+
// We need to know the provider to PATCH — get it from the phone number data
|
|
419
|
+
const provider = phoneRes.data.provider ?? "twilio";
|
|
420
|
+
const patchRes = await vapiRequest("PATCH", `/phone-number/${phoneNumberId}`, apiKey, {
|
|
421
|
+
provider,
|
|
422
|
+
assistantId,
|
|
423
|
+
}, signal);
|
|
424
|
+
if (!patchRes.ok) {
|
|
425
|
+
return err(`Error assigning assistant to phone number: VAPI returned ${patchRes.status}: ${JSON.stringify(patchRes.data)}`);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
const number = phoneRes.data.number ?? phoneRes.data.sipUri ?? phoneNumberId;
|
|
429
|
+
return ok(`Inbound assistant configured on ${number}:\n` +
|
|
430
|
+
`- **Assistant ID:** ${assistantId}\n` +
|
|
431
|
+
`- **Name:** ${assistantName}\n` +
|
|
432
|
+
`- **Max duration:** ${maxDuration}s\n` +
|
|
433
|
+
`- **Recording:** ${shouldRecord ? "enabled" : "disabled"}\n\n` +
|
|
434
|
+
`Any incoming calls to this number will now be answered by the AI assistant.`, { assistantId, phoneNumberId, number });
|
|
435
|
+
}
|
|
436
|
+
catch (e) {
|
|
437
|
+
return err(`Error setting up inbound: ${e.message}`);
|
|
438
|
+
}
|
|
439
|
+
},
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
// ─── phone_get_inbound_config ───
|
|
443
|
+
const PhoneGetInboundConfigSchema = Type.Object({});
|
|
444
|
+
function createPhoneGetInboundConfigTool(vault) {
|
|
445
|
+
return {
|
|
446
|
+
name: "phone_get_inbound_config",
|
|
447
|
+
label: "Get Inbound Config",
|
|
448
|
+
description: "Get the current inbound call configuration for your VAPI phone number. Shows the assigned assistant, voice, instructions, and other settings.",
|
|
449
|
+
parameters: PhoneGetInboundConfigSchema,
|
|
450
|
+
async execute(_toolCallId, _params, signal) {
|
|
451
|
+
const apiKey = getVapiApiKey(vault);
|
|
452
|
+
if (!apiKey) {
|
|
453
|
+
return err("Error: VAPI_API_KEY not found.");
|
|
454
|
+
}
|
|
455
|
+
const phoneNumberId = getVapiPhoneNumberId(vault);
|
|
456
|
+
if (!phoneNumberId) {
|
|
457
|
+
return err("Error: VAPI_PHONE_NUMBER_ID not found.");
|
|
458
|
+
}
|
|
459
|
+
try {
|
|
460
|
+
// Get phone number details
|
|
461
|
+
const phoneRes = await vapiRequest("GET", `/phone-number/${phoneNumberId}`, apiKey, undefined, signal);
|
|
462
|
+
if (!phoneRes.ok) {
|
|
463
|
+
return err(`Error: VAPI returned ${phoneRes.status}`);
|
|
464
|
+
}
|
|
465
|
+
const phone = phoneRes.data;
|
|
466
|
+
const number = phone.number ?? phone.sipUri ?? phoneNumberId;
|
|
467
|
+
const parts = [];
|
|
468
|
+
parts.push(`**Phone Number:** ${number}`);
|
|
469
|
+
parts.push(`**Status:** ${phone.status ?? "unknown"}`);
|
|
470
|
+
parts.push(`**Provider:** ${phone.provider ?? "unknown"}`);
|
|
471
|
+
if (!phone.assistantId) {
|
|
472
|
+
parts.push(`\n**Inbound:** Not configured — calls will not be answered by AI.`);
|
|
473
|
+
parts.push(`Use phone_setup_inbound to configure an AI assistant for incoming calls.`);
|
|
474
|
+
return ok(parts.join("\n"), { phoneNumberId, number, configured: false });
|
|
475
|
+
}
|
|
476
|
+
parts.push(`**Assistant ID:** ${phone.assistantId}`);
|
|
477
|
+
// Get assistant details
|
|
478
|
+
const assistantRes = await vapiRequest("GET", `/assistant/${phone.assistantId}`, apiKey, undefined, signal);
|
|
479
|
+
if (assistantRes.ok) {
|
|
480
|
+
const asst = assistantRes.data;
|
|
481
|
+
parts.push(`**Assistant Name:** ${asst.name ?? "unnamed"}`);
|
|
482
|
+
if (asst.model?.messages?.[0]?.content) {
|
|
483
|
+
const instructions = asst.model.messages[0].content;
|
|
484
|
+
const truncated = instructions.length > 500 ? instructions.slice(0, 500) + "..." : instructions;
|
|
485
|
+
parts.push(`**Instructions:**\n${truncated}`);
|
|
486
|
+
}
|
|
487
|
+
if (asst.firstMessage) {
|
|
488
|
+
parts.push(`**First Message:** ${asst.firstMessage}`);
|
|
489
|
+
}
|
|
490
|
+
if (asst.voice) {
|
|
491
|
+
parts.push(`**Voice:** ${asst.voice.provider ?? "default"}:${asst.voice.voiceId ?? "default"}`);
|
|
492
|
+
}
|
|
493
|
+
parts.push(`**Max Duration:** ${asst.maxDurationSeconds ?? 600}s`);
|
|
494
|
+
parts.push(`**Recording:** ${asst.artifactPlan?.recordingEnabled !== false ? "enabled" : "disabled"}`);
|
|
495
|
+
}
|
|
496
|
+
return ok(parts.join("\n"), { phoneNumberId, number, assistantId: phone.assistantId, configured: true });
|
|
497
|
+
}
|
|
498
|
+
catch (e) {
|
|
499
|
+
return err(`Error getting inbound config: ${e.message}`);
|
|
500
|
+
}
|
|
501
|
+
},
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
// ─── phone_disable_inbound ───
|
|
505
|
+
const PhoneDisableInboundSchema = Type.Object({});
|
|
506
|
+
function createPhoneDisableInboundTool(vault) {
|
|
507
|
+
return {
|
|
508
|
+
name: "phone_disable_inbound",
|
|
509
|
+
label: "Disable Inbound Calls",
|
|
510
|
+
description: "Disable the AI assistant for incoming calls on your VAPI phone number. Calls will no longer be answered by the AI. The assistant is deleted.",
|
|
511
|
+
parameters: PhoneDisableInboundSchema,
|
|
512
|
+
async execute(_toolCallId, _params, signal) {
|
|
513
|
+
const apiKey = getVapiApiKey(vault);
|
|
514
|
+
if (!apiKey) {
|
|
515
|
+
return err("Error: VAPI_API_KEY not found.");
|
|
516
|
+
}
|
|
517
|
+
const phoneNumberId = getVapiPhoneNumberId(vault);
|
|
518
|
+
if (!phoneNumberId) {
|
|
519
|
+
return err("Error: VAPI_PHONE_NUMBER_ID not found.");
|
|
520
|
+
}
|
|
521
|
+
try {
|
|
522
|
+
// Get current phone number config
|
|
523
|
+
const phoneRes = await vapiRequest("GET", `/phone-number/${phoneNumberId}`, apiKey, undefined, signal);
|
|
524
|
+
if (!phoneRes.ok) {
|
|
525
|
+
return err(`Error: VAPI returned ${phoneRes.status}`);
|
|
526
|
+
}
|
|
527
|
+
const assistantId = phoneRes.data.assistantId;
|
|
528
|
+
if (!assistantId) {
|
|
529
|
+
return ok("Inbound is already disabled — no assistant is assigned to this phone number.");
|
|
530
|
+
}
|
|
531
|
+
// Remove assistant from phone number
|
|
532
|
+
const provider = phoneRes.data.provider ?? "twilio";
|
|
533
|
+
const patchRes = await vapiRequest("PATCH", `/phone-number/${phoneNumberId}`, apiKey, {
|
|
534
|
+
provider,
|
|
535
|
+
assistantId: null,
|
|
536
|
+
}, signal);
|
|
537
|
+
if (!patchRes.ok) {
|
|
538
|
+
return err(`Error removing assistant from phone number: VAPI returned ${patchRes.status}`);
|
|
539
|
+
}
|
|
540
|
+
// Delete the assistant
|
|
541
|
+
await vapiRequest("DELETE", `/assistant/${assistantId}`, apiKey, undefined, signal);
|
|
542
|
+
const number = phoneRes.data.number ?? phoneRes.data.sipUri ?? phoneNumberId;
|
|
543
|
+
return ok(`Inbound disabled on ${number}. Assistant ${assistantId} removed and deleted.\n` +
|
|
544
|
+
`Incoming calls will no longer be answered by AI.`, { phoneNumberId, number, deletedAssistantId: assistantId });
|
|
545
|
+
}
|
|
546
|
+
catch (e) {
|
|
547
|
+
return err(`Error disabling inbound: ${e.message}`);
|
|
548
|
+
}
|
|
549
|
+
},
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
export const ALL_PHONE_TOOL_NAMES = [
|
|
553
|
+
"phone_call", "phone_get_call", "phone_list_calls", "phone_hangup",
|
|
554
|
+
"phone_setup_inbound", "phone_get_inbound_config", "phone_disable_inbound",
|
|
555
|
+
];
|
|
556
|
+
/**
|
|
557
|
+
* Create VAPI-powered phone call tools.
|
|
558
|
+
*
|
|
559
|
+
* @param vault - Resolved vault credentials (looks for VAPI_API_KEY, VAPI_PHONE_NUMBER_ID)
|
|
560
|
+
* @param allowedTools - Optional filter
|
|
561
|
+
*/
|
|
562
|
+
export function createPhoneTools(vault, allowedTools) {
|
|
563
|
+
const factories = {
|
|
564
|
+
phone_call: () => createPhoneCallTool(vault),
|
|
565
|
+
phone_get_call: () => createPhoneGetCallTool(vault),
|
|
566
|
+
phone_list_calls: () => createPhoneListCallsTool(vault),
|
|
567
|
+
phone_hangup: () => createPhoneHangupTool(vault),
|
|
568
|
+
phone_setup_inbound: () => createPhoneSetupInboundTool(vault),
|
|
569
|
+
phone_get_inbound_config: () => createPhoneGetInboundConfigTool(vault),
|
|
570
|
+
phone_disable_inbound: () => createPhoneDisableInboundTool(vault),
|
|
571
|
+
};
|
|
572
|
+
const names = allowedTools
|
|
573
|
+
? ALL_PHONE_TOOL_NAMES.filter((n) => allowedTools.some((a) => a.toLowerCase() === n))
|
|
574
|
+
: [...ALL_PHONE_TOOL_NAMES];
|
|
575
|
+
return names.map((n) => factories[n]());
|
|
576
|
+
}
|
|
577
|
+
//# sourceMappingURL=phone-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phone-tools.js","sourceRoot":"","sources":["../src/phone-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe environment variable filtering for child processes.
|
|
3
|
+
*
|
|
4
|
+
* Instead of passing the full `process.env` (which leaks API keys, tokens,
|
|
5
|
+
* and secrets to every subprocess), this module provides a filtered env
|
|
6
|
+
* containing only system-essential variables plus an explicit allowlist.
|
|
7
|
+
*
|
|
8
|
+
* Security motivation:
|
|
9
|
+
* - Bash tool commands can read env vars via `env`, `echo $SECRET`, etc.
|
|
10
|
+
* - Any subprocess with full env access has all API keys and credentials.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Create a filtered copy of process.env containing only safe variables.
|
|
14
|
+
*
|
|
15
|
+
* @param extra - Additional env vars to include (e.g. from MCP config).
|
|
16
|
+
* These take precedence over process.env values.
|
|
17
|
+
* @param allowVars - Additional var names to pass through from process.env.
|
|
18
|
+
* Use this for specific Polpo env vars agents need.
|
|
19
|
+
*/
|
|
20
|
+
export declare function safeEnv(extra?: Record<string, string>, allowVars?: string[]): Record<string, string>;
|
|
21
|
+
/**
|
|
22
|
+
* Convenience: create safe env for bash tool.
|
|
23
|
+
* Includes system vars only — no API keys, no secrets.
|
|
24
|
+
*/
|
|
25
|
+
export declare function bashSafeEnv(): Record<string, string>;
|
|
26
|
+
//# sourceMappingURL=safe-env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-env.d.ts","sourceRoot":"","sources":["../src/safe-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA8BH;;;;;;;GAOG;AACH,wBAAgB,OAAO,CACrB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,SAAS,CAAC,EAAE,MAAM,EAAE,GACnB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAyBxB;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEpD"}
|