relaymessenger 0.1.6-staging.8 → 0.1.6
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 +52 -23
- package/dist/acp-bridge.d.ts +129 -0
- package/dist/acp-bridge.d.ts.map +1 -0
- package/dist/acp-bridge.js +324 -0
- package/dist/acp-bridge.js.map +1 -0
- package/dist/acp-threads.d.ts +33 -0
- package/dist/acp-threads.d.ts.map +1 -0
- package/dist/acp-threads.js +64 -0
- package/dist/acp-threads.js.map +1 -0
- package/dist/agent-create.d.ts.map +1 -1
- package/dist/agent-create.js +13 -6
- package/dist/agent-create.js.map +1 -1
- package/dist/agent-session.js +2 -2
- package/dist/agent-session.js.map +1 -1
- package/dist/agents.d.ts +12 -3
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +45 -33
- package/dist/agents.js.map +1 -1
- package/dist/clack-theme.d.ts +38 -0
- package/dist/clack-theme.d.ts.map +1 -0
- package/dist/clack-theme.js +148 -0
- package/dist/clack-theme.js.map +1 -0
- package/dist/cli.js +5 -0
- package/dist/cli.js.map +1 -1
- package/dist/codex-bridge.d.ts +140 -0
- package/dist/codex-bridge.d.ts.map +1 -0
- package/dist/codex-bridge.js +454 -0
- package/dist/codex-bridge.js.map +1 -0
- package/dist/codex-threads.d.ts +31 -0
- package/dist/codex-threads.d.ts.map +1 -0
- package/dist/codex-threads.js +62 -0
- package/dist/codex-threads.js.map +1 -0
- package/dist/coding-agents/claude-code.d.ts +1 -1
- package/dist/coding-agents/claude-code.d.ts.map +1 -1
- package/dist/coding-agents/claude-code.js +6 -0
- package/dist/coding-agents/claude-code.js.map +1 -1
- package/dist/coding-agents/cline.d.ts.map +1 -1
- package/dist/coding-agents/cline.js +11 -4
- package/dist/coding-agents/cline.js.map +1 -1
- package/dist/coding-agents/codex-project-config.d.ts +20 -0
- package/dist/coding-agents/codex-project-config.d.ts.map +1 -0
- package/dist/coding-agents/codex-project-config.js +33 -0
- package/dist/coding-agents/codex-project-config.js.map +1 -0
- package/dist/coding-agents/codex.d.ts.map +1 -1
- package/dist/coding-agents/codex.js +11 -2
- package/dist/coding-agents/codex.js.map +1 -1
- package/dist/coding-agents/cursor.d.ts.map +1 -1
- package/dist/coding-agents/cursor.js +12 -3
- package/dist/coding-agents/cursor.js.map +1 -1
- package/dist/coding-agents/gemini-cli.d.ts.map +1 -1
- package/dist/coding-agents/gemini-cli.js +12 -2
- package/dist/coding-agents/gemini-cli.js.map +1 -1
- package/dist/coding-agents/hermes.d.ts.map +1 -1
- package/dist/coding-agents/hermes.js +6 -0
- package/dist/coding-agents/hermes.js.map +1 -1
- package/dist/coding-agents/openclaw.d.ts.map +1 -1
- package/dist/coding-agents/openclaw.js +9 -0
- package/dist/coding-agents/openclaw.js.map +1 -1
- package/dist/coding-agents/opencode.d.ts.map +1 -1
- package/dist/coding-agents/opencode.js +15 -4
- package/dist/coding-agents/opencode.js.map +1 -1
- package/dist/coding-agents/shared.d.ts +47 -1
- package/dist/coding-agents/shared.d.ts.map +1 -1
- package/dist/coding-agents/vscode.d.ts.map +1 -1
- package/dist/coding-agents/vscode.js +1 -0
- package/dist/coding-agents/vscode.js.map +1 -1
- package/dist/coding-agents.d.ts +24 -21
- package/dist/coding-agents.d.ts.map +1 -1
- package/dist/coding-agents.js +1 -3
- package/dist/coding-agents.js.map +1 -1
- package/dist/config.d.ts +42 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +107 -5
- package/dist/config.js.map +1 -1
- package/dist/connect.d.ts +96 -17
- package/dist/connect.d.ts.map +1 -1
- package/dist/connect.js +519 -173
- package/dist/connect.js.map +1 -1
- package/dist/console-auth.d.ts +47 -0
- package/dist/console-auth.d.ts.map +1 -0
- package/dist/console-auth.js +394 -0
- package/dist/console-auth.js.map +1 -0
- package/dist/error-codes.d.ts +1 -1
- package/dist/error-codes.d.ts.map +1 -1
- package/dist/error-codes.js +3 -1
- package/dist/error-codes.js.map +1 -1
- package/dist/errors.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/event-listen.d.ts +12 -2
- package/dist/event-listen.d.ts.map +1 -1
- package/dist/event-listen.js +13 -3
- package/dist/event-listen.js.map +1 -1
- package/dist/folder-link.d.ts +37 -0
- package/dist/folder-link.d.ts.map +1 -0
- package/dist/folder-link.js +82 -0
- package/dist/folder-link.js.map +1 -0
- package/dist/help-groups.d.ts +2 -3
- package/dist/help-groups.d.ts.map +1 -1
- package/dist/help-groups.js +40 -15
- package/dist/help-groups.js.map +1 -1
- package/dist/interactive.d.ts +18 -11
- package/dist/interactive.d.ts.map +1 -1
- package/dist/interactive.js +15 -16
- package/dist/interactive.js.map +1 -1
- package/dist/program.d.ts +10 -3
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +369 -77
- package/dist/program.js.map +1 -1
- package/dist/qr-terminal.d.ts +52 -4
- package/dist/qr-terminal.d.ts.map +1 -1
- package/dist/qr-terminal.js +85 -36
- package/dist/qr-terminal.js.map +1 -1
- package/dist/relay-brand.d.ts +18 -0
- package/dist/relay-brand.d.ts.map +1 -0
- package/dist/relay-brand.js +38 -0
- package/dist/relay-brand.js.map +1 -0
- package/dist/runtime-sniff.d.ts +2 -0
- package/dist/runtime-sniff.d.ts.map +1 -1
- package/dist/runtime-sniff.js +1 -1
- package/dist/runtime-sniff.js.map +1 -1
- package/dist/skill-offer.d.ts.map +1 -1
- package/dist/skill-offer.js +4 -5
- package/dist/skill-offer.js.map +1 -1
- package/dist/spawn-command.d.ts +31 -0
- package/dist/spawn-command.d.ts.map +1 -0
- package/dist/spawn-command.js +17 -0
- package/dist/spawn-command.js.map +1 -0
- package/dist/terminal-session.d.ts +2 -1
- package/dist/terminal-session.d.ts.map +1 -1
- package/dist/terminal-session.js +50 -24
- package/dist/terminal-session.js.map +1 -1
- package/dist/terminal-watch.js +1 -1
- package/dist/terminal-watch.js.map +1 -1
- package/dist/ui-colour.d.ts +38 -0
- package/dist/ui-colour.d.ts.map +1 -0
- package/dist/ui-colour.js +39 -0
- package/dist/ui-colour.js.map +1 -0
- package/package.json +5 -2
- package/dist/coding-agents/claude-desktop.d.ts +0 -4
- package/dist/coding-agents/claude-desktop.d.ts.map +0 -1
- package/dist/coding-agents/claude-desktop.js +0 -25
- package/dist/coding-agents/claude-desktop.js.map +0 -1
package/README.md
CHANGED
|
@@ -53,9 +53,9 @@ With no terminal, a command that needs an answer prints the flags that would
|
|
|
53
53
|
have answered it and exits 2 rather than a usage block. With `--json`, every
|
|
54
54
|
error is `{ "error": …, "next_step": … }`.
|
|
55
55
|
|
|
56
|
-
`relay
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
`relay` and `relaymessenger` open with the Relay mark, version, usage, topics,
|
|
57
|
+
and concise commands, like the Linq CLI. Run `relay help <command>` for the
|
|
58
|
+
full options for any command.
|
|
59
59
|
|
|
60
60
|
Before interactive creation or sign-in setup, the CLI may offer the Relay skill
|
|
61
61
|
once if it is absent from the standard install locations. Declining skips skill
|
|
@@ -108,6 +108,16 @@ typed carries on afterwards.
|
|
|
108
108
|
`docs` prints `https://docs.relayapp.im/llms.txt`: its contents when there is no
|
|
109
109
|
terminal, and its address when there is one or when Relay cannot reach it.
|
|
110
110
|
|
|
111
|
+
## Authentication
|
|
112
|
+
|
|
113
|
+
`relay login` signs this computer into Relay Console using a browser/device
|
|
114
|
+
flow. It stores the Console session locally; Relay Console names your first
|
|
115
|
+
organization after you. Use `organization update --name` to rename it and
|
|
116
|
+
optional `--website` to set its website.
|
|
117
|
+
|
|
118
|
+
For legacy integrations, `relay auth login --with-token` keeps the explicit
|
|
119
|
+
Agent Token import path. The token is read from stdin and is never printed.
|
|
120
|
+
|
|
111
121
|
## Agent Token authentication
|
|
112
122
|
|
|
113
123
|
Use `agents create` for a new agent, or import an existing Agent Token. Tokens
|
|
@@ -190,7 +200,7 @@ Messages to users remain supported subject to Contacts eligibility and blocking.
|
|
|
190
200
|
There are no add-request, phone address-book, mutual-contact, human discovery, or
|
|
191
201
|
human invite-link commands.
|
|
192
202
|
|
|
193
|
-
##
|
|
203
|
+
## Organization creation and saved agents
|
|
194
204
|
|
|
195
205
|
```sh
|
|
196
206
|
relay agents create
|
|
@@ -203,7 +213,7 @@ Creation stores the one-time Agent Token in a new named profile and prints only
|
|
|
203
213
|
public metadata, a share link, and a terminal QR. JSON output includes
|
|
204
214
|
`token: "stored"`, never the secret. Use an explicit `--profile <new-name>` to
|
|
205
215
|
choose a new profile name; existing profiles and the current profile selection
|
|
206
|
-
are preserved.
|
|
216
|
+
are preserved. New agents are provisioned in the signed-in Console organization.
|
|
207
217
|
|
|
208
218
|
`agents list` shows the agents saved on this computer, not every agent on your
|
|
209
219
|
account. Each row is `profile`, `handle`, `display_name`, `image_url`, `api_url`
|
|
@@ -231,13 +241,14 @@ agent, and it never overwrites a token that is already there.
|
|
|
231
241
|
|
|
232
242
|
```sh
|
|
233
243
|
relay agents create \
|
|
234
|
-
--handle my_helper
|
|
244
|
+
--handle my_helper --name "My Helper" \
|
|
235
245
|
--image-url https://images.example.com/helper.png
|
|
236
246
|
```
|
|
237
247
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
248
|
+
A handle is one word, such as `my_helper`: 3 to 32 lowercase letters, numbers
|
|
249
|
+
or underscores. Dotted handles such as `my_helper.dev` are rejected, not
|
|
250
|
+
reinterpreted. Names are at most 30 characters. A collision is
|
|
251
|
+
an error, never a request for a different handle. Interactive creation asks `Handle (optional)`, `Name (optional)`, and `Image
|
|
241
252
|
(optional)` with a single help line; blank answers preserve defaults. Selecting
|
|
242
253
|
Create already expresses intent, so no second create confirmation is shown.
|
|
243
254
|
Recipe files remain an advanced `--image-recipe` flag, not another setup question.
|
|
@@ -265,24 +276,42 @@ server's response supplies the permanent public image URL.
|
|
|
265
276
|
|
|
266
277
|
## Local event forwarding
|
|
267
278
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
279
|
+
There are two ways to run an agent backend, the way Slack has Socket Mode for
|
|
280
|
+
local work and request URLs once deployed, and Stripe has `stripe listen
|
|
281
|
+
--forward-to` for local work and a registered endpoint once deployed. Deployed,
|
|
282
|
+
Relay POSTs events to your webhook. While you develop, `relay listen` reads the
|
|
283
|
+
same events over the socket and POSTs each one to a route on this computer,
|
|
284
|
+
signed exactly like a deployed webhook, so the same handler runs unchanged:
|
|
273
285
|
|
|
274
286
|
```sh
|
|
275
|
-
relay
|
|
276
|
-
|
|
277
|
-
|
|
287
|
+
relay listen --forward-to http://localhost:3000/relay-events
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
It prints the address it forwards to and the local signing secret, then one
|
|
291
|
+
line per event, the way `relay watch` shows them:
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
Forwarding events to http://localhost:3000/relay-events
|
|
295
|
+
Local signing secret whsec_… (set RELAY_WEBHOOK_SECRET to it while you develop)
|
|
296
|
+
Events read here count as delivered; a deployed webhook for this agent does not get them.
|
|
278
297
|
```
|
|
279
298
|
|
|
280
|
-
|
|
281
|
-
`
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
299
|
+
Set `RELAY_WEBHOOK_SECRET` to that secret where your handler runs. Each POST
|
|
300
|
+
carries `webhook-id`, `webhook-timestamp` and `webhook-signature` (Standard
|
|
301
|
+
Webhooks, HMAC-SHA256 over the exact bytes sent), plus `x-relay-event-id` and
|
|
302
|
+
`x-relay-event-type`, so `verifyWebhookSignature` and the Chat SDK adapter accept
|
|
303
|
+
it as they accept Relay's own deliveries. The secret is made once per profile and
|
|
304
|
+
kept in the CLI's private config, the way Stripe keeps one per account, so a
|
|
305
|
+
restart does not make you change it. `--forward-to` must be an address on your
|
|
306
|
+
own computer, such as `http://127.0.0.1:3000`. If your route answers with an
|
|
307
|
+
error, this command stops rather than let the event be lost, so Relay can send
|
|
308
|
+
it again. Your receiver must ignore an `event_id` it has already seen.
|
|
309
|
+
|
|
310
|
+
Reading events here delivers them: a deployed webhook for this agent does not get
|
|
311
|
+
them, so run it against the agent you are developing, never one something else
|
|
312
|
+
is reading. The older `relay --profile <name> events listen --acknowledge-events
|
|
313
|
+
[--forward-to <url>]` still works for scripts, prints the raw envelope, and signs
|
|
314
|
+
its forwards the same way.
|
|
286
315
|
|
|
287
316
|
If the agent has been away longer than Relay keeps its events, Relay wants to send
|
|
288
317
|
everything it missed. This command cannot go back over old events and says so
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type Relay from "@relaymessenger/sdk";
|
|
2
|
+
import { ClientSideConnection, type RequestPermissionRequest, type RequestPermissionResponse, type McpServer } from "@agentclientprotocol/sdk";
|
|
3
|
+
import type { AcpSessionStore } from "./acp-threads.js";
|
|
4
|
+
/**
|
|
5
|
+
* What `relay connect cursor|gemini-cli|cline|opencode` leaves running so the
|
|
6
|
+
* agent answers Relay messages by itself.
|
|
7
|
+
*
|
|
8
|
+
* These agents reach Relay through MCP, and MCP cannot start a turn, so a
|
|
9
|
+
* message waits until somebody asks the agent to read it. This is the process
|
|
10
|
+
* that asks. It speaks the Agent Client Protocol (ACP) — the same protocol Zed
|
|
11
|
+
* uses to drive Cursor, Gemini CLI and OpenCode in the background — over the
|
|
12
|
+
* official `@agentclientprotocol/sdk`. It runs the agent's own ACP command
|
|
13
|
+
* (`cursor-agent acp`, `gemini --experimental-acp`, `opencode acp`), gives every
|
|
14
|
+
* chat its own ACP session, and sends the final answer back to the same chat.
|
|
15
|
+
*
|
|
16
|
+
* Relay's own tools travel through the session, natively: the Relay MCP server
|
|
17
|
+
* connect would otherwise write into the agent's `mcp.json` is handed to
|
|
18
|
+
* `session/new` instead, so the agent keeps Relay's send, read and react tools
|
|
19
|
+
* while this process drives its turns. This mirrors `codex-bridge.ts`, which
|
|
20
|
+
* does the same over Codex's `app-server`; the two never share a session file.
|
|
21
|
+
*/
|
|
22
|
+
/** Relay takes 1 to 255 characters for an idempotency key (contracts/relay-v1-openapi.yaml). */
|
|
23
|
+
export declare const replyKey: (eventId: string) => string;
|
|
24
|
+
/** What the agent is told this client is (`clientInfo`, InitializeRequest). */
|
|
25
|
+
export declare const CLIENT_NAME = "relaymessenger";
|
|
26
|
+
/**
|
|
27
|
+
* One message, as the prompt the agent is given. The agent keeps its Relay
|
|
28
|
+
* tools during the turn, so the prompt says who answers the person: this
|
|
29
|
+
* process sends the final message, and the agent must not send a second one.
|
|
30
|
+
* Copied word for word from `codexPrompt` (codex-bridge.ts) so both bridges say
|
|
31
|
+
* the same thing.
|
|
32
|
+
*/
|
|
33
|
+
export declare const acpPrompt: (sender: string, text: string) => string;
|
|
34
|
+
/** What to run for the agent: the file, and the words that put it in ACP mode. */
|
|
35
|
+
export interface AcpCommand {
|
|
36
|
+
/** The executable, e.g. `cursor-agent`, or the absolute path connect found. */
|
|
37
|
+
command: string;
|
|
38
|
+
/** The ACP sub-command and flags, e.g. `["acp"]` or `["--experimental-acp"]`. */
|
|
39
|
+
args: readonly string[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The file to run for the agent. connect hands over the one its own sniff found
|
|
43
|
+
* on PATH, and the bare name when it found none (connect.ts). Windows has no
|
|
44
|
+
* file called `cursor-agent`: npm installs a `.cmd` shim, so a bare name is
|
|
45
|
+
* looked up again here and, failing that, left with the extension `cmd.exe` can
|
|
46
|
+
* find. The ACP words are kept as they are (runtime-sniff.ts, spawn-command.ts).
|
|
47
|
+
*/
|
|
48
|
+
export declare const acpCommand: (found: string, args: readonly string[], env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform) => Promise<AcpCommand>;
|
|
49
|
+
/** The Relay MCP server as ACP takes it (`McpServerStdio`, schema/types.gen). */
|
|
50
|
+
export declare const relayMcpServer: (spec: {
|
|
51
|
+
command: string;
|
|
52
|
+
args: readonly string[];
|
|
53
|
+
env: Record<string, string>;
|
|
54
|
+
}) => McpServer;
|
|
55
|
+
/**
|
|
56
|
+
* Nobody is at the keyboard, so a tool the agent asks to run is allowed the
|
|
57
|
+
* same way Codex's `approvalPolicy: "never"` allows it: the agent proceeds. The
|
|
58
|
+
* first `allow` option is chosen; when none is offered the request is cancelled
|
|
59
|
+
* (`RequestPermissionOutcome`, schema/types.gen), which the reference client
|
|
60
|
+
* does too (openclaw/src/acp/client-helpers.ts, `resolvePermissionRequest`).
|
|
61
|
+
*/
|
|
62
|
+
export declare const autoPermission: (params: RequestPermissionRequest) => RequestPermissionResponse;
|
|
63
|
+
/** One running ACP agent, and the calls this bridge makes to it. */
|
|
64
|
+
export interface AcpAgent {
|
|
65
|
+
client: Pick<ClientSideConnection, "initialize" | "newSession" | "loadSession" | "prompt" | "cancel">;
|
|
66
|
+
/**
|
|
67
|
+
* Collect the answer streamed for one session's running turn. Every
|
|
68
|
+
* `agent_message_chunk` of text is handed to the sink until the returned
|
|
69
|
+
* function is called. Turns are serial within a session, so at most one sink
|
|
70
|
+
* is registered per session at a time.
|
|
71
|
+
*/
|
|
72
|
+
collect(sessionId: string, sink: (text: string) => void): () => void;
|
|
73
|
+
/** True once the agent advertised `session/load`; set after `initialize`. */
|
|
74
|
+
canLoad: boolean;
|
|
75
|
+
/** Resolves, with the line to show the person, when the process is gone. */
|
|
76
|
+
stopped: Promise<string>;
|
|
77
|
+
/** True once the process is gone, so the next message starts a new one. */
|
|
78
|
+
gone(): boolean;
|
|
79
|
+
}
|
|
80
|
+
/** Starts the agent's ACP command and drives it over the official SDK. */
|
|
81
|
+
export declare const startAcpAgent: (acp: AcpCommand, cwd: string, signal: AbortSignal) => AcpAgent;
|
|
82
|
+
/** The turn the agent is running for one chat right now. */
|
|
83
|
+
export interface LiveTurn {
|
|
84
|
+
sessionId: string;
|
|
85
|
+
/** A newer message for this chat replaced it, so its answer is not sent. */
|
|
86
|
+
dropped: boolean;
|
|
87
|
+
}
|
|
88
|
+
/** How a turn ended (`StopReason`, schema/types.gen), and what it said. */
|
|
89
|
+
export interface TurnOutcome {
|
|
90
|
+
/** `end_turn`, `cancelled`, `refusal`, `max_tokens` or `max_turn_requests`. */
|
|
91
|
+
stopReason: string;
|
|
92
|
+
answer: string;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Runs one turn in one session, and gives back what the agent answered.
|
|
96
|
+
*
|
|
97
|
+
* The answer is every `agent_message_chunk` of text the agent streamed before
|
|
98
|
+
* `session/prompt` returned its stop reason, joined in order.
|
|
99
|
+
*/
|
|
100
|
+
export declare const runTurn: (agent: AcpAgent, input: {
|
|
101
|
+
sessionId: string;
|
|
102
|
+
prompt: string;
|
|
103
|
+
onStarted(turn: LiveTurn): void;
|
|
104
|
+
}) => Promise<TurnOutcome>;
|
|
105
|
+
export interface AcpBridgeInput {
|
|
106
|
+
client: Pick<Relay, "chats" | "websocket">;
|
|
107
|
+
/** The agent's ACP command, and the folder to run it in. */
|
|
108
|
+
acp: AcpCommand;
|
|
109
|
+
cwd: string;
|
|
110
|
+
/** The Relay MCP server handed to every session, so Relay's tools travel with it. */
|
|
111
|
+
mcpServers: readonly McpServer[];
|
|
112
|
+
/** The label shown to the person, e.g. "Cursor". */
|
|
113
|
+
label: string;
|
|
114
|
+
/** Which ACP session belongs to which chat, across restarts. */
|
|
115
|
+
sessions: AcpSessionStore;
|
|
116
|
+
signal: AbortSignal;
|
|
117
|
+
/** One line to the terminal the person is watching. */
|
|
118
|
+
say(line: string): void;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Answers every message that arrives until the signal stops it.
|
|
122
|
+
*
|
|
123
|
+
* Turns run one at a time inside a chat and at the same time across chats,
|
|
124
|
+
* which is what one agent with one session per chat allows. A message for a
|
|
125
|
+
* chat whose turn is still running cancels that turn (`session/cancel`) and
|
|
126
|
+
* takes its place; the cancelled turn sends nothing.
|
|
127
|
+
*/
|
|
128
|
+
export declare const runAcpBridge: (input: AcpBridgeInput) => Promise<void>;
|
|
129
|
+
//# sourceMappingURL=acp-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acp-bridge.d.ts","sourceRoot":"","sources":["../src/acp-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { ClientSideConnection, PROTOCOL_VERSION, ndJsonStream, } from "@agentclientprotocol/sdk";
|
|
2
|
+
import { Readable, Writable } from "node:stream";
|
|
3
|
+
import { isAbsolute } from "node:path";
|
|
4
|
+
import { bridgeTurn, MAX_RELAY_TEXT } from "./codex-bridge.js";
|
|
5
|
+
import { findExecutable } from "./runtime-sniff.js";
|
|
6
|
+
import { packageVersion } from "./config.js";
|
|
7
|
+
import { spawnCommand } from "./spawn-command.js";
|
|
8
|
+
/**
|
|
9
|
+
* What `relay connect cursor|gemini-cli|cline|opencode` leaves running so the
|
|
10
|
+
* agent answers Relay messages by itself.
|
|
11
|
+
*
|
|
12
|
+
* These agents reach Relay through MCP, and MCP cannot start a turn, so a
|
|
13
|
+
* message waits until somebody asks the agent to read it. This is the process
|
|
14
|
+
* that asks. It speaks the Agent Client Protocol (ACP) — the same protocol Zed
|
|
15
|
+
* uses to drive Cursor, Gemini CLI and OpenCode in the background — over the
|
|
16
|
+
* official `@agentclientprotocol/sdk`. It runs the agent's own ACP command
|
|
17
|
+
* (`cursor-agent acp`, `gemini --experimental-acp`, `opencode acp`), gives every
|
|
18
|
+
* chat its own ACP session, and sends the final answer back to the same chat.
|
|
19
|
+
*
|
|
20
|
+
* Relay's own tools travel through the session, natively: the Relay MCP server
|
|
21
|
+
* connect would otherwise write into the agent's `mcp.json` is handed to
|
|
22
|
+
* `session/new` instead, so the agent keeps Relay's send, read and react tools
|
|
23
|
+
* while this process drives its turns. This mirrors `codex-bridge.ts`, which
|
|
24
|
+
* does the same over Codex's `app-server`; the two never share a session file.
|
|
25
|
+
*/
|
|
26
|
+
/** Relay takes 1 to 255 characters for an idempotency key (contracts/relay-v1-openapi.yaml). */
|
|
27
|
+
export const replyKey = (eventId) => `acp-bridge-${eventId}`;
|
|
28
|
+
/** What the agent is told this client is (`clientInfo`, InitializeRequest). */
|
|
29
|
+
export const CLIENT_NAME = "relaymessenger";
|
|
30
|
+
/**
|
|
31
|
+
* One message, as the prompt the agent is given. The agent keeps its Relay
|
|
32
|
+
* tools during the turn, so the prompt says who answers the person: this
|
|
33
|
+
* process sends the final message, and the agent must not send a second one.
|
|
34
|
+
* Copied word for word from `codexPrompt` (codex-bridge.ts) so both bridges say
|
|
35
|
+
* the same thing.
|
|
36
|
+
*/
|
|
37
|
+
export const acpPrompt = (sender, text) => [
|
|
38
|
+
`@${sender} sent you this message on Relay:`,
|
|
39
|
+
"",
|
|
40
|
+
text.slice(0, MAX_RELAY_TEXT),
|
|
41
|
+
"",
|
|
42
|
+
"Write your answer as your final message. Relay sends that answer to the chat for you, so do not send it yourself.",
|
|
43
|
+
].join("\n");
|
|
44
|
+
/**
|
|
45
|
+
* The file to run for the agent. connect hands over the one its own sniff found
|
|
46
|
+
* on PATH, and the bare name when it found none (connect.ts). Windows has no
|
|
47
|
+
* file called `cursor-agent`: npm installs a `.cmd` shim, so a bare name is
|
|
48
|
+
* looked up again here and, failing that, left with the extension `cmd.exe` can
|
|
49
|
+
* find. The ACP words are kept as they are (runtime-sniff.ts, spawn-command.ts).
|
|
50
|
+
*/
|
|
51
|
+
export const acpCommand = async (found, args, env = process.env, platform = process.platform) => {
|
|
52
|
+
if (isAbsolute(found))
|
|
53
|
+
return { command: found, args };
|
|
54
|
+
const onPath = await findExecutable(found, env, platform);
|
|
55
|
+
return { command: onPath ?? (platform === "win32" ? `${found}.cmd` : found), args };
|
|
56
|
+
};
|
|
57
|
+
/** The Relay MCP server as ACP takes it (`McpServerStdio`, schema/types.gen). */
|
|
58
|
+
export const relayMcpServer = (spec) => ({
|
|
59
|
+
name: "relay",
|
|
60
|
+
command: spec.command,
|
|
61
|
+
args: [...spec.args],
|
|
62
|
+
env: Object.entries(spec.env).map(([name, value]) => ({ name, value })),
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* Nobody is at the keyboard, so a tool the agent asks to run is allowed the
|
|
66
|
+
* same way Codex's `approvalPolicy: "never"` allows it: the agent proceeds. The
|
|
67
|
+
* first `allow` option is chosen; when none is offered the request is cancelled
|
|
68
|
+
* (`RequestPermissionOutcome`, schema/types.gen), which the reference client
|
|
69
|
+
* does too (openclaw/src/acp/client-helpers.ts, `resolvePermissionRequest`).
|
|
70
|
+
*/
|
|
71
|
+
export const autoPermission = (params) => {
|
|
72
|
+
const allow = params.options.find((option) => option.kind === "allow_once")
|
|
73
|
+
?? params.options.find((option) => option.kind === "allow_always");
|
|
74
|
+
return allow
|
|
75
|
+
? { outcome: { outcome: "selected", optionId: allow.optionId } }
|
|
76
|
+
: { outcome: { outcome: "cancelled" } };
|
|
77
|
+
};
|
|
78
|
+
/** Starts the agent's ACP command and drives it over the official SDK. */
|
|
79
|
+
export const startAcpAgent = (acp, cwd, signal) => {
|
|
80
|
+
// Started the way every other command this CLI runs is started, so the `.cmd`
|
|
81
|
+
// shim npm installs on Windows runs too (spawn-command.ts). Nothing a person
|
|
82
|
+
// wrote travels on this command line: messages go down the ACP stream.
|
|
83
|
+
const child = spawnCommand(acp.command, acp.args, {
|
|
84
|
+
cwd, stdio: ["pipe", "pipe", "pipe"], signal,
|
|
85
|
+
});
|
|
86
|
+
const sinks = new Map();
|
|
87
|
+
let dead = false;
|
|
88
|
+
let announce;
|
|
89
|
+
const stopped = new Promise((resolve) => { announce = resolve; });
|
|
90
|
+
const die = (line) => {
|
|
91
|
+
if (dead)
|
|
92
|
+
return;
|
|
93
|
+
dead = true;
|
|
94
|
+
announce(line);
|
|
95
|
+
};
|
|
96
|
+
// The agent writes its own diagnostics to stderr; the person watching this
|
|
97
|
+
// terminal is waiting for an answer, not for a log.
|
|
98
|
+
child.stderr?.resume();
|
|
99
|
+
child.stdin?.on("error", () => { });
|
|
100
|
+
child.once("error", () => die("The agent could not be started. Trying again on the next message."));
|
|
101
|
+
child.once("close", () => die("The agent stopped. Starting it again on the next message."));
|
|
102
|
+
if (!child.stdin || !child.stdout) {
|
|
103
|
+
die("The agent gave this bridge no way to talk to it.");
|
|
104
|
+
}
|
|
105
|
+
const input = Writable.toWeb(child.stdin);
|
|
106
|
+
const output = Readable.toWeb(child.stdout);
|
|
107
|
+
const stream = ndJsonStream(input, output);
|
|
108
|
+
const handlers = {
|
|
109
|
+
sessionUpdate: async (params) => {
|
|
110
|
+
const sink = sinks.get(params.sessionId);
|
|
111
|
+
if (!sink)
|
|
112
|
+
return;
|
|
113
|
+
const update = params.update;
|
|
114
|
+
if (update.sessionUpdate === "agent_message_chunk" && update.content.type === "text") {
|
|
115
|
+
sink(update.content.text);
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
requestPermission: async (params) => autoPermission(params),
|
|
119
|
+
};
|
|
120
|
+
const client = new ClientSideConnection(() => handlers, stream);
|
|
121
|
+
return {
|
|
122
|
+
client,
|
|
123
|
+
collect: (sessionId, sink) => {
|
|
124
|
+
sinks.set(sessionId, sink);
|
|
125
|
+
return () => { if (sinks.get(sessionId) === sink)
|
|
126
|
+
sinks.delete(sessionId); };
|
|
127
|
+
},
|
|
128
|
+
canLoad: false,
|
|
129
|
+
stopped,
|
|
130
|
+
gone: () => dead,
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Runs one turn in one session, and gives back what the agent answered.
|
|
135
|
+
*
|
|
136
|
+
* The answer is every `agent_message_chunk` of text the agent streamed before
|
|
137
|
+
* `session/prompt` returned its stop reason, joined in order.
|
|
138
|
+
*/
|
|
139
|
+
export const runTurn = async (agent, input) => {
|
|
140
|
+
const chunks = [];
|
|
141
|
+
const stop = agent.collect(input.sessionId, (text) => chunks.push(text));
|
|
142
|
+
try {
|
|
143
|
+
input.onStarted({ sessionId: input.sessionId, dropped: false });
|
|
144
|
+
const response = await Promise.race([
|
|
145
|
+
agent.client.prompt({ sessionId: input.sessionId, prompt: [{ type: "text", text: input.prompt }] }),
|
|
146
|
+
agent.stopped.then((line) => { throw new Error(line); }),
|
|
147
|
+
]);
|
|
148
|
+
return { stopReason: response.stopReason, answer: chunks.join("").trim() };
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
stop();
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
/** One line of what arrived, short enough to read at a glance. */
|
|
155
|
+
const arrival = (turn) => `@${turn.sender} ${turn.text.replace(/\s+/gu, " ").slice(0, 160)}`;
|
|
156
|
+
/**
|
|
157
|
+
* Answers every message that arrives until the signal stops it.
|
|
158
|
+
*
|
|
159
|
+
* Turns run one at a time inside a chat and at the same time across chats,
|
|
160
|
+
* which is what one agent with one session per chat allows. A message for a
|
|
161
|
+
* chat whose turn is still running cancels that turn (`session/cancel`) and
|
|
162
|
+
* takes its place; the cancelled turn sends nothing.
|
|
163
|
+
*/
|
|
164
|
+
export const runAcpBridge = async (input) => {
|
|
165
|
+
const answered = new Set();
|
|
166
|
+
const lanes = new Map();
|
|
167
|
+
let session;
|
|
168
|
+
let sessionGone = false;
|
|
169
|
+
/** The ACP session each chat is holding open in the agent running now. */
|
|
170
|
+
let opened = new Map();
|
|
171
|
+
const acpAgent = () => {
|
|
172
|
+
if (session && !sessionGone)
|
|
173
|
+
return session;
|
|
174
|
+
opened = new Map();
|
|
175
|
+
session = (async () => {
|
|
176
|
+
const started = startAcpAgent(input.acp, input.cwd, input.signal);
|
|
177
|
+
// A stop the person asked for, with Control-C, is not news.
|
|
178
|
+
void started.stopped.then((line) => {
|
|
179
|
+
sessionGone = true;
|
|
180
|
+
if (!input.signal.aborted)
|
|
181
|
+
input.say(line);
|
|
182
|
+
});
|
|
183
|
+
// `initialize` negotiates the protocol version and reads back whether the
|
|
184
|
+
// agent can take an old session back with `session/load` (ACP spec,
|
|
185
|
+
// Initialization). The reference client sends the same capabilities
|
|
186
|
+
// (openclaw/src/acp/client.ts).
|
|
187
|
+
const info = await started.client.initialize({
|
|
188
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
189
|
+
clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: true },
|
|
190
|
+
clientInfo: { name: CLIENT_NAME, title: "Relay", version: packageVersion() },
|
|
191
|
+
});
|
|
192
|
+
started.canLoad = info.agentCapabilities?.loadSession === true;
|
|
193
|
+
return started;
|
|
194
|
+
})().catch((error) => {
|
|
195
|
+
sessionGone = true;
|
|
196
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
197
|
+
});
|
|
198
|
+
sessionGone = false;
|
|
199
|
+
return session;
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* The session for this chat: the saved one if the agent still has it, a new
|
|
203
|
+
* one if it does not. `session/load` is only tried when the agent said it can
|
|
204
|
+
* (`agentCapabilities.loadSession`); a load the agent refuses starts a new
|
|
205
|
+
* session, the same fallback the Codex bridge makes for a lost thread.
|
|
206
|
+
*/
|
|
207
|
+
const openSession = async (agent, chatId) => {
|
|
208
|
+
const settings = { cwd: input.cwd, mcpServers: [...input.mcpServers] };
|
|
209
|
+
// This agent already has the session open; it is taken back by id once per
|
|
210
|
+
// run of the process, not once per message.
|
|
211
|
+
const open = opened.get(chatId);
|
|
212
|
+
if (open !== undefined)
|
|
213
|
+
return open;
|
|
214
|
+
const saved = input.sessions.get(chatId);
|
|
215
|
+
if (saved !== undefined && agent.canLoad) {
|
|
216
|
+
try {
|
|
217
|
+
await agent.client.loadSession({ ...settings, sessionId: saved });
|
|
218
|
+
opened.set(chatId, saved);
|
|
219
|
+
return saved;
|
|
220
|
+
}
|
|
221
|
+
catch { /* Named below, once, for the one case a person can act on. */ }
|
|
222
|
+
input.say(`${input.label} no longer has this chat's session. It starts a new one.`);
|
|
223
|
+
}
|
|
224
|
+
const created = await agent.client.newSession(settings);
|
|
225
|
+
const id = created.sessionId;
|
|
226
|
+
if (!id)
|
|
227
|
+
throw new Error("The agent opened a session with no id.");
|
|
228
|
+
opened.set(chatId, id);
|
|
229
|
+
await input.sessions.set(chatId, id);
|
|
230
|
+
return id;
|
|
231
|
+
};
|
|
232
|
+
const answerOne = async (turn, lane, started) => {
|
|
233
|
+
let typing = false;
|
|
234
|
+
try {
|
|
235
|
+
await input.client.chats.startTyping(turn.chatId);
|
|
236
|
+
typing = true;
|
|
237
|
+
}
|
|
238
|
+
catch { /* The answer matters more than the typing indicator. */ }
|
|
239
|
+
const stopTyping = async () => {
|
|
240
|
+
if (!typing)
|
|
241
|
+
return;
|
|
242
|
+
typing = false;
|
|
243
|
+
try {
|
|
244
|
+
await input.client.chats.stopTyping(turn.chatId);
|
|
245
|
+
}
|
|
246
|
+
catch { /* As above. */ }
|
|
247
|
+
};
|
|
248
|
+
let mine;
|
|
249
|
+
let outcome;
|
|
250
|
+
try {
|
|
251
|
+
const agent = await acpAgent();
|
|
252
|
+
const sessionId = await openSession(agent, turn.chatId);
|
|
253
|
+
outcome = await runTurn(agent, {
|
|
254
|
+
sessionId, prompt: acpPrompt(turn.sender, turn.text),
|
|
255
|
+
onStarted: (live) => { mine = live; lane.live = live; started(); },
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
catch { /* Named below, with everything else the agent can fail at. */ }
|
|
259
|
+
if (lane.live === mine)
|
|
260
|
+
lane.live = undefined;
|
|
261
|
+
if (mine?.dropped === true || outcome?.stopReason === "cancelled") {
|
|
262
|
+
await stopTyping();
|
|
263
|
+
input.say(`A newer message came in, so the answer to @${turn.sender} was dropped.`);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
const answer = (outcome?.answer ?? "").trim();
|
|
267
|
+
if (!answer) {
|
|
268
|
+
await stopTyping();
|
|
269
|
+
input.say(`${input.label} gave no answer to @${turn.sender}, so nothing was sent.`);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
try {
|
|
273
|
+
await input.client.chats.messages.send(turn.chatId, {
|
|
274
|
+
message: {
|
|
275
|
+
parts: [{ type: "text", value: answer.slice(0, MAX_RELAY_TEXT) }],
|
|
276
|
+
// The message that arrived is the key, so a retry after a dropped
|
|
277
|
+
// connection cannot answer the same person twice.
|
|
278
|
+
idempotency_key: replyKey(turn.eventId),
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
input.say(`Sent the answer to @${turn.sender}.`);
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
input.say(`The answer to @${turn.sender} did not reach Relay.`);
|
|
285
|
+
}
|
|
286
|
+
finally {
|
|
287
|
+
await stopTyping();
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
await input.client.websocket.run({
|
|
291
|
+
signal: input.signal,
|
|
292
|
+
onEvent: async (event) => {
|
|
293
|
+
const turn = bridgeTurn(event);
|
|
294
|
+
if (!turn || answered.has(turn.eventId))
|
|
295
|
+
return;
|
|
296
|
+
answered.add(turn.eventId);
|
|
297
|
+
input.say(arrival(turn));
|
|
298
|
+
const lane = lanes.get(turn.chatId) ?? { chain: Promise.resolve() };
|
|
299
|
+
lanes.set(turn.chatId, lane);
|
|
300
|
+
const live = lane.live;
|
|
301
|
+
if (live !== undefined) {
|
|
302
|
+
live.dropped = true;
|
|
303
|
+
try {
|
|
304
|
+
await (await acpAgent()).client.cancel({ sessionId: live.sessionId });
|
|
305
|
+
}
|
|
306
|
+
catch { /* The turn ended by itself, which is the same outcome. */ }
|
|
307
|
+
}
|
|
308
|
+
let ready;
|
|
309
|
+
const handed = new Promise((resolve) => { ready = resolve; });
|
|
310
|
+
// Nothing may be thrown here: a failure would close the connection, and
|
|
311
|
+
// the agent failing to answer one message is not a reason to stop.
|
|
312
|
+
lane.chain = lane.chain.then(() => answerOne(turn, lane, ready)).catch(() => undefined).finally(() => { ready(); });
|
|
313
|
+
// Relay is told the message is handled once the agent is working on it.
|
|
314
|
+
// The rest of the turn does not hold this connection, because every other
|
|
315
|
+
// chat's messages, and the next message in this one, arrive down it.
|
|
316
|
+
await handed;
|
|
317
|
+
},
|
|
318
|
+
onFullSync: async () => {
|
|
319
|
+
// This process keeps no copy of any chat, so there is nothing to rebuild.
|
|
320
|
+
input.say(`${input.label} was away longer than Relay keeps its messages. It answers the new ones from now on.`);
|
|
321
|
+
},
|
|
322
|
+
});
|
|
323
|
+
};
|
|
324
|
+
//# sourceMappingURL=acp-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acp-bridge.js","sourceRoot":"","sources":["../src/acp-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ConfigContext } from "./config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Which ACP session belongs to which Relay chat, kept where the profile that
|
|
4
|
+
* owns the agent is kept.
|
|
5
|
+
*
|
|
6
|
+
* An ACP agent (cursor, gemini-cli, opencode) gives every `session/new` a
|
|
7
|
+
* session id, and takes an old one back with `session/load` when it advertises
|
|
8
|
+
* that it can (`agentCapabilities.loadSession`). The bridge is the only thing
|
|
9
|
+
* that knows which session belongs to which chat, and it would forget on every
|
|
10
|
+
* restart while the ids lived in memory. They live here instead, beside
|
|
11
|
+
* `config.json`, so a chat keeps its context across restarts of the bridge and
|
|
12
|
+
* of the agent itself. This is the shape `codex-threads.ts` uses for Codex,
|
|
13
|
+
* kept in its own file so the two never share a key.
|
|
14
|
+
*/
|
|
15
|
+
export declare const acpSessionsPath: (context?: ConfigContext) => string;
|
|
16
|
+
/** The agent a set of sessions belongs to. */
|
|
17
|
+
export interface AcpSessionOwner {
|
|
18
|
+
/** The Relay the agent lives on, so staging and production never share a session. */
|
|
19
|
+
apiURL: string;
|
|
20
|
+
/** The agent that answers, so two agents in one folder never share a session. */
|
|
21
|
+
handle: string;
|
|
22
|
+
}
|
|
23
|
+
/** One chat's key in the file: the Relay, the agent, and the chat. */
|
|
24
|
+
export declare const acpSessionKey: (owner: AcpSessionOwner, chatId: string) => string;
|
|
25
|
+
/** The session ids for one agent, read once and written on every change. */
|
|
26
|
+
export interface AcpSessionStore {
|
|
27
|
+
/** The session the agent opened for this chat, if this computer still remembers one. */
|
|
28
|
+
get(chatId: string): string | undefined;
|
|
29
|
+
/** Remembers the session the agent just opened for this chat. */
|
|
30
|
+
set(chatId: string, sessionId: string): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export declare const openAcpSessions: (owner: AcpSessionOwner, context?: ConfigContext) => Promise<AcpSessionStore>;
|
|
33
|
+
//# sourceMappingURL=acp-threads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acp-threads.d.ts","sourceRoot":"","sources":["../src/acp-threads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAK7D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,GAAI,UAAS,aAAkB,KAAG,MACL,CAAC;AAE1D,8CAA8C;AAC9C,MAAM,WAAW,eAAe;IAC9B,qFAAqF;IACrF,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,sEAAsE;AACtE,eAAO,MAAM,aAAa,GAAI,OAAO,eAAe,EAAE,QAAQ,MAAM,KAAG,MAC1B,CAAC;AA0B9C,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC9B,wFAAwF;IACxF,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACxC,iEAAiE;IACjE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAED,eAAO,MAAM,eAAe,GAC1B,OAAO,eAAe,EACtB,UAAS,aAAkB,KAC1B,OAAO,CAAC,eAAe,CAYzB,CAAC"}
|