pinecall 0.1.0__tar.gz
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.
- pinecall-0.1.0/.claude/skills/add-a-vendor/SKILL.md +105 -0
- pinecall-0.1.0/.claude/skills/debug-a-call/SKILL.md +77 -0
- pinecall-0.1.0/.claude/skills/deploy/SKILL.md +95 -0
- pinecall-0.1.0/.env.example +256 -0
- pinecall-0.1.0/.github/workflows/ci.yml +100 -0
- pinecall-0.1.0/.github/workflows/release.yml +101 -0
- pinecall-0.1.0/.gitignore +24 -0
- pinecall-0.1.0/.python-version +1 -0
- pinecall-0.1.0/.squawk.toml +22 -0
- pinecall-0.1.0/ARCHITECTURE.md +376 -0
- pinecall-0.1.0/CHANGELOG.md +558 -0
- pinecall-0.1.0/CLAUDE.md +126 -0
- pinecall-0.1.0/CONTRIBUTING.md +14 -0
- pinecall-0.1.0/LICENSE +202 -0
- pinecall-0.1.0/Makefile +195 -0
- pinecall-0.1.0/PKG-INFO +237 -0
- pinecall-0.1.0/README.md +201 -0
- pinecall-0.1.0/docs/a-box-in-production.md +486 -0
- pinecall-0.1.0/docs/design/pinecall-v2-design.html +1012 -0
- pinecall-0.1.0/docs/design/research-synthesis.md +137 -0
- pinecall-0.1.0/docs/design/voice-stack-graph.md +684 -0
- pinecall-0.1.0/docs/from-zero.md +516 -0
- pinecall-0.1.0/docs/images/dark/admin-fleet.png +0 -0
- pinecall-0.1.0/docs/images/dark/admin-orgs.png +0 -0
- pinecall-0.1.0/docs/images/dark/admin-routes.png +0 -0
- pinecall-0.1.0/docs/images/dark/admin-usage.png +0 -0
- pinecall-0.1.0/docs/images/dark/agents.png +0 -0
- pinecall-0.1.0/docs/images/dark/calls.png +0 -0
- pinecall-0.1.0/docs/images/dark/chat.png +0 -0
- pinecall-0.1.0/docs/images/dark/evals.png +0 -0
- pinecall-0.1.0/docs/images/dark/keys.png +0 -0
- pinecall-0.1.0/docs/images/dark/knowledge.png +0 -0
- pinecall-0.1.0/docs/images/dark/live.png +0 -0
- pinecall-0.1.0/docs/images/dark/memory.png +0 -0
- pinecall-0.1.0/docs/images/dark/numbers.png +0 -0
- pinecall-0.1.0/docs/images/dark/pipeline.png +0 -0
- pinecall-0.1.0/docs/images/dark/providers.png +0 -0
- pinecall-0.1.0/docs/images/dark/sessions.png +0 -0
- pinecall-0.1.0/docs/images/dark/talk.png +0 -0
- pinecall-0.1.0/docs/images/dark/team.png +0 -0
- pinecall-0.1.0/docs/images/dark/usage.png +0 -0
- pinecall-0.1.0/docs/images/light/admin-fleet.png +0 -0
- pinecall-0.1.0/docs/images/light/admin-orgs.png +0 -0
- pinecall-0.1.0/docs/images/light/admin-routes.png +0 -0
- pinecall-0.1.0/docs/images/light/admin-usage.png +0 -0
- pinecall-0.1.0/docs/images/light/agents.png +0 -0
- pinecall-0.1.0/docs/images/light/calls.png +0 -0
- pinecall-0.1.0/docs/images/light/chat.png +0 -0
- pinecall-0.1.0/docs/images/light/evals.png +0 -0
- pinecall-0.1.0/docs/images/light/keys.png +0 -0
- pinecall-0.1.0/docs/images/light/knowledge.png +0 -0
- pinecall-0.1.0/docs/images/light/live.png +0 -0
- pinecall-0.1.0/docs/images/light/memory.png +0 -0
- pinecall-0.1.0/docs/images/light/numbers.png +0 -0
- pinecall-0.1.0/docs/images/light/pipeline.png +0 -0
- pinecall-0.1.0/docs/images/light/providers.png +0 -0
- pinecall-0.1.0/docs/images/light/sessions.png +0 -0
- pinecall-0.1.0/docs/images/light/talk.png +0 -0
- pinecall-0.1.0/docs/images/light/team.png +0 -0
- pinecall-0.1.0/docs/images/light/usage.png +0 -0
- pinecall-0.1.0/docs/multi-tenancy.md +286 -0
- pinecall-0.1.0/docs/protocol/dev-verbs.md +42 -0
- pinecall-0.1.0/docs/protocol/every-door.md +68 -0
- pinecall-0.1.0/docs/protocol/gateway-api.md +400 -0
- pinecall-0.1.0/docs/protocol/numbers.md +96 -0
- pinecall-0.1.0/docs/protocol/operator-api.md +389 -0
- pinecall-0.1.0/docs/protocol/people.md +88 -0
- pinecall-0.1.0/docs/protocol/pipeline-api.md +56 -0
- pinecall-0.1.0/docs/protocol/projections.md +79 -0
- pinecall-0.1.0/docs/protocol/provider-keys.md +35 -0
- pinecall-0.1.0/docs/protocol/tokens.md +148 -0
- pinecall-0.1.0/docs/reports/ms-8.md +197 -0
- pinecall-0.1.0/docs/retrieval/spec.md +225 -0
- pinecall-0.1.0/docs/scaling.md +172 -0
- pinecall-0.1.0/docs/security/prompt-injection.md +230 -0
- pinecall-0.1.0/docs/the-fleet.html +152 -0
- pinecall-0.1.0/docs/the-runtime-cli.md +393 -0
- pinecall-0.1.0/infra/README.md +134 -0
- pinecall-0.1.0/infra/box/Makefile +168 -0
- pinecall-0.1.0/infra/box/README.md +398 -0
- pinecall-0.1.0/infra/box/caddy/Caddyfile +21 -0
- pinecall-0.1.0/infra/box/caddy/pinecall.conf +8 -0
- pinecall-0.1.0/infra/box/cloud-init.yaml +62 -0
- pinecall-0.1.0/infra/box/containers/pinecall-livekit.container +32 -0
- pinecall-0.1.0/infra/box/containers/pinecall-postgres.container +31 -0
- pinecall-0.1.0/infra/box/containers/pinecall-postgres.volume +3 -0
- pinecall-0.1.0/infra/box/containers/pinecall-redis.container +21 -0
- pinecall-0.1.0/infra/box/containers/pinecall-sip.container +32 -0
- pinecall-0.1.0/infra/box/containers/pinecall-tei.container +41 -0
- pinecall-0.1.0/infra/box/containers/pinecall-tei.volume +5 -0
- pinecall-0.1.0/infra/box/containers/pinecall.network +4 -0
- pinecall-0.1.0/infra/box/livekit.yaml +24 -0
- pinecall-0.1.0/infra/box/nftables.conf +89 -0
- pinecall-0.1.0/infra/box/pinecall-fleet.service +43 -0
- pinecall-0.1.0/infra/box/pinecall-gateway.service +99 -0
- pinecall-0.1.0/infra/box/pinecall-operator-key.service +32 -0
- pinecall-0.1.0/infra/box/pinecall-overflow.service +33 -0
- pinecall-0.1.0/infra/box/pinecall-postgres-image.service +14 -0
- pinecall-0.1.0/infra/box/pinecall-secrets.service +16 -0
- pinecall-0.1.0/infra/box/pinecall-worker-key.service +34 -0
- pinecall-0.1.0/infra/box/pinecall-worker.service +92 -0
- pinecall-0.1.0/infra/box/sip.yaml +29 -0
- pinecall-0.1.0/infra/box/sysusers.d/pinecall.conf +5 -0
- pinecall-0.1.0/infra/box/tmpfiles.d/pinecall.conf +22 -0
- pinecall-0.1.0/infra/compose/.env.example +24 -0
- pinecall-0.1.0/infra/compose/dev.yml +203 -0
- pinecall-0.1.0/infra/compose/livekit.yaml +29 -0
- pinecall-0.1.0/infra/compose/postgres/Dockerfile +41 -0
- pinecall-0.1.0/infra/compose/postgres/init.sql +3 -0
- pinecall-0.1.0/infra/compose/sip.yaml +22 -0
- pinecall-0.1.0/infra/fleet/README.md +60 -0
- pinecall-0.1.0/infra/fleet/aws +37 -0
- pinecall-0.1.0/infra/fleet/gcp +34 -0
- pinecall-0.1.0/infra/fleet/hetzner +29 -0
- pinecall-0.1.0/infra/seed/routes.json +14 -0
- pinecall-0.1.0/infra/tools/.ruff.toml +10 -0
- pinecall-0.1.0/infra/tools/carrier_cidrs.py +37 -0
- pinecall-0.1.0/infra/tools/pyrightconfig.json +14 -0
- pinecall-0.1.0/infra/tools/sip_call.py +138 -0
- pinecall-0.1.0/infra/tools/sip_probe.py +77 -0
- pinecall-0.1.0/infra/tools/tests/conftest.py +9 -0
- pinecall-0.1.0/infra/tools/tests/test_carrier_cidrs.py +55 -0
- pinecall-0.1.0/infra/tools/tests/test_twilio_trunk.py +193 -0
- pinecall-0.1.0/infra/tools/twilio_rest.py +61 -0
- pinecall-0.1.0/infra/tools/twilio_trunk.py +337 -0
- pinecall-0.1.0/pyproject.toml +175 -0
- pinecall-0.1.0/scripts/bootstrap +6 -0
- pinecall-0.1.0/scripts/console +23 -0
- pinecall-0.1.0/scripts/format +7 -0
- pinecall-0.1.0/scripts/generate-env-example +12 -0
- pinecall-0.1.0/scripts/lint +14 -0
- pinecall-0.1.0/scripts/lint-migrations +28 -0
- pinecall-0.1.0/scripts/refresh-prices +11 -0
- pinecall-0.1.0/scripts/refresh_prices.py +96 -0
- pinecall-0.1.0/scripts/test +8 -0
- pinecall-0.1.0/scripts/the-version +18 -0
- pinecall-0.1.0/src/pinecall/__init__.py +9 -0
- pinecall-0.1.0/src/pinecall/_env_example.py +38 -0
- pinecall-0.1.0/src/pinecall/_env_files.py +31 -0
- pinecall-0.1.0/src/pinecall/_exceptions.py +5 -0
- pinecall-0.1.0/src/pinecall/_settings.py +387 -0
- pinecall-0.1.0/src/pinecall/_vendor_keys.py +283 -0
- pinecall-0.1.0/src/pinecall/_version.py +4 -0
- pinecall-0.1.0/src/pinecall/api/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/api/_deps.py +384 -0
- pinecall-0.1.0/src/pinecall/api/_live.py +246 -0
- pinecall-0.1.0/src/pinecall/api/_operator.py +50 -0
- pinecall-0.1.0/src/pinecall/api/_refusals.py +40 -0
- pinecall-0.1.0/src/pinecall/api/_serving.py +49 -0
- pinecall-0.1.0/src/pinecall/api/agents/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/api/agents/dev.py +177 -0
- pinecall-0.1.0/src/pinecall/api/agents/doors.py +136 -0
- pinecall-0.1.0/src/pinecall/api/agents/endpoints.py +164 -0
- pinecall-0.1.0/src/pinecall/api/agents/handlers.py +120 -0
- pinecall-0.1.0/src/pinecall/api/agents/holding.py +71 -0
- pinecall-0.1.0/src/pinecall/api/agents/on_a_call.py +146 -0
- pinecall-0.1.0/src/pinecall/api/agents/provider_keys.py +28 -0
- pinecall-0.1.0/src/pinecall/api/agents/registry.py +399 -0
- pinecall-0.1.0/src/pinecall/api/agents/socket.py +240 -0
- pinecall-0.1.0/src/pinecall/api/app.py +312 -0
- pinecall-0.1.0/src/pinecall/api/calls/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/api/calls/chat.py +236 -0
- pinecall-0.1.0/src/pinecall/api/calls/commands.py +52 -0
- pinecall-0.1.0/src/pinecall/api/calls/events.py +395 -0
- pinecall-0.1.0/src/pinecall/api/calls/listing.py +86 -0
- pinecall-0.1.0/src/pinecall/api/calls/lookup.py +45 -0
- pinecall-0.1.0/src/pinecall/api/calls/opening.py +98 -0
- pinecall-0.1.0/src/pinecall/api/calls/recording.py +46 -0
- pinecall-0.1.0/src/pinecall/api/calls/sink.py +281 -0
- pinecall-0.1.0/src/pinecall/api/calls/state.py +48 -0
- pinecall-0.1.0/src/pinecall/api/calls/tools.py +85 -0
- pinecall-0.1.0/src/pinecall/api/contacts.py +124 -0
- pinecall-0.1.0/src/pinecall/api/discovery.py +41 -0
- pinecall-0.1.0/src/pinecall/api/evals/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/api/evals/attachment.py +83 -0
- pinecall-0.1.0/src/pinecall/api/evals/caller.py +31 -0
- pinecall-0.1.0/src/pinecall/api/evals/conversation.py +179 -0
- pinecall-0.1.0/src/pinecall/api/evals/listening.py +93 -0
- pinecall-0.1.0/src/pinecall/api/evals/replay.py +75 -0
- pinecall-0.1.0/src/pinecall/api/evals/runner.py +329 -0
- pinecall-0.1.0/src/pinecall/api/evals/runs.py +124 -0
- pinecall-0.1.0/src/pinecall/api/evals/scoring.py +128 -0
- pinecall-0.1.0/src/pinecall/api/evals/settling.py +43 -0
- pinecall-0.1.0/src/pinecall/api/evals/spoken.py +96 -0
- pinecall-0.1.0/src/pinecall/api/evals/voice.py +100 -0
- pinecall-0.1.0/src/pinecall/api/extraction.py +97 -0
- pinecall-0.1.0/src/pinecall/api/fleet.py +157 -0
- pinecall-0.1.0/src/pinecall/api/floor.py +51 -0
- pinecall-0.1.0/src/pinecall/api/keys.py +117 -0
- pinecall-0.1.0/src/pinecall/api/knowledge.py +136 -0
- pinecall-0.1.0/src/pinecall/api/listen.py +24 -0
- pinecall-0.1.0/src/pinecall/api/login.py +196 -0
- pinecall-0.1.0/src/pinecall/api/managed.py +100 -0
- pinecall-0.1.0/src/pinecall/api/members.py +266 -0
- pinecall-0.1.0/src/pinecall/api/numbers.py +362 -0
- pinecall-0.1.0/src/pinecall/api/orgs.py +274 -0
- pinecall-0.1.0/src/pinecall/api/pages.py +84 -0
- pinecall-0.1.0/src/pinecall/api/pairing.py +88 -0
- pinecall-0.1.0/src/pinecall/api/pipeline.py +56 -0
- pinecall-0.1.0/src/pinecall/api/pipeline_report.py +168 -0
- pinecall-0.1.0/src/pinecall/api/provider_keys.py +99 -0
- pinecall-0.1.0/src/pinecall/api/providers.py +95 -0
- pinecall-0.1.0/src/pinecall/api/routes.py +114 -0
- pinecall-0.1.0/src/pinecall/api/signup.py +115 -0
- pinecall-0.1.0/src/pinecall/api/supervise/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/api/supervise/aiming.py +148 -0
- pinecall-0.1.0/src/pinecall/api/supervise/verbs.py +51 -0
- pinecall-0.1.0/src/pinecall/api/supervise_seat.py +28 -0
- pinecall-0.1.0/src/pinecall/api/tokens.py +184 -0
- pinecall-0.1.0/src/pinecall/api/usage.py +103 -0
- pinecall-0.1.0/src/pinecall/api/whatsapp/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/api/whatsapp/doors.py +38 -0
- pinecall-0.1.0/src/pinecall/api/whatsapp/threads.py +236 -0
- pinecall-0.1.0/src/pinecall/api/whatsapp/webhook.py +119 -0
- pinecall-0.1.0/src/pinecall/api/whoami.py +100 -0
- pinecall-0.1.0/src/pinecall/auth/__init__.py +21 -0
- pinecall-0.1.0/src/pinecall/auth/bearer.py +30 -0
- pinecall-0.1.0/src/pinecall/auth/codes.py +62 -0
- pinecall-0.1.0/src/pinecall/auth/invitations.py +30 -0
- pinecall-0.1.0/src/pinecall/auth/keys.py +378 -0
- pinecall-0.1.0/src/pinecall/auth/members.py +390 -0
- pinecall-0.1.0/src/pinecall/auth/pairing.py +115 -0
- pinecall-0.1.0/src/pinecall/auth/passwords.py +37 -0
- pinecall-0.1.0/src/pinecall/auth/scopes.py +240 -0
- pinecall-0.1.0/src/pinecall/auth/throttle.py +43 -0
- pinecall-0.1.0/src/pinecall/cli/__init__.py +87 -0
- pinecall-0.1.0/src/pinecall/cli/box/__init__.py +5 -0
- pinecall-0.1.0/src/pinecall/cli/box/verbs.py +136 -0
- pinecall-0.1.0/src/pinecall/cli/columns.py +12 -0
- pinecall-0.1.0/src/pinecall/cli/doctor/__init__.py +5 -0
- pinecall-0.1.0/src/pinecall/cli/doctor/probes.py +58 -0
- pinecall-0.1.0/src/pinecall/cli/doctor/verbs.py +339 -0
- pinecall-0.1.0/src/pinecall/cli/fleet/__init__.py +5 -0
- pinecall-0.1.0/src/pinecall/cli/fleet/verbs.py +206 -0
- pinecall-0.1.0/src/pinecall/cli/gateway.py +36 -0
- pinecall-0.1.0/src/pinecall/cli/init.py +106 -0
- pinecall-0.1.0/src/pinecall/cli/keys/__init__.py +5 -0
- pinecall-0.1.0/src/pinecall/cli/keys/verbs.py +193 -0
- pinecall-0.1.0/src/pinecall/cli/migrate.py +103 -0
- pinecall-0.1.0/src/pinecall/cli/operator.py +125 -0
- pinecall-0.1.0/src/pinecall/cli/orgs/__init__.py +5 -0
- pinecall-0.1.0/src/pinecall/cli/orgs/verbs.py +340 -0
- pinecall-0.1.0/src/pinecall/cli/providers/__init__.py +5 -0
- pinecall-0.1.0/src/pinecall/cli/providers/verbs.py +61 -0
- pinecall-0.1.0/src/pinecall/cli/routes/__init__.py +5 -0
- pinecall-0.1.0/src/pinecall/cli/routes/verbs.py +187 -0
- pinecall-0.1.0/src/pinecall/cli/sessions/__init__.py +5 -0
- pinecall-0.1.0/src/pinecall/cli/sessions/render.py +163 -0
- pinecall-0.1.0/src/pinecall/cli/sessions/source.py +55 -0
- pinecall-0.1.0/src/pinecall/cli/sessions/verbs.py +266 -0
- pinecall-0.1.0/src/pinecall/cli/worker.py +148 -0
- pinecall-0.1.0/src/pinecall/evals/__init__.py +76 -0
- pinecall-0.1.0/src/pinecall/evals/answers.py +39 -0
- pinecall-0.1.0/src/pinecall/evals/bridge.py +186 -0
- pinecall-0.1.0/src/pinecall/evals/caller.py +151 -0
- pinecall-0.1.0/src/pinecall/evals/calling.py +298 -0
- pinecall-0.1.0/src/pinecall/evals/case.py +117 -0
- pinecall-0.1.0/src/pinecall/evals/checks/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/evals/checks/consent.py +48 -0
- pinecall-0.1.0/src/pinecall/evals/checks/errors.py +24 -0
- pinecall-0.1.0/src/pinecall/evals/checks/latency.py +41 -0
- pinecall-0.1.0/src/pinecall/evals/checks/register.py +43 -0
- pinecall-0.1.0/src/pinecall/evals/checks/replayed.py +90 -0
- pinecall-0.1.0/src/pinecall/evals/checks/verdict.py +44 -0
- pinecall-0.1.0/src/pinecall/evals/goldens.py +79 -0
- pinecall-0.1.0/src/pinecall/evals/headless.py +104 -0
- pinecall-0.1.0/src/pinecall/evals/judges/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/evals/judges/asking.py +86 -0
- pinecall-0.1.0/src/pinecall/evals/judges/consent.py +53 -0
- pinecall-0.1.0/src/pinecall/evals/judges/expected.py +201 -0
- pinecall-0.1.0/src/pinecall/evals/judges/grounded.py +237 -0
- pinecall-0.1.0/src/pinecall/evals/judges/model.py +77 -0
- pinecall-0.1.0/src/pinecall/evals/judges/policy.py +53 -0
- pinecall-0.1.0/src/pinecall/evals/judges/register.py +68 -0
- pinecall-0.1.0/src/pinecall/evals/line.py +89 -0
- pinecall-0.1.0/src/pinecall/evals/matrix.py +144 -0
- pinecall-0.1.0/src/pinecall/evals/polling.py +22 -0
- pinecall-0.1.0/src/pinecall/evals/remembering.py +33 -0
- pinecall-0.1.0/src/pinecall/evals/report.py +120 -0
- pinecall-0.1.0/src/pinecall/evals/runs.py +179 -0
- pinecall-0.1.0/src/pinecall/evals/score.py +160 -0
- pinecall-0.1.0/src/pinecall/evals/speech.py +94 -0
- pinecall-0.1.0/src/pinecall/evals/transcript.py +39 -0
- pinecall-0.1.0/src/pinecall/evals/verdicts.py +75 -0
- pinecall-0.1.0/src/pinecall/extensions/__init__.py +6 -0
- pinecall-0.1.0/src/pinecall/extensions/loading.py +43 -0
- pinecall-0.1.0/src/pinecall/extensions/points.py +28 -0
- pinecall-0.1.0/src/pinecall/fleet/__init__.py +37 -0
- pinecall-0.1.0/src/pinecall/fleet/clouds.py +88 -0
- pinecall-0.1.0/src/pinecall/fleet/decisions.py +168 -0
- pinecall-0.1.0/src/pinecall/fleet/loop.py +104 -0
- pinecall-0.1.0/src/pinecall/fleet/roster.py +151 -0
- pinecall-0.1.0/src/pinecall/gateway/admin/assets/index-C3WMXdfL.css +1 -0
- pinecall-0.1.0/src/pinecall/gateway/admin/assets/index-DR1mxoAh.js +58 -0
- pinecall-0.1.0/src/pinecall/gateway/admin/index.html +20 -0
- pinecall-0.1.0/src/pinecall/gateway/console/assets/index-DCTnou52.css +1 -0
- pinecall-0.1.0/src/pinecall/gateway/console/assets/index-dOcE4usU.js +99 -0
- pinecall-0.1.0/src/pinecall/gateway/console/index.html +20 -0
- pinecall-0.1.0/src/pinecall/gateway/console/logo-mark.png +0 -0
- pinecall-0.1.0/src/pinecall/knowledge/__init__.py +6 -0
- pinecall-0.1.0/src/pinecall/knowledge/chunking.py +111 -0
- pinecall-0.1.0/src/pinecall/knowledge/protocol.py +69 -0
- pinecall-0.1.0/src/pinecall/knowledge/scoring.py +87 -0
- pinecall-0.1.0/src/pinecall/knowledge/store.py +267 -0
- pinecall-0.1.0/src/pinecall/log/__init__.py +33 -0
- pinecall-0.1.0/src/pinecall/log/entry.py +38 -0
- pinecall-0.1.0/src/pinecall/log/fanout.py +108 -0
- pinecall-0.1.0/src/pinecall/log/filters.py +67 -0
- pinecall-0.1.0/src/pinecall/log/latencies.py +67 -0
- pinecall-0.1.0/src/pinecall/log/logs.py +139 -0
- pinecall-0.1.0/src/pinecall/log/pii.py +133 -0
- pinecall-0.1.0/src/pinecall/log/projection.py +244 -0
- pinecall-0.1.0/src/pinecall/log/reduce.py +396 -0
- pinecall-0.1.0/src/pinecall/log/replay.py +166 -0
- pinecall-0.1.0/src/pinecall/log/room.py +69 -0
- pinecall-0.1.0/src/pinecall/log/snapshots.py +43 -0
- pinecall-0.1.0/src/pinecall/log/store/__init__.py +21 -0
- pinecall-0.1.0/src/pinecall/log/store/memory.py +145 -0
- pinecall-0.1.0/src/pinecall/log/store/migrating.py +205 -0
- pinecall-0.1.0/src/pinecall/log/store/pool.py +26 -0
- pinecall-0.1.0/src/pinecall/log/store/postgres.py +373 -0
- pinecall-0.1.0/src/pinecall/log/store/protocol.py +94 -0
- pinecall-0.1.0/src/pinecall/log/usage.py +134 -0
- pinecall-0.1.0/src/pinecall/log/wording.py +25 -0
- pinecall-0.1.0/src/pinecall/log/writers.py +126 -0
- pinecall-0.1.0/src/pinecall/lookups/__init__.py +5 -0
- pinecall-0.1.0/src/pinecall/lookups/answers.py +44 -0
- pinecall-0.1.0/src/pinecall/lookups/entries.py +69 -0
- pinecall-0.1.0/src/pinecall/lookups/service.py +242 -0
- pinecall-0.1.0/src/pinecall/memory/__init__.py +11 -0
- pinecall-0.1.0/src/pinecall/memory/extraction.py +231 -0
- pinecall-0.1.0/src/pinecall/memory/goldens.py +226 -0
- pinecall-0.1.0/src/pinecall/memory/pgvector.py +324 -0
- pinecall-0.1.0/src/pinecall/memory/protocol.py +105 -0
- pinecall-0.1.0/src/pinecall/memory/ranking.py +48 -0
- pinecall-0.1.0/src/pinecall/memory/scoring.py +99 -0
- pinecall-0.1.0/src/pinecall/migrations/0001_call_log.sql +62 -0
- pinecall-0.1.0/src/pinecall/migrations/0002_api_keys.sql +16 -0
- pinecall-0.1.0/src/pinecall/migrations/0003_routes.sql +19 -0
- pinecall-0.1.0/src/pinecall/migrations/0004_eval_runs.sql +22 -0
- pinecall-0.1.0/src/pinecall/migrations/0005_tokens.sql +20 -0
- pinecall-0.1.0/src/pinecall/migrations/0006_orgs.sql +64 -0
- pinecall-0.1.0/src/pinecall/migrations/0007_provider_keys.sql +20 -0
- pinecall-0.1.0/src/pinecall/migrations/0008_memory.sql +46 -0
- pinecall-0.1.0/src/pinecall/migrations/0009_knowledge.sql +49 -0
- pinecall-0.1.0/src/pinecall/migrations/0010_memory_model.sql +14 -0
- pinecall-0.1.0/src/pinecall/migrations/0011_feature_quotas.sql +14 -0
- pinecall-0.1.0/src/pinecall/migrations/0012_pipeline_overrides.sql +26 -0
- pinecall-0.1.0/src/pinecall/migrations/0013_environments.sql +39 -0
- pinecall-0.1.0/src/pinecall/migrations/0014_members.sql +38 -0
- pinecall-0.1.0/src/pinecall/migrations/0015_carriers.sql +20 -0
- pinecall-0.1.0/src/pinecall/migrations/0016_managed_numbers.sql +11 -0
- pinecall-0.1.0/src/pinecall/migrations/0017_provider_scope.sql +16 -0
- pinecall-0.1.0/src/pinecall/migrations/0018_worlds_in_the_data.sql +50 -0
- pinecall-0.1.0/src/pinecall/migrations/0019_seats.sql +13 -0
- pinecall-0.1.0/src/pinecall/migrations/0020_operators.sql +18 -0
- pinecall-0.1.0/src/pinecall/migrations/0021_a_developers_own.sql +48 -0
- pinecall-0.1.0/src/pinecall/migrations/0022_a_tts_knob.sql +17 -0
- pinecall-0.1.0/src/pinecall/migrations/0023_sandbox.sql +42 -0
- pinecall-0.1.0/src/pinecall/migrations/migrations.lock +11 -0
- pinecall-0.1.0/src/pinecall/orgs/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/orgs/admission.py +135 -0
- pinecall-0.1.0/src/pinecall/orgs/carriers.py +144 -0
- pinecall-0.1.0/src/pinecall/orgs/meter.py +46 -0
- pinecall-0.1.0/src/pinecall/orgs/table.py +198 -0
- pinecall-0.1.0/src/pinecall/orgs/turned.py +62 -0
- pinecall-0.1.0/src/pinecall/orgs/vault.py +154 -0
- pinecall-0.1.0/src/pinecall/providers/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/providers/_inference.py +51 -0
- pinecall-0.1.0/src/pinecall/providers/blocks.py +79 -0
- pinecall-0.1.0/src/pinecall/providers/catalog.py +303 -0
- pinecall-0.1.0/src/pinecall/providers/declaration.py +231 -0
- pinecall-0.1.0/src/pinecall/providers/embed/__init__.py +109 -0
- pinecall-0.1.0/src/pinecall/providers/embed/perplexity.py +193 -0
- pinecall-0.1.0/src/pinecall/providers/embed/tei.py +100 -0
- pinecall-0.1.0/src/pinecall/providers/embed/wire.py +63 -0
- pinecall-0.1.0/src/pinecall/providers/embedder.py +89 -0
- pinecall-0.1.0/src/pinecall/providers/knocks.py +39 -0
- pinecall-0.1.0/src/pinecall/providers/llm/__init__.py +5 -0
- pinecall-0.1.0/src/pinecall/providers/llm/anthropic.py +20 -0
- pinecall-0.1.0/src/pinecall/providers/llm/livekit.py +14 -0
- pinecall-0.1.0/src/pinecall/providers/llm/openai.py +18 -0
- pinecall-0.1.0/src/pinecall/providers/models.py +59 -0
- pinecall-0.1.0/src/pinecall/providers/overrides.py +233 -0
- pinecall-0.1.0/src/pinecall/providers/pipeline.py +108 -0
- pinecall-0.1.0/src/pinecall/providers/plugin.py +150 -0
- pinecall-0.1.0/src/pinecall/providers/prices.py +240 -0
- pinecall-0.1.0/src/pinecall/providers/published.py +71 -0
- pinecall-0.1.0/src/pinecall/providers/published_prices.json +5344 -0
- pinecall-0.1.0/src/pinecall/providers/registry.py +193 -0
- pinecall-0.1.0/src/pinecall/providers/standing.py +40 -0
- pinecall-0.1.0/src/pinecall/providers/stt/__init__.py +20 -0
- pinecall-0.1.0/src/pinecall/providers/stt/deepgram.py +26 -0
- pinecall-0.1.0/src/pinecall/providers/stt/livekit.py +23 -0
- pinecall-0.1.0/src/pinecall/providers/stt/soniox.py +38 -0
- pinecall-0.1.0/src/pinecall/providers/tts/__init__.py +5 -0
- pinecall-0.1.0/src/pinecall/providers/tts/elevenlabs.py +57 -0
- pinecall-0.1.0/src/pinecall/providers/tts/livekit.py +26 -0
- pinecall-0.1.0/src/pinecall/providers/tts/voices.py +113 -0
- pinecall-0.1.0/src/pinecall/providers/usage.py +40 -0
- pinecall-0.1.0/src/pinecall/routes/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/routes/answering.py +89 -0
- pinecall-0.1.0/src/pinecall/routes/table.py +253 -0
- pinecall-0.1.0/src/pinecall/routes/trunks.py +160 -0
- pinecall-0.1.0/src/pinecall/routes/twilio.py +236 -0
- pinecall-0.1.0/src/pinecall/session/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/session/asking.py +71 -0
- pinecall-0.1.0/src/pinecall/session/clock.py +54 -0
- pinecall-0.1.0/src/pinecall/session/declaring.py +57 -0
- pinecall-0.1.0/src/pinecall/session/first_entries.py +41 -0
- pinecall-0.1.0/src/pinecall/session/greeting.py +33 -0
- pinecall-0.1.0/src/pinecall/session/knowing.py +22 -0
- pinecall-0.1.0/src/pinecall/session/lookups.py +284 -0
- pinecall-0.1.0/src/pinecall/session/pending.py +72 -0
- pinecall-0.1.0/src/pinecall/session/remembering.py +48 -0
- pinecall-0.1.0/src/pinecall/session/scoring.py +21 -0
- pinecall-0.1.0/src/pinecall/session/supervising.py +39 -0
- pinecall-0.1.0/src/pinecall/session/text/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/session/text/agent.py +148 -0
- pinecall-0.1.0/src/pinecall/session/text/measure.py +92 -0
- pinecall-0.1.0/src/pinecall/session/text/running.py +45 -0
- pinecall-0.1.0/src/pinecall/session/text/session.py +328 -0
- pinecall-0.1.0/src/pinecall/session/text/supervising.py +94 -0
- pinecall-0.1.0/src/pinecall/session/text/turns.py +144 -0
- pinecall-0.1.0/src/pinecall/session/visibility.py +46 -0
- pinecall-0.1.0/src/pinecall/session/voice/__init__.py +5 -0
- pinecall-0.1.0/src/pinecall/session/voice/agent.py +124 -0
- pinecall-0.1.0/src/pinecall/session/voice/barge_in.py +63 -0
- pinecall-0.1.0/src/pinecall/session/voice/commands.py +252 -0
- pinecall-0.1.0/src/pinecall/session/voice/dead_end.py +23 -0
- pinecall-0.1.0/src/pinecall/session/voice/events.py +257 -0
- pinecall-0.1.0/src/pinecall/session/voice/hanging_up.py +75 -0
- pinecall-0.1.0/src/pinecall/session/voice/hearing.py +59 -0
- pinecall-0.1.0/src/pinecall/session/voice/kit.py +24 -0
- pinecall-0.1.0/src/pinecall/session/voice/metrics.py +161 -0
- pinecall-0.1.0/src/pinecall/session/voice/platform.py +44 -0
- pinecall-0.1.0/src/pinecall/session/voice/reading_back.py +21 -0
- pinecall-0.1.0/src/pinecall/session/voice/room/__init__.py +7 -0
- pinecall-0.1.0/src/pinecall/session/voice/room/datachannel.py +248 -0
- pinecall-0.1.0/src/pinecall/session/voice/room/facts.py +210 -0
- pinecall-0.1.0/src/pinecall/session/voice/room/holding.py +50 -0
- pinecall-0.1.0/src/pinecall/session/voice/room/invite.py +40 -0
- pinecall-0.1.0/src/pinecall/session/voice/room/mute.py +50 -0
- pinecall-0.1.0/src/pinecall/session/voice/room/remove.py +21 -0
- pinecall-0.1.0/src/pinecall/session/voice/room/send.py +22 -0
- pinecall-0.1.0/src/pinecall/session/voice/session.py +173 -0
- pinecall-0.1.0/src/pinecall/session/voice/sip.py +83 -0
- pinecall-0.1.0/src/pinecall/session/voice/supervising.py +139 -0
- pinecall-0.1.0/src/pinecall/session/voice/tools.py +114 -0
- pinecall-0.1.0/src/pinecall/session/voice/transfer.py +74 -0
- pinecall-0.1.0/src/pinecall/session/voice/voice.py +391 -0
- pinecall-0.1.0/src/pinecall/session/voice/writing.py +70 -0
- pinecall-0.1.0/src/pinecall/tokens/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/tokens/ledger.py +107 -0
- pinecall-0.1.0/src/pinecall/tokens/room.py +49 -0
- pinecall-0.1.0/src/pinecall/tokens/seating.py +62 -0
- pinecall-0.1.0/src/pinecall/tokens/spending.py +37 -0
- pinecall-0.1.0/src/pinecall/types/__init__.py +152 -0
- pinecall-0.1.0/src/pinecall/types/agent.py +157 -0
- pinecall-0.1.0/src/pinecall/types/call.py +93 -0
- pinecall-0.1.0/src/pinecall/types/carrier.py +88 -0
- pinecall-0.1.0/src/pinecall/types/channel.py +19 -0
- pinecall-0.1.0/src/pinecall/types/consent.py +128 -0
- pinecall-0.1.0/src/pinecall/types/counting.py +11 -0
- pinecall-0.1.0/src/pinecall/types/dispatch.py +28 -0
- pinecall-0.1.0/src/pinecall/types/fusion.py +32 -0
- pinecall-0.1.0/src/pinecall/types/goldens.py +60 -0
- pinecall-0.1.0/src/pinecall/types/json.py +6 -0
- pinecall-0.1.0/src/pinecall/types/key.py +120 -0
- pinecall-0.1.0/src/pinecall/types/knowledge.py +90 -0
- pinecall-0.1.0/src/pinecall/types/lookup.py +102 -0
- pinecall-0.1.0/src/pinecall/types/member.py +100 -0
- pinecall-0.1.0/src/pinecall/types/org.py +117 -0
- pinecall-0.1.0/src/pinecall/types/prompt.py +99 -0
- pinecall-0.1.0/src/pinecall/types/provider_keys.py +15 -0
- pinecall-0.1.0/src/pinecall/types/refused.py +8 -0
- pinecall-0.1.0/src/pinecall/types/route.py +68 -0
- pinecall-0.1.0/src/pinecall/types/token.py +139 -0
- pinecall-0.1.0/src/pinecall/types/tool.py +74 -0
- pinecall-0.1.0/src/pinecall/whatsapp/__init__.py +1 -0
- pinecall-0.1.0/src/pinecall/whatsapp/graph.py +97 -0
- pinecall-0.1.0/src/pinecall/whatsapp/inbound.py +130 -0
- pinecall-0.1.0/src/pinecall/whatsapp/meta.py +9 -0
- pinecall-0.1.0/src/pinecall/whatsapp/routing.py +44 -0
- pinecall-0.1.0/src/pinecall/whatsapp/sending.py +47 -0
- pinecall-0.1.0/src/pinecall/whatsapp/signing.py +23 -0
- pinecall-0.1.0/src/pinecall/worker/__init__.py +22 -0
- pinecall-0.1.0/src/pinecall/worker/client.py +227 -0
- pinecall-0.1.0/src/pinecall/worker/commanding.py +56 -0
- pinecall-0.1.0/src/pinecall/worker/entry.py +200 -0
- pinecall-0.1.0/src/pinecall/worker/heartbeat.py +91 -0
- pinecall-0.1.0/src/pinecall/worker/load.py +120 -0
- pinecall-0.1.0/src/pinecall/worker/main.py +140 -0
- pinecall-0.1.0/src/pinecall/worker/overflow.py +172 -0
- pinecall-0.1.0/src/pinecall/worker/recordings.py +78 -0
- pinecall-0.1.0/src/pinecall/worker/router.py +111 -0
- pinecall-0.1.0/src/pinecall/worker/seat.py +92 -0
- pinecall-0.1.0/tests/__init__.py +1 -0
- pinecall-0.1.0/tests/api/__init__.py +1 -0
- pinecall-0.1.0/tests/api/agents/__init__.py +1 -0
- pinecall-0.1.0/tests/api/agents/test_dev_relay.py +156 -0
- pinecall-0.1.0/tests/api/agents/test_registry.py +325 -0
- pinecall-0.1.0/tests/api/agents/test_socket.py +240 -0
- pinecall-0.1.0/tests/api/agents/test_the_line.py +218 -0
- pinecall-0.1.0/tests/api/agents/test_the_team_sees_every_corner.py +107 -0
- pinecall-0.1.0/tests/api/agents/test_two_developers.py +352 -0
- pinecall-0.1.0/tests/api/agents/test_two_worlds.py +122 -0
- pinecall-0.1.0/tests/api/calls/__init__.py +1 -0
- pinecall-0.1.0/tests/api/calls/test_chat.py +370 -0
- pinecall-0.1.0/tests/api/calls/test_events.py +294 -0
- pinecall-0.1.0/tests/api/calls/test_listing.py +81 -0
- pinecall-0.1.0/tests/api/calls/test_live_reader.py +178 -0
- pinecall-0.1.0/tests/api/calls/test_lookup.py +144 -0
- pinecall-0.1.0/tests/api/calls/test_opening.py +62 -0
- pinecall-0.1.0/tests/api/calls/test_overrides.py +55 -0
- pinecall-0.1.0/tests/api/calls/test_recording.py +82 -0
- pinecall-0.1.0/tests/api/calls/test_state.py +227 -0
- pinecall-0.1.0/tests/api/calls/test_text.py +342 -0
- pinecall-0.1.0/tests/api/calls/test_the_orgs_own_key.py +55 -0
- pinecall-0.1.0/tests/api/calls/test_who_is_calling.py +45 -0
- pinecall-0.1.0/tests/api/carriers.py +107 -0
- pinecall-0.1.0/tests/api/conftest.py +396 -0
- pinecall-0.1.0/tests/api/evals/__init__.py +1 -0
- pinecall-0.1.0/tests/api/evals/conftest.py +143 -0
- pinecall-0.1.0/tests/api/evals/test_a_golden_opens_mid_call.py +65 -0
- pinecall-0.1.0/tests/api/evals/test_replay_door.py +78 -0
- pinecall-0.1.0/tests/api/evals/test_the_app_that_left.py +125 -0
- pinecall-0.1.0/tests/api/evals/test_the_caller_door.py +111 -0
- pinecall-0.1.0/tests/api/evals/test_the_costless_judge.py +142 -0
- pinecall-0.1.0/tests/api/evals/test_the_day_a_golden_runs_on.py +73 -0
- pinecall-0.1.0/tests/api/evals/test_the_run_door.py +310 -0
- pinecall-0.1.0/tests/api/evals/test_the_runs_list.py +89 -0
- pinecall-0.1.0/tests/api/evals/test_when_a_spoken_caller_may_hang_up.py +86 -0
- pinecall-0.1.0/tests/api/fake_graph.py +24 -0
- pinecall-0.1.0/tests/api/orgs/__init__.py +1 -0
- pinecall-0.1.0/tests/api/orgs/test_moving_an_agent.py +140 -0
- pinecall-0.1.0/tests/api/orgs/test_ops_orgs.py +142 -0
- pinecall-0.1.0/tests/api/orgs/test_provider_keys.py +311 -0
- pinecall-0.1.0/tests/api/orgs/test_quotas.py +144 -0
- pinecall-0.1.0/tests/api/orgs/test_the_operators_own_doors.py +109 -0
- pinecall-0.1.0/tests/api/orgs/test_two_orgs_never_cross.py +158 -0
- pinecall-0.1.0/tests/api/orgs/test_usage_door.py +91 -0
- pinecall-0.1.0/tests/api/people.py +49 -0
- pinecall-0.1.0/tests/api/pipeline/__init__.py +1 -0
- pinecall-0.1.0/tests/api/pipeline/conftest.py +44 -0
- pinecall-0.1.0/tests/api/pipeline/test_pipeline_doors.py +232 -0
- pinecall-0.1.0/tests/api/pipeline/test_pipeline_without_a_key.py +29 -0
- pinecall-0.1.0/tests/api/policy.py +16 -0
- pinecall-0.1.0/tests/api/routes/__init__.py +1 -0
- pinecall-0.1.0/tests/api/routes/test_doors.py +140 -0
- pinecall-0.1.0/tests/api/supervise/__init__.py +1 -0
- pinecall-0.1.0/tests/api/supervise/test_the_seat_is_named.py +82 -0
- pinecall-0.1.0/tests/api/supervise/test_verbs_door.py +271 -0
- pinecall-0.1.0/tests/api/supervise/test_verbs_on_a_text_call.py +292 -0
- pinecall-0.1.0/tests/api/talking.py +145 -0
- pinecall-0.1.0/tests/api/test_a_person_does_not_hold_production.py +117 -0
- pinecall-0.1.0/tests/api/test_buying_numbers.py +143 -0
- pinecall-0.1.0/tests/api/test_contacts.py +178 -0
- pinecall-0.1.0/tests/api/test_extraction.py +134 -0
- pinecall-0.1.0/tests/api/test_fleet_doors.py +129 -0
- pinecall-0.1.0/tests/api/test_knowledge.py +193 -0
- pinecall-0.1.0/tests/api/test_many_apps.py +257 -0
- pinecall-0.1.0/tests/api/test_members_and_login.py +238 -0
- pinecall-0.1.0/tests/api/test_no_provider_key_in_the_log.py +219 -0
- pinecall-0.1.0/tests/api/test_numbers.py +259 -0
- pinecall-0.1.0/tests/api/test_ops_keys.py +150 -0
- pinecall-0.1.0/tests/api/test_pairing.py +170 -0
- pinecall-0.1.0/tests/api/test_providers.py +63 -0
- pinecall-0.1.0/tests/api/test_pushing_into_a_capped_plan.py +113 -0
- pinecall-0.1.0/tests/api/test_refusals.py +80 -0
- pinecall-0.1.0/tests/api/test_scopes_at_the_doors.py +197 -0
- pinecall-0.1.0/tests/api/test_seating_a_team.py +105 -0
- pinecall-0.1.0/tests/api/test_served_call.py +216 -0
- pinecall-0.1.0/tests/api/test_signup.py +168 -0
- pinecall-0.1.0/tests/api/test_the_orgs_floor.py +129 -0
- pinecall-0.1.0/tests/api/test_the_orgs_own_keys.py +193 -0
- pinecall-0.1.0/tests/api/test_the_orgs_tables.py +131 -0
- pinecall-0.1.0/tests/api/test_the_pages_are_served.py +192 -0
- pinecall-0.1.0/tests/api/test_two_worlds_never_cross.py +224 -0
- pinecall-0.1.0/tests/api/test_whoami.py +63 -0
- pinecall-0.1.0/tests/api/test_worker_doors.py +178 -0
- pinecall-0.1.0/tests/api/tokens/__init__.py +1 -0
- pinecall-0.1.0/tests/api/tokens/test_listen_door.py +90 -0
- pinecall-0.1.0/tests/api/tokens/test_spending.py +91 -0
- pinecall-0.1.0/tests/api/tokens/test_supervise_door.py +69 -0
- pinecall-0.1.0/tests/api/tokens/test_the_door.py +248 -0
- pinecall-0.1.0/tests/api/whatsapp/__init__.py +1 -0
- pinecall-0.1.0/tests/api/whatsapp/conftest.py +201 -0
- pinecall-0.1.0/tests/api/whatsapp/test_routing.py +52 -0
- pinecall-0.1.0/tests/api/whatsapp/test_the_desk_holds_a_thread.py +154 -0
- pinecall-0.1.0/tests/api/whatsapp/test_the_door.py +327 -0
- pinecall-0.1.0/tests/auth/__init__.py +1 -0
- pinecall-0.1.0/tests/auth/test_codes.py +41 -0
- pinecall-0.1.0/tests/auth/test_keys.py +251 -0
- pinecall-0.1.0/tests/auth/test_members.py +88 -0
- pinecall-0.1.0/tests/auth/test_passwords.py +48 -0
- pinecall-0.1.0/tests/auth/test_postgres_members.py +67 -0
- pinecall-0.1.0/tests/auth/test_scopes.py +38 -0
- pinecall-0.1.0/tests/auth/test_throttle.py +31 -0
- pinecall-0.1.0/tests/auth/test_tokens.py +160 -0
- pinecall-0.1.0/tests/cli/__init__.py +1 -0
- pinecall-0.1.0/tests/cli/box/__init__.py +1 -0
- pinecall-0.1.0/tests/cli/box/test_verbs.py +99 -0
- pinecall-0.1.0/tests/cli/conftest.py +5 -0
- pinecall-0.1.0/tests/cli/doctor/__init__.py +1 -0
- pinecall-0.1.0/tests/cli/doctor/reading.py +29 -0
- pinecall-0.1.0/tests/cli/doctor/test_verbs.py +354 -0
- pinecall-0.1.0/tests/cli/doctor/test_which_keys_are_honoured.py +26 -0
- pinecall-0.1.0/tests/cli/keys/__init__.py +1 -0
- pinecall-0.1.0/tests/cli/keys/conftest.py +60 -0
- pinecall-0.1.0/tests/cli/keys/test_verbs.py +120 -0
- pinecall-0.1.0/tests/cli/orgs/__init__.py +1 -0
- pinecall-0.1.0/tests/cli/orgs/conftest.py +60 -0
- pinecall-0.1.0/tests/cli/orgs/test_verbs.py +139 -0
- pinecall-0.1.0/tests/cli/routes/__init__.py +1 -0
- pinecall-0.1.0/tests/cli/routes/conftest.py +60 -0
- pinecall-0.1.0/tests/cli/routes/test_verbs.py +111 -0
- pinecall-0.1.0/tests/cli/sessions/__init__.py +1 -0
- pinecall-0.1.0/tests/cli/sessions/test_postgres.py +74 -0
- pinecall-0.1.0/tests/cli/sessions/test_render.py +185 -0
- pinecall-0.1.0/tests/cli/sessions/test_verbs.py +206 -0
- pinecall-0.1.0/tests/cli/test_dispatcher.py +111 -0
- pinecall-0.1.0/tests/cli/test_init.py +116 -0
- pinecall-0.1.0/tests/cli/test_migrate.py +42 -0
- pinecall-0.1.0/tests/cli/test_migrate_key.py +67 -0
- pinecall-0.1.0/tests/cli/test_worker.py +246 -0
- pinecall-0.1.0/tests/conftest.py +86 -0
- pinecall-0.1.0/tests/evals/__init__.py +1 -0
- pinecall-0.1.0/tests/evals/checks/__init__.py +1 -0
- pinecall-0.1.0/tests/evals/checks/conftest.py +43 -0
- pinecall-0.1.0/tests/evals/checks/test_checks.py +83 -0
- pinecall-0.1.0/tests/evals/checks/test_consent.py +48 -0
- pinecall-0.1.0/tests/evals/clinica.py +55 -0
- pinecall-0.1.0/tests/evals/conversations.py +65 -0
- pinecall-0.1.0/tests/evals/fakes.py +106 -0
- pinecall-0.1.0/tests/evals/fixtures/clinica-norte/declaration.json +103 -0
- pinecall-0.1.0/tests/evals/fixtures/clinica-norte/state-0.txt +38 -0
- pinecall-0.1.0/tests/evals/fixtures/clinica-norte/state-1.txt +47 -0
- pinecall-0.1.0/tests/evals/fixtures/clinica-norte/state-2.txt +38 -0
- pinecall-0.1.0/tests/evals/logs/booking-before-the-yes.json +10 -0
- pinecall-0.1.0/tests/evals/logs/booking-confirmed-by-somebody-else.json +10 -0
- pinecall-0.1.0/tests/evals/logs/booking-confirmed.json +11 -0
- pinecall-0.1.0/tests/evals/logs/booking-with-no-gate.json +8 -0
- pinecall-0.1.0/tests/evals/logs.py +85 -0
- pinecall-0.1.0/tests/evals/measuring.py +18 -0
- pinecall-0.1.0/tests/evals/test_a_golden_that_remembers.py +59 -0
- pinecall-0.1.0/tests/evals/test_a_simulated_call_hangs_up.py +98 -0
- pinecall-0.1.0/tests/evals/test_bridge.py +141 -0
- pinecall-0.1.0/tests/evals/test_clinica_turns.py +129 -0
- pinecall-0.1.0/tests/evals/test_consent.py +94 -0
- pinecall-0.1.0/tests/evals/test_expected.py +204 -0
- pinecall-0.1.0/tests/evals/test_goldens.py +45 -0
- pinecall-0.1.0/tests/evals/test_grounded.py +208 -0
- pinecall-0.1.0/tests/evals/test_matrix.py +106 -0
- pinecall-0.1.0/tests/evals/test_register.py +58 -0
- pinecall-0.1.0/tests/evals/test_report.py +85 -0
- pinecall-0.1.0/tests/evals/test_the_callers_voice.py +44 -0
- pinecall-0.1.0/tests/evals/test_the_degraded_line.py +129 -0
- pinecall-0.1.0/tests/evals/test_the_goldens.py +47 -0
- pinecall-0.1.0/tests/evals/test_the_public_surface.py +63 -0
- pinecall-0.1.0/tests/evals/test_the_sources_the_gateway_writes.py +49 -0
- pinecall-0.1.0/tests/evals/test_the_verdict_on_a_call.py +180 -0
- pinecall-0.1.0/tests/evals/test_the_vocabulary.py +56 -0
- pinecall-0.1.0/tests/evals/test_when_the_caller_says_its_next_line.py +65 -0
- pinecall-0.1.0/tests/extensions/__init__.py +1 -0
- pinecall-0.1.0/tests/extensions/test_the_points.py +73 -0
- pinecall-0.1.0/tests/fleet/__init__.py +1 -0
- pinecall-0.1.0/tests/fleet/test_clouds.py +65 -0
- pinecall-0.1.0/tests/fleet/test_decisions.py +154 -0
- pinecall-0.1.0/tests/fleet/test_loop.py +95 -0
- pinecall-0.1.0/tests/fleet/test_roster.py +109 -0
- pinecall-0.1.0/tests/knowledge/__init__.py +1 -0
- pinecall-0.1.0/tests/knowledge/files.py +24 -0
- pinecall-0.1.0/tests/knowledge/test_chunking.py +103 -0
- pinecall-0.1.0/tests/knowledge/test_scoring.py +89 -0
- pinecall-0.1.0/tests/knowledge/test_store.py +289 -0
- pinecall-0.1.0/tests/knowledge/test_the_push.py +88 -0
- pinecall-0.1.0/tests/log/__init__.py +1 -0
- pinecall-0.1.0/tests/log/_sigkill_writer.py +19 -0
- pinecall-0.1.0/tests/log/test_0021_against_rows.py +108 -0
- pinecall-0.1.0/tests/log/test_an_unreadable_entry.py +64 -0
- pinecall-0.1.0/tests/log/test_fanout.py +92 -0
- pinecall-0.1.0/tests/log/test_filters.py +52 -0
- pinecall-0.1.0/tests/log/test_latencies.py +52 -0
- pinecall-0.1.0/tests/log/test_logs.py +98 -0
- pinecall-0.1.0/tests/log/test_migrating.py +183 -0
- pinecall-0.1.0/tests/log/test_migrations.py +43 -0
- pinecall-0.1.0/tests/log/test_pii.py +104 -0
- pinecall-0.1.0/tests/log/test_postgres.py +111 -0
- pinecall-0.1.0/tests/log/test_reduce.py +240 -0
- pinecall-0.1.0/tests/log/test_replay.py +137 -0
- pinecall-0.1.0/tests/log/test_sigkill.py +65 -0
- pinecall-0.1.0/tests/log/test_store.py +185 -0
- pinecall-0.1.0/tests/log/test_usage.py +125 -0
- pinecall-0.1.0/tests/log/test_wording.py +24 -0
- pinecall-0.1.0/tests/lookups/__init__.py +1 -0
- pinecall-0.1.0/tests/lookups/fakes.py +349 -0
- pinecall-0.1.0/tests/lookups/test_end_to_end.py +115 -0
- pinecall-0.1.0/tests/lookups/test_service.py +326 -0
- pinecall-0.1.0/tests/memory/__init__.py +1 -0
- pinecall-0.1.0/tests/memory/conftest.py +115 -0
- pinecall-0.1.0/tests/memory/facts.py +31 -0
- pinecall-0.1.0/tests/memory/test_extraction.py +140 -0
- pinecall-0.1.0/tests/memory/test_goldens.py +198 -0
- pinecall-0.1.0/tests/memory/test_one_developers_own.py +69 -0
- pinecall-0.1.0/tests/memory/test_pgvector.py +344 -0
- pinecall-0.1.0/tests/memory/test_ranking.py +67 -0
- pinecall-0.1.0/tests/memory/test_scoring.py +101 -0
- pinecall-0.1.0/tests/migrations.py +74 -0
- pinecall-0.1.0/tests/orgs/__init__.py +1 -0
- pinecall-0.1.0/tests/orgs/test_a_turned_knob_survives_a_restart.py +89 -0
- pinecall-0.1.0/tests/orgs/test_carriers.py +68 -0
- pinecall-0.1.0/tests/orgs/test_orgs_migration.py +167 -0
- pinecall-0.1.0/tests/orgs/test_provider_keys_migration.py +110 -0
- pinecall-0.1.0/tests/orgs/test_the_quotas_table.py +80 -0
- pinecall-0.1.0/tests/postgres.py +137 -0
- pinecall-0.1.0/tests/providers/__init__.py +1 -0
- pinecall-0.1.0/tests/providers/embed/__init__.py +1 -0
- pinecall-0.1.0/tests/providers/embed/test_perplexity.py +271 -0
- pinecall-0.1.0/tests/providers/embed/test_tei.py +116 -0
- pinecall-0.1.0/tests/providers/embed/test_the_builder.py +96 -0
- pinecall-0.1.0/tests/providers/test_a_turned_knob_is_written_through.py +44 -0
- pinecall-0.1.0/tests/providers/test_blocks.py +310 -0
- pinecall-0.1.0/tests/providers/test_catalog.py +96 -0
- pinecall-0.1.0/tests/providers/test_declaration.py +45 -0
- pinecall-0.1.0/tests/providers/test_models.py +144 -0
- pinecall-0.1.0/tests/providers/test_pipeline.py +72 -0
- pinecall-0.1.0/tests/providers/test_plugin.py +65 -0
- pinecall-0.1.0/tests/providers/test_prices.py +195 -0
- pinecall-0.1.0/tests/providers/test_provider_keys.py +102 -0
- pinecall-0.1.0/tests/providers/test_published.py +52 -0
- pinecall-0.1.0/tests/providers/test_registry.py +104 -0
- pinecall-0.1.0/tests/providers/test_stt.py +89 -0
- pinecall-0.1.0/tests/providers/test_tts.py +93 -0
- pinecall-0.1.0/tests/providers/test_voices.py +50 -0
- pinecall-0.1.0/tests/providers/vendors/__init__.py +12 -0
- pinecall-0.1.0/tests/providers/vendors/acme.py +12 -0
- pinecall-0.1.0/tests/routes/__init__.py +1 -0
- pinecall-0.1.0/tests/routes/test_answering.py +62 -0
- pinecall-0.1.0/tests/routes/test_postgres_table.py +109 -0
- pinecall-0.1.0/tests/routes/test_table.py +57 -0
- pinecall-0.1.0/tests/routes/test_trunks.py +33 -0
- pinecall-0.1.0/tests/routes/test_twilio.py +148 -0
- pinecall-0.1.0/tests/session/__init__.py +1 -0
- pinecall-0.1.0/tests/session/fake_llm.py +168 -0
- pinecall-0.1.0/tests/session/test_a_run_never_greets.py +36 -0
- pinecall-0.1.0/tests/session/test_asking.py +157 -0
- pinecall-0.1.0/tests/session/test_clock.py +67 -0
- pinecall-0.1.0/tests/session/test_first_entries.py +47 -0
- pinecall-0.1.0/tests/session/test_greeting.py +114 -0
- pinecall-0.1.0/tests/session/test_lookups.py +334 -0
- pinecall-0.1.0/tests/session/test_remembering.py +58 -0
- pinecall-0.1.0/tests/session/test_visibility.py +59 -0
- pinecall-0.1.0/tests/session/text/__init__.py +1 -0
- pinecall-0.1.0/tests/session/text/test_llm_live.py +57 -0
- pinecall-0.1.0/tests/session/text/test_lookups.py +180 -0
- pinecall-0.1.0/tests/session/text/test_metrics_passthrough.py +115 -0
- pinecall-0.1.0/tests/session/text/test_prompt.py +65 -0
- pinecall-0.1.0/tests/session/text/test_running.py +102 -0
- pinecall-0.1.0/tests/session/text/test_session.py +107 -0
- pinecall-0.1.0/tests/session/voice/__init__.py +1 -0
- pinecall-0.1.0/tests/session/voice/fakes.py +214 -0
- pinecall-0.1.0/tests/session/voice/room/__init__.py +1 -0
- pinecall-0.1.0/tests/session/voice/room/fakes.py +293 -0
- pinecall-0.1.0/tests/session/voice/room/test_datachannel.py +265 -0
- pinecall-0.1.0/tests/session/voice/room/test_facts.py +183 -0
- pinecall-0.1.0/tests/session/voice/room/test_verbs.py +168 -0
- pinecall-0.1.0/tests/session/voice/silence.py +85 -0
- pinecall-0.1.0/tests/session/voice/test_agent.py +106 -0
- pinecall-0.1.0/tests/session/voice/test_barge_in.py +33 -0
- pinecall-0.1.0/tests/session/voice/test_commands.py +177 -0
- pinecall-0.1.0/tests/session/voice/test_events.py +268 -0
- pinecall-0.1.0/tests/session/voice/test_hanging_up.py +78 -0
- pinecall-0.1.0/tests/session/voice/test_hearing.py +54 -0
- pinecall-0.1.0/tests/session/voice/test_kit.py +37 -0
- pinecall-0.1.0/tests/session/voice/test_lookups.py +259 -0
- pinecall-0.1.0/tests/session/voice/test_metrics.py +214 -0
- pinecall-0.1.0/tests/session/voice/test_prompt.py +130 -0
- pinecall-0.1.0/tests/session/voice/test_reading_back.py +70 -0
- pinecall-0.1.0/tests/session/voice/test_session.py +185 -0
- pinecall-0.1.0/tests/session/voice/test_sip.py +88 -0
- pinecall-0.1.0/tests/session/voice/test_supervising.py +236 -0
- pinecall-0.1.0/tests/session/voice/test_tools.py +141 -0
- pinecall-0.1.0/tests/session/voice/test_transfer.py +116 -0
- pinecall-0.1.0/tests/session/voice/test_voice.py +242 -0
- pinecall-0.1.0/tests/session/voice/test_whisper_changes_the_next_line.py +137 -0
- pinecall-0.1.0/tests/session/voice/test_writing.py +39 -0
- pinecall-0.1.0/tests/test_box_packages.py +210 -0
- pinecall-0.1.0/tests/test_env_example.py +40 -0
- pinecall-0.1.0/tests/test_isolation.py +153 -0
- pinecall-0.1.0/tests/test_layout.py +112 -0
- pinecall-0.1.0/tests/test_one_definition_per_thing.py +33 -0
- pinecall-0.1.0/tests/test_settings.py +190 -0
- pinecall-0.1.0/tests/test_settings_from_credentials.py +47 -0
- pinecall-0.1.0/tests/test_the_public_surface.py +47 -0
- pinecall-0.1.0/tests/test_vectors.py +38 -0
- pinecall-0.1.0/tests/tokens/__init__.py +1 -0
- pinecall-0.1.0/tests/tokens/test_ledger.py +31 -0
- pinecall-0.1.0/tests/tokens/test_postgres_ledger.py +48 -0
- pinecall-0.1.0/tests/tree.py +89 -0
- pinecall-0.1.0/tests/types/__init__.py +1 -0
- pinecall-0.1.0/tests/types/test_agent.py +115 -0
- pinecall-0.1.0/tests/types/test_call.py +85 -0
- pinecall-0.1.0/tests/types/test_carrier.py +36 -0
- pinecall-0.1.0/tests/types/test_consent.py +126 -0
- pinecall-0.1.0/tests/types/test_fusion.py +32 -0
- pinecall-0.1.0/tests/types/test_goldens.py +57 -0
- pinecall-0.1.0/tests/types/test_member.py +63 -0
- pinecall-0.1.0/tests/types/test_org.py +67 -0
- pinecall-0.1.0/tests/types/test_prompt.py +85 -0
- pinecall-0.1.0/tests/types/test_route.py +47 -0
- pinecall-0.1.0/tests/types/test_token.py +82 -0
- pinecall-0.1.0/tests/types/test_tool.py +87 -0
- pinecall-0.1.0/tests/types/test_wire_agreement.py +89 -0
- pinecall-0.1.0/tests/vectors.py +56 -0
- pinecall-0.1.0/tests/whatsapp/__init__.py +1 -0
- pinecall-0.1.0/tests/whatsapp/bodies.py +81 -0
- pinecall-0.1.0/tests/whatsapp/test_inbound.py +61 -0
- pinecall-0.1.0/tests/whatsapp/test_signing.py +38 -0
- pinecall-0.1.0/tests/worker/__init__.py +1 -0
- pinecall-0.1.0/tests/worker/fakes.py +119 -0
- pinecall-0.1.0/tests/worker/test_client.py +220 -0
- pinecall-0.1.0/tests/worker/test_entry.py +250 -0
- pinecall-0.1.0/tests/worker/test_heartbeat.py +84 -0
- pinecall-0.1.0/tests/worker/test_load.py +126 -0
- pinecall-0.1.0/tests/worker/test_main.py +208 -0
- pinecall-0.1.0/tests/worker/test_overflow.py +43 -0
- pinecall-0.1.0/tests/worker/test_recordings.py +109 -0
- pinecall-0.1.0/tests/worker/test_router.py +117 -0
- pinecall-0.1.0/tests/worker/test_seat.py +110 -0
- pinecall-0.1.0/uv.lock +4734 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: add-a-vendor
|
|
3
|
+
description: Add an LLM, STT or TTS vendor the way this tree does it — a catalog row, a key, and the four places that are still by hand. Use when adding a provider, a model row, a price, or a provider key.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Adding a vendor
|
|
7
|
+
|
|
8
|
+
**Almost always, there is nothing to add.** `providers/catalog.py` already holds every vendor
|
|
9
|
+
livekit-agents ships a plugin for, `providers/plugin.py` builds any of them out of the plugin's own
|
|
10
|
+
constructor signature, and `_vendor_keys.py` holds a field for each. Check first:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
uv run pinecall-runtime providers --does tts | grep -i <the vendor>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
- **`ready`** — it runs today. Nothing to do.
|
|
17
|
+
- **`install`** — the row is right and the plugin is not on this box: add its extra to
|
|
18
|
+
`[project.optional-dependencies] providers` in `pyproject.toml`, `uv lock`, deploy. Use
|
|
19
|
+
`providers-big` when it drags a cloud SDK (boto3, azure-cognitiveservices-speech,
|
|
20
|
+
google-cloud-*, onnxruntime) — that is a decision a box makes, never a default.
|
|
21
|
+
- **`no key`** — `printf '%s' <the key> | make secret NAME=<ITS_VARIABLE>` from the checkout, then
|
|
22
|
+
`make restart`. The variable is in the `providers` table's own column.
|
|
23
|
+
- **not listed at all** — livekit added a plugin since. One row, below.
|
|
24
|
+
|
|
25
|
+
## A row in the catalog
|
|
26
|
+
|
|
27
|
+
`providers/catalog.py`, alphabetical, positional in the order the fields are declared:
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
(Provider("acme", ("stt", "tts"), "ACME_API_KEY", ("acmeai",), "what a person is choosing"),)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- `does` is what the plugin's own `__all__` exports — `tests/providers/test_catalog.py` checks the
|
|
34
|
+
row against the plugin and fails if they disagree.
|
|
35
|
+
- `env` is the variable **the plugin itself reads**, spelled the vendor's way. `None` when the
|
|
36
|
+
vendor has no single-string credential (AWS's chain, Google's service account, RTZR's pair):
|
|
37
|
+
BYOK then does not apply to it and nothing anywhere asks for one.
|
|
38
|
+
- An alias must **never** also be a model name of that vendor. A bare word that names a vendor IS
|
|
39
|
+
the vendor at the pipeline door, so `sonic`, `octave`, `sonar`, `mist`, `nova` and `aura` are
|
|
40
|
+
deliberately not aliases — every one of them is something a person could type meaning the model.
|
|
41
|
+
|
|
42
|
+
Then **one field in `_vendor_keys.py`**, named the variable lowercased. That rule is the whole of
|
|
43
|
+
the key wiring: `catalog.settings_field_of` reads it, the doctor reads it, the vault accepts the
|
|
44
|
+
vendor, `.env.example` and the box's units list it. `tests/providers/test_provider_keys.py` fails
|
|
45
|
+
while a row has no field.
|
|
46
|
+
|
|
47
|
+
## A tuned file — only when this build has an OPINION
|
|
48
|
+
|
|
49
|
+
A file under `providers/llm/`, `stt/` or `tts/` exists to **override a plugin default**: a model a
|
|
50
|
+
phone line should not wait for, an endpointing number, a model this build forbids. Five of them do.
|
|
51
|
+
If there is nothing to override, do not write one — the generic path is not a fallback, it is the
|
|
52
|
+
normal case, and a file that only forwards `model=` and `api_key=` is one more thing to go stale.
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
"""Acme: one line saying what the plugin is, and the one default this repo overrides."""
|
|
56
|
+
|
|
57
|
+
from livekit.plugins import acme
|
|
58
|
+
|
|
59
|
+
from pinecall.providers.llm import VENDORS
|
|
60
|
+
from pinecall.providers.registry import Asked, Chat, a_key
|
|
61
|
+
|
|
62
|
+
DEFAULT_MODEL = "acme-fast" # the plugin's own is acme-large (acme/llm.py:67)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@VENDORS.registers("acme")
|
|
66
|
+
def build(asked: Asked) -> Chat:
|
|
67
|
+
return acme.LLM(model=asked.model or DEFAULT_MODEL, api_key=a_key("acme", asked))
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## The four places that are still by hand
|
|
71
|
+
|
|
72
|
+
1. `providers/knocks.py` — the vendor's cheapest authenticated GET, so `doctor` knocks and
|
|
73
|
+
`make deploy` refuses a dead key by name. **Only a URL you have opened with a live key and
|
|
74
|
+
watched answer 200.** A guessed one 404s a perfectly good key and refuses a box that was fine;
|
|
75
|
+
a vendor with no row is simply not knocked, which is honest.
|
|
76
|
+
2. `providers/prices.py` — a row only where you read the vendor's own page, with `AS_OF` beside
|
|
77
|
+
it. Everything else is priced by `published_prices.json`
|
|
78
|
+
(`scripts/refresh-prices`, mahimailabs/voice-prices), and the hand-read table wins where the
|
|
79
|
+
two disagree — Soniox is the row that says why.
|
|
80
|
+
3. `infra/box/*.service` and `WORKER_CREDENTIALS` in the `Makefile` — one `ImportCredential=` line
|
|
81
|
+
each and one name, when the vendor has an env.
|
|
82
|
+
4. `tests/conftest.py` — a dead sentinel, if a suite needs to construct that vendor.
|
|
83
|
+
|
|
84
|
+
Then `scripts/generate-env-example` (a test fails while it drifts), and `CHANGELOG.md`.
|
|
85
|
+
|
|
86
|
+
## What the tests will refuse
|
|
87
|
+
|
|
88
|
+
- A vendor SDK import anywhere but `providers/` (`tests/test_isolation.py`, `VENDOR_SDKS`).
|
|
89
|
+
- A catalog row that disagrees with its plugin's `__all__` (`tests/providers/test_catalog.py`).
|
|
90
|
+
- A catalogued vendor with no settings field (`tests/providers/test_provider_keys.py`).
|
|
91
|
+
- A second definition of a default model, a header name, a URL: `grep` first
|
|
92
|
+
(`tests/test_one_definition_per_thing.py`).
|
|
93
|
+
- Two files in one directory one letter apart (`openai.py` next to `openia.py`).
|
|
94
|
+
- A public name added to `pinecall.providers` without editing `tests/test_the_public_surface.py`.
|
|
95
|
+
|
|
96
|
+
## Verify
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
scripts/format && scripts/lint && uv run pytest -m unit -q # three times: it is shuffled
|
|
100
|
+
uv run pinecall-runtime providers --does stt # the row, and what it wants
|
|
101
|
+
uv run pinecall-runtime doctor # the knock, with a real key in .env
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
An STT vendor is verified on a spoken call (`debug-a-call`): the transcript entries name the
|
|
105
|
+
vendor in `metrics.stt`. A TTS vendor: `tts_node_ttfb` on `turn.agent`.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debug-a-call
|
|
3
|
+
description: Read a call's log to find what went wrong, and drive a simulated voice or text call at a gateway (local or a box) to reproduce it. Use for "the agent said nothing", a 503 from simulate, a slow turn, a tool that never answered, or proving a worker takes calls.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Debugging a call
|
|
7
|
+
|
|
8
|
+
The log is the truth: every event of a call, with a `seq`, in `call_log`. Read it before reading
|
|
9
|
+
any process's stdout.
|
|
10
|
+
|
|
11
|
+
## Read the log
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv run pinecall-runtime sessions list # newest first, off Postgres, gateway up or not
|
|
15
|
+
uv run pinecall-runtime sessions show <call> # entry by entry, every metric under its turn
|
|
16
|
+
uv run pinecall-runtime sessions tail <call> # as it happens (polls)
|
|
17
|
+
uv run pinecall-runtime sessions recording <call> # where the audio went (RECORD=1)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
What to look for, in order: `call.started` (channel, direction) → `turn.user` / `turn.agent`
|
|
21
|
+
with their metrics (`e2e_latency`, `llm_node_ttft`, `tts_node_ttfb`) → `tool.call` /
|
|
22
|
+
`tool.result` (did the app answer? `timeout_s` on the ToolSpec) → `metrics.*` errors, the
|
|
23
|
+
session's own `error` entries → `call.summary` (usage, cost) → `call.score` (the judges: `panel`
|
|
24
|
+
is who RAN, `judges` who ANSWERED; `not_judged` means the session was built without a Scorer).
|
|
25
|
+
|
|
26
|
+
A call with `turn.user` and no `turn.agent`: the LLM or TTS — see the worker's journal. A call
|
|
27
|
+
with no `turn.user`: the STT, or the seat (`worker/seat.py`: which participant is the caller).
|
|
28
|
+
|
|
29
|
+
## Drive a call
|
|
30
|
+
|
|
31
|
+
From an example in the agents repo, against whichever gateway you name:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
cd ~/pinecall-v2/agents/examples/clinica-norte
|
|
35
|
+
PINECALL_URL=https://box.pinecall.io node ../../bin/pinecall.js whoami # which key, from where
|
|
36
|
+
PINECALL_URL=… node ../../bin/pinecall.js simulate --persona apurado --turns 3 # text
|
|
37
|
+
PINECALL_URL=… node ../../bin/pinecall.js simulate --persona apurado --voice --judge # voice
|
|
38
|
+
node ../../bin/pinecall.js personas list
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`--voice` mounts the class in THIS terminal (it serves the call the runtime opens), asks the
|
|
42
|
+
gateway to put a synthetic caller on a real line, and prints each turn with its latencies; with
|
|
43
|
+
`--judge`, `call.score` read back. The key comes from `PINECALL_API_KEY` in the env or
|
|
44
|
+
`~/.pinecall/credentials`; `PINECALL_URL` picks the gateway (otherwise the local dev file).
|
|
45
|
+
|
|
46
|
+
What a `503` from simulate means:
|
|
47
|
+
- `this box has no speech tool` — the GATEWAY's box lacks `espeak-ng` (macOS: `say`). It is in
|
|
48
|
+
`PACKAGES`; `make deploy` installs it.
|
|
49
|
+
- `no agent joined room … in 20s: is pinecall-runtime worker up?` — no worker took the job:
|
|
50
|
+
none registered on the SFU, or the one that did crashed on the job (its journal has a traceback:
|
|
51
|
+
`NoProvider: <vendor> has no API key in this process` is a missing or empty credential).
|
|
52
|
+
|
|
53
|
+
## Which worker took it
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
ssh <hub> 'sudo podman logs --since 10m pinecall-livekit 2>&1 | grep -E "worker registered|job"'
|
|
57
|
+
ssh <worker> "sudo journalctl -u pinecall-worker --since '$START' -o cat" \
|
|
58
|
+
| grep -iE "received job|pipeline is live|error|exception" \
|
|
59
|
+
| sed -E 's/(key|secret|token)[=:] *[^ ]+/\1=***/Ig'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`received job request` names `job_id`, `dispatch_id`, `room`; `the pipeline is live N s after
|
|
63
|
+
the job arrived` is the number to watch (0.5 s on the box). To prove a call lands on ONE worker,
|
|
64
|
+
stop the others first (`sudo systemctl stop pinecall-worker` on the hub), never guess from load.
|
|
65
|
+
|
|
66
|
+
## Local
|
|
67
|
+
|
|
68
|
+
`uv run pinecall-runtime doctor` first. `unset PINECALL_API_KEY` before `pinecall run` against a
|
|
69
|
+
dev-key gateway (it is ignored out loud; a bare 403 is that). Native Postgres on the laptop:
|
|
70
|
+
`DATABASE_URL=…@[::1]:5432/…`. A `.env` the runtime ignored is never silent: the doctor's first
|
|
71
|
+
line says which file it read.
|
|
72
|
+
|
|
73
|
+
## Never
|
|
74
|
+
|
|
75
|
+
Print a key or a token from a journal, a `.env`, or `~/.pinecall/credentials` (the `sed` above
|
|
76
|
+
on every journal read). Run `simulate` against production with a persona that books: `consent`
|
|
77
|
+
is judged, but the tool still runs in the app you mounted.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deploy
|
|
3
|
+
description: Deploy this checkout to a box (hub, worker, or one machine) and verify it, without a secret ever reaching a screen. Use for make deploy, a second box, rotating a vendor key, or when the doctor refuses a key.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Deploying a box
|
|
7
|
+
|
|
8
|
+
The deploy is the root `Makefile`: rsync + ssh + make + curl, from a checkout, to the account
|
|
9
|
+
cloud-init made. Nothing on the box can clone; nothing here uses shipway. The box's identity is
|
|
10
|
+
`deploy.local.mk` beside the Makefile (git-ignored): `BOX`, `DOMAIN`, optional `SSH_KEY`.
|
|
11
|
+
|
|
12
|
+
## NEVER
|
|
13
|
+
|
|
14
|
+
- Print a secret: not a credential's value, not a key from the shell, not a line of a journal
|
|
15
|
+
that carries one. Compare credentials by fingerprint (below). Pipe every journal read through
|
|
16
|
+
`sed -E 's/(key|secret|token)[=:] *[^ ]+/\1=***/Ig'`.
|
|
17
|
+
- Fix the box by hand and stop there. An `apt install`, a credential rewritten with
|
|
18
|
+
`systemd-creds`, a unit edited in `/etc`: each is at most a probe. The same fix goes in the
|
|
19
|
+
tree (`PACKAGES` in `infra/box/Makefile`, `make secret`, a doctor check, the unit file) and the
|
|
20
|
+
box re-converges through `make deploy` before the turn ends.
|
|
21
|
+
- Restart a container (`pinecall-livekit`, `-sip`, `-postgres`, `-redis`) during a call. The
|
|
22
|
+
deploy never does; a changed `.container` is restarted between two calls, by a person.
|
|
23
|
+
- Run `shipway deploy` anywhere near this tree. `~/pinecall/v2/shipway.yml` points at the same box.
|
|
24
|
+
- Leave `PINECALL_API_KEY` exported while running the deploy or anything that opens a socket:
|
|
25
|
+
`unset PINECALL_API_KEY` first.
|
|
26
|
+
|
|
27
|
+
## The path
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
unset PINECALL_API_KEY
|
|
31
|
+
make deploy # sync → install → restart → doctor
|
|
32
|
+
make deploy BOX=deploy@<ip> DOMAIN=<domain> # another box, same tree
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
What each step proves: `sync` — the two directories the box needs; `install` — every file of
|
|
36
|
+
`infra/box/` where systemd reads it, the packages the box is missing, the role's units enabled and
|
|
37
|
+
the others' disabled, `uv sync --frozen` as the service user; `restart` — by role: `all` restarts
|
|
38
|
+
gateway → health through Caddy → worker; `hub` restarts the gateway only (`systemctl restart`
|
|
39
|
+
would START a worker the role disabled); `worker` restarts its one unit; `doctor` — the runtime's
|
|
40
|
+
doctor as the units see the box, every vendor knocked with the key the box holds.
|
|
41
|
+
|
|
42
|
+
A deploy that ends in `✗ provider keys answer refused ELEVEN_API_KEY (HTTP 401)` is a dead key,
|
|
43
|
+
not a deploy failure: rotate it (below), `make restart`, `make doctor`.
|
|
44
|
+
|
|
45
|
+
## Fingerprints, never values
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
ssh <box> "sudo systemd-creds decrypt --name=$N /etc/credstore.encrypted/$N - | sha256sum | cut -c1-12; \
|
|
49
|
+
sudo systemd-creds decrypt --name=$N /etc/credstore.encrypted/$N - | wc -c"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Two boxes agree when the twelve characters and the byte count agree. `e3b0c44298fc` is the
|
|
53
|
+
sha256 of the EMPTY string: a credential written from an unset shell variable. The shell may call
|
|
54
|
+
a key differently from the runtime (`ELEVENLABS_API_KEY` vs `ELEVEN_API_KEY`); `.env.example`
|
|
55
|
+
is the runtime's list.
|
|
56
|
+
|
|
57
|
+
## Rotating a vendor key
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
printf '%s' "$ELEVENLABS_API_KEY" | make secret NAME=ELEVEN_API_KEY # the value on stdin, on no screen
|
|
61
|
+
make restart && make doctor
|
|
62
|
+
make worker-secrets WORKER=deploy@<worker-ip> # every worker takes the hub's copy
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`box secrets` (the generated ones: LiveKit pair, Postgres, ops, vault) never rotates; `box secret
|
|
66
|
+
<NAME>` replaces in place.
|
|
67
|
+
|
|
68
|
+
## A second box
|
|
69
|
+
|
|
70
|
+
The hub keeps the gateway and the media plane (`PINECALL_ROLE=hub` in its `/etc/pinecall/box.env`);
|
|
71
|
+
each worker is `PINECALL_ROLE=worker` with `LIVEKIT_URL=wss://<hub-domain>`,
|
|
72
|
+
`PINECALL_GATEWAY_URL=https://<hub-domain>`, `PINECALL_MAX_JOBS=<measured>` — cloud-init writes
|
|
73
|
+
those lines. Order: `make worker-secrets WORKER=…` · `make deploy BOX=<worker> DOMAIN=<hub>` · the
|
|
74
|
+
hub's SFU log says `worker registered` with a new `AW_` id · one voice call lands there (the
|
|
75
|
+
`debug-a-call` skill) · only then the hub's role flips to `hub` and `make deploy` runs on it.
|
|
76
|
+
|
|
77
|
+
## Reading the box
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
make status # every unit and container, one line each
|
|
81
|
+
make logs UNIT=worker # gateway (default) · worker · caddy
|
|
82
|
+
ssh <box> 'sudo podman logs --since 5m pinecall-livekit 2>&1 | grep -E "worker registered|job"'
|
|
83
|
+
ssh <box> "sudo journalctl -u pinecall-worker --since '$START' -o cat" | sed -E 's/(key|secret|token)[=:] *[^ ]+/\1=***/Ig'
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Gotchas
|
|
87
|
+
|
|
88
|
+
- A fresh box has `/opt/pinecall/app` and nothing under it; `sync` makes the two directories.
|
|
89
|
+
- The fence lives in `prerouting` (raw priority) because DNAT'd container traffic never hits
|
|
90
|
+
`input`, and it must accept udp/tcp 53 from `podman*` or containers cannot resolve each other.
|
|
91
|
+
- A credential file is named EXACTLY as the credential, no extension; `ImportCredential=` accepts
|
|
92
|
+
a trailing glob only (`PINECALL_*`).
|
|
93
|
+
- The units run `/opt/pinecall/venv/bin/pinecall-runtime`, never `uv run`.
|
|
94
|
+
- `livekit` on the hub reads a worker's load every 0.5 s and stops routing at 0.7 of it:
|
|
95
|
+
`PINECALL_MAX_JOBS` is one under the measured ceiling.
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# The only .env ever committed, and it is GENERATED: `scripts/generate-env-example` renders it
|
|
2
|
+
# from the aliases src/pinecall/_settings.py declares, and a test fails when the two drift.
|
|
3
|
+
# Copy it to .env and fill what you have. A real environment variable wins over the file,
|
|
4
|
+
# and a name this runtime does not read is ignored, never an error.
|
|
5
|
+
|
|
6
|
+
# Anthropic, llm. Every provider key keeps the vendor's own variable name.
|
|
7
|
+
ANTHROPIC_API_KEY=
|
|
8
|
+
|
|
9
|
+
# OpenAI, llm, stt and tts. The other LLM a call may run on.
|
|
10
|
+
OPENAI_API_KEY=
|
|
11
|
+
|
|
12
|
+
# Soniox, stt and tts. A call needs one key of each role: llm, stt, tts.
|
|
13
|
+
SONIOX_API_KEY=
|
|
14
|
+
|
|
15
|
+
# Deepgram, stt and tts. Flux and Nova for the ears, Aura for the voice.
|
|
16
|
+
DEEPGRAM_API_KEY=
|
|
17
|
+
|
|
18
|
+
# ElevenLabs, stt and tts. The voice this runtime speaks with by default.
|
|
19
|
+
ELEVEN_API_KEY=
|
|
20
|
+
|
|
21
|
+
# AssemblyAI, stt. Universal-Streaming.
|
|
22
|
+
ASSEMBLYAI_API_KEY=
|
|
23
|
+
|
|
24
|
+
# Async AI, tts.
|
|
25
|
+
ASYNCAI_API_KEY=
|
|
26
|
+
|
|
27
|
+
# Azure Speech, stt and tts. Needs AZURE_SPEECH_REGION beside the key.
|
|
28
|
+
AZURE_SPEECH_KEY=
|
|
29
|
+
|
|
30
|
+
# Baseten, llm, stt and tts. Open models on Baseten's own endpoints.
|
|
31
|
+
BASETEN_API_KEY=
|
|
32
|
+
|
|
33
|
+
# Bland, tts.
|
|
34
|
+
BLAND_API_KEY=
|
|
35
|
+
|
|
36
|
+
# Camb.ai, tts.
|
|
37
|
+
CAMB_API_KEY=
|
|
38
|
+
|
|
39
|
+
# Cartesia, stt and tts. Sonic, and Ink-Whisper for the ears.
|
|
40
|
+
CARTESIA_API_KEY=
|
|
41
|
+
|
|
42
|
+
# Cerebras, llm.
|
|
43
|
+
CEREBRAS_API_KEY=
|
|
44
|
+
|
|
45
|
+
# Naver CLOVA, stt. Needs CLOVA_STT_INVOKE_URL beside the secret.
|
|
46
|
+
CLOVA_STT_SECRET_KEY=
|
|
47
|
+
|
|
48
|
+
# fal, stt. Wizper. Batch, not a live socket.
|
|
49
|
+
FAL_KEY=
|
|
50
|
+
|
|
51
|
+
# Fireworks AI, stt.
|
|
52
|
+
FIREWORKS_API_KEY=
|
|
53
|
+
|
|
54
|
+
# Fish Audio, tts.
|
|
55
|
+
FISH_API_KEY=
|
|
56
|
+
|
|
57
|
+
# Gladia, stt.
|
|
58
|
+
GLADIA_API_KEY=
|
|
59
|
+
|
|
60
|
+
# Gnani, stt and tts.
|
|
61
|
+
GNANI_API_KEY=
|
|
62
|
+
|
|
63
|
+
# Google, llm, stt and tts. Gemini on the key; Speech-to-Text and Text-to-Speech want a service account.
|
|
64
|
+
GOOGLE_API_KEY=
|
|
65
|
+
|
|
66
|
+
# Gradium, stt and tts.
|
|
67
|
+
GRADIUM_API_KEY=
|
|
68
|
+
|
|
69
|
+
# Groq, llm, stt and tts. Whisper and open models, fast.
|
|
70
|
+
GROQ_API_KEY=
|
|
71
|
+
|
|
72
|
+
# Hume, tts.
|
|
73
|
+
HUME_API_KEY=
|
|
74
|
+
|
|
75
|
+
# Inworld, stt and tts.
|
|
76
|
+
INWORLD_API_KEY=
|
|
77
|
+
|
|
78
|
+
# LMNT, tts.
|
|
79
|
+
LMNT_API_KEY=
|
|
80
|
+
|
|
81
|
+
# MiniMax, tts.
|
|
82
|
+
MINIMAX_API_KEY=
|
|
83
|
+
|
|
84
|
+
# Mistral AI, llm, stt and tts.
|
|
85
|
+
MISTRAL_API_KEY=
|
|
86
|
+
|
|
87
|
+
# Murf, tts.
|
|
88
|
+
MURF_API_KEY=
|
|
89
|
+
|
|
90
|
+
# Neuphonic, tts.
|
|
91
|
+
NEUPHONIC_API_KEY=
|
|
92
|
+
|
|
93
|
+
# NVIDIA Riva, stt and tts.
|
|
94
|
+
NVIDIA_API_KEY=
|
|
95
|
+
|
|
96
|
+
# Palabra, stt and tts.
|
|
97
|
+
PALABRA_API_KEY=
|
|
98
|
+
|
|
99
|
+
# Perplexity, llm. Sonar, and the embedder: the contextual model and the flat.
|
|
100
|
+
PERPLEXITY_API_KEY=
|
|
101
|
+
|
|
102
|
+
# Resemble AI, tts.
|
|
103
|
+
RESEMBLE_API_KEY=
|
|
104
|
+
|
|
105
|
+
# Respeecher, tts.
|
|
106
|
+
RESPEECHER_API_KEY=
|
|
107
|
+
|
|
108
|
+
# Rime, tts.
|
|
109
|
+
RIME_API_KEY=
|
|
110
|
+
|
|
111
|
+
# Sarvam AI, llm, stt and tts. The Indian languages, all three jobs on one account.
|
|
112
|
+
SARVAM_API_KEY=
|
|
113
|
+
|
|
114
|
+
# Simplismart, stt and tts.
|
|
115
|
+
SIMPLISMART_API_KEY=
|
|
116
|
+
|
|
117
|
+
# slng, stt and tts.
|
|
118
|
+
SLNG_API_KEY=
|
|
119
|
+
|
|
120
|
+
# Smallest AI, stt and tts.
|
|
121
|
+
SMALLEST_API_KEY=
|
|
122
|
+
|
|
123
|
+
# Speechify, tts.
|
|
124
|
+
SPEECHIFY_API_KEY=
|
|
125
|
+
|
|
126
|
+
# Speechmatics, stt and tts.
|
|
127
|
+
SPEECHMATICS_API_KEY=
|
|
128
|
+
|
|
129
|
+
# Spitch, stt and tts. The African languages.
|
|
130
|
+
SPITCH_API_KEY=
|
|
131
|
+
|
|
132
|
+
# Upliftai, tts.
|
|
133
|
+
UPLIFTAI_API_KEY=
|
|
134
|
+
|
|
135
|
+
# Vakyam, tts.
|
|
136
|
+
VAKYAM_API_KEY=
|
|
137
|
+
|
|
138
|
+
# xAI, stt and tts. Grok speaks and hears here; Grok the LLM is reached through livekit or openai.
|
|
139
|
+
XAI_API_KEY=
|
|
140
|
+
|
|
141
|
+
# OpenRouter, an embedder: the other way to the flat model, no contextual door.
|
|
142
|
+
OPENROUTER_API_KEY=
|
|
143
|
+
|
|
144
|
+
# The box's own WhatsApp Cloud API token, used for an org that brought none.
|
|
145
|
+
WHATSAPP_ACCESS_TOKEN=
|
|
146
|
+
|
|
147
|
+
# LiveKit: the media plane both processes talk to. One port serves ws and http.
|
|
148
|
+
LIVEKIT_URL=ws://127.0.0.1:7880
|
|
149
|
+
|
|
150
|
+
# The LiveKit API key, as the LiveKit server's own config declares it.
|
|
151
|
+
LIVEKIT_API_KEY=
|
|
152
|
+
|
|
153
|
+
# Its secret. It also signs the call tokens, so there is no second one.
|
|
154
|
+
LIVEKIT_API_SECRET=
|
|
155
|
+
|
|
156
|
+
# The LiveKit URL a browser is told to join. Unset, it hears LIVEKIT_URL.
|
|
157
|
+
LIVEKIT_PUBLIC_URL=
|
|
158
|
+
|
|
159
|
+
# The box's Twilio account, for the numbers it buys for a tenant.
|
|
160
|
+
TWILIO_ACCOUNT_SID=
|
|
161
|
+
|
|
162
|
+
# An API key SID on that account, revocable on its own; else the account SID.
|
|
163
|
+
TWILIO_API_KEY=
|
|
164
|
+
|
|
165
|
+
# The API key's secret, or the account's auth token when no key is set.
|
|
166
|
+
TWILIO_API_SECRET=
|
|
167
|
+
|
|
168
|
+
# The box's public name: where a carrier sends a call. Unset, nothing imports.
|
|
169
|
+
PINECALL_DOMAIN=
|
|
170
|
+
|
|
171
|
+
# Postgres 17 with pgvector and pg_textsearch: the one stateful service.
|
|
172
|
+
DATABASE_URL=postgresql://pinecall:pinecall@127.0.0.1:5432/pinecall
|
|
173
|
+
|
|
174
|
+
# TEI, the embedder. 8081, because the gateway serves 8080 on the same host.
|
|
175
|
+
TEI_URL=http://127.0.0.1:8081
|
|
176
|
+
|
|
177
|
+
# Who embeds: tei · perplexity · openrouter. The other two need their API key.
|
|
178
|
+
EMBED_PROVIDER=tei
|
|
179
|
+
|
|
180
|
+
# The embedding model. Unset: BAAI/bge-m3 · pplx-embed-context-v1-0.6b · perplexity/pplx-embed-v1-0.6b, by provider.
|
|
181
|
+
EMBED_MODEL=
|
|
182
|
+
|
|
183
|
+
# Where it is asked. Unset: the provider's own door, and TEI_URL for TEI.
|
|
184
|
+
EMBED_BASE_URL=
|
|
185
|
+
|
|
186
|
+
# The Meta app's App Secret: every webhook body is HMAC-SHA256-signed with it. Unset, the WhatsApp door is closed.
|
|
187
|
+
PINECALL_WHATSAPP_APP_SECRET=
|
|
188
|
+
|
|
189
|
+
# The word Meta echoes back when the webhook is subscribed. Choose it; type it in the Meta app.
|
|
190
|
+
PINECALL_WHATSAPP_VERIFY_TOKEN=
|
|
191
|
+
|
|
192
|
+
# Whether a call's audio is kept at all. 0, false, no and off all mean no.
|
|
193
|
+
RECORD=true
|
|
194
|
+
|
|
195
|
+
# Where a kept recording lands, absolute or relative to the working directory.
|
|
196
|
+
PINECALL_RECORDINGS=recordings
|
|
197
|
+
|
|
198
|
+
# The gateway a worker's job asks. Read in the job process, never the parent.
|
|
199
|
+
PINECALL_GATEWAY_URL=http://127.0.0.1:8080
|
|
200
|
+
|
|
201
|
+
# The agent a job that names none is for.
|
|
202
|
+
PINECALL_AGENT=
|
|
203
|
+
|
|
204
|
+
# Calls this worker holds at once, measured on its machine. Unset: gate on CPU.
|
|
205
|
+
PINECALL_MAX_JOBS=
|
|
206
|
+
|
|
207
|
+
# Where the worker's own health server binds, on loopback. Not 8080 or 8081.
|
|
208
|
+
PINECALL_WORKER_HTTP_PORT=8082
|
|
209
|
+
|
|
210
|
+
# What this worker is called in its heartbeats. Unset: the short hostname.
|
|
211
|
+
PINECALL_WORKER_NAME=
|
|
212
|
+
|
|
213
|
+
# What the overflow agent says when the fleet is full, before it hangs up.
|
|
214
|
+
PINECALL_OVERFLOW_SAYS=En este momento todas nuestras líneas están ocupadas. Hemos tomado nota de su número y le devolveremos la llamada en cuanto se libere una. Gracias por su paciencia.
|
|
215
|
+
|
|
216
|
+
# The app socket a job's call claims. Unset, the call takes the newest holder.
|
|
217
|
+
PINECALL_APP=
|
|
218
|
+
|
|
219
|
+
# What this box runs: all · hub · worker. The doctor asks after what it has.
|
|
220
|
+
PINECALL_ROLE=all
|
|
221
|
+
|
|
222
|
+
# How short a member's password may be. 0 is no rule.
|
|
223
|
+
PINECALL_MIN_PASSWORD=8
|
|
224
|
+
|
|
225
|
+
# The key /v1/ops/* is authenticated by. Unset, the operator API is closed.
|
|
226
|
+
PINECALL_OPS_KEY=
|
|
227
|
+
|
|
228
|
+
# Pinecall's hosted gateway: a plan, billed.
|
|
229
|
+
PINECALL_CLOUD=false
|
|
230
|
+
|
|
231
|
+
# Whether a stranger may make an org at this gateway. Off unless you say.
|
|
232
|
+
PINECALL_SIGNUP=false
|
|
233
|
+
|
|
234
|
+
# Packages that plug a policy into the runtime's points, comma separated.
|
|
235
|
+
PINECALL_EXTENSIONS=
|
|
236
|
+
|
|
237
|
+
# The org key the worker knocks its gateway with, as `keys issue` printed it.
|
|
238
|
+
PINECALL_WORKER_KEY=
|
|
239
|
+
|
|
240
|
+
# A Fernet key, generated once on the box by `pinecall-runtime box secrets`: a tenant's own provider keys are encrypted under it. Unset, the provider-key doors answer 503.
|
|
241
|
+
PINECALL_VAULT_KEY=
|
|
242
|
+
|
|
243
|
+
# How much both processes say: DEBUG, INFO, WARNING or ERROR.
|
|
244
|
+
PINECALL_LOG_LEVEL=INFO
|
|
245
|
+
|
|
246
|
+
# What judging one call may spend on a model, in euros. Zero: no judge asks.
|
|
247
|
+
PINECALL_JUDGE_CEILING_EUR=0.002
|
|
248
|
+
|
|
249
|
+
# What a spoken turn waits for the recall and search it started while the caller was still talking, in ms. It is silence on the line, so it is small.
|
|
250
|
+
PINECALL_VOICE_LOOKUP_BUDGET_MS=250
|
|
251
|
+
|
|
252
|
+
# What a written turn waits for recall and search, in ms. A written caller sends a whole message, so the lookup only starts at the end — and nobody hears the wait.
|
|
253
|
+
PINECALL_TEXT_LOOKUP_BUDGET_MS=3000
|
|
254
|
+
|
|
255
|
+
# What a hang-up waits for memory to be written, in s. Past it the call seals.
|
|
256
|
+
PINECALL_REMEMBER_BUDGET_S=8.0
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# The gate: lint, then both test rings, on every push and every pull request. One job, because the
|
|
2
|
+
# whole check is a few minutes and a matrix would only make a failure harder to read.
|
|
3
|
+
#
|
|
4
|
+
# Two repositories, laid out the way a laptop has them: `pyproject.toml` names
|
|
5
|
+
# `../protocol/python` as an editable path dependency, so the second checkout is what makes the
|
|
6
|
+
# wire resolvable — until pinecall-protocol is published and the line becomes a version range.
|
|
7
|
+
name: ci
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
branches: ["**"]
|
|
12
|
+
pull_request:
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
# release.yml corre ESTE archivo como su gate, en vez de repetir los pasos: el gate del release
|
|
15
|
+
# y el de cada push son el mismo, o uno de los dos miente.
|
|
16
|
+
workflow_call:
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
|
|
21
|
+
concurrency:
|
|
22
|
+
group: ci-${{ github.ref }}
|
|
23
|
+
cancel-in-progress: true
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
check:
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
# Most of these minutes are the Postgres image: pgvector and pg_textsearch are compiled from
|
|
29
|
+
# source, because the image with both is this repository's own and is built, not published.
|
|
30
|
+
#
|
|
31
|
+
# `max_connections=300` on that container: pytest-xdist opens a worker per core and each one
|
|
32
|
+
# of them a pool, and a runner has more cores than a laptop — the default hundred ran out and
|
|
33
|
+
# answered `sorry, too many clients already`.
|
|
34
|
+
timeout-minutes: 30
|
|
35
|
+
|
|
36
|
+
env:
|
|
37
|
+
DATABASE_URL: postgresql://pinecall:pinecall@127.0.0.1:5432/pinecall
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v4
|
|
41
|
+
with:
|
|
42
|
+
path: runtime
|
|
43
|
+
|
|
44
|
+
- uses: actions/checkout@v4
|
|
45
|
+
with:
|
|
46
|
+
repository: pinecall/protocol
|
|
47
|
+
path: protocol
|
|
48
|
+
|
|
49
|
+
# What a person does with `docker compose -f infra/compose/dev.yml up -d`, in one step.
|
|
50
|
+
#
|
|
51
|
+
# The schema needs BOTH extensions — `halfvec` in 0008 and 0009, a `bm25` index in 0009 —
|
|
52
|
+
# so the stock image cannot run a migration at all: it stops at `type "halfvec" does not
|
|
53
|
+
# exist`. It is started as a STEP and not as a service, because a `services:` block starts
|
|
54
|
+
# before any step runs and so cannot wait for a build. The two CREATE EXTENSIONs are here
|
|
55
|
+
# because no migration creates one — the same two a person types once by hand.
|
|
56
|
+
- name: postgres with the two extensions the schema needs
|
|
57
|
+
run: |
|
|
58
|
+
docker build -q -t pinecall/postgres:ci runtime/infra/compose/postgres
|
|
59
|
+
docker run -d --name postgres -p 5432:5432 \
|
|
60
|
+
-e POSTGRES_USER=pinecall -e POSTGRES_PASSWORD=pinecall -e POSTGRES_DB=pinecall \
|
|
61
|
+
pinecall/postgres:ci -c max_connections=300
|
|
62
|
+
# NOT pg_isready: postgres's entrypoint runs initdb behind a TEMPORARY server on the
|
|
63
|
+
# same socket, so `accepting connections` is true a second before POSTGRES_DB exists
|
|
64
|
+
# and the next line dies with `database "pinecall" does not exist`. Wait for the thing
|
|
65
|
+
# that actually matters — the database answering a query as the user.
|
|
66
|
+
for _ in $(seq 1 90); do
|
|
67
|
+
docker exec postgres psql -U pinecall -d pinecall -c 'select 1' >/dev/null 2>&1 && break
|
|
68
|
+
sleep 1
|
|
69
|
+
done
|
|
70
|
+
docker exec postgres psql -U pinecall -d pinecall \
|
|
71
|
+
-c "CREATE EXTENSION IF NOT EXISTS vector" \
|
|
72
|
+
-c "CREATE EXTENSION IF NOT EXISTS pg_textsearch"
|
|
73
|
+
|
|
74
|
+
- uses: astral-sh/setup-uv@v5
|
|
75
|
+
with:
|
|
76
|
+
enable-cache: true
|
|
77
|
+
cache-dependency-glob: runtime/uv.lock
|
|
78
|
+
|
|
79
|
+
# `--extra runtime` carries livekit-agents and its plugins; `--extra providers` the vendor
|
|
80
|
+
# SDKs the provider tables construct. The dev group holds the checkers and squawk.
|
|
81
|
+
- run: uv sync --locked --extra runtime --extra providers --group dev
|
|
82
|
+
working-directory: runtime
|
|
83
|
+
|
|
84
|
+
# ruff, pyright, mypy, then squawk over the migrations that have not landed.
|
|
85
|
+
- run: scripts/lint
|
|
86
|
+
working-directory: runtime
|
|
87
|
+
|
|
88
|
+
# `public`, migrated, which is what a dev box has and what the app's own pool reads. The
|
|
89
|
+
# Postgres ring gives itself a schema per worker and migrates that; the API tests do not —
|
|
90
|
+
# they build the real app, whose lifespan opens a pool the moment DATABASE_URL answers, and
|
|
91
|
+
# a database that answers with no tables in it is `relation "pipeline_overrides" does not
|
|
92
|
+
# exist` a hundred and sixty times. On a laptop this is invisible: `public` was migrated
|
|
93
|
+
# months ago, or nothing answers at all.
|
|
94
|
+
- run: uv run pinecall-runtime migrate up
|
|
95
|
+
working-directory: runtime
|
|
96
|
+
|
|
97
|
+
# Ring 0 and the Postgres ring: no key, no model, no network. A test that needs a real
|
|
98
|
+
# ANTHROPIC_API_KEY skips itself by name rather than failing.
|
|
99
|
+
- run: scripts/test
|
|
100
|
+
working-directory: runtime
|