Repository navigation
Expand file tree
/
Copy path.env.example
More file actions
151 lines (134 loc) · 7 KB
/
Copy path.env.example
File metadata and controls
151 lines (134 loc) · 7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# Copy to .env and fill in for live mode. Stub mode needs none of these.
# Never commit .env. It is in .gitignore.
# Telnyx. API key from Mission Control, and the Call Control application id
# (called connection_id by the Calls API). TELNYX_PUBLIC_KEY is the webhook
# signing public key. Store it on the Worker with wrangler secret put.
TELNYX_API_KEY=
TELNYX_CONNECTION_ID=
TELNYX_PUBLIC_KEY=
# Shared Telnyx FROM for every Treena user (Cap GO). Fly live sets both
# keys to the same E.164. Product code has no default digits. Stub
# without these uses +15555550100. Distinct from LINQ_FROM_E164.
TELNYX_FROM_NUMBER=+12135690899
TELNYX_PHONE_NUMBER=+12135690899
# L16 asks Telnyx for 16 kHz PCM and passes it to GPT-Live untouched. PCMU is the 8 kHz fallback.
TELNYX_STREAM_CODEC=L16
# OpenAI GPT-Live. The bridge connects to wss://api.openai.com/v1/live/sessions.
# OPENAI_LIVE_EXTRA_HEADERS is optional, for a version header such as
# "OpenAI-Alpha: quicksilver=v3" when your account needs one.
OPENAI_API_KEY=
OPENAI_LIVE_MODEL=gpt-live-1
OPENAI_LIVE_VOICE=marin
OPENAI_LIVE_EXTRA_HEADERS=
OPENAI_RESPONSES_MODEL=gpt-5.6-terra
# Responses/delegation thinking only. Speech (gpt-live-1) has no effort knob.
# Wire: session.delegation.responses.reasoning.effort
# gpt-5.6-terra supports none|low|medium|high|xhigh|max (API default medium).
# Cap light aliases to OpenAI low. Env-overridable; default light.
OPENAI_RESPONSES_EFFORT=light
# Where Telnyx reaches media and, for CLI --live, the per-call webhook.
# Must be a public https URL (ngrok, Cloudflare Tunnel) that forwards to
# CALL_AGENT_PORT on this machine. CLI --live hosts CallHandle in this
# process. Fly https://hidden-beacon-080.fly.dev is a different process
# with no BOOK entry and is not valid for Mac CLI live. The live verb
# probes GET /health until HTTP 200 and serve_token match before it
# dials. A printed trycloudflare URL is not enough; DNS can lag.
PUBLIC_BASE_URL=
# Required for CLI --live: set this to the same tunnel as PUBLIC_BASE_URL
# so webhook_url and stream_url hit the local BOOK process. Process env
# overrides .env, so a leftover PUBLIC_WEBHOOK_URL can send webhooks to a
# stale host while media follows PUBLIC_BASE_URL (Fly media + old
# tunnel). CLI live fails before dial if the hosts diverge after
# wss/https normalize. Fly linq-to-call uses PUBLIC_BASE_URL and
# PUBLIC_WEBHOOK_URL both set to https://hidden-beacon-080.fly.dev.
# The Call Control application webhook_event_url is independently
# https://call-agent-webhooks.usetreena.workers.dev/webhooks/telnyx.
PUBLIC_WEBHOOK_URL=
CALL_AGENT_PORT=8000
# Linq Partner API V3. Stub mode needs none of these. Token is a box secret.
# LINQ_FROM_E164 is the one shared Treena iMessage bot for everyone (Cap
# account model). Not a unique Treena DID per user. Linq sandbox until
# ~Sep 18; ops will confirm if the E.164 changes. LINQ_WEBHOOK_URL is
# the Workers HTTPS target. LINQ_WEBHOOK_SIGNING_SECRET is the
# subscription signing secret. APP_BASE_URL is a Worker var/secret
# (FastAPI origin, no path), not a Python Settings field. Prod origin is
# https://hidden-beacon-080.fly.dev. Set it on the Worker, not in this
# process:
# cd workers/webhooks
# npx wrangler secret put APP_BASE_URL
# npx wrangler deploy
LINQ_API_TOKEN=
LINQ_FROM_E164=+12138653024
LINQ_WEBHOOK_SIGNING_SECRET=
LINQ_WEBHOOK_URL=
# L1 iMessage kickoff. Each account stores the user's own phone
# (`users.phone`, the inbound iMessage sender). The shared bot people
# text is LINQ_FROM_E164, not a per-user Treena DID. The outbound Telnyx
# caller ID is TELNYX_FROM_NUMBER / TELNYX_PHONE_NUMBER (Cap GO
# +12135690899). Kickoff does not require users.from_did.
# Seed a tester with:
# call-agent account upsert --phone <user iMessage> --name <first>
# Caller name comes from the users row, never from iMessage and never
# from LINQ_KICKOFF_CALLER.
# HMAC secret for POST /accounts/sync and POST /billing/metered-pack.
# Fly is the sole writer of users. call-agent-web POSTs signed
# checkout/settings payloads and TEST pack credits here. CLI
# `account upsert` / `account credit-pack` seed without this secret.
ACCOUNT_SYNC_SECRET=
# Cap locked 2026-09-14: $1.00 per 5 connected minutes (100 cents).
# Max 12 packs / 60 prepaid minutes. Stripe TEST only (sk_test_).
# Set to 0 to block purchase (ops kill switch). Never set sk_live_.
METERED_PACK_PRICE_CENTS=100
STRIPE_SECRET_KEY=
# Local state. The ledger is one SQLite file. During a call, artifacts are
# one directory per call: dial.json, session_start.json, events.jsonl,
# transcript.json, audio/, hangup.json, result.json. After hangup those
# files are deleted unless RETAIN_CALL_ARTIFACTS=1. Leave Neon and R2
# unset on a laptop.
CALL_AGENT_DB_PATH=./call_agent.sqlite3
CALL_AGENT_ARTIFACTS_DIR=./artifacts
# Durable ledger. When set, did provision/list and users (accounts)
# use Neon (Postgres) with the same dids and users schemas. Unset or
# blank keeps SQLite. The package depends on psycopg[binary]; the Fly
# image installs it via pip install . Live Fly sha bb91810 (PR #39):
# health 200, Neon/psycopg baked. Do not hot-install on the machine.
NEON_DATABASE_URL=
# After hangup, default wipe deletes the run-dir audio, transcript, and
# history files. Set to 1 to keep them (and publish the durable subset to R2
# when R2_* is complete). Account opt-in UI is call-agent-web, not this CLI.
RETAIN_CALL_ARTIFACTS=0
# Durable artifacts. When all four required vars are set *and* retention is
# on, finish also puts transcript.json, result.json, call_report.json, and
# both audio files to R2. Default wipe skips that publish. Partial set fails
# at startup. R2_ENDPOINT defaults to
# https://<R2_ACCOUNT_ID>.r2.cloudflarestorage.com.
R2_ACCOUNT_ID=
R2_ACCESS_KEY_ID=
R2_SECRET_ACCESS_KEY=
R2_BUCKET=
R2_ENDPOINT=
# Live mode gate. quick-ask --live and verify-quick-ask --mode live refuse to
# run unless this is 1 and the keys above are set. CI leaves it at 0.
QUICK_ASK_LIVE=0
# Seconds a live call may go without any Telnyx or GPT-Live event before the
# run fails. After dial_placed with no ringing, answer, or media, the reason
# names webhook/media delivery and the dial hosts. Stub runs never wait.
EVENT_TIMEOUT_S=30
# Seconds CLI --live waits for PUBLIC_BASE_URL/health to reach this process
# before it dials. Cloudflare quick tunnels often need a settle window.
LIVE_INGRESS_TIMEOUT_S=15
# After the verdict the agent waits for Telnyx to echo the mark that follows
# the last audio it played, then this many seconds of silence, then hangs up.
# If the echo never arrives it hangs up after the drain timeout instead and
# verify-quick-ask fails clean_hangup.
HANGUP_TRAILING_SILENCE_S=0.4
HANGUP_DRAIN_TIMEOUT_S=10
# If GPT-Live goes quiet while the hangup track is still idle, steer after
# this many seconds, then hang up via=stall. This is a failsafe, not a
# spoken commentary nudge. 16 kHz L16 passthrough is not the silence fix.
LIVE_SILENCE_FAILSAFE_S=20
FAREWELL_IDLE_S=0.8
FAREWELL_MAX_S=4
# After we send call.hangup, wait this many seconds for Telnyx call.hangup
# before finishing as HangupUnconfirmed.
HANGUP_CONFIRM_TIMEOUT_S=5