phonic
Version:
[](https://buildwithfern.com?utm_source=github&utm_medium=github&utm_campaign=readme&utm_source=https%3A%2F%2Fgithub.com%2FPhonic-Co%2Fphonic-node) [ • 18 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
Phonic: () => Phonic
});
module.exports = __toCommonJS(index_exports);
// package.json
var version = "0.29.1";
// src/agents/index.ts
var Agents = class {
constructor(phonic) {
this.phonic = phonic;
}
getQueryString(params) {
const project = params?.project;
const queryString = new URLSearchParams({
...project !== void 0 && { project }
}).toString();
return queryString;
}
getTemplateVariablesForBody(templateVariables) {
if (templateVariables === void 0) {
return void 0;
}
return Object.fromEntries(
Object.entries(templateVariables).map(([key, value]) => [
key,
{
default_value: value.defaultValue
}
])
);
}
getConfigurationEndpointForBody(configurationEndpoint) {
if (configurationEndpoint === void 0 || configurationEndpoint === null) {
return configurationEndpoint;
}
return {
url: configurationEndpoint.url,
headers: configurationEndpoint.headers,
timeout_ms: configurationEndpoint.timeoutMs
};
}
async list(params) {
const response = await this.phonic.get(
`/agents?${this.getQueryString(params)}`
);
return response;
}
async get(nameOrId, params) {
const response = await this.phonic.get(
`/agents/${nameOrId}?${this.getQueryString(params)}`
);
return response;
}
async create(params) {
const response = await this.phonic.post(
`/agents?${this.getQueryString(params)}`,
{
name: params.name,
phone_number: params.phoneNumber,
timezone: params.timezone,
audio_format: params.phoneNumber === "assign-automatically" ? "mulaw_8000" : params.audioFormat,
audio_speed: params.audioSpeed,
voice_id: params.voiceId,
welcome_message: params.welcomeMessage,
system_prompt: params.systemPrompt,
template_variables: this.getTemplateVariablesForBody(
params.templateVariables
),
tools: params.tools,
no_input_poke_sec: params.noInputPokeSec,
no_input_poke_text: params.noInputPokeText,
no_input_end_conversation_sec: params.noInputEndConversationSec,
boosted_keywords: params.boostedKeywords,
configuration_endpoint: this.getConfigurationEndpointForBody(
params.configurationEndpoint
)
}
);
return response;
}
async update(nameOrId, params) {
const response = await this.phonic.patch(
`/agents/${nameOrId}?${this.getQueryString(params)}`,
{
name: params.name,
phone_number: params.phoneNumber,
timezone: params.timezone,
audio_format: params.phoneNumber === "assign-automatically" ? "mulaw_8000" : params.audioFormat,
voice_id: params.voiceId,
audio_speed: params.audioSpeed,
welcome_message: params.welcomeMessage,
system_prompt: params.systemPrompt,
template_variables: this.getTemplateVariablesForBody(
params.templateVariables
),
tools: params.tools,
no_input_poke_sec: params.noInputPokeSec,
no_input_poke_text: params.noInputPokeText,
no_input_end_conversation_sec: params.noInputEndConversationSec,
boosted_keywords: params.boostedKeywords,
configuration_endpoint: this.getConfigurationEndpointForBody(
params.configurationEndpoint
)
}
);
return response;
}
async upsert(params) {
const response = await this.phonic.put(
`/agents/upsert?${this.getQueryString(params)}`,
{
name: params.name,
phone_number: params.phoneNumber,
timezone: params.timezone,
audio_format: params.phoneNumber === "assign-automatically" ? "mulaw_8000" : params.audioFormat,
voice_id: params.voiceId,
welcome_message: params.welcomeMessage,
system_prompt: params.systemPrompt,
audio_speed: params.audioSpeed,
template_variables: this.getTemplateVariablesForBody(
params.templateVariables
),
tools: params.tools,
no_input_poke_sec: params.noInputPokeSec,
no_input_poke_text: params.noInputPokeText,
no_input_end_conversation_sec: params.noInputEndConversationSec,
boosted_keywords: params.boostedKeywords,
configuration_endpoint: this.getConfigurationEndpointForBody(
params.configurationEndpoint
)
}
);
return response;
}
async delete(nameOrId, params) {
const response = await this.phonic.delete(
`/agents/${nameOrId}?${this.getQueryString(params)}`
);
return response;
}
};
// src/conversations/twilio/index.ts
var Twilio = class {
constructor(phonic) {
this.phonic = phonic;
}
async outboundCall(params, config) {
const response = await this.phonic.post(
"/conversations/twilio/outbound_call",
{
from_phone_number: params.from_phone_number,
to_phone_number: params.to_phone_number,
config
},
{
"X-Twilio-Account-Sid": params.account_sid,
"X-Twilio-Api-Key-Sid": params.api_key_sid,
"X-Twilio-Api-Key-Secret": params.api_key_secret
}
);
return response;
}
};
// src/conversations/index.ts
var Conversations = class {
constructor(phonic) {
this.phonic = phonic;
this.twilio = new Twilio(phonic);
}
twilio;
async list({
project,
durationMin,
durationMax,
startedAtMin,
startedAtMax
}) {
const queryString = new URLSearchParams({
...project !== void 0 && { project },
...durationMin !== void 0 && { duration_min: String(durationMin) },
...durationMax !== void 0 && { duration_max: String(durationMax) },
...startedAtMin !== void 0 && { started_at_min: startedAtMin },
...startedAtMax !== void 0 && { started_at_max: startedAtMax }
}).toString();
const response = await this.phonic.get(
`/conversations?${queryString}`
);
return response;
}
async get(id) {
const response = await this.phonic.get(
`/conversations/${id}`
);
return response;
}
async getByExternalId({
project,
externalId
}) {
const queryString = new URLSearchParams({
...project !== void 0 && { project },
external_id: externalId
}).toString();
const response = await this.phonic.get(
`/conversations?${queryString}`
);
return response;
}
async outboundCall(toPhoneNumber, config) {
const response = await this.phonic.post(
"/conversations/outbound_call",
{
to_phone_number: toPhoneNumber,
config
}
);
return response;
}
};
// src/projects/index.ts
var Projects = class {
constructor(phonic) {
this.phonic = phonic;
}
async list() {
const response = await this.phonic.get("/projects");
return response;
}
async get(nameOrId) {
const response = await this.phonic.get(
`/projects/${nameOrId}`
);
return response;
}
async create(params) {
const response = await this.phonic.post(
"/projects",
{
name: params.name
}
);
return response;
}
async update(nameOrId, params) {
const response = await this.phonic.patch(
`/projects/${nameOrId}`,
{
name: params.name,
default_agent: params.defaultAgent
}
);
return response;
}
async delete(nameOrId) {
const response = await this.phonic.delete(
`/projects/${nameOrId}`
);
return response;
}
};
// src/sts/index.ts
var import_ws = __toESM(require("ws"));
// src/sts/websocket.ts
var PhonicSTSWebSocket = class {
constructor(ws, config) {
this.ws = ws;
this.config = config;
this.buffer.push(
JSON.stringify({
type: "config",
...this.config
})
);
this.ws.onopen = () => {
for (const message of this.buffer) {
this.ws.send(message);
}
this.isOpen = true;
};
this.ws.onmessage = (event) => {
if (this.onMessageCallback === null) {
return;
}
if (typeof event.data !== "string") {
throw new Error("Received non-string message");
}
const dataObj = JSON.parse(
event.data
);
this.onMessageCallback(dataObj);
};
this.ws.onclose = (event) => {
if (this.onCloseCallback === null) {
return;
}
this.onCloseCallback(event);
};
this.ws.onerror = (event) => {
if (this.onErrorCallback === null) {
return;
}
this.onErrorCallback(event);
};
this.onMessage = this.onMessage.bind(this);
this.onClose = this.onClose.bind(this);
this.onError = this.onError.bind(this);
this.audioChunk = this.audioChunk.bind(this);
this.sendToolCallOutput = this.sendToolCallOutput.bind(this);
this.updateSystemPrompt = this.updateSystemPrompt.bind(this);
this.setExternalId = this.setExternalId.bind(this);
this.close = this.close.bind(this);
}
onMessageCallback = null;
onCloseCallback = null;
onErrorCallback = null;
buffer = [];
isOpen = false;
processUserMessage(message) {
const messageStr = JSON.stringify(message);
if (this.isOpen) {
this.ws.send(messageStr);
} else {
this.buffer.push(messageStr);
}
}
onMessage(callback) {
this.onMessageCallback = callback;
}
onClose(callback) {
this.onCloseCallback = callback;
}
onError(callback) {
this.onErrorCallback = callback;
}
audioChunk({ audio }) {
this.processUserMessage({
type: "audio_chunk",
audio
});
}
sendToolCallOutput({
toolCallId,
output
}) {
this.processUserMessage({
type: "tool_call_output",
tool_call_id: toolCallId,
output
});
}
updateSystemPrompt({ systemPrompt }) {
this.processUserMessage({
type: "update_system_prompt",
system_prompt: systemPrompt
});
}
setExternalId({ externalId }) {
this.processUserMessage({
type: "set_external_id",
external_id: externalId
});
}
close(code) {
this.ws.close(code ?? 1e3);
}
};
// src/sts/index.ts
var SpeechToSpeech = class {
constructor(phonic) {
this.phonic = phonic;
}
websocket(config) {
const wsBaseUrl = this.phonic.baseUrl.replace(/^http/, "ws");
const queryString = new URLSearchParams({
...this.phonic.__downstreamWebSocketUrl !== null && {
downstream_websocket_url: this.phonic.__downstreamWebSocketUrl
}
}).toString();
const phonicApiWsUrl = `${wsBaseUrl}/v1/sts/ws?${queryString}`;
const ws = new import_ws.default(phonicApiWsUrl, {
headers: this.phonic.headers
});
return new PhonicSTSWebSocket(ws, config);
}
};
// src/tools/index.ts
var Tools = class {
constructor(phonic) {
this.phonic = phonic;
}
getQueryString(params) {
const project = params?.project;
const queryString = new URLSearchParams({
...project !== void 0 && { project }
}).toString();
return queryString;
}
getParametersForBody(parameters) {
if (parameters === void 0) {
return void 0;
}
return parameters.map((parameter) => {
return {
type: parameter.type,
name: parameter.name,
description: parameter.description,
is_required: parameter.isRequired,
...parameter.type === "array" && {
item_type: parameter.itemType
}
};
});
}
async list(params) {
const response = await this.phonic.get(
`/tools?${this.getQueryString(params)}`
);
return response;
}
async get(nameOrId, params) {
const response = await this.phonic.get(
`/tools/${nameOrId}?${this.getQueryString(params)}`
);
return response;
}
async create(params) {
const body = {
name: params.name,
description: params.description,
type: params.type,
execution_mode: params.executionMode,
parameters: this.getParametersForBody(params.parameters)
};
if (params.type === "custom_webhook") {
body.endpoint_method = params.endpointMethod;
body.endpoint_url = params.endpointUrl;
body.endpoint_headers = params.endpointHeaders;
body.endpoint_timeout_ms = params.endpointTimeoutMs;
}
if (params.type === "custom_websocket") {
body.tool_call_output_timeout_ms = params.toolCallOutputTimeoutMs;
}
const response = await this.phonic.post(
`/tools?${this.getQueryString(params)}`,
body
);
return response;
}
async update(nameOrId, params) {
const response = await this.phonic.patch(
`/tools/${nameOrId}?${this.getQueryString(params)}`,
{
name: params.name,
description: params.description,
type: params.type,
execution_mode: params.executionMode,
endpoint_method: params.endpointMethod,
endpoint_url: params.endpointUrl,
endpoint_headers: params.endpointHeaders,
endpoint_timeout_ms: params.endpointTimeoutMs,
parameters: this.getParametersForBody(params.parameters),
tool_call_output_timeout_ms: params.toolCallOutputTimeoutMs
}
);
return response;
}
async delete(nameOrId, params) {
const response = await this.phonic.delete(
`/tools/${nameOrId}?${this.getQueryString(params)}`
);
return response;
}
};
// src/voices/index.ts
var Voices = class {
constructor(phonic) {
this.phonic = phonic;
}
async list({ model }) {
const response = await this.phonic.get(
`/voices?model=${encodeURIComponent(model)}`
);
return response;
}
async get(id) {
const response = await this.phonic.get(
`/voices/${id}`
);
return response;
}
};
// src/phonic.ts
var defaultBaseUrl = "https://api.phonic.co";
var defaultUserAgent = `phonic-node:${version}`;
var Phonic = class {
constructor(apiKey, config) {
this.apiKey = apiKey;
if (typeof process === "undefined") {
throw new Error(
"Phonic SDK is intended to be used in Node.js environment."
);
}
if (!this.apiKey) {
throw new Error(
'API key is missing. Pass it to the constructor: `new Phonic("ph_...")`'
);
}
this.baseUrl = (config?.baseUrl ?? defaultBaseUrl).replace(/\/$/, "");
this.__downstreamWebSocketUrl = config?.__downstreamWebSocketUrl || null;
this.headers = {
Authorization: `Bearer ${this.apiKey}`,
"User-Agent": process.env.PHONIC_USER_AGENT || defaultUserAgent,
"Content-Type": "application/json",
...config?.headers
};
}
baseUrl;
__downstreamWebSocketUrl;
headers;
agents = new Agents(this);
conversations = new Conversations(this);
projects = new Projects(this);
tools = new Tools(this);
voices = new Voices(this);
sts = new SpeechToSpeech(this);
async fetchRequest(path, options) {
try {
const { headers, ...restOptions } = options;
const response = await fetch(`${this.baseUrl}/v1${path}`, {
headers: {
...this.headers,
...headers
},
...restOptions
});
if (response.ok) {
const data = await response.json();
return { data, error: null };
}
try {
const data = await response.json();
return {
data: null,
error: {
message: data.error.message || response.statusText,
param_errors: data.param_errors
}
};
} catch (error) {
return {
data: null,
error: {
message: response.statusText
}
};
}
} catch (error) {
console.error(error);
return {
data: null,
error: {
message: "Fetch request failed"
}
};
}
}
async get(path) {
return this.fetchRequest(path, { method: "GET" });
}
async post(path, body, headers) {
return this.fetchRequest(path, {
method: "POST",
body: JSON.stringify(body),
headers
});
}
async patch(path, body, headers) {
return this.fetchRequest(path, {
method: "PATCH",
body: JSON.stringify(body),
headers
});
}
async put(path, body, headers) {
return this.fetchRequest(path, {
method: "PUT",
body: JSON.stringify(body),
headers
});
}
async delete(path, headers) {
return this.fetchRequest(path, {
method: "DELETE",
headers
});
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Phonic
});