@borgee/agents-host 0.2.44 → 0.2.62
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 +24 -27
- package/dist/agents-host.d.ts +27 -5
- package/dist/agents-host.js +266 -201
- package/dist/chat/chat-control-plane.d.ts +3 -0
- package/dist/chat/sdk-chat-control-plane.d.ts +4 -3
- package/dist/chat/sdk-chat-control-plane.js +3 -0
- package/dist/cli.js +1 -5
- package/dist/compatibility-gates.d.ts +4 -0
- package/dist/compatibility-gates.js +20 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.js +21 -0
- package/dist/context/claude-file-brief.d.ts +2 -0
- package/dist/context/claude-file-brief.js +83 -0
- package/dist/context/compaction.d.ts +20 -0
- package/dist/context/compaction.js +59 -0
- package/dist/context/injection.d.ts +58 -7
- package/dist/context/injection.js +370 -36
- package/dist/context/main-session-delegation.d.ts +1 -1
- package/dist/context/projection-strategy.d.ts +24 -0
- package/dist/context/projection-strategy.js +90 -0
- package/dist/context/prompt.d.ts +16 -1
- package/dist/context/prompt.js +464 -26
- package/dist/context/resolved-workspace.d.ts +3 -0
- package/dist/context/resolved-workspace.js +106 -0
- package/dist/context/skill-manual.d.ts +1 -0
- package/dist/context/skill-manual.js +4 -1
- package/dist/context/turn-preparation.d.ts +8 -2
- package/dist/context/turn-preparation.js +64 -14
- package/dist/gateway/localhost-gateway.js +4 -5
- package/dist/local-config.js +11 -1
- package/dist/managed-daemon.js +127 -9
- package/dist/plugin-sdk.js +264 -364
- package/dist/plugin-sdk.js.map +4 -4
- package/dist/policy/copilot-permission.d.ts +1 -0
- package/dist/policy/copilot-permission.js +18 -0
- package/dist/policy/gateway-authorization.js +2 -2
- package/dist/progress-to-activity.d.ts +16 -0
- package/dist/progress-to-activity.js +24 -0
- package/dist/projection-strategy-values.d.ts +4 -0
- package/dist/projection-strategy-values.js +28 -0
- package/dist/providers/acp-progress-collector.d.ts +44 -0
- package/dist/providers/acp-progress-collector.js +130 -0
- package/dist/providers/awaiting-user.d.ts +2 -3
- package/dist/providers/awaiting-user.js +5 -7
- package/dist/providers/claude/activity-metadata.d.ts +14 -0
- package/dist/providers/claude/activity-metadata.js +81 -0
- package/dist/providers/claude/cli-client.d.ts +2 -3
- package/dist/providers/claude/cli-client.js +220 -120
- package/dist/providers/codex/cli-client.d.ts +2 -0
- package/dist/providers/codex/cli-client.js +28 -104
- package/dist/providers/codex/project-doc.js +12 -11
- package/dist/providers/copilot/cli-client.d.ts +1 -1
- package/dist/providers/copilot/cli-client.js +12 -86
- package/dist/providers/create-provider.d.ts +2 -0
- package/dist/providers/create-provider.js +22 -4
- package/dist/state-paths.d.ts +1 -1
- package/dist/state-paths.js +3 -3
- package/dist/task-thread-resolution.d.ts +3 -2
- package/dist/types.d.ts +143 -6
- package/package.json +2 -2
- package/skills/borgee-agent/SKILL.md +12 -4
- package/skills/borgee-agent/references/errors.md +2 -2
- package/skills/borgee-agent/references/task-properties.md +6 -2
- package/dist/durable-cursor-store.d.ts +0 -5
- package/dist/durable-cursor-store.js +0 -7
package/dist/plugin-sdk.js
CHANGED
|
@@ -3224,7 +3224,7 @@ var require_stream = __commonJS({
|
|
|
3224
3224
|
};
|
|
3225
3225
|
duplex._final = function(callback) {
|
|
3226
3226
|
if (ws.readyState === ws.CONNECTING) {
|
|
3227
|
-
ws.once("open", function
|
|
3227
|
+
ws.once("open", function open() {
|
|
3228
3228
|
duplex._final(callback);
|
|
3229
3229
|
});
|
|
3230
3230
|
return;
|
|
@@ -3245,7 +3245,7 @@ var require_stream = __commonJS({
|
|
|
3245
3245
|
};
|
|
3246
3246
|
duplex._write = function(chunk, encoding, callback) {
|
|
3247
3247
|
if (ws.readyState === ws.CONNECTING) {
|
|
3248
|
-
ws.once("open", function
|
|
3248
|
+
ws.once("open", function open() {
|
|
3249
3249
|
duplex._write(chunk, encoding, callback);
|
|
3250
3250
|
});
|
|
3251
3251
|
return;
|
|
@@ -3706,123 +3706,8 @@ var require_websocket_server = __commonJS({
|
|
|
3706
3706
|
}
|
|
3707
3707
|
});
|
|
3708
3708
|
|
|
3709
|
-
// ../sdk/plugin-ts/dist/cursor-store.js
|
|
3710
|
-
import { randomUUID } from "node:crypto";
|
|
3711
|
-
import { mkdir, open, readFile, rename, unlink } from "node:fs/promises";
|
|
3712
|
-
import { dirname } from "node:path";
|
|
3713
|
-
var MemoryCursorStore = class {
|
|
3714
|
-
cursors = /* @__PURE__ */ new Map();
|
|
3715
|
-
async read(agentId) {
|
|
3716
|
-
return this.cursors.get(agentId) ?? -1;
|
|
3717
|
-
}
|
|
3718
|
-
async write(agentId, cursor) {
|
|
3719
|
-
this.cursors.set(agentId, cursor);
|
|
3720
|
-
}
|
|
3721
|
-
};
|
|
3722
|
-
var nodeCursorFileOps = {
|
|
3723
|
-
mkdir: (path) => mkdir(path, { recursive: true }),
|
|
3724
|
-
open: (path, flags, mode) => open(path, flags, mode),
|
|
3725
|
-
rename,
|
|
3726
|
-
unlink
|
|
3727
|
-
};
|
|
3728
|
-
var FileCursorStore = class {
|
|
3729
|
-
resolvePathFn;
|
|
3730
|
-
fs;
|
|
3731
|
-
platform;
|
|
3732
|
-
constructor(options) {
|
|
3733
|
-
this.resolvePathFn = options.resolvePath;
|
|
3734
|
-
this.fs = options.fs ?? nodeCursorFileOps;
|
|
3735
|
-
this.platform = options.platform ?? process.platform;
|
|
3736
|
-
}
|
|
3737
|
-
async read(agentId) {
|
|
3738
|
-
const filePath = this.resolvePathFn(agentId);
|
|
3739
|
-
let raw;
|
|
3740
|
-
try {
|
|
3741
|
-
raw = await readFile(filePath, "utf8");
|
|
3742
|
-
} catch (error) {
|
|
3743
|
-
if (error.code === "ENOENT") {
|
|
3744
|
-
return -1;
|
|
3745
|
-
}
|
|
3746
|
-
throw error;
|
|
3747
|
-
}
|
|
3748
|
-
const parsed = JSON.parse(raw);
|
|
3749
|
-
if (!Number.isSafeInteger(parsed.cursor) || parsed.cursor < 0) {
|
|
3750
|
-
throw new Error(`invalid cursor file: ${filePath}`);
|
|
3751
|
-
}
|
|
3752
|
-
return parsed.cursor;
|
|
3753
|
-
}
|
|
3754
|
-
async write(agentId, cursor) {
|
|
3755
|
-
if (!Number.isSafeInteger(cursor) || cursor < 0) {
|
|
3756
|
-
throw new Error(`invalid cursor: ${cursor}`);
|
|
3757
|
-
}
|
|
3758
|
-
const filePath = this.resolvePathFn(agentId);
|
|
3759
|
-
const parentPath = dirname(filePath);
|
|
3760
|
-
await this.fs.mkdir(parentPath);
|
|
3761
|
-
const temporaryPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
|
|
3762
|
-
let temporaryHandle;
|
|
3763
|
-
try {
|
|
3764
|
-
temporaryHandle = await this.fs.open(temporaryPath, "wx", 384);
|
|
3765
|
-
await temporaryHandle.writeFile(JSON.stringify({ cursor, updatedAt: Date.now() }), {
|
|
3766
|
-
encoding: "utf8"
|
|
3767
|
-
});
|
|
3768
|
-
await temporaryHandle.sync();
|
|
3769
|
-
await temporaryHandle.close();
|
|
3770
|
-
temporaryHandle = void 0;
|
|
3771
|
-
await this.fs.rename(temporaryPath, filePath);
|
|
3772
|
-
await this.syncDirectory(parentPath);
|
|
3773
|
-
} catch (error) {
|
|
3774
|
-
if (temporaryHandle) {
|
|
3775
|
-
try {
|
|
3776
|
-
await temporaryHandle.close();
|
|
3777
|
-
} catch {
|
|
3778
|
-
}
|
|
3779
|
-
}
|
|
3780
|
-
try {
|
|
3781
|
-
await this.fs.unlink(temporaryPath);
|
|
3782
|
-
} catch {
|
|
3783
|
-
}
|
|
3784
|
-
throw error;
|
|
3785
|
-
}
|
|
3786
|
-
}
|
|
3787
|
-
shouldIgnoreDirectorySyncError(error) {
|
|
3788
|
-
const code = error.code;
|
|
3789
|
-
return this.platform === "win32" && (code === "EPERM" || code === "EINVAL");
|
|
3790
|
-
}
|
|
3791
|
-
async syncDirectory(path) {
|
|
3792
|
-
let directoryHandle;
|
|
3793
|
-
try {
|
|
3794
|
-
try {
|
|
3795
|
-
directoryHandle = await this.fs.open(path, "r");
|
|
3796
|
-
} catch (error) {
|
|
3797
|
-
if (!this.shouldIgnoreDirectorySyncError(error)) {
|
|
3798
|
-
throw error;
|
|
3799
|
-
}
|
|
3800
|
-
return;
|
|
3801
|
-
}
|
|
3802
|
-
try {
|
|
3803
|
-
await directoryHandle.sync();
|
|
3804
|
-
} catch (error) {
|
|
3805
|
-
if (!this.shouldIgnoreDirectorySyncError(error)) {
|
|
3806
|
-
throw error;
|
|
3807
|
-
}
|
|
3808
|
-
}
|
|
3809
|
-
} catch (error) {
|
|
3810
|
-
if (directoryHandle) {
|
|
3811
|
-
try {
|
|
3812
|
-
await directoryHandle.close();
|
|
3813
|
-
} catch {
|
|
3814
|
-
}
|
|
3815
|
-
}
|
|
3816
|
-
throw error;
|
|
3817
|
-
}
|
|
3818
|
-
if (directoryHandle) {
|
|
3819
|
-
await directoryHandle.close();
|
|
3820
|
-
}
|
|
3821
|
-
}
|
|
3822
|
-
};
|
|
3823
|
-
|
|
3824
3709
|
// ../sdk/plugin-ts/dist/bpp/bpp-transport.js
|
|
3825
|
-
import { randomUUID
|
|
3710
|
+
import { randomUUID } from "node:crypto";
|
|
3826
3711
|
|
|
3827
3712
|
// ../../node_modules/.pnpm/ws@8.21.1/node_modules/ws/wrapper.mjs
|
|
3828
3713
|
var import_stream = __toESM(require_stream(), 1);
|
|
@@ -3870,31 +3755,29 @@ var CONFIG_ACK_REASONS = /* @__PURE__ */ new Set([
|
|
|
3870
3755
|
]);
|
|
3871
3756
|
var WS_CLOSE_AUTH_FAILED = 4004;
|
|
3872
3757
|
var RESULT_STATUS_OK = "ok";
|
|
3758
|
+
var STOP_TURN_ACTION = "stop_turn";
|
|
3759
|
+
var STOP_TURN_CHANNEL_ID_INVALID = "stop_turn_channel_id_invalid";
|
|
3760
|
+
var SERVER_REQUEST_FAILED = "server_request_failed";
|
|
3873
3761
|
var BppTransport = class {
|
|
3874
3762
|
performTimeoutMs;
|
|
3875
3763
|
heartbeatIntervalMs;
|
|
3876
3764
|
reconnectBaseMs;
|
|
3877
3765
|
reconnectMaxMs;
|
|
3878
3766
|
autoReconnect;
|
|
3879
|
-
resumeAckTimeoutMs;
|
|
3880
3767
|
configApplyTimeoutMs;
|
|
3881
3768
|
ctx;
|
|
3882
3769
|
handlers;
|
|
3883
3770
|
serverRequestHandler;
|
|
3771
|
+
stopTurnHandler;
|
|
3884
3772
|
ws;
|
|
3885
3773
|
pending = /* @__PURE__ */ new Map();
|
|
3886
|
-
legacyAckSockets = /* @__PURE__ */ new WeakSet();
|
|
3887
|
-
legacyReconnectSockets = /* @__PURE__ */ new WeakSet();
|
|
3888
3774
|
closed = false;
|
|
3889
|
-
// ONLINE =
|
|
3890
|
-
//
|
|
3775
|
+
// ONLINE = this socket's handshake has been written and its identity is known.
|
|
3776
|
+
// Outbound semantic actions gate on this rather than on a raw open socket, so a
|
|
3777
|
+
// send issued during a reconnect never races ahead of the handshake.
|
|
3891
3778
|
online = false;
|
|
3892
3779
|
terminal = false;
|
|
3893
|
-
|
|
3894
|
-
replayRemaining = 0;
|
|
3895
|
-
replayHighWater = -1;
|
|
3896
|
-
lastConsumedCursor = -1;
|
|
3897
|
-
cursorFailed = false;
|
|
3780
|
+
inboundFailed = false;
|
|
3898
3781
|
inboundChain = Promise.resolve();
|
|
3899
3782
|
configChain = Promise.resolve();
|
|
3900
3783
|
configAcks = /* @__PURE__ */ new Map();
|
|
@@ -3903,7 +3786,8 @@ var BppTransport = class {
|
|
|
3903
3786
|
reconnectAttempt = 0;
|
|
3904
3787
|
heartbeatTimer;
|
|
3905
3788
|
reconnectTimer;
|
|
3906
|
-
//
|
|
3789
|
+
// The agent id resolved by get_me when the caller supplied none; stamped on
|
|
3790
|
+
// every outbound frame that names an agent.
|
|
3907
3791
|
agentId = "";
|
|
3908
3792
|
constructor(options = {}) {
|
|
3909
3793
|
this.performTimeoutMs = options.performTimeoutMs ?? 3e4;
|
|
@@ -3911,15 +3795,11 @@ var BppTransport = class {
|
|
|
3911
3795
|
this.reconnectBaseMs = options.reconnectBaseMs ?? 500;
|
|
3912
3796
|
this.reconnectMaxMs = options.reconnectMaxMs ?? 3e4;
|
|
3913
3797
|
this.autoReconnect = options.autoReconnect ?? true;
|
|
3914
|
-
this.resumeAckTimeoutMs = options.resumeAckTimeoutMs ?? 5e3;
|
|
3915
3798
|
this.configApplyTimeoutMs = options.configApplyTimeoutMs ?? 5e3;
|
|
3916
3799
|
}
|
|
3917
3800
|
get logger() {
|
|
3918
3801
|
return this.ctx?.logger;
|
|
3919
3802
|
}
|
|
3920
|
-
get cursorStore() {
|
|
3921
|
-
return this.ctx?.cursorStore;
|
|
3922
|
-
}
|
|
3923
3803
|
currentAgentId() {
|
|
3924
3804
|
return this.agentId || this.ctx?.agentId || "";
|
|
3925
3805
|
}
|
|
@@ -3929,6 +3809,9 @@ var BppTransport = class {
|
|
|
3929
3809
|
setServerRequestHandler(handler) {
|
|
3930
3810
|
this.serverRequestHandler = handler;
|
|
3931
3811
|
}
|
|
3812
|
+
setStopTurnHandler(handler) {
|
|
3813
|
+
this.stopTurnHandler = handler;
|
|
3814
|
+
}
|
|
3932
3815
|
getResolvedAgentId() {
|
|
3933
3816
|
return this.currentAgentId();
|
|
3934
3817
|
}
|
|
@@ -3948,8 +3831,6 @@ var BppTransport = class {
|
|
|
3948
3831
|
this.online = false;
|
|
3949
3832
|
this.stopHeartbeat();
|
|
3950
3833
|
this.rejectReconnectWaiters(new BorgeeError("transport not connected", "bpp.not_connected"));
|
|
3951
|
-
if (this.resumeWaiter)
|
|
3952
|
-
this.rejectResumeWaiter(this.resumeWaiter.ws, new BorgeeError("transport closed", "bpp.transport_closed"));
|
|
3953
3834
|
this.rejectAllPending(new BorgeeError("transport closed", "bpp.transport_closed"));
|
|
3954
3835
|
const ws = this.ws;
|
|
3955
3836
|
this.ws = void 0;
|
|
@@ -3974,17 +3855,21 @@ var BppTransport = class {
|
|
|
3974
3855
|
this.sendTyping(action);
|
|
3975
3856
|
return void 0;
|
|
3976
3857
|
}
|
|
3858
|
+
if (action.op === "report_activity") {
|
|
3859
|
+
this.sendActivity(action);
|
|
3860
|
+
return void 0;
|
|
3861
|
+
}
|
|
3977
3862
|
const deadline = Date.now() + this.performTimeoutMs;
|
|
3978
3863
|
if (this.closed || this.terminal) {
|
|
3979
3864
|
throw new BorgeeError("transport not connected", "bpp.not_connected");
|
|
3980
3865
|
}
|
|
3981
|
-
if (opts?.
|
|
3866
|
+
if (opts?.handshake) {
|
|
3982
3867
|
if (!this.isOpen())
|
|
3983
3868
|
throw new BorgeeError("transport not connected", "bpp.not_connected");
|
|
3984
3869
|
} else if (!this.online) {
|
|
3985
3870
|
await this.waitUntilOnline(action.op, deadline);
|
|
3986
3871
|
}
|
|
3987
|
-
const nonce =
|
|
3872
|
+
const nonce = randomUUID();
|
|
3988
3873
|
const frame = {
|
|
3989
3874
|
type: "semantic_action",
|
|
3990
3875
|
agent_id: this.currentAgentId(),
|
|
@@ -4004,7 +3889,7 @@ var BppTransport = class {
|
|
|
4004
3889
|
}
|
|
4005
3890
|
// ---- socket 生命周期 ----
|
|
4006
3891
|
// Transition the given socket to ONLINE. Bails if the socket is stale (a reconnect replaced it),
|
|
4007
|
-
// so a
|
|
3892
|
+
// so a handshake completing on a prior socket cannot flip online across a reconnect.
|
|
4008
3893
|
goOnline(source) {
|
|
4009
3894
|
if (!source || source !== this.ws)
|
|
4010
3895
|
return;
|
|
@@ -4015,7 +3900,7 @@ var BppTransport = class {
|
|
|
4015
3900
|
isOpen() {
|
|
4016
3901
|
return this.ws !== void 0 && this.ws.readyState === import_websocket.default.OPEN;
|
|
4017
3902
|
}
|
|
4018
|
-
openSocket(
|
|
3903
|
+
openSocket() {
|
|
4019
3904
|
const ctx = this.ctx;
|
|
4020
3905
|
if (!ctx)
|
|
4021
3906
|
throw new BorgeeError("connect() called without context", "bpp.no_context");
|
|
@@ -4043,7 +3928,7 @@ var BppTransport = class {
|
|
|
4043
3928
|
settled = true;
|
|
4044
3929
|
reject(error);
|
|
4045
3930
|
}
|
|
4046
|
-
}
|
|
3931
|
+
});
|
|
4047
3932
|
});
|
|
4048
3933
|
ws.on("message", (data) => {
|
|
4049
3934
|
this.onMessage(rawToString(data), ws);
|
|
@@ -4056,11 +3941,7 @@ var BppTransport = class {
|
|
|
4056
3941
|
}
|
|
4057
3942
|
});
|
|
4058
3943
|
ws.on("close", (code, reason) => {
|
|
4059
|
-
const legacyReconnect = this.legacyReconnectSockets.has(ws);
|
|
4060
|
-
if (legacyReconnect)
|
|
4061
|
-
this.legacyReconnectSockets.delete(ws);
|
|
4062
3944
|
connectionAbort.abort();
|
|
4063
|
-
this.rejectResumeWaiter(ws, new BorgeeError("ws closed before resume acknowledgement", "bpp.resume_incomplete"));
|
|
4064
3945
|
const wasCurrent = this.ws === ws;
|
|
4065
3946
|
if (wasCurrent) {
|
|
4066
3947
|
this.online = false;
|
|
@@ -4077,11 +3958,11 @@ var BppTransport = class {
|
|
|
4077
3958
|
if (wasCurrent) {
|
|
4078
3959
|
this.rejectAllPending(authFailed ? new BorgeeError("authentication failed: invalid or revoked API key", "bpp.auth_failed") : new BorgeeError("connection lost", "bpp.connection_lost"));
|
|
4079
3960
|
}
|
|
4080
|
-
if (!settled
|
|
3961
|
+
if (!settled) {
|
|
4081
3962
|
settled = true;
|
|
4082
|
-
reject(authFailed ? new BorgeeError("authentication failed: invalid or revoked API key", "bpp.auth_failed") : new BorgeeError(opened ? "ws closed before
|
|
3963
|
+
reject(authFailed ? new BorgeeError("authentication failed: invalid or revoked API key", "bpp.auth_failed") : new BorgeeError(opened ? "ws closed before the handshake was written" : "ws closed before open", opened ? "bpp.handshake_incomplete" : "bpp.connect_failed"));
|
|
4083
3964
|
}
|
|
4084
|
-
if (authFailed ||
|
|
3965
|
+
if (authFailed || !wasCurrent) {
|
|
4085
3966
|
if (authFailed && wasCurrent) {
|
|
4086
3967
|
this.rejectReconnectWaiters(new BorgeeError("authentication failed: invalid or revoked API key", "bpp.auth_failed"));
|
|
4087
3968
|
}
|
|
@@ -4095,7 +3976,7 @@ var BppTransport = class {
|
|
|
4095
3976
|
});
|
|
4096
3977
|
});
|
|
4097
3978
|
}
|
|
4098
|
-
async onOpen(ws, resolve, reject
|
|
3979
|
+
async onOpen(ws, resolve, reject) {
|
|
4099
3980
|
const ctx = this.ctx;
|
|
4100
3981
|
if (!ctx)
|
|
4101
3982
|
return;
|
|
@@ -4109,155 +3990,21 @@ var BppTransport = class {
|
|
|
4109
3990
|
this.sendTo(ws, connectFrame);
|
|
4110
3991
|
try {
|
|
4111
3992
|
if (!this.currentAgentId()) {
|
|
4112
|
-
const identity = await this.perform({ op: "get_me" }, {
|
|
3993
|
+
const identity = await this.perform({ op: "get_me" }, { handshake: true });
|
|
4113
3994
|
const resolved = identity && typeof identity === "object" ? identity.id : "";
|
|
4114
3995
|
if (!resolved)
|
|
4115
3996
|
throw new BorgeeError("authenticated agent identity could not be resolved", "bpp.identity_unresolved");
|
|
4116
3997
|
this.agentId = resolved;
|
|
4117
3998
|
}
|
|
4118
|
-
|
|
4119
|
-
this.
|
|
4120
|
-
|
|
4121
|
-
this.sendLegacyReconnect(ws, Math.max(cursor, 0), resolve);
|
|
4122
|
-
return;
|
|
4123
|
-
}
|
|
4124
|
-
this.sendResumeRequest(ws, Math.max(cursor, 0), resolve, reject);
|
|
3999
|
+
this.startHeartbeat();
|
|
4000
|
+
this.goOnline(ws);
|
|
4001
|
+
resolve();
|
|
4125
4002
|
} catch (error) {
|
|
4126
|
-
const failure = error instanceof BorgeeError ? error : new BorgeeError(`
|
|
4003
|
+
const failure = error instanceof BorgeeError ? error : new BorgeeError(`agent identity handshake failed: ${String(error)}`, "bpp.identity_unresolved");
|
|
4127
4004
|
reject(failure);
|
|
4128
4005
|
this.failTerminal(failure, ws);
|
|
4129
4006
|
}
|
|
4130
4007
|
}
|
|
4131
|
-
sendResumeRequest(ws, sinceCursor, resolve, reject) {
|
|
4132
|
-
const ctx = this.ctx;
|
|
4133
|
-
if (!ctx || ws !== this.ws)
|
|
4134
|
-
return;
|
|
4135
|
-
const replayMode = ctx.replayMode ?? "latest_n";
|
|
4136
|
-
const frame = {
|
|
4137
|
-
type: "session.resume",
|
|
4138
|
-
replay_mode: replayMode,
|
|
4139
|
-
since_cursor: sinceCursor,
|
|
4140
|
-
...replayMode === "latest_n" ? { latest_n: ctx.replayLatestN ?? 200 } : {}
|
|
4141
|
-
};
|
|
4142
|
-
this.handlers?.onStateChange({ status: "resuming" });
|
|
4143
|
-
const priorWaiter = this.resumeWaiter;
|
|
4144
|
-
if (priorWaiter?.ws === ws) {
|
|
4145
|
-
clearTimeout(priorWaiter.timer);
|
|
4146
|
-
}
|
|
4147
|
-
const timeoutMs = ctx.resumeAckTimeoutMs ?? this.resumeAckTimeoutMs;
|
|
4148
|
-
let waiter;
|
|
4149
|
-
const timer = setTimeout(() => {
|
|
4150
|
-
if (this.resumeWaiter !== waiter || this.ws !== ws)
|
|
4151
|
-
return;
|
|
4152
|
-
this.resumeWaiter = void 0;
|
|
4153
|
-
if (this.retryWithLegacyReconnect(ws, resolve, reject))
|
|
4154
|
-
return;
|
|
4155
|
-
const error = new BorgeeError("session.resume_ack timed out", "bpp.resume_ack_timeout");
|
|
4156
|
-
reject(error);
|
|
4157
|
-
this.failTerminal(error, ws);
|
|
4158
|
-
}, timeoutMs);
|
|
4159
|
-
waiter = { ws, resolve, reject, timer };
|
|
4160
|
-
this.resumeWaiter = waiter;
|
|
4161
|
-
this.send(frame);
|
|
4162
|
-
}
|
|
4163
|
-
sendLegacyReconnect(ws, sinceCursor, resolve) {
|
|
4164
|
-
const ctx = this.ctx;
|
|
4165
|
-
if (!ctx || ws !== this.ws || ws.readyState !== import_websocket.default.OPEN)
|
|
4166
|
-
return;
|
|
4167
|
-
this.legacyAckSockets.add(ws);
|
|
4168
|
-
const now = Date.now();
|
|
4169
|
-
const frame = {
|
|
4170
|
-
type: "reconnect_handshake",
|
|
4171
|
-
plugin_id: ctx.pluginId ?? "",
|
|
4172
|
-
agent_id: this.currentAgentId(),
|
|
4173
|
-
last_known_cursor: sinceCursor,
|
|
4174
|
-
disconnect_at: now,
|
|
4175
|
-
reconnect_at: now
|
|
4176
|
-
};
|
|
4177
|
-
this.replayRemaining = 0;
|
|
4178
|
-
this.replayHighWater = Math.max(this.replayHighWater, sinceCursor);
|
|
4179
|
-
this.sendTo(ws, frame);
|
|
4180
|
-
resolve();
|
|
4181
|
-
this.startHeartbeat();
|
|
4182
|
-
this.goOnline(ws);
|
|
4183
|
-
}
|
|
4184
|
-
retryWithLegacyReconnect(ws, resolve, reject) {
|
|
4185
|
-
if (ws !== this.ws || ws.readyState !== import_websocket.default.OPEN)
|
|
4186
|
-
return false;
|
|
4187
|
-
this.legacyReconnectSockets.add(ws);
|
|
4188
|
-
try {
|
|
4189
|
-
ws.close();
|
|
4190
|
-
} catch {
|
|
4191
|
-
this.legacyReconnectSockets.delete(ws);
|
|
4192
|
-
return false;
|
|
4193
|
-
}
|
|
4194
|
-
void this.openSocket("legacy").then(resolve).catch(reject);
|
|
4195
|
-
return true;
|
|
4196
|
-
}
|
|
4197
|
-
finishReplayIfReady(source) {
|
|
4198
|
-
if (this.replayRemaining !== 0)
|
|
4199
|
-
return Promise.resolve();
|
|
4200
|
-
const highWater = this.replayHighWater;
|
|
4201
|
-
if (highWater <= this.lastConsumedCursor) {
|
|
4202
|
-
this.goOnline(source);
|
|
4203
|
-
return Promise.resolve();
|
|
4204
|
-
}
|
|
4205
|
-
return this.persistCursor(highWater).then(() => {
|
|
4206
|
-
this.goOnline(source);
|
|
4207
|
-
});
|
|
4208
|
-
}
|
|
4209
|
-
handleResumeAck(frame, source) {
|
|
4210
|
-
const waiter = this.resumeWaiter;
|
|
4211
|
-
const compatibilityAck = source === this.ws && this.legacyAckSockets.has(source) && (!waiter || waiter.ws !== source);
|
|
4212
|
-
if (!compatibilityAck && (!waiter || waiter.ws !== source || source !== this.ws))
|
|
4213
|
-
return;
|
|
4214
|
-
if (waiter?.ws === source)
|
|
4215
|
-
clearTimeout(waiter.timer);
|
|
4216
|
-
if (!Number.isSafeInteger(frame.count) || frame.count < 0 || frame.count > 500 || !Number.isSafeInteger(frame.high_water) || frame.high_water < 0) {
|
|
4217
|
-
if (waiter?.ws === source)
|
|
4218
|
-
this.resumeWaiter = void 0;
|
|
4219
|
-
if (compatibilityAck)
|
|
4220
|
-
this.legacyAckSockets.delete(source);
|
|
4221
|
-
const error = new BorgeeError("invalid session.resume_ack bounds", "bpp.resume_ack_invalid");
|
|
4222
|
-
if (waiter?.ws === source)
|
|
4223
|
-
waiter.reject(error);
|
|
4224
|
-
this.failTerminal(error, source);
|
|
4225
|
-
return;
|
|
4226
|
-
}
|
|
4227
|
-
if (frame.reset) {
|
|
4228
|
-
if (waiter?.ws === source)
|
|
4229
|
-
this.resumeWaiter = void 0;
|
|
4230
|
-
void this.resetCursor(frame.high_water).then(() => {
|
|
4231
|
-
if (compatibilityAck)
|
|
4232
|
-
this.legacyAckSockets.delete(source);
|
|
4233
|
-
this.replayRemaining = 0;
|
|
4234
|
-
this.replayHighWater = frame.high_water;
|
|
4235
|
-
waiter?.resolve();
|
|
4236
|
-
this.startHeartbeat();
|
|
4237
|
-
this.inboundChain = this.inboundChain.then(() => this.finishReplayIfReady(source)).catch((error) => {
|
|
4238
|
-
this.failTerminal(this.cursorFailure(error), source);
|
|
4239
|
-
});
|
|
4240
|
-
}).catch((error) => {
|
|
4241
|
-
const failure = this.cursorFailure(error);
|
|
4242
|
-
waiter?.reject(failure);
|
|
4243
|
-
this.failTerminal(failure, source);
|
|
4244
|
-
});
|
|
4245
|
-
return;
|
|
4246
|
-
}
|
|
4247
|
-
if (waiter?.ws === source)
|
|
4248
|
-
this.resumeWaiter = void 0;
|
|
4249
|
-
if (compatibilityAck)
|
|
4250
|
-
this.legacyAckSockets.delete(source);
|
|
4251
|
-
this.replayRemaining = frame.count;
|
|
4252
|
-
this.replayHighWater = frame.high_water;
|
|
4253
|
-
waiter?.resolve();
|
|
4254
|
-
this.startHeartbeat();
|
|
4255
|
-
if (frame.count === 0) {
|
|
4256
|
-
this.inboundChain = this.inboundChain.then(() => this.finishReplayIfReady(source)).catch((error) => {
|
|
4257
|
-
this.failTerminal(this.cursorFailure(error), source);
|
|
4258
|
-
});
|
|
4259
|
-
}
|
|
4260
|
-
}
|
|
4261
4008
|
scheduleReconnect() {
|
|
4262
4009
|
if (this.closed || this.terminal || !this.autoReconnect)
|
|
4263
4010
|
return;
|
|
@@ -4312,13 +4059,7 @@ var BppTransport = class {
|
|
|
4312
4059
|
void this.handleServerRequest(env);
|
|
4313
4060
|
break;
|
|
4314
4061
|
case "inbound_message":
|
|
4315
|
-
this.handleInbound(env
|
|
4316
|
-
break;
|
|
4317
|
-
case "session.resume_ack":
|
|
4318
|
-
this.handleResumeAck(env, source);
|
|
4319
|
-
break;
|
|
4320
|
-
case "session.summary":
|
|
4321
|
-
this.handleSummary(env, source);
|
|
4062
|
+
this.handleInbound(env);
|
|
4322
4063
|
break;
|
|
4323
4064
|
case "semantic_action_result":
|
|
4324
4065
|
this.handleActionResult(env);
|
|
@@ -4337,40 +4078,14 @@ var BppTransport = class {
|
|
|
4337
4078
|
break;
|
|
4338
4079
|
}
|
|
4339
4080
|
}
|
|
4340
|
-
handleInbound(frame
|
|
4341
|
-
this.inboundChain = this.inboundChain.then(
|
|
4342
|
-
if (this.
|
|
4343
|
-
return;
|
|
4344
|
-
if (!Number.isSafeInteger(frame.cursor) || frame.cursor <= this.lastConsumedCursor) {
|
|
4345
|
-
throw new BorgeeError(`non-monotonic inbound cursor ${frame.cursor}`, "bpp.cursor_non_monotonic");
|
|
4346
|
-
}
|
|
4347
|
-
const event = mapInbound(frame);
|
|
4348
|
-
this.handlers?.onInbound(event);
|
|
4349
|
-
await this.persistCursor(frame.cursor);
|
|
4350
|
-
if (this.replayRemaining > 0) {
|
|
4351
|
-
this.replayRemaining -= 1;
|
|
4352
|
-
await this.finishReplayIfReady(source);
|
|
4353
|
-
}
|
|
4354
|
-
}).catch((error) => {
|
|
4355
|
-
this.cursorFailed = true;
|
|
4356
|
-
this.failTerminal(this.cursorFailure(error), this.ws);
|
|
4357
|
-
});
|
|
4358
|
-
}
|
|
4359
|
-
handleSummary(frame, source) {
|
|
4360
|
-
this.inboundChain = this.inboundChain.then(async () => {
|
|
4361
|
-
if (this.cursorFailed)
|
|
4081
|
+
handleInbound(frame) {
|
|
4082
|
+
this.inboundChain = this.inboundChain.then(() => {
|
|
4083
|
+
if (this.inboundFailed)
|
|
4362
4084
|
return;
|
|
4363
|
-
|
|
4364
|
-
throw new BorgeeError(`non-monotonic summary cursor ${frame.cursor}`, "bpp.cursor_non_monotonic");
|
|
4365
|
-
this.handlers?.onReplaySummary({ cursor: frame.cursor, missedCount: frame.missed_count, sinceCursor: frame.since_cursor, throughCursor: frame.through_cursor, summary: frame.summary });
|
|
4366
|
-
await this.persistCursor(frame.cursor);
|
|
4367
|
-
if (this.replayRemaining > 0) {
|
|
4368
|
-
this.replayRemaining -= 1;
|
|
4369
|
-
await this.finishReplayIfReady(source);
|
|
4370
|
-
}
|
|
4085
|
+
this.handlers?.onInbound(mapInbound(frame));
|
|
4371
4086
|
}).catch((error) => {
|
|
4372
|
-
this.
|
|
4373
|
-
this.failTerminal(this.
|
|
4087
|
+
this.inboundFailed = true;
|
|
4088
|
+
this.failTerminal(this.inboundFailure(error), this.ws);
|
|
4374
4089
|
});
|
|
4375
4090
|
}
|
|
4376
4091
|
handleActionResult(frame) {
|
|
@@ -4380,7 +4095,7 @@ var BppTransport = class {
|
|
|
4380
4095
|
this.pending.delete(frame.nonce);
|
|
4381
4096
|
clearTimeout(p.timer);
|
|
4382
4097
|
if (frame.status === RESULT_STATUS_OK) {
|
|
4383
|
-
const result = decodeActionResult(p.op, frame.payload
|
|
4098
|
+
const result = decodeActionResult(p.op, frame.payload);
|
|
4384
4099
|
if (p.op === "get_me" && result && typeof result === "object") {
|
|
4385
4100
|
const id = result.id;
|
|
4386
4101
|
if (id)
|
|
@@ -4509,6 +4224,10 @@ var BppTransport = class {
|
|
|
4509
4224
|
return;
|
|
4510
4225
|
const data = env.data ?? {};
|
|
4511
4226
|
const action = typeof data.action === "string" ? data.action : "";
|
|
4227
|
+
if (action === STOP_TURN_ACTION) {
|
|
4228
|
+
await this.answerStopTurn(id, data);
|
|
4229
|
+
return;
|
|
4230
|
+
}
|
|
4512
4231
|
if (!this.serverRequestHandler) {
|
|
4513
4232
|
this.send({ type: "response", id, error: "no_server_request_handler" });
|
|
4514
4233
|
return;
|
|
@@ -4520,6 +4239,40 @@ var BppTransport = class {
|
|
|
4520
4239
|
this.send({ type: "response", id, error: err instanceof Error ? err.message : String(err) });
|
|
4521
4240
|
}
|
|
4522
4241
|
}
|
|
4242
|
+
// Precedence: the specific handler wins, an onServerRequest callback gets
|
|
4243
|
+
// stop_turn only while no specific one is registered, and with neither the
|
|
4244
|
+
// SDK answers the request itself. That order is what lets a plugin that
|
|
4245
|
+
// already switches on the action name inside one callback keep working
|
|
4246
|
+
// unchanged, and lets it move onto onStopTurn one action at a time.
|
|
4247
|
+
async answerStopTurn(id, data) {
|
|
4248
|
+
const channelId = data.channel_id;
|
|
4249
|
+
if (typeof channelId !== "string" || channelId === "") {
|
|
4250
|
+
this.send({ type: "response", id, error: STOP_TURN_CHANNEL_ID_INVALID });
|
|
4251
|
+
return;
|
|
4252
|
+
}
|
|
4253
|
+
const specific = this.stopTurnHandler;
|
|
4254
|
+
const generic = this.serverRequestHandler;
|
|
4255
|
+
try {
|
|
4256
|
+
const answer = specific ? await specific(channelId) : generic ? await generic(STOP_TURN_ACTION, data) : { aborted: false };
|
|
4257
|
+
this.send({ type: "response", id, data: this.asStopTurnResult(answer) });
|
|
4258
|
+
} catch (err) {
|
|
4259
|
+
this.logger?.warn("bpp.stop_turn_handler_failed", err);
|
|
4260
|
+
this.send({ type: "response", id, error: SERVER_REQUEST_FAILED });
|
|
4261
|
+
}
|
|
4262
|
+
}
|
|
4263
|
+
// The rail's answer is one boolean and nothing else, so that is what goes on
|
|
4264
|
+
// the wire whatever the handler returned. A callback switching on action names
|
|
4265
|
+
// answers actions it does not implement with something else entirely — and
|
|
4266
|
+
// "the callback does not implement stopping" is one of the things false
|
|
4267
|
+
// already covers, so it is reported as such rather than as a broken agent.
|
|
4268
|
+
asStopTurnResult(answer) {
|
|
4269
|
+
const aborted = answer?.aborted;
|
|
4270
|
+
if (typeof aborted !== "boolean") {
|
|
4271
|
+
this.logger?.warn("bpp.stop_turn_answer_unusable", answer);
|
|
4272
|
+
return { aborted: false };
|
|
4273
|
+
}
|
|
4274
|
+
return { aborted };
|
|
4275
|
+
}
|
|
4523
4276
|
// ---- task 生命周期上行 ----
|
|
4524
4277
|
sendTaskStarted(action) {
|
|
4525
4278
|
const frame = {
|
|
@@ -4544,6 +4297,59 @@ var BppTransport = class {
|
|
|
4544
4297
|
};
|
|
4545
4298
|
this.send(frame);
|
|
4546
4299
|
}
|
|
4300
|
+
// sendActivity flattens the four-shape union onto one frame. The union is
|
|
4301
|
+
// how a producer says which shape it is reporting; the wire puts the
|
|
4302
|
+
// discriminator beside its payload with no wrapper object, matching both the
|
|
4303
|
+
// protocol this relays and inbound_message's own `kind`.
|
|
4304
|
+
//
|
|
4305
|
+
// The frame names no agent: identity is stamped by the server from the
|
|
4306
|
+
// authenticated connection, so nothing here can report as another agent.
|
|
4307
|
+
sendActivity(action) {
|
|
4308
|
+
const frame = {
|
|
4309
|
+
type: "agent_activity",
|
|
4310
|
+
channel_id: action.channelId,
|
|
4311
|
+
sequence: action.sequence,
|
|
4312
|
+
shape: action.activity.shape,
|
|
4313
|
+
activity_id: "",
|
|
4314
|
+
label: "",
|
|
4315
|
+
description: "",
|
|
4316
|
+
kind: "",
|
|
4317
|
+
status: "",
|
|
4318
|
+
detail: "",
|
|
4319
|
+
parent_id: "",
|
|
4320
|
+
subagent: false,
|
|
4321
|
+
reason: "",
|
|
4322
|
+
stream: "",
|
|
4323
|
+
text: "",
|
|
4324
|
+
turn_state: ""
|
|
4325
|
+
};
|
|
4326
|
+
switch (action.activity.shape) {
|
|
4327
|
+
case "activity":
|
|
4328
|
+
frame.activity_id = action.activity.id;
|
|
4329
|
+
frame.label = action.activity.label ?? "";
|
|
4330
|
+
frame.description = action.activity.description ?? "";
|
|
4331
|
+
frame.kind = action.activity.kind ?? "";
|
|
4332
|
+
frame.status = action.activity.status ?? "";
|
|
4333
|
+
frame.detail = action.activity.detail ?? "";
|
|
4334
|
+
frame.parent_id = action.activity.parentId ?? "";
|
|
4335
|
+
frame.subagent = action.activity.subagent ?? false;
|
|
4336
|
+
frame.reason = action.activity.reason ?? "";
|
|
4337
|
+
if (action.activity.paths)
|
|
4338
|
+
frame.paths = action.activity.paths;
|
|
4339
|
+
break;
|
|
4340
|
+
case "plan":
|
|
4341
|
+
frame.plan = action.activity.entries.map((entry) => ({ label: entry.label, status: entry.status }));
|
|
4342
|
+
break;
|
|
4343
|
+
case "output":
|
|
4344
|
+
frame.stream = action.activity.stream;
|
|
4345
|
+
frame.text = action.activity.text;
|
|
4346
|
+
break;
|
|
4347
|
+
case "turn":
|
|
4348
|
+
frame.turn_state = action.activity.state;
|
|
4349
|
+
break;
|
|
4350
|
+
}
|
|
4351
|
+
this.send(frame);
|
|
4352
|
+
}
|
|
4547
4353
|
sendTyping(action) {
|
|
4548
4354
|
this.send({ type: "typing", channel_id: action.channelId });
|
|
4549
4355
|
}
|
|
@@ -4566,28 +4372,10 @@ var BppTransport = class {
|
|
|
4566
4372
|
this.logger?.warn("bpp.send_failed", err);
|
|
4567
4373
|
}
|
|
4568
4374
|
}
|
|
4569
|
-
|
|
4570
|
-
if (cursor <= this.lastConsumedCursor)
|
|
4571
|
-
return;
|
|
4572
|
-
await this.cursorStore?.write(this.currentAgentId(), cursor);
|
|
4573
|
-
this.lastConsumedCursor = cursor;
|
|
4574
|
-
}
|
|
4575
|
-
async resetCursor(cursor) {
|
|
4576
|
-
await this.cursorStore?.write(this.currentAgentId(), cursor);
|
|
4577
|
-
this.lastConsumedCursor = cursor;
|
|
4578
|
-
}
|
|
4579
|
-
cursorFailure(error) {
|
|
4375
|
+
inboundFailure(error) {
|
|
4580
4376
|
if (error instanceof BorgeeError)
|
|
4581
4377
|
return error;
|
|
4582
|
-
return new BorgeeError(`
|
|
4583
|
-
}
|
|
4584
|
-
rejectResumeWaiter(ws, error) {
|
|
4585
|
-
const waiter = this.resumeWaiter;
|
|
4586
|
-
if (!waiter || waiter.ws !== ws)
|
|
4587
|
-
return;
|
|
4588
|
-
clearTimeout(waiter.timer);
|
|
4589
|
-
this.resumeWaiter = void 0;
|
|
4590
|
-
waiter.reject(error);
|
|
4378
|
+
return new BorgeeError(`inbound dispatch failed: ${String(error)}`, "bpp.inbound_dispatch_failed");
|
|
4591
4379
|
}
|
|
4592
4380
|
failTerminal(error, ws) {
|
|
4593
4381
|
if (this.terminal)
|
|
@@ -4595,8 +4383,6 @@ var BppTransport = class {
|
|
|
4595
4383
|
this.terminal = true;
|
|
4596
4384
|
this.online = false;
|
|
4597
4385
|
this.handlers?.onStateChange({ status: "error", reason: "unknown", code: error.code });
|
|
4598
|
-
if (ws)
|
|
4599
|
-
this.rejectResumeWaiter(ws, error);
|
|
4600
4386
|
this.rejectReconnectWaiters(error);
|
|
4601
4387
|
this.rejectAllPending(error);
|
|
4602
4388
|
try {
|
|
@@ -4739,11 +4525,11 @@ function encodeActionPayload(action) {
|
|
|
4739
4525
|
return {};
|
|
4740
4526
|
}
|
|
4741
4527
|
}
|
|
4742
|
-
function decodeActionResult(op, payloadJSON
|
|
4528
|
+
function decodeActionResult(op, payloadJSON) {
|
|
4743
4529
|
const p = safeParseJSON(payloadJSON);
|
|
4744
4530
|
switch (op) {
|
|
4745
4531
|
case "send_message":
|
|
4746
|
-
return { messageId: String(p.message_id ?? "")
|
|
4532
|
+
return { messageId: String(p.message_id ?? "") };
|
|
4747
4533
|
case "create_dm":
|
|
4748
4534
|
return { channelId: String(p.channel_id ?? "") };
|
|
4749
4535
|
case "get_me":
|
|
@@ -4856,7 +4642,6 @@ function mapInbound(frame) {
|
|
|
4856
4642
|
const kind = frame.kind;
|
|
4857
4643
|
const base = {
|
|
4858
4644
|
kind,
|
|
4859
|
-
cursor: frame.cursor,
|
|
4860
4645
|
channelId: frame.channel_id,
|
|
4861
4646
|
channelType: frame.channel_type,
|
|
4862
4647
|
authorName: frame.author_name,
|
|
@@ -4931,6 +4716,102 @@ function rawToString(data) {
|
|
|
4931
4716
|
return String(data);
|
|
4932
4717
|
}
|
|
4933
4718
|
|
|
4719
|
+
// ../sdk/plugin-ts/dist/activity-reporter.js
|
|
4720
|
+
var DEFAULT_THROTTLE_MS = 150;
|
|
4721
|
+
var OUTPUT_TAIL_CHARS = 2e3;
|
|
4722
|
+
var defaultScheduler = (callback, delayMs) => {
|
|
4723
|
+
const timer = setTimeout(callback, delayMs);
|
|
4724
|
+
timer.unref?.();
|
|
4725
|
+
return () => clearTimeout(timer);
|
|
4726
|
+
};
|
|
4727
|
+
function outputTail(text) {
|
|
4728
|
+
if (text.length <= OUTPUT_TAIL_CHARS) {
|
|
4729
|
+
return text;
|
|
4730
|
+
}
|
|
4731
|
+
const tail = text.slice(text.length - OUTPUT_TAIL_CHARS);
|
|
4732
|
+
return /^[\uDC00-\uDFFF]/.test(tail) ? tail.slice(1) : tail;
|
|
4733
|
+
}
|
|
4734
|
+
function throttleKey(activity) {
|
|
4735
|
+
switch (activity.shape) {
|
|
4736
|
+
case "activity":
|
|
4737
|
+
return `activity:${activity.id}`;
|
|
4738
|
+
case "plan":
|
|
4739
|
+
return "plan";
|
|
4740
|
+
case "output":
|
|
4741
|
+
return `output:${activity.stream}`;
|
|
4742
|
+
}
|
|
4743
|
+
}
|
|
4744
|
+
var TurnActivityReporter = class {
|
|
4745
|
+
options;
|
|
4746
|
+
windows = /* @__PURE__ */ new Map();
|
|
4747
|
+
throttleMs;
|
|
4748
|
+
scheduler;
|
|
4749
|
+
ended = false;
|
|
4750
|
+
constructor(options) {
|
|
4751
|
+
this.options = options;
|
|
4752
|
+
this.throttleMs = options.throttleMs ?? DEFAULT_THROTTLE_MS;
|
|
4753
|
+
this.scheduler = options.scheduler ?? defaultScheduler;
|
|
4754
|
+
}
|
|
4755
|
+
start() {
|
|
4756
|
+
this.report({ shape: "turn", state: "started" });
|
|
4757
|
+
}
|
|
4758
|
+
progress(activity) {
|
|
4759
|
+
if (this.ended) {
|
|
4760
|
+
return;
|
|
4761
|
+
}
|
|
4762
|
+
this.offer(activity.shape === "output" ? { ...activity, text: outputTail(activity.text) } : activity);
|
|
4763
|
+
}
|
|
4764
|
+
/**
|
|
4765
|
+
* Ends the turn. What the windows still hold goes first, so the last thing a
|
|
4766
|
+
* reader sees of a turn is that turn's own last word rather than whatever
|
|
4767
|
+
* happened to fall outside a window.
|
|
4768
|
+
*/
|
|
4769
|
+
end() {
|
|
4770
|
+
if (this.ended) {
|
|
4771
|
+
return;
|
|
4772
|
+
}
|
|
4773
|
+
this.ended = true;
|
|
4774
|
+
this.drain();
|
|
4775
|
+
this.report({ shape: "turn", state: "ended" });
|
|
4776
|
+
}
|
|
4777
|
+
offer(activity) {
|
|
4778
|
+
const key = throttleKey(activity);
|
|
4779
|
+
const open = this.windows.get(key);
|
|
4780
|
+
if (open) {
|
|
4781
|
+
open.latest = activity;
|
|
4782
|
+
return;
|
|
4783
|
+
}
|
|
4784
|
+
this.report(activity);
|
|
4785
|
+
this.openWindow(key);
|
|
4786
|
+
}
|
|
4787
|
+
openWindow(key) {
|
|
4788
|
+
const window = { latest: null, cancel: null };
|
|
4789
|
+
window.cancel = this.scheduler(() => {
|
|
4790
|
+
this.windows.delete(key);
|
|
4791
|
+
if (window.latest) {
|
|
4792
|
+
this.offer(window.latest);
|
|
4793
|
+
}
|
|
4794
|
+
}, this.throttleMs);
|
|
4795
|
+
this.windows.set(key, window);
|
|
4796
|
+
}
|
|
4797
|
+
drain() {
|
|
4798
|
+
const held = [...this.windows.values()];
|
|
4799
|
+
this.windows.clear();
|
|
4800
|
+
for (const window of held) {
|
|
4801
|
+
window.cancel?.();
|
|
4802
|
+
if (window.latest) {
|
|
4803
|
+
this.report(window.latest);
|
|
4804
|
+
}
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4807
|
+
report(activity) {
|
|
4808
|
+
if (this.options.canReport && !this.options.canReport()) {
|
|
4809
|
+
return;
|
|
4810
|
+
}
|
|
4811
|
+
this.options.deliver({ channelId: this.options.channelId, activity });
|
|
4812
|
+
}
|
|
4813
|
+
};
|
|
4814
|
+
|
|
4934
4815
|
// ../sdk/plugin-ts/dist/client.js
|
|
4935
4816
|
var noopLogger = {
|
|
4936
4817
|
debug() {
|
|
@@ -4946,21 +4827,19 @@ var Client = class {
|
|
|
4946
4827
|
opts;
|
|
4947
4828
|
t;
|
|
4948
4829
|
logger;
|
|
4949
|
-
cursorStore;
|
|
4950
4830
|
_agentId;
|
|
4831
|
+
activitySequence = 0;
|
|
4951
4832
|
_state = { status: "connecting" };
|
|
4952
4833
|
listeners = {
|
|
4953
4834
|
message: /* @__PURE__ */ new Set(),
|
|
4954
4835
|
configUpdate: /* @__PURE__ */ new Set(),
|
|
4955
4836
|
permissionDenied: /* @__PURE__ */ new Set(),
|
|
4956
|
-
connectionState: /* @__PURE__ */ new Set()
|
|
4957
|
-
replaySummary: /* @__PURE__ */ new Set()
|
|
4837
|
+
connectionState: /* @__PURE__ */ new Set()
|
|
4958
4838
|
};
|
|
4959
4839
|
constructor(opts, transport) {
|
|
4960
4840
|
this.opts = opts;
|
|
4961
4841
|
this.t = transport;
|
|
4962
4842
|
this.logger = opts.logger ?? noopLogger;
|
|
4963
|
-
this.cursorStore = opts.cursorStore ?? new MemoryCursorStore();
|
|
4964
4843
|
this._agentId = opts.agentId ?? "";
|
|
4965
4844
|
}
|
|
4966
4845
|
get agentId() {
|
|
@@ -5060,6 +4939,31 @@ var Client = class {
|
|
|
5060
4939
|
reason: input.reason
|
|
5061
4940
|
}).catch((err) => this.logger.warn("reportTaskFinished failed", err));
|
|
5062
4941
|
}
|
|
4942
|
+
reportActivity(input) {
|
|
4943
|
+
void this.t.perform({
|
|
4944
|
+
op: "report_activity",
|
|
4945
|
+
channelId: input.channelId,
|
|
4946
|
+
sequence: this.nextActivitySequence(),
|
|
4947
|
+
activity: input.activity
|
|
4948
|
+
}).catch((err) => this.logger.warn("reportActivity failed", err));
|
|
4949
|
+
}
|
|
4950
|
+
reportTurnActivity(input) {
|
|
4951
|
+
return new TurnActivityReporter({
|
|
4952
|
+
...input,
|
|
4953
|
+
deliver: (report) => this.reportActivity(report)
|
|
4954
|
+
});
|
|
4955
|
+
}
|
|
4956
|
+
/**
|
|
4957
|
+
* The counter every activity report carries. It belongs to the connection
|
|
4958
|
+
* rather than to a producer: both readers use it only to drop anything not
|
|
4959
|
+
* newer, so two producers on one agent numbering independently would silently
|
|
4960
|
+
* erase each other, and the failure would present as a missing report rather
|
|
4961
|
+
* than as a wrong one. Nothing outside this client can supply or observe it.
|
|
4962
|
+
*/
|
|
4963
|
+
nextActivitySequence() {
|
|
4964
|
+
this.activitySequence += 1;
|
|
4965
|
+
return this.activitySequence;
|
|
4966
|
+
}
|
|
5063
4967
|
// ─── Task CRUD (BPP semantic actions) ───────────────────
|
|
5064
4968
|
// Semantic actions rather than REST: the blueprint's protocol red line
|
|
5065
4969
|
// (plugin-protocol.md 1.3) is that a plugin does not reach past the semantic
|
|
@@ -5143,6 +5047,9 @@ var Client = class {
|
|
|
5143
5047
|
onServerRequest(handler) {
|
|
5144
5048
|
this.t.setServerRequestHandler?.(handler);
|
|
5145
5049
|
}
|
|
5050
|
+
onStopTurn(handler) {
|
|
5051
|
+
this.t.setStopTurnHandler?.(handler);
|
|
5052
|
+
}
|
|
5146
5053
|
emit(event, payload) {
|
|
5147
5054
|
for (const h of this.listeners[event])
|
|
5148
5055
|
h(payload);
|
|
@@ -5153,7 +5060,6 @@ var Client = class {
|
|
|
5153
5060
|
onConfigUpdate: (u) => this.emit("configUpdate", u),
|
|
5154
5061
|
applyConfigUpdate: this.opts.configUpdateHandler,
|
|
5155
5062
|
onPermissionDenied: (d) => this.emit("permissionDenied", d),
|
|
5156
|
-
onReplaySummary: (summary) => this.emit("replaySummary", summary),
|
|
5157
5063
|
onStateChange: (s) => {
|
|
5158
5064
|
this._state = s;
|
|
5159
5065
|
this.emit("connectionState", s);
|
|
@@ -5166,12 +5072,8 @@ var Client = class {
|
|
|
5166
5072
|
apiKey: this.opts.apiKey,
|
|
5167
5073
|
agentId: this._agentId,
|
|
5168
5074
|
pluginId: this.opts.pluginId,
|
|
5169
|
-
cursorStore: this.cursorStore,
|
|
5170
5075
|
logger: this.logger,
|
|
5171
|
-
|
|
5172
|
-
configApplyTimeoutMs: this.opts.configApplyTimeoutMs,
|
|
5173
|
-
replayMode: this.opts.replayMode,
|
|
5174
|
-
replayLatestN: this.opts.replayLatestN
|
|
5076
|
+
configApplyTimeoutMs: this.opts.configApplyTimeoutMs
|
|
5175
5077
|
};
|
|
5176
5078
|
}
|
|
5177
5079
|
};
|
|
@@ -5180,8 +5082,6 @@ function createBorgeePlugin(opts) {
|
|
|
5180
5082
|
}
|
|
5181
5083
|
export {
|
|
5182
5084
|
BorgeeError,
|
|
5183
|
-
FileCursorStore,
|
|
5184
|
-
MemoryCursorStore,
|
|
5185
5085
|
PermissionDeniedError,
|
|
5186
5086
|
createBorgeePlugin
|
|
5187
5087
|
};
|