claude-phone-local 2.1.2 → 2.2.1
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.
- package/README.md +46 -0
- package/claude-api-server/server.js +12 -0
- package/cli/README.md +13 -5
- package/cli/lib/commands/setup.js +14 -3
- package/docs/SETUP.md +245 -0
- package/package.json +1 -1
- package/voice-app/lib/sip-handler.js +18 -0
package/README.md
CHANGED
|
@@ -134,6 +134,50 @@ claude mcp add claude-phone --scope user \
|
|
|
134
134
|
-- node /absolute/path/to/mcp-server/index.js
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
+
## What can you do with this?
|
|
138
|
+
|
|
139
|
+
Since Claude has real shell access to the host PC, "call your extension" is
|
|
140
|
+
really "call a machine that can run anything on your network." Some
|
|
141
|
+
examples:
|
|
142
|
+
|
|
143
|
+
### Home automation
|
|
144
|
+
|
|
145
|
+
- **"Turn off the living room lights and lock the front door."** — if your
|
|
146
|
+
smart home exposes a CLI, API, or Home Assistant instance on the same
|
|
147
|
+
network, Claude can hit it directly. No separate voice assistant skill to
|
|
148
|
+
write.
|
|
149
|
+
- **"Is the garage door open?"** — ask a status question from bed without
|
|
150
|
+
reaching for an app.
|
|
151
|
+
- **"Call me if the washing machine cycle finishes"** — Claude polls
|
|
152
|
+
something (a smart plug's power draw, a sensor) in the background while
|
|
153
|
+
doing other work, then rings you via the [MCP server](docs/MCP-SERVER.md)
|
|
154
|
+
when it's done.
|
|
155
|
+
- **Multilingual household** — parents ask in Hindi or Marathi, kids ask in
|
|
156
|
+
English, same extension, same session — see [Languages](#languages).
|
|
157
|
+
|
|
158
|
+
### Inside a company / office
|
|
159
|
+
|
|
160
|
+
- **"What's the status of the nightly backup job?"** — ask from your car on
|
|
161
|
+
the way in, get a real answer pulled from actual logs, not a canned reply.
|
|
162
|
+
- **"Restart the staging server and let me know when it's back up."** —
|
|
163
|
+
fire-and-forget a real ops task, then Claude calls you back when it's
|
|
164
|
+
actually done (see [Claude calling you](#claude-calling-you)) instead of
|
|
165
|
+
you babysitting a terminal.
|
|
166
|
+
- **On-call triage** — "walk me through what's alerting right now" while
|
|
167
|
+
driving, hands-free, with Claude actually querying your monitoring stack
|
|
168
|
+
instead of reading a static runbook.
|
|
169
|
+
- **A shared team extension** — dial in from any phone (no app, no VPN
|
|
170
|
+
client) to ask about deploy status, check disk space on a shared box, or
|
|
171
|
+
kick off a known-safe script — useful when someone's laptop isn't handy but
|
|
172
|
+
a phone is.
|
|
173
|
+
- **Slack handoff for long tasks** — ask something that takes a while ("audit
|
|
174
|
+
every repo for hardcoded secrets"), hang up, and have the results posted to
|
|
175
|
+
a Slack channel instead of waiting on hold.
|
|
176
|
+
|
|
177
|
+
None of this requires a PBX-side integration or webhook plumbing — it's the
|
|
178
|
+
same shell access you'd have SSH'd into the box yourself, just reachable from
|
|
179
|
+
any phone that can dial the extension.
|
|
180
|
+
|
|
137
181
|
## Configuration
|
|
138
182
|
|
|
139
183
|
Common knobs in `.env`:
|
|
@@ -189,6 +233,8 @@ more: **[docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)**.
|
|
|
189
233
|
|
|
190
234
|
## Documentation
|
|
191
235
|
|
|
236
|
+
- [docs/SETUP.md](docs/SETUP.md) — full walkthrough: 3CX extension → SBC →
|
|
237
|
+
Docker → npm install → `claude-phone setup` → `claude-phone start`
|
|
192
238
|
- [CLAUDE.md](CLAUDE.md) — architecture and design decisions
|
|
193
239
|
- [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) — every failure mode we hit
|
|
194
240
|
- [docs/LANGUAGES.md](docs/LANGUAGES.md) — Hindi/Marathi setup
|
|
@@ -159,10 +159,22 @@ SLACK DELIVERY: When the caller requests delivery to Slack (phrases like "send t
|
|
|
159
159
|
|
|
160
160
|
The caller may hang up while you're working (they'll hear hold music). That's fine - complete the work and send to Slack. They'll see it there.
|
|
161
161
|
|
|
162
|
+
END OF CALL: The phone app matches a fixed list of goodbye words (bye, goodbye, hang up, etc.) to end the call automatically, so it misses anything phrased differently - "that's everything, thanks", "I'm all set", "nothing else for now", "we're done here". You understand intent better than a keyword match does, so ALSO add a third line whenever the caller's message signals the conversation is actually finished (a clear goodbye/thanks-and-done in any wording, in any language) - not for a mid-conversation pause, not for "give me a second", not merely because their immediate question was answered:
|
|
163
|
+
|
|
164
|
+
🔚 END_CALL: true
|
|
165
|
+
|
|
166
|
+
Omit this line entirely (do not write "false") on every turn that isn't a real goodbye - most turns won't have it.
|
|
167
|
+
|
|
162
168
|
Example query: "What's the weather in Royce City?"
|
|
163
169
|
Example response:
|
|
164
170
|
🗣️ VOICE_RESPONSE: It's 65 degrees and partly cloudy in Royce City right now. Great weather for being outside!
|
|
165
171
|
🎯 COMPLETED: Weather lookup for Royce City done.
|
|
172
|
+
|
|
173
|
+
Example query: "Great, that's everything, thanks!"
|
|
174
|
+
Example response:
|
|
175
|
+
🗣️ VOICE_RESPONSE: You're welcome! Have a great day.
|
|
176
|
+
🎯 COMPLETED: Caller signed off, no further requests.
|
|
177
|
+
🔚 END_CALL: true
|
|
166
178
|
[END VOICE CONTEXT]
|
|
167
179
|
|
|
168
180
|
`;
|
package/cli/README.md
CHANGED
|
@@ -61,17 +61,25 @@ Select this when setting up the Claude API wrapper on a machine with Claude Code
|
|
|
61
61
|
|
|
62
62
|
### Both (All-in-One)
|
|
63
63
|
|
|
64
|
-
Select this for a single machine running everything.
|
|
64
|
+
Select this for a single machine running everything — most people want this.
|
|
65
|
+
Full prompt-by-prompt walkthrough: [docs/SETUP.md](../docs/SETUP.md).
|
|
65
66
|
|
|
66
67
|
**What it asks for:**
|
|
67
68
|
1. Local or cloud speech (local = faster-whisper + Piper, no API keys; cloud = ElevenLabs + OpenAI)
|
|
68
|
-
2. 3CX
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
2. Whether a 3CX SBC is running on this same PC (auto-avoids its port 5060,
|
|
70
|
+
and tracks this PC's LAN IP for the registrar automatically)
|
|
71
|
+
3. 3CX SIP domain (and registrar IP, if no local SBC)
|
|
72
|
+
4. Device configuration (name, extension, auth, voice, prompt)
|
|
73
|
+
5. Whether to auto-detect this PC's LAN IP on every `claude-phone start`
|
|
74
|
+
(recommended — survives network changes without re-running setup), API
|
|
75
|
+
port, and HTTP port
|
|
76
|
+
6. A callback number for the MCP server (must differ from the device
|
|
77
|
+
extension — 3CX rejects a device calling itself)
|
|
71
78
|
|
|
72
79
|
**What `claude-phone start` does:**
|
|
73
80
|
- Starts the `claude-phone` container (drachtio, FreeSWITCH, voice-app, STT, TTS under supervisord)
|
|
74
|
-
-
|
|
81
|
+
- Waits for the voice stack to actually be ready to accept calls
|
|
82
|
+
- Starts claude-api-server and verifies it's healthy before reporting success
|
|
75
83
|
|
|
76
84
|
### Pi Auto-Detection
|
|
77
85
|
|
|
@@ -1253,8 +1253,19 @@ async function setupDevice(config) {
|
|
|
1253
1253
|
async function setupServer(config) {
|
|
1254
1254
|
const localIp = getLocalIP();
|
|
1255
1255
|
|
|
1256
|
-
const
|
|
1256
|
+
const { ipMode } = await inquirer.prompt([
|
|
1257
1257
|
{
|
|
1258
|
+
type: 'confirm',
|
|
1259
|
+
name: 'ipMode',
|
|
1260
|
+
message: `Auto-detect the LAN IP on every "claude-phone start" (currently ${localIp})? ` +
|
|
1261
|
+
'Recommended if this machine moves networks (laptop, DHCP) - answering ' +
|
|
1262
|
+
'no locks in a fixed IP that goes stale the next time it changes.',
|
|
1263
|
+
default: config.server.externalIp === 'auto' || config.server.externalIp === undefined
|
|
1264
|
+
}
|
|
1265
|
+
]);
|
|
1266
|
+
|
|
1267
|
+
const answers = await inquirer.prompt([
|
|
1268
|
+
...(ipMode ? [] : [{
|
|
1258
1269
|
type: 'input',
|
|
1259
1270
|
name: 'externalIp',
|
|
1260
1271
|
message: 'Server LAN IP (for RTP audio):',
|
|
@@ -1268,7 +1279,7 @@ async function setupServer(config) {
|
|
|
1268
1279
|
}
|
|
1269
1280
|
return true;
|
|
1270
1281
|
}
|
|
1271
|
-
},
|
|
1282
|
+
}]),
|
|
1272
1283
|
{
|
|
1273
1284
|
type: 'input',
|
|
1274
1285
|
name: 'claudeApiPort',
|
|
@@ -1297,7 +1308,7 @@ async function setupServer(config) {
|
|
|
1297
1308
|
}
|
|
1298
1309
|
]);
|
|
1299
1310
|
|
|
1300
|
-
config.server.externalIp = answers.externalIp;
|
|
1311
|
+
config.server.externalIp = ipMode ? 'auto' : answers.externalIp;
|
|
1301
1312
|
config.server.claudeApiPort = parseInt(answers.claudeApiPort, 10);
|
|
1302
1313
|
config.server.httpPort = parseInt(answers.httpPort, 10);
|
|
1303
1314
|
|
package/docs/SETUP.md
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# Setup Guide
|
|
2
|
+
|
|
3
|
+
End-to-end walkthrough for a single-PC install: 3CX extension, SBC, Docker,
|
|
4
|
+
npm install, `claude-phone setup`, `claude-phone start`. Written for the
|
|
5
|
+
"Both (all-in-one)" installation type — everything on one Windows/Mac/Linux
|
|
6
|
+
machine, which is what most people want. For Raspberry Pi split deployments
|
|
7
|
+
see [cli/README.md](../cli/README.md#split-deployment-example).
|
|
8
|
+
|
|
9
|
+
## Order of operations
|
|
10
|
+
|
|
11
|
+
1. Create a 3CX extension
|
|
12
|
+
2. Install the 3CX SBC on this PC (only if this PC isn't already inside your
|
|
13
|
+
3CX network)
|
|
14
|
+
3. Install Docker Desktop
|
|
15
|
+
4. `npm install -g claude-phone-local`
|
|
16
|
+
5. `claude-phone setup`
|
|
17
|
+
6. `claude-phone start`
|
|
18
|
+
|
|
19
|
+
Do them in this order — `claude-phone setup` asks for the extension's
|
|
20
|
+
credentials, and detects whether a 3CX SBC is already running on this PC.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 1. Create a 3CX extension
|
|
25
|
+
|
|
26
|
+
In the 3CX Admin Console:
|
|
27
|
+
|
|
28
|
+
1. **Users → Add User** (or reuse an existing one you don't mind dedicating
|
|
29
|
+
to this).
|
|
30
|
+
2. Give it an extension number, e.g. `17512`.
|
|
31
|
+
3. Under the user's **SIP/VoIP Devices** or **Authentication** tab, note:
|
|
32
|
+
- **Extension** (e.g. `17512`)
|
|
33
|
+
- **Auth ID** — often different from the extension number
|
|
34
|
+
- **Authentication password**
|
|
35
|
+
4. Note your **3CX domain** too (e.g. `yourcompany.3cx.us` or
|
|
36
|
+
`1234.3cx.cloud`) — shown in the Admin Console URL or under **General
|
|
37
|
+
Settings**.
|
|
38
|
+
|
|
39
|
+
You'll type all four of these into `claude-phone setup` later. Keep this tab
|
|
40
|
+
open.
|
|
41
|
+
|
|
42
|
+
**Security tip:** don't reuse an extension you actually answer calls on
|
|
43
|
+
personally — Claude answers this one with full shell access to the host
|
|
44
|
+
(see [Security](../README.md#security)). A dedicated extension with
|
|
45
|
+
restricted inbound routing is safer.
|
|
46
|
+
|
|
47
|
+
## 2. Install the 3CX SBC (only if needed)
|
|
48
|
+
|
|
49
|
+
Skip this step if this PC is already on the same LAN as your 3CX PBX with no
|
|
50
|
+
NAT/firewall between them — you can register directly against the PBX and
|
|
51
|
+
skip the SBC.
|
|
52
|
+
|
|
53
|
+
Install the SBC when this PC is remote from the PBX (e.g. cloud-hosted 3CX,
|
|
54
|
+
this PC on a different network) — the SBC is a local relay that keeps the
|
|
55
|
+
inbound SIP path this app cares about all on `127.0.0.1`/LAN, and it's what
|
|
56
|
+
lets you skip poking holes in your firewall for SIP directly to this PC.
|
|
57
|
+
|
|
58
|
+
1. In 3CX Admin Console: **Admin → SBC → Add SBC**, choose **Generic /
|
|
59
|
+
Windows**, and follow the download link (or find the "3CX Session Border
|
|
60
|
+
Controller" installer under downloads for your PBX).
|
|
61
|
+
2. Run the installer on this PC. It'll ask for a **provisioning link** — copy
|
|
62
|
+
it from the Admin Console's SBC page.
|
|
63
|
+
3. Once installed, the SBC runs as a Windows service (`3CXSBC`) and binds SIP
|
|
64
|
+
on port **5060**. `claude-phone setup` checks for this automatically later
|
|
65
|
+
and, if found, tells drachtio (this app's SIP stack) to use port **5070**
|
|
66
|
+
instead — so the two never fight over the same port.
|
|
67
|
+
4. The SBC config file lives at `C:\ProgramData\3CXSBC\3cxsbc.conf` and
|
|
68
|
+
normally needs no manual editing — `LocalSipAddr=0.0.0.0` means it
|
|
69
|
+
self-detects this PC's current LAN IP every time it starts, so it survives
|
|
70
|
+
network changes (new office, DHCP renewal) without reconfiguration.
|
|
71
|
+
|
|
72
|
+
## 3. Install Docker Desktop
|
|
73
|
+
|
|
74
|
+
- Windows/Mac: [Docker Desktop](https://www.docker.com/products/docker-desktop/)
|
|
75
|
+
— enable the WSL2 backend on Windows during install.
|
|
76
|
+
- Linux: [Docker Engine](https://docs.docker.com/engine/install/) + the
|
|
77
|
+
Compose plugin.
|
|
78
|
+
|
|
79
|
+
Verify it's running:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
docker --version
|
|
83
|
+
docker compose version
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
You'll also need **Node.js 18+** and the **Claude Code CLI**, logged in
|
|
87
|
+
(`claude --version`).
|
|
88
|
+
|
|
89
|
+
## 4. Install claude-phone-local
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npm install -g claude-phone-local
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
This installs the `claude-phone` CLI globally and automatically installs the
|
|
96
|
+
host-side dependencies for `claude-api-server` and `mcp-server` — no manual
|
|
97
|
+
`npm install` in subfolders needed.
|
|
98
|
+
|
|
99
|
+
Verify:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
claude-phone --version
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## 5. Run the setup wizard
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
claude-phone setup
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
It asks these questions, in this order (for "Both (all-in-one)" — the
|
|
112
|
+
default and most common choice):
|
|
113
|
+
|
|
114
|
+
### Installation type
|
|
115
|
+
|
|
116
|
+
> **What are you installing?**
|
|
117
|
+
> - Voice Server (Pi/Linux) — this machine only runs the phone/audio side,
|
|
118
|
+
> talks to a remote API server (e.g. a Raspberry Pi calling out to your
|
|
119
|
+
> main PC)
|
|
120
|
+
> - API Server — this machine only runs the Claude wrapper, no phone
|
|
121
|
+
> hardware/Docker here
|
|
122
|
+
> - Both (all-in-one) — full stack on one machine ← most people want this,
|
|
123
|
+
> and what the rest of this guide walks through
|
|
124
|
+
|
|
125
|
+
### Speech (STT/TTS) mode
|
|
126
|
+
|
|
127
|
+
> **How should speech-to-text and text-to-speech work?**
|
|
128
|
+
> - Local (offline, no API keys, no cost) — faster-whisper + Piper, run as
|
|
129
|
+
> Docker containers, fully private
|
|
130
|
+
> - Cloud (ElevenLabs + OpenAI) — requires paid API keys, higher voice
|
|
131
|
+
> quality, needs internet
|
|
132
|
+
|
|
133
|
+
Choosing **Local** then asks:
|
|
134
|
+
- **Piper voice** to use (default `en_US-lessac-medium`) — auto-downloaded
|
|
135
|
+
- **faster-whisper model size** (`tiny`/`base`/`small`/`medium`) — bigger is
|
|
136
|
+
more accurate but slower; `medium` is recommended for Hindi/Marathi
|
|
137
|
+
|
|
138
|
+
Choosing **Cloud** asks for an **ElevenLabs API key** (validated live) and a
|
|
139
|
+
default **ElevenLabs voice ID**, then an **OpenAI API key** for Whisper STT.
|
|
140
|
+
|
|
141
|
+
### SIP / 3CX configuration
|
|
142
|
+
|
|
143
|
+
Setup first checks port 5060 and the SBC process on its own — if it finds one
|
|
144
|
+
running, the next question defaults to "yes" automatically.
|
|
145
|
+
|
|
146
|
+
> **Is the 3CX SBC service running on this same PC?**
|
|
147
|
+
|
|
148
|
+
Answer **yes** if you installed the SBC in step 2. This makes drachtio use
|
|
149
|
+
port 5070 automatically (avoiding the SBC's port 5060) and makes the
|
|
150
|
+
registrar address self-track this PC's current LAN IP on every
|
|
151
|
+
`claude-phone start` — so it survives network changes without re-running
|
|
152
|
+
setup.
|
|
153
|
+
|
|
154
|
+
Answer **no** if you're registering directly against a remote/cloud 3CX PBX,
|
|
155
|
+
or another SIP provider entirely — you'll then be asked for the registrar IP
|
|
156
|
+
directly.
|
|
157
|
+
|
|
158
|
+
> **3CX domain** (e.g. `your-3cx.3cx.us`)
|
|
159
|
+
|
|
160
|
+
The tenant hostname from step 1.
|
|
161
|
+
|
|
162
|
+
> **3CX registrar IP** (only if you answered "no" above)
|
|
163
|
+
|
|
164
|
+
The IP/hostname SIP REGISTER requests actually go to.
|
|
165
|
+
|
|
166
|
+
### Device configuration
|
|
167
|
+
|
|
168
|
+
This is the extension Claude answers on — the one from step 1.
|
|
169
|
+
|
|
170
|
+
> **Device name** (e.g. `Maya`)
|
|
171
|
+
> **SIP extension number** (e.g. `17512`)
|
|
172
|
+
> **SIP auth ID**
|
|
173
|
+
> **SIP password**
|
|
174
|
+
> **System prompt** — her personality/instructions, e.g. "You are a helpful
|
|
175
|
+
> AI assistant. Keep voice responses under 40 words."
|
|
176
|
+
|
|
177
|
+
If you chose **Local** speech mode: **Piper voice for this device** (falls
|
|
178
|
+
back to the default voice you picked earlier). If you chose **Cloud**:
|
|
179
|
+
**ElevenLabs voice ID** (validated live).
|
|
180
|
+
|
|
181
|
+
### Server configuration
|
|
182
|
+
|
|
183
|
+
> **Auto-detect the LAN IP on every "claude-phone start"?**
|
|
184
|
+
|
|
185
|
+
**Recommended: yes.** This is the IP that goes into RTP/SDP so the SBC/PBX
|
|
186
|
+
knows where to send call audio. Auto mode re-detects this PC's current LAN
|
|
187
|
+
IP every time you run `claude-phone start`, so moving between networks
|
|
188
|
+
(home, office, a different Wi-Fi) doesn't require re-running setup. Answering
|
|
189
|
+
no locks in whatever IP is current right now — you'll need to re-run
|
|
190
|
+
`claude-phone setup` if it ever changes.
|
|
191
|
+
|
|
192
|
+
> **Claude API server port** (default `3333`)
|
|
193
|
+
> **Voice app HTTP port** (default `3000`)
|
|
194
|
+
|
|
195
|
+
Both are safe to leave at their defaults unless something else on this PC
|
|
196
|
+
already uses them.
|
|
197
|
+
|
|
198
|
+
### MCP server (lets Claude call you)
|
|
199
|
+
|
|
200
|
+
> **Number/extension for Claude to call YOU on**
|
|
201
|
+
|
|
202
|
+
This must be a **different** number from the device extension above — 3CX
|
|
203
|
+
rejects a device calling itself. If you only have the one extension from
|
|
204
|
+
step 1, you'll need a second number here (your mobile, a second 3CX
|
|
205
|
+
extension, or a DID) for the "call me when it's done" feature to work. See
|
|
206
|
+
[Claude calling you](../README.md#claude-calling-you).
|
|
207
|
+
|
|
208
|
+
Setup then registers the MCP server with your Claude Code CLI automatically.
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## 6. Start it
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
claude-phone start
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
This:
|
|
219
|
+
1. Runs prerequisite checks (Node, Docker, disk space, network)
|
|
220
|
+
2. Builds/starts the Docker container (drachtio, FreeSWITCH, voice-app, STT,
|
|
221
|
+
TTS) — first run downloads ~2GB of speech models, cached in `./data` (well,
|
|
222
|
+
`~/.claude-phone/data`) for every future start
|
|
223
|
+
3. Waits for the voice stack to actually be ready to accept calls (not just
|
|
224
|
+
for the container to be up)
|
|
225
|
+
4. Starts `claude-api-server` on the host and verifies it's actually healthy
|
|
226
|
+
|
|
227
|
+
When you see `✓ All services running!` with your extension listed under
|
|
228
|
+
"Ready to receive calls on", call it.
|
|
229
|
+
|
|
230
|
+
## Check it worked
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
claude-phone status
|
|
234
|
+
claude-phone doctor # deeper health check
|
|
235
|
+
claude-phone logs api-server # host-side Claude wrapper log
|
|
236
|
+
docker logs claude-phone -f # container-side SIP/voice log
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
If registration succeeded you'll see a line like:
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
[MULTI-REGISTRAR] Maya SUCCESS - Registered as ext 17512
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Full failure-mode reference: [docs/TROUBLESHOOTING.md](TROUBLESHOOTING.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-phone-local",
|
|
3
|
-
"version": "2.1
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "Local/offline fork of NetworkChuck's claude-phone: talk to Claude Code over 3CX/SIP with faster-whisper STT + Piper TTS in one Docker container.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -162,6 +162,17 @@ function extractVoiceLine(response) {
|
|
|
162
162
|
return response.substring(0, 500).trim();
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Whether Claude's raw response signals the conversation is actually over.
|
|
167
|
+
* Complements isGoodbye()'s fixed phrase match on the caller's own words -
|
|
168
|
+
* Claude sees the full exchange and can recognize a sign-off phrased in ways
|
|
169
|
+
* the keyword list doesn't cover ("that's everything, thanks", "I'm all
|
|
170
|
+
* set"), in any language, without maintaining a growing keyword list.
|
|
171
|
+
*/
|
|
172
|
+
function hasEndCallMarker(response) {
|
|
173
|
+
return /🔚\s*END_CALL:\s*true/i.test(response);
|
|
174
|
+
}
|
|
175
|
+
|
|
165
176
|
/**
|
|
166
177
|
* Play a clip the caller is allowed to interrupt.
|
|
167
178
|
*
|
|
@@ -443,6 +454,13 @@ async function conversationLoop(endpoint, dialog, callUuid, options, deviceConfi
|
|
|
443
454
|
const responseBarge = await playInterruptible(endpoint, session, responseUrl);
|
|
444
455
|
if (responseBarge) {
|
|
445
456
|
pendingUtterance = responseBarge;
|
|
457
|
+
} else if (hasEndCallMarker(claudeResponse)) {
|
|
458
|
+
// Claude judged this a real sign-off from the caller's own words
|
|
459
|
+
// (not just isGoodbye()'s fixed phrase match) - she already said
|
|
460
|
+
// her goodbye as part of the normal response above, so just end
|
|
461
|
+
// the call rather than waiting for another turn.
|
|
462
|
+
console.log('[' + new Date().toISOString() + '] CONVERSATION Claude signaled end of call');
|
|
463
|
+
break;
|
|
446
464
|
}
|
|
447
465
|
}
|
|
448
466
|
|