@teamlearners/clawops
v0.6.0
Published
Official Node.js/TypeScript SDK for the ClawOps Voice API
Maintainers
Readme
ClawOps Node.js SDK
ClawOps Voice API의 공식 Node.js/TypeScript 라이브러리입니다.
설치
# REST API SDK만 사용
npm install @teamlearners/clawops
# AI Agent 포함 (필요한 프로바이더를 함께 설치)
npm install @teamlearners/clawops ws openai # OpenAI Realtime 모드
npm install @teamlearners/clawops ws @google/genai # Gemini Realtime 모드
npm install @teamlearners/clawops ws @deepgram/sdk openai elevenlabs # Pipeline 모드 (OpenAI LLM)
npm install @teamlearners/clawops ws @deepgram/sdk @anthropic-ai/sdk elevenlabs # Pipeline 모드 (Anthropic LLM)AI Agent (음성 에이전트)
ClawOpsAgent를 사용하면 한 줄로 인바운드 전화를 AI로 처리할 수 있습니다. ngrok 없이 WebSocket 역방향 연결로 동작합니다.
import { ClawOpsAgent, OpenAIRealtime } from '@teamlearners/clawops/agent';
const agent = new ClawOpsAgent({
from: '07012341234',
session: new OpenAIRealtime({
systemPrompt: '친절한 상담원입니다. 고객의 질문에 답변해주세요.',
voice: 'marin',
language: 'ko',
}),
});
agent.tool('check_order', '주문 상태를 확인합니다.', { orderId: { type: 'string' } }, async ({ orderId }) => {
return '배송 완료';
});
agent.on('call_start', async (call) => {
console.log(`통화 시작: ${call.fromNumber} -> ${call.toNumber}`);
});
await agent.serve(); // Ctrl+C로 종료MCP 서버 연동
MCP 서버를 연결하여 AI에게 외부 도구를 제공할 수 있습니다.
npm install @teamlearners/clawops ws @modelcontextprotocol/sdkimport { ClawOpsAgent, OpenAIRealtime, mcpServerStdio, mcpServerHTTP } from '@teamlearners/clawops/agent';
const agent = new ClawOpsAgent({
from: '07012341234',
session: new OpenAIRealtime({
systemPrompt: '상담원입니다.',
}),
mcpServers: [
mcpServerStdio('npx', { args: ['@modelcontextprotocol/server-google'], env: { GOOGLE_API_KEY: '...' } }),
mcpServerHTTP('https://my-mcp-server.com', { headers: { Authorization: 'Bearer token' } }),
],
});
await agent.serve(); // Ctrl+C로 종료MCP 서버는 전화가 올 때마다 자동으로 시작되고, 통화 종료 시 정리됩니다. MCP 서버가 제공하는 도구는 agent.tool()로 등록한 도구와 함께 세션에 자동 등록됩니다.
OpenTelemetry Tracing
통화 흐름, MCP 도구 호출, LLM 세션을 OpenTelemetry로 추적할 수 있습니다.
npm install @teamlearners/clawops ws @opentelemetry/api @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-grpcimport { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
const provider = new NodeTracerProvider();
provider.addSpanProcessor(new BatchSpanProcessor(new OTLPTraceExporter()));
provider.register();
import { ClawOpsAgent, OpenAIRealtime, setTracingConfig } from '@teamlearners/clawops/agent';
setTracingConfig({ enabled: true, serviceName: 'my-call-center' });
const agent = new ClawOpsAgent({
from: '07012341234',
session: new OpenAIRealtime({ systemPrompt: '상담원입니다.' }),
});Span 계층:
call→mcp.connect→llm.session→tool.call→mcp.call_tool
자세한 사용법은 Agent 문서 를 참고하세요. (Tool, 이벤트, 통화 녹음, 파이프라인 모드, 커스텀 제공자, MCP 연동, Tracing 등)
REST API 사용법
import ClawOps from '@teamlearners/clawops';
const client = new ClawOps({
apiKey: 'sk_...', // 또는 CLAWOPS_API_KEY 환경변수 사용
accountId: 'AC1a2b3c4d', // 또는 CLAWOPS_ACCOUNT_ID 환경변수 사용
});통화 (Calls)
// 발신 전화 생성
const call = await client.calls.create({
to: '01012345678',
from: '07052358010',
url: 'https://my-app.com/twiml',
statusCallback: 'https://my-app.com/status',
statusCallbackEvent: 'initiated ringing answered completed',
});
console.log(call.callId);
// 통화 목록 조회 (페이지네이션)
const page = await client.calls.list({ status: 'completed', page: 0, pageSize: 20 });
for (const call of page) {
console.log(call.callId, call.status);
}
// 모든 통화를 자동으로 순회
for await (const call of (await client.calls.list()).autoPagingIter()) {
console.log(call.callId);
}
// 특정 통화 조회
const detail = await client.calls.get('CAabcdef1234567890');
// 통화 종료
await client.calls.update('CAabcdef1234567890', { status: 'completed' });전화번호 (Numbers)
// 번호 구매
const number = await client.numbers.create({ source: 'pool' });
console.log(number.phoneNumber);
// 번호 목록 조회
const numbers = await client.numbers.list();
// 웹훅 URL 변경
await client.numbers.update('07012340001', { webhookUrl: 'https://my-app.com/webhook' });
// 번호 해제
await client.numbers.delete('07012340001');메시지 (Messages)
// SMS 발송
const msg = await client.messages.create({
to: '01012345678',
from: '07052358010',
body: '안녕하세요',
});
console.log(msg.messageId);
// MMS 발송
const mms = await client.messages.create({
to: '01012345678',
from: '07052358010',
body: '사진 첨부',
type: 'mms',
subject: '제목',
});
// LMS (장문 문자) 발송
const lms = await client.messages.create({
to: '01012345678',
from: '07052358010',
body: '긴 내용의 메시지입니다...',
type: 'lms',
subject: '알림',
});
// 메시지 목록 조회 (필터링)
const msgPage = await client.messages.list({ type: 'sms', status: 'sent', page: 0, pageSize: 20 });
for (const m of msgPage) {
console.log(m.messageId, m.status);
}
// 모든 메시지를 자동으로 순회
for await (const m of (await client.messages.list()).autoPagingIter()) {
console.log(m.messageId);
}
// 특정 메시지 조회
const detail = await client.messages.get('MG0123456789abcdef');멀티 계정 접근
// 다른 계정의 리소스에 접근
const other = client.accounts('AC_other_account_id');
await other.calls.list();
await other.numbers.list();
await other.messages.list();웹훅 서명 검증
client.webhooks.verify({
url: 'https://my-app.com/webhook',
params: { CallId: 'CA...', CallStatus: 'completed' },
signature: request.headers['x-signature'],
signingKey: 'your_account_signing_key',
});서명이 유효하지 않으면 WebhookVerificationError가 발생합니다.
에러 처리
import ClawOps, { BadRequestError, AuthenticationError, NotFoundError } from '@teamlearners/clawops';
const client = new ClawOps();
try {
const call = await client.calls.create({ to: '01012345678', from: '07052358010', url: 'https://...' });
} catch (e) {
if (e instanceof BadRequestError) {
console.log(`잘못된 요청: ${e.statusCode} - ${JSON.stringify(e.body)}`);
} else if (e instanceof AuthenticationError) {
console.log(`유효하지 않은 API 키: ${e.statusCode}`);
} else if (e instanceof NotFoundError) {
console.log(`리소스를 찾을 수 없음: ${e.statusCode}`);
}
}모든 에러는 ClawOpsError를 상속합니다. HTTP 에러는 statusCode, body 속성을 제공합니다.
| 에러 | 상태 코드 |
| -------------------------- | --------- |
| BadRequestError | 400 |
| AuthenticationError | 401 |
| PermissionDeniedError | 403 |
| NotFoundError | 404 |
| ConflictError | 409 |
| UnprocessableEntityError | 422 |
| InternalServerError | 500+ |
| ServiceUnavailableError | 503 |
설정
재시도
기본적으로 408, 409, 429, 500+ 에러 시 지수 백오프로 최대 2회 재시도합니다.
const client = new ClawOps({ maxRetries: 5 });
// 재시도 비활성화
const client = new ClawOps({ maxRetries: 0 });타임아웃
기본 타임아웃은 600초입니다. 클라이언트 단위로 변경할 수 있습니다:
const client = new ClawOps({ timeout: 30_000 }); // 30초 (밀리초)커스텀 fetch
프록시 등 고급 설정이 필요한 경우 커스텀 fetch 함수를 주입할 수 있습니다:
import { ProxyAgent } from 'undici';
const dispatcher = new ProxyAgent('http://proxy.example.com:8080');
const client = new ClawOps({
fetch: (url, init) => fetch(url, { ...init, dispatcher }),
});환경변수
| 변수 | 설명 | 필수 여부 |
| -------------------- | ---------------------- | ------------------------------------------- |
| CLAWOPS_API_KEY | API 키 (sk_...) | 예 (생성자에 전달하지 않은 경우) |
| CLAWOPS_ACCOUNT_ID | 기본 계정 ID (AC...) | 예 (생성자에 전달하지 않은 경우) |
| CLAWOPS_BASE_URL | API 기본 URL | 아니오 (기본값: https://api.claw-ops.com) |
| OPENAI_API_KEY | OpenAI API 키 | OpenAI Realtime 사용 시 |
| GOOGLE_API_KEY | Google API 키 | Gemini Realtime 사용 시 |
문서
- AI Agent 가이드 — 음성 에이전트 상세 사용법, 파이프라인 모드, 커스텀 제공자, MCP 연동
다른 언어
| 언어 | 패키지 | 저장소 |
|------|--------|--------|
| Python | clawops | clawops-python |
요구사항
- Node.js 18+
zod>= 3.23ws>= 8.0 (Agent 사용 시)
라이선스
Apache-2.0
