尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗AgentCaller is an API for AI agents that need to call a business when no useful online workflow exists. The intended MVP handles restaurant reservations, appointments, availability checks, and information requests in English or Spanish, with per-call time and spend limits.
[!IMPORTANT] This repository is a pre-production prototype. Its main components exist and type-check, but the system is not ready to place or bill unattended production calls. See Release readiness for outstanding work and Feasibility for the current assessment.
An accepted task should be narrow, reversible, and easy to verify. The intended
MVP supports calls to Spain and the United States and excludes purchases,
payment-card handling, regulated services, emergency calls, and unrestricted
automatic redialing. The connect_me exception below permits bounded retries
only for confirmed busy/no-answer outcomes.
The target lifecycle is:
The current implementation reaches parts of this flow, but not the complete contract.
connect_me connects a Spanish or Italian landline or mobile business number
to a Spanish mobile, with independently configured business and callback languages.
Its contract, PostgreSQL attempt/leg ledger, scheduler, worker and private
press-1 handoff are implemented and tested offline. Operators can use the
operator-funded test mode
without x402. It requires an enabled server-managed operator profile, an explicit
funding header, and a per-job spend cap (CONNECT_OPERATOR_MAX_USD, default $5).
Paid connect-me requests remain disabled. Stripe monthly invoicing has a
separate release gate; the x402 scheme cannot fund these jobs.
Operator jobs record their authorization and paymentState: not_required; they
do not create a payment receipt or settle through x402.
connect_me supports Call now with callingWindow: "now" and
maxAttempts: 1, or a scheduled weekly window with bounded retries. Call now
ignores local hours and weekdays, never postpones or redials, and is eligible
only before the explicit expiresAt. It does not guarantee immediate worker
availability. Expiry also ends active sessions; it is not just a dialing deadline.
Call now is the default for new portal calls. The portal generates a fixed expiry
30 minutes after the first valid submission and retains it across submission
retries. API callers must supply expiresAt themselves. See
connection timing for
admission limits and scheduled redial behavior.
The platform reserves the worst-case quoted cost of both legs before each
attempt and does not release that hold. Admission rejects a cap that cannot
fund every maxAttempts reserve. Only scheduled jobs with confirmed busy/no-answer
can schedule another attempt. Unknown dial outcomes, refusal, voicemail,
uncertain classification and failed handoff stop the job. Local observation of
SIP answer/disconnection drives leg usage;
missing cost stays null. Reservations are deliberately not refunded between
attempts. They bound quoted usage, not an unverified carrier invoice.
The business and mobile remain in separate LiveKit rooms until callback DTMF 1 and a durable acceptance check. Both AI sessions are silenced before the mobile moves into the business room. The worker remains alive to supervise cleanup. Recording is disabled. LiveKit AMD plus conversational signals are fallible; Spanish/Italian accuracy and all real PSTN behavior remain unverified.
See the connect-me deployment and controlled test procedure and the decision record. The existing API exposes job details and cancellation; the portal shows outcomes and a cancel action. Job deletion is blocked pending provider cleanup and payment reconciliation.
The active product is a pnpm/Turborepo:
| Path | Responsibility |
|---|---|
apps/platform | Next.js API, developer portal, authentication, call ledger, settlement, and webhook delivery |
apps/voice-agent | LiveKit realtime voice worker |
apps/docs | Public API documentation for agents and humans, served at https://docs.agentcaller.io |
packages/contracts | Shared Zod request and state definitions |
packages/database | Active Drizzle schema and database client |
supabase/migrations | Append-only database migration history |
docs/operations.md | Operator runbook: configuration, scheduled drains, testing and discovery checks |
docs/specs | Historical product and implementation designs |
.agents/notes | Dated review evidence and architectural decisions |
The platform publishes /robots.txt, /sitemap.xml,
/.well-known/api-catalog, /openapi.json, and /auth.md. Homepage Link
headers point agents to the catalog, API description, documentation, and
credential provisioning instructions. The API uses operator-provisioned bearer
keys with the ac_ prefix. Optional MCP OAuth onboarding requires human sign-in
and tool consent, and can create a first client profile. MCP_ENABLED defaults
to false.
When MCP is enabled and configured, /.well-known/oauth-protected-resource/mcp
advertises the /mcp resource and configured Supabase authorization server.
OAuth bearer credentials authorize the integration's granted billing and paid
call operations. Paid Stripe calling retains its separate release gates and
stays disabled by default.
See discovery maintenance and validation.
The overall split is appropriate for the product:
Supabase provides PostgreSQL and GitHub OAuth. LiveKit Cloud connects the worker to Telnyx SIP trunks and xAI inference. Coinbase's x402 facilitator is intended to handle Base payments. Cloudflare R2 is intended for consented recordings.
Keeping call state separate from payment state is a sound choice: a call can end while settlement is still pending or failed. The existing idempotency key, single-settlement constraint, tenant-scoped API access, per-client webhook secrets, and webhook retry lease are also useful foundations.
The product is technically feasible, but the current repository is a prototype rather than a working MVP.
| Area | Assessment |
|---|---|
| Control plane | Good foundation; authentication, idempotency, rate limits, state, and webhook delivery exist |
| Voice path | Worker owns dialing and waits for SIP answer; connect-me detection and handoff require live verification |
| Payment | Saved-card monthly invoicing is tested offline and disabled; x402 variable capture remains blocked |
| Task result | Blocked; the worker returns a generic end reason instead of a schema-validated result |
| Hangup | Connect-me deletes both LiveKit rooms on every exit, including refusal, timeout, and cancellation |
| Recording and retention | Incomplete; consent capture, recording creation, redaction, and scheduled expiry are not implemented |
| Deployment | Worker deploys to LiveKit Cloud from the repository root; provider limits require live verification |
| Compliance | Requires a launch review and enforceable destination, consent, disclosure, recording, and task policies |
| Verification | Offline contracts, worker/provider mocks and PostgreSQL concurrency tests exist; real PSTN scenarios remain unverified |
Remote MCP supports protected-resource discovery, human tool consent, first-time profiles and connection revocation. Six tools cover billing setup, readiness, quotes, reservations, call status and usage. Saved-card enrollment, spending controls and monthly Stripe Invoicing are implemented and tested offline. Paid calling stays disabled until issuer/host, tariff, carrier and Stripe acceptance checks pass. Existing x402/operator behavior retains its own gates.
See the operations runbook for MCP and OAuth and Stripe billing, the billing guide and billing implementation record for configuration, invariants and implementation evidence.
The most important provider mismatches are documented upstream:
upto as the usage-based authorization scheme and
batch-settlement as a payment-channel flow. See the
x402 scheme overview and
Coinbase network support.Before any live pilot, obtain jurisdiction-specific review. AI-generated voice calls can trigger consent and disclosure rules in the United States, and Spain has separate restrictions for automated and commercial calls. Starting points include the FCC's AI voice ruling and Spain's calling rules. These links provide context, not legal advice.
Release readiness is the canonical checklist for
the saved-card connect_me pilot, broader product gaps, and optional future
integrations. It distinguishes implemented behavior from outstanding validation
and release gates, with links to the supporting decision records.
packageManagerPATHThe full call flow also needs provisioned Supabase, LiveKit, Telnyx, Coinbase Developer Platform, Base, and Cloudflare R2 resources.
corepack enable
pnpm install --frozen-lockfile
If an asdf shim reports that no pnpm version is configured, install pnpm 10.16.1
through asdf or put Corepack's pnpm shim before asdf on PATH. Turbo launches
workspace scripts through pnpm, so pnpm itself must be resolvable.
Copy the application-specific examples and fill in local credentials:
cp apps/platform/.env.example apps/platform/.env.local
cp apps/voice-agent/.env.example apps/voice-agent/.env
The platform dashboard and email/password login require a database URL, a
Supabase URL, and a Supabase publishable key. The canonical names are
DATABASE_URL, SUPABASE_URL, and SUPABASE_PUBLISHABLE_KEY. The Vercel
Supabase integration names POSTGRES_URL, NEXT_PUBLIC_SUPABASE_URL, and
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY are accepted as fallbacks. Set
NEXT_PUBLIC_APP_URL for a production or non-Vercel deployment. The remaining
blocks in apps/platform/.env.example are validated when their API, scheduler,
telephony, payment, or recording path runs. Do not add placeholder provider
credentials to make the dashboard load.
DATABASE_URL must point to the PostgreSQL database where the
supabase/migrations files were applied. When Supabase Auth and Supabase
PostgreSQL share a project, confirm that the project reference in the database
connection matches SUPABASE_URL. For Vercel, copy the Transaction pooler
URI from the Supabase Connect panel, replace its password placeholder, and set
it for the matching Vercel environment. A database URL left by another storage
integration will authenticate the user and then fail when the portal queries
client_profiles.
The platform uses one short-lived postgres.js connection per Vercel instance,
with prepared statements disabled so the Supabase transaction pooler can
multiplex it. sslmode=require encrypts that connection without a CA bundle.
Connections that request verify-ca or verify-full keep certificate
verification enabled and must provide the appropriate CA configuration.
Connect the Supabase resource to every Vercel environment that runs the platform. Feature branches use Vercel's Preview environment even when they act as staging. Integration variables scoped only to Production are absent from preview functions. Redeploy after changing the resource connection scope.
Password recovery uses NEXT_PUBLIC_APP_URL or Vercel's stable deployment
origin and returns through /auth/callback. In Supabase Authentication → URL
Configuration, set the Site URL to the stable deployment and allow these
redirect URLs:
http://localhost:3000/auth/callback*
https://agentcaller-git-feat-bounded-connect-me-gianpaj.vercel.app/auth/callback*
The trailing * permits the allowlisted callback's recovery query string. Add
the callback pattern for each stable deployment. For changing Vercel preview
hosts, Supabase also supports a preview wildcard such as
https://*-gianpaj.vercel.app/**. Keep the narrow callback pattern for
production. The password-reset email template must use
{{ .ConfirmationURL }} or otherwise honor {{ .RedirectTo }} so the
application-provided callback is preserved.
NEXT_PUBLIC_APP_URL is optional for Vercel previews. The platform uses
Vercel's stable VERCEL_BRANCH_URL, which requires Automatically expose
System Environment Variables in the Vercel project settings. Each push gets a
new immutable deployment URL, but its branch URL remains stable.
Never commit populated environment files. Apply the SQL files under
supabase/migrations in timestamp order through the project's Supabase
environment before running the platform.
Run the local workspace:
pnpm dev
Turbo starts the platform, docs, voice worker, and a development connection
scheduler. Set CRON_SECRET (at least 32 characters) in
apps/platform/.env.local. The scheduler reads that file, with shell values
taking precedence, and sends an authenticated drain request to
http://localhost:3000 at startup and every 30 seconds. It waits through
platform startup, never overlaps requests, and stops with Ctrl+C. Idle ticks
stay quiet; HTTP failures, timeouts, and failed room cleanup appear in logs.
To run applications separately:
pnpm --filter @agentcaller/platform dev
pnpm --filter @agentcaller/docs dev
pnpm --filter @agentcaller/voice-agent dev
pnpm dev:scheduler
Direct package dev commands do not start the scheduler. Production deployments need their own recurring drain trigger; the development script is local only.
The voice worker dev command loads apps/voice-agent/.env. Values already set
in the environment stay in place. The production start command does not read
that file.
The agentcaller-docs Vercel project builds apps/docs (Root Directory) from
main and serves it at https://docs.agentcaller.io. Previews use the same
project. Vercel skips builds for commits that do not affect apps/docs or its
dependencies. The Cloudflare docs CNAME points to the target Vercel lists for
the domain, with the proxy off. Pages live at the site root; old /docs/* URLs
redirect permanently.
The voice worker runs as a LiveKit Cloud agent. The root livekit.toml names
the LiveKit project and agent ID, and the root Dockerfile builds only the
worker. Both live at the repository root because the build needs the pnpm
lockfile and packages/contracts. Deploy from the root with the
LiveKit CLI:
lk agent deploy --skip-sdk-check
lk agent status
The CLI uploads the root, excluding files matched by .gitignore or
.dockerignore, and LiveKit Cloud builds the image. --skip-sdk-check skips a
preflight that looks for @livekit/agents in the root package files; the
dependency is declared in apps/voice-agent/package.json. The flag is hidden
from lk agent deploy --help in CLI 2.18.8. Prebuilt images (--image) require
an Enterprise LiveKit project, so this project builds from source.
Each version is tagged with the current commit. Deploy from a clean, committed
tree; a dirty tree only gets a tree hash, which is hard to trace back. When
packages/contracts changes, deploy the worker before the platform so the
active worker can parse newly admitted connect_me payloads (callingWindow: "now" and mobile business destinations).
Production configuration comes from the agent's LiveKit secrets, not
apps/voice-agent/.env. List their names with lk agent secrets and change
them with lk agent update-secrets. The worker registers under
LIVEKIT_AGENT_NAME. The platform's LIVEKIT_AGENT_EU and LIVEKIT_AGENT_US
must each match a deployed agent's name, or those calls are never picked up.
The LIVEKIT_SIP_TRUNK_* secrets must name outbound trunks in the same LiveKit
project; check them with lk sip outbound list.
Run the workspace checks from the repository root:
pnpm typecheck
pnpm test
pnpm test:connect-db # isolated disposable PostgreSQL; requires Docker
pnpm test:billing-db # isolated onboarding/migration PostgreSQL tests
pnpm format:check
pnpm build
The 2026-08-18 review records baseline failures. The worker build emits its entrypoint; repository-wide formatting drift remains. When changing a scoped package, run its checks directly as well:
pnpm --filter @agentcaller/platform typecheck
pnpm --filter @agentcaller/platform test
pnpm --filter @agentcaller/voice-agent typecheck
pnpm --filter @agentcaller/voice-agent test
See
docs/specs/2026-07-10-agentcaller-mvp-design.md
for the original MVP design and
.agents/notes/2026-08-18-architecture-review.md
for the evidence and decisions behind this review.