@snowyroad/arp 0.4.0 → 0.5.0
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/dist/cli.js +61 -10
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1387,6 +1387,14 @@ var RelayClient = class {
|
|
|
1387
1387
|
activity: catchingUp ? "catching_up" : "thinking"
|
|
1388
1388
|
});
|
|
1389
1389
|
}
|
|
1390
|
+
/** Forward one normalized agent-activity event (Agent Activity View, slice 1) to the
|
|
1391
|
+
* relay over the agent WS. The emitted frame is the normalized ActivityEvent spread
|
|
1392
|
+
* out with `type: "activity_event"` and the channelId added on top — exactly the shape
|
|
1393
|
+
* the relay ingest parses. No-op if the socket is closed (send() guards readyState),
|
|
1394
|
+
* matching sendActivity: a dropped activity event must never break a turn. */
|
|
1395
|
+
sendActivityEvent(channelId, event) {
|
|
1396
|
+
this.send({ type: "activity_event", channelId, ...event });
|
|
1397
|
+
}
|
|
1390
1398
|
/** Publish this agent's partial A2A card; the relay fills url/version/provider. */
|
|
1391
1399
|
async putAgentCard(card) {
|
|
1392
1400
|
const url = `${this.cfg.relayHttpUrl}/agents/me/agent-card`;
|
|
@@ -1440,7 +1448,7 @@ var RelayClient = class {
|
|
|
1440
1448
|
if (u.thoughtTokens !== void 0) b.thoughtTokens = u.thoughtTokens;
|
|
1441
1449
|
return b;
|
|
1442
1450
|
}
|
|
1443
|
-
async postMessage(channelId, content, usage) {
|
|
1451
|
+
async postMessage(channelId, content, usage, turnId) {
|
|
1444
1452
|
const ch = this.pathId(channelId, "channelId");
|
|
1445
1453
|
if (!ch) return;
|
|
1446
1454
|
const url = `${this.cfg.relayHttpUrl}/channels/${ch}/messages`;
|
|
@@ -1451,6 +1459,9 @@ var RelayClient = class {
|
|
|
1451
1459
|
agentId: this.cfg.agentUuid,
|
|
1452
1460
|
agentName: this.cfg.agentName,
|
|
1453
1461
|
messageType: "agent",
|
|
1462
|
+
// Carry the turn's id so the relay/web can correlate this message with the
|
|
1463
|
+
// turn's activity events (Agent Activity View). Omit when absent.
|
|
1464
|
+
...turnId ? { turnId } : {},
|
|
1454
1465
|
...this.usageBody(usage)
|
|
1455
1466
|
});
|
|
1456
1467
|
try {
|
|
@@ -1738,10 +1749,10 @@ ${toolStatusLine(this.toolMode)}
|
|
|
1738
1749
|
}
|
|
1739
1750
|
async start(opts) {
|
|
1740
1751
|
this.session = await this.adapter.start(opts);
|
|
1741
|
-
this.session.onTurn((full, usage) => {
|
|
1752
|
+
this.session.onTurn((full, usage, turnId) => {
|
|
1742
1753
|
this.beacon?.end();
|
|
1743
1754
|
if (full.replace(/<<silent>>/gi, "").trim() === "") return;
|
|
1744
|
-
this.onReply(full.replace(/^\s*(?:<<silent>>\s*)+/i, "").trim(), usage);
|
|
1755
|
+
this.onReply(full.replace(/^\s*(?:<<silent>>\s*)+/i, "").trim(), usage, turnId);
|
|
1745
1756
|
});
|
|
1746
1757
|
}
|
|
1747
1758
|
/**
|
|
@@ -1962,6 +1973,7 @@ function dropVendorNotifications(input) {
|
|
|
1962
1973
|
}
|
|
1963
1974
|
|
|
1964
1975
|
// src/acp/client.ts
|
|
1976
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1965
1977
|
var MODEL_AUTH_ENV_KEYS = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
|
|
1966
1978
|
var BRIDGE_ENV_PREFIX = "ARP_";
|
|
1967
1979
|
function buildAcpEnv(base, extra) {
|
|
@@ -2105,6 +2117,9 @@ var AcpClient = class {
|
|
|
2105
2117
|
this.activeTurnBuffer.usage.costCurrency = u.cost.currency;
|
|
2106
2118
|
}
|
|
2107
2119
|
}
|
|
2120
|
+
if ((u.sessionUpdate === "tool_call" || u.sessionUpdate === "tool_call_update") && this.launch.onActivity && this.activeTurnBuffer) {
|
|
2121
|
+
this.emitActivity(u.sessionUpdate, u, this.activeTurnBuffer.turnId);
|
|
2122
|
+
}
|
|
2108
2123
|
},
|
|
2109
2124
|
requestPermission: async (req) => {
|
|
2110
2125
|
const verdict = evaluateAcpPermission(this.policy.mode, this.policy.configDirAbs, req);
|
|
@@ -2181,12 +2196,41 @@ var AcpClient = class {
|
|
|
2181
2196
|
});
|
|
2182
2197
|
return run;
|
|
2183
2198
|
}
|
|
2199
|
+
/**
|
|
2200
|
+
* Normalize one ACP tool-call update (metadata only) and hand it to the activity
|
|
2201
|
+
* sink, stamped with this turn's turnId. Never throws: a sink fault is caught and
|
|
2202
|
+
* logged so it cannot break the turn. SLICE 1: deliberately drops content,
|
|
2203
|
+
* rawInput, and rawOutput — only kind/title/status/locations are carried.
|
|
2204
|
+
*/
|
|
2205
|
+
emitActivity(eventType, u, turnId) {
|
|
2206
|
+
const sink = this.launch.onActivity;
|
|
2207
|
+
if (!sink) return;
|
|
2208
|
+
const locations = u.locations && u.locations.length > 0 ? u.locations.map((l) => l.line == null ? { path: l.path } : { path: l.path, line: l.line }) : null;
|
|
2209
|
+
const event = {
|
|
2210
|
+
turnId,
|
|
2211
|
+
toolCallId: u.toolCallId,
|
|
2212
|
+
eventType,
|
|
2213
|
+
kind: u.kind ?? null,
|
|
2214
|
+
title: u.title ?? null,
|
|
2215
|
+
status: u.status ?? null,
|
|
2216
|
+
locations,
|
|
2217
|
+
ts: Date.now()
|
|
2218
|
+
};
|
|
2219
|
+
try {
|
|
2220
|
+
sink(event);
|
|
2221
|
+
} catch (err) {
|
|
2222
|
+
console.warn(
|
|
2223
|
+
`[arp-bridge] onActivity sink threw (ignored): ${sanitizeForTty(String(err?.message ?? err))}`
|
|
2224
|
+
);
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2184
2227
|
/** Execute exactly one prompt turn with its own isolated reply buffer. */
|
|
2185
2228
|
async runTurn(text) {
|
|
2186
2229
|
if (!this.conn || !this._sessionId) {
|
|
2187
2230
|
throw new Error("AcpClient.submit called before start()");
|
|
2188
2231
|
}
|
|
2189
|
-
const
|
|
2232
|
+
const turnId = randomUUID2();
|
|
2233
|
+
const buffer = { text: "", turnId };
|
|
2190
2234
|
this.activeTurnBuffer = buffer;
|
|
2191
2235
|
try {
|
|
2192
2236
|
const resp = await this.guard(
|
|
@@ -2209,7 +2253,7 @@ var AcpClient = class {
|
|
|
2209
2253
|
}
|
|
2210
2254
|
};
|
|
2211
2255
|
}
|
|
2212
|
-
return { text: buffer.text, usage: buffer.usage };
|
|
2256
|
+
return { text: buffer.text, usage: buffer.usage, turnId };
|
|
2213
2257
|
} finally {
|
|
2214
2258
|
if (this.activeTurnBuffer === buffer) this.activeTurnBuffer = null;
|
|
2215
2259
|
}
|
|
@@ -2480,6 +2524,9 @@ var AcpAdapter = class {
|
|
|
2480
2524
|
cwd,
|
|
2481
2525
|
mcpServers: opts.mcpServers,
|
|
2482
2526
|
env: { ...this.launch.env, ...opts.env },
|
|
2527
|
+
// Agent Activity View: forward normalized tool-call events to the bridge-supplied
|
|
2528
|
+
// sink (wired to RelayClient.sendActivityEvent). Absent => no activity surfaced.
|
|
2529
|
+
onActivity: opts.onActivity,
|
|
2483
2530
|
session: this.session ? {
|
|
2484
2531
|
persistedId: rec?.sessionId ?? null,
|
|
2485
2532
|
save: (id) => this.session.save(mergeSessionPointer(this.session.load(), id, cwd))
|
|
@@ -2547,7 +2594,7 @@ var AcpAdapter = class {
|
|
|
2547
2594
|
const result = await client.submit(text);
|
|
2548
2595
|
this.consecutiveRestarts = 0;
|
|
2549
2596
|
const usage = this.usageSource?.forTurn(result.usage);
|
|
2550
|
-
this.turnCbs.forEach((cb) => cb(result.text, usage));
|
|
2597
|
+
this.turnCbs.forEach((cb) => cb(result.text, usage, result.turnId));
|
|
2551
2598
|
return true;
|
|
2552
2599
|
} catch (err) {
|
|
2553
2600
|
if (this.stopped) {
|
|
@@ -2830,7 +2877,7 @@ import http from "http";
|
|
|
2830
2877
|
import os from "os";
|
|
2831
2878
|
import path from "path";
|
|
2832
2879
|
import fs from "fs";
|
|
2833
|
-
import { randomUUID as
|
|
2880
|
+
import { randomUUID as randomUUID3, randomBytes } from "crypto";
|
|
2834
2881
|
var SourceBroker = class {
|
|
2835
2882
|
constructor(channelId, reader) {
|
|
2836
2883
|
this.channelId = channelId;
|
|
@@ -2843,7 +2890,7 @@ var SourceBroker = class {
|
|
|
2843
2890
|
socketPath = "";
|
|
2844
2891
|
async start() {
|
|
2845
2892
|
if (this.server) throw new Error("SourceBroker already started");
|
|
2846
|
-
this.socketPath = path.join(os.tmpdir(), `arp-broker-${
|
|
2893
|
+
this.socketPath = path.join(os.tmpdir(), `arp-broker-${randomUUID3()}.sock`);
|
|
2847
2894
|
try {
|
|
2848
2895
|
fs.unlinkSync(this.socketPath);
|
|
2849
2896
|
} catch {
|
|
@@ -2939,7 +2986,7 @@ async function startBridge(cfg, relay, deps) {
|
|
|
2939
2986
|
const beacon = new ActivityBeacon((state) => relay.sendActivity(channelId, state));
|
|
2940
2987
|
const session = new ChannelSession(
|
|
2941
2988
|
adapter,
|
|
2942
|
-
(text, usage) => void relay.postMessage(channelId, text, usage),
|
|
2989
|
+
(text, usage, turnId) => void relay.postMessage(channelId, text, usage, turnId),
|
|
2943
2990
|
cfg.agentName,
|
|
2944
2991
|
channelId,
|
|
2945
2992
|
{
|
|
@@ -2962,7 +3009,11 @@ async function startBridge(cfg, relay, deps) {
|
|
|
2962
3009
|
]
|
|
2963
3010
|
}];
|
|
2964
3011
|
try {
|
|
2965
|
-
await session.start({
|
|
3012
|
+
await session.start({
|
|
3013
|
+
model: cfg.model,
|
|
3014
|
+
mcpServers,
|
|
3015
|
+
onActivity: (event) => relay.sendActivityEvent(channelId, event)
|
|
3016
|
+
});
|
|
2966
3017
|
} catch (err) {
|
|
2967
3018
|
void broker.stop();
|
|
2968
3019
|
throw err;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snowyroad/arp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Connect your own coding agent (Claude Code, Codex, Gemini, Grok) to an Agent Relay Protocol channel and collaborate with other agents and humans.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"author": "SnowyRoad",
|