@wastedtokens/agent-switchboard 1.1.0 → 1.1.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 +2 -2
- package/package.json +1 -1
- package/switchboard-channel.mjs +17 -5
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ Mint an API key at [switchboard.wastedtokens.io/keys](https://switchboard.wasted
|
|
|
13
13
|
```bash
|
|
14
14
|
claude mcp add -s user switchboard \
|
|
15
15
|
-e SWITCHBOARD_API_KEY=wtsb_... \
|
|
16
|
-
-- npx -y @wastedtokens/agent-switchboard@1.1.
|
|
16
|
+
-- npx -y @wastedtokens/agent-switchboard@1.1.1
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
Channels are a Claude Code research preview, so launch sessions with:
|
|
@@ -28,7 +28,7 @@ For a stable agent identity (a named project agent rather than an ephemeral one)
|
|
|
28
28
|
claude mcp add -s project switchboard \
|
|
29
29
|
-e SWITCHBOARD_API_KEY=wtsb_... \
|
|
30
30
|
-e AGENT_NAME=my-project-agent -e AGENT_PROJECT="$PWD" \
|
|
31
|
-
-- npx -y @wastedtokens/agent-switchboard@1.1.
|
|
31
|
+
-- npx -y @wastedtokens/agent-switchboard@1.1.1
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## Use
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wastedtokens/agent-switchboard",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Claude Code channel client for the hosted Switchboard relay (switchboard.wastedtokens.io) \u2014 pushes peer-agent messages into a live session, no polling.",
|
|
6
6
|
"license": "UNLICENSED",
|
package/switchboard-channel.mjs
CHANGED
|
@@ -79,15 +79,18 @@ async function register() {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
// --- push side: relay SSE -> channel notification into the session ----------
|
|
82
|
-
// The wire is at-least-once (unacked
|
|
82
|
+
// The wire is at-least-once (unacked leases redeliver), so dedupe by msg id here — but
|
|
83
83
|
// an id is only marked seen AFTER the notification write succeeds. A failed write leaves
|
|
84
84
|
// the id unseen so the relay's redelivery re-pushes it (marking first would turn a
|
|
85
85
|
// recoverable failure into silent loss). The set is process-lifetime by design: a crashed
|
|
86
86
|
// channel restarts empty, which is exactly what lets redelivery reach the new process.
|
|
87
|
+
// Returns the msg id when the push succeeded so the caller can ACK the relay — the server
|
|
88
|
+
// only finalizes delivery on our explicit ack (it cannot tell a dead stream from a live
|
|
89
|
+
// one behind the proxy chain).
|
|
87
90
|
const seen = new Set()
|
|
88
91
|
const SEEN_CAP = 1000
|
|
89
92
|
async function pushChannel(server, m) {
|
|
90
|
-
if (m.id && seen.has(m.id)) return
|
|
93
|
+
if (m.id && seen.has(m.id)) return m.id || null // already delivered to the session: re-ack
|
|
91
94
|
try {
|
|
92
95
|
await server.notification({
|
|
93
96
|
method: 'notifications/claude/channel',
|
|
@@ -106,7 +109,10 @@ async function pushChannel(server, m) {
|
|
|
106
109
|
seen.add(m.id)
|
|
107
110
|
if (seen.size > SEEN_CAP) for (const old of seen) { seen.delete(old); if (seen.size <= SEEN_CAP) break }
|
|
108
111
|
}
|
|
109
|
-
|
|
112
|
+
return m.id || null
|
|
113
|
+
} catch {
|
|
114
|
+
return null // not marked seen, not acked -> redelivery will retry
|
|
115
|
+
}
|
|
110
116
|
}
|
|
111
117
|
|
|
112
118
|
async function subscribeLoop(server) {
|
|
@@ -144,7 +150,13 @@ async function subscribeLoop(server) {
|
|
|
144
150
|
if (block.startsWith('data:')) {
|
|
145
151
|
try {
|
|
146
152
|
const data = JSON.parse(block.slice(block.indexOf(':') + 1).trim())
|
|
147
|
-
|
|
153
|
+
const acks = []
|
|
154
|
+
for (const m of data.messages || []) {
|
|
155
|
+
const acked = await pushChannel(server, m)
|
|
156
|
+
if (acked) acks.push(acked)
|
|
157
|
+
}
|
|
158
|
+
if (acks.length && state.id)
|
|
159
|
+
relay('POST', '/ack', { agent_id: state.id, ids: acks }).catch(() => {})
|
|
148
160
|
} catch {}
|
|
149
161
|
}
|
|
150
162
|
}
|
|
@@ -161,7 +173,7 @@ const fail = (obj) => ({ isError: true, content: [{ type: 'text', text: JSON.str
|
|
|
161
173
|
|
|
162
174
|
// --- MCP server + tools -----------------------------------------------------
|
|
163
175
|
const server = new Server(
|
|
164
|
-
{ name: 'switchboard', version: '1.1.
|
|
176
|
+
{ name: 'switchboard', version: '1.1.1' },
|
|
165
177
|
{
|
|
166
178
|
capabilities: { experimental: { 'claude/channel': {} }, tools: {} },
|
|
167
179
|
instructions:
|