@linkedclaw/openclaw-plugin 0.1.10 → 0.1.11
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/index.d.ts +8 -0
- package/dist/index.js +222 -65
- package/dist/index.js.map +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -136,6 +136,14 @@ interface PluginRuntimeConfig extends ProviderConfig {
|
|
|
136
136
|
autoAcceptInvokes: boolean;
|
|
137
137
|
autoAcceptSessions: boolean;
|
|
138
138
|
autoAcceptGigTasks: boolean;
|
|
139
|
+
/**
|
|
140
|
+
* Which OpenClaw agent serves marketplace jobs — the `<agent>` segment of the
|
|
141
|
+
* subagent session key (`agent:<id>:subagent:...`). Default `"main"`. Point
|
|
142
|
+
* this at a dedicated Docker-sandboxed agent (sandbox mode=all, scope=agent,
|
|
143
|
+
* restricted tools) so untrusted requester prompts run inside a real boundary,
|
|
144
|
+
* not the operator's main agent. See the provider skill's security step.
|
|
145
|
+
*/
|
|
146
|
+
servingAgentId: string;
|
|
139
147
|
}
|
|
140
148
|
declare function parseConfig(raw: Record<string, unknown>): PluginRuntimeConfig;
|
|
141
149
|
|
package/dist/index.js
CHANGED
|
@@ -11964,6 +11964,19 @@ var DEFAULT_AUTH_FAILURE_CODES = Object.freeze([
|
|
|
11964
11964
|
1008,
|
|
11965
11965
|
...Array.from({ length: 99 }, (_, i) => 4001 + i)
|
|
11966
11966
|
]);
|
|
11967
|
+
var DEFAULT_AUTH_FATAL_FRAME_CODES = Object.freeze([
|
|
11968
|
+
"identify_invalid",
|
|
11969
|
+
"secret_isolation_violation",
|
|
11970
|
+
"key_revoked",
|
|
11971
|
+
"key_scope_insufficient",
|
|
11972
|
+
"token_invalid",
|
|
11973
|
+
"agent_unauthorized",
|
|
11974
|
+
"actor_unauthorized",
|
|
11975
|
+
"agent_not_found",
|
|
11976
|
+
"mandate_not_found",
|
|
11977
|
+
"mandate_inactive",
|
|
11978
|
+
"mandate_binding_failed"
|
|
11979
|
+
]);
|
|
11967
11980
|
var RelayClient = class extends EventEmitter {
|
|
11968
11981
|
url;
|
|
11969
11982
|
agentId;
|
|
@@ -11973,14 +11986,19 @@ var RelayClient = class extends EventEmitter {
|
|
|
11973
11986
|
reconnectBaseMs;
|
|
11974
11987
|
reconnectMaxMs;
|
|
11975
11988
|
authGraceMs;
|
|
11989
|
+
handshakeTimeoutMs;
|
|
11976
11990
|
authFailureCloseCodes;
|
|
11991
|
+
authFatalFrameCodes;
|
|
11977
11992
|
connector;
|
|
11978
11993
|
transport;
|
|
11979
11994
|
heartbeatTimer;
|
|
11980
11995
|
authGraceTimer;
|
|
11981
11996
|
stopped = false;
|
|
11982
11997
|
reconnectAttempt = 0;
|
|
11998
|
+
throttled = false;
|
|
11983
11999
|
fatalState = null;
|
|
12000
|
+
fireEnd;
|
|
12001
|
+
loopPromise;
|
|
11984
12002
|
constructor(opts) {
|
|
11985
12003
|
super();
|
|
11986
12004
|
this.url = opts.url;
|
|
@@ -11991,9 +12009,9 @@ var RelayClient = class extends EventEmitter {
|
|
|
11991
12009
|
this.reconnectBaseMs = opts.reconnectBaseMs ?? 1e3;
|
|
11992
12010
|
this.reconnectMaxMs = opts.reconnectMaxMs ?? 3e4;
|
|
11993
12011
|
this.authGraceMs = opts.authGraceMs ?? 5e3;
|
|
11994
|
-
this.
|
|
11995
|
-
|
|
11996
|
-
);
|
|
12012
|
+
this.handshakeTimeoutMs = opts.handshakeTimeoutMs ?? 1e4;
|
|
12013
|
+
this.authFailureCloseCodes = new Set(opts.authFailureCloseCodes ?? DEFAULT_AUTH_FAILURE_CODES);
|
|
12014
|
+
this.authFatalFrameCodes = new Set(opts.authFatalFrameCodes ?? DEFAULT_AUTH_FATAL_FRAME_CODES);
|
|
11997
12015
|
this.connector = opts.connector ?? nodeWsConnector;
|
|
11998
12016
|
}
|
|
11999
12017
|
getFatal() {
|
|
@@ -12005,27 +12023,17 @@ var RelayClient = class extends EventEmitter {
|
|
|
12005
12023
|
emit(event, ...args) {
|
|
12006
12024
|
return super.emit(event, ...args);
|
|
12007
12025
|
}
|
|
12026
|
+
/**
|
|
12027
|
+
* Open the first connection. Resolves once identify is sent; rejects on
|
|
12028
|
+
* first-attempt failure ("initial failure = caller's problem" — e.g. the
|
|
12029
|
+
* plugin holders surface it to the operator). Either way, NO background
|
|
12030
|
+
* reconnect chains survive a failed connect().
|
|
12031
|
+
*/
|
|
12008
12032
|
async connect() {
|
|
12009
12033
|
this.stopped = false;
|
|
12010
|
-
|
|
12011
|
-
|
|
12012
|
-
|
|
12013
|
-
try {
|
|
12014
|
-
const { transport, ready } = await this.connector(this.url);
|
|
12015
|
-
this.transport = transport;
|
|
12016
|
-
transport.addMessageListener((data) => this.handleFrame(data));
|
|
12017
|
-
transport.addCloseListener(
|
|
12018
|
-
(code, reason) => this.handleClose(code, `close ${code}: ${reason}`)
|
|
12019
|
-
);
|
|
12020
|
-
transport.addErrorListener((err) => this.handleClose(null, `error: ${err.message}`));
|
|
12021
|
-
await ready;
|
|
12022
|
-
await this.sendIdentify();
|
|
12023
|
-
this.startHeartbeat();
|
|
12024
|
-
this.emit("connected");
|
|
12025
|
-
this.startAuthGraceTimer();
|
|
12026
|
-
} catch (err) {
|
|
12027
|
-
throw new NetworkError(`relay connect failed: ${err.message}`, err);
|
|
12028
|
-
}
|
|
12034
|
+
this.fatalState = null;
|
|
12035
|
+
const first = await this.openConnection();
|
|
12036
|
+
this.loopPromise = this.runLoop(first.ended);
|
|
12029
12037
|
}
|
|
12030
12038
|
async send(frame) {
|
|
12031
12039
|
if (!this.transport) throw new NetworkError("relay not connected");
|
|
@@ -12042,7 +12050,132 @@ var RelayClient = class extends EventEmitter {
|
|
|
12042
12050
|
}
|
|
12043
12051
|
this.transport = void 0;
|
|
12044
12052
|
}
|
|
12053
|
+
this.fireEnd?.({ code: 1e3, reason: "client_stop" });
|
|
12054
|
+
await this.loopPromise?.catch(() => {
|
|
12055
|
+
});
|
|
12056
|
+
this.loopPromise = void 0;
|
|
12057
|
+
}
|
|
12058
|
+
// ------------------------------------------------------------------
|
|
12059
|
+
// Connection lifecycle (single-flight)
|
|
12060
|
+
// ------------------------------------------------------------------
|
|
12061
|
+
async openConnection() {
|
|
12062
|
+
let resolveEnd;
|
|
12063
|
+
const ended = new Promise((r) => {
|
|
12064
|
+
resolveEnd = r;
|
|
12065
|
+
});
|
|
12066
|
+
let fired = false;
|
|
12067
|
+
const fireEnd = (e) => {
|
|
12068
|
+
if (!fired) {
|
|
12069
|
+
fired = true;
|
|
12070
|
+
resolveEnd(e);
|
|
12071
|
+
}
|
|
12072
|
+
};
|
|
12073
|
+
this.fireEnd = fireEnd;
|
|
12074
|
+
try {
|
|
12075
|
+
const { transport, ready } = await this.connector(this.url, {
|
|
12076
|
+
handshakeTimeoutMs: this.handshakeTimeoutMs
|
|
12077
|
+
});
|
|
12078
|
+
transport.addMessageListener((data) => this.handleFrame(data));
|
|
12079
|
+
transport.addCloseListener((code, reason) => fireEnd({ code, reason: `close ${code}: ${reason}` }));
|
|
12080
|
+
transport.addErrorListener(
|
|
12081
|
+
(err) => fireEnd({
|
|
12082
|
+
code: null,
|
|
12083
|
+
reason: `error: ${err.message}`,
|
|
12084
|
+
httpStatus: err.httpStatus
|
|
12085
|
+
})
|
|
12086
|
+
);
|
|
12087
|
+
await this.withHandshakeTimeout(ready);
|
|
12088
|
+
this.transport = transport;
|
|
12089
|
+
await this.sendIdentify();
|
|
12090
|
+
this.startHeartbeat();
|
|
12091
|
+
this.emit("connected");
|
|
12092
|
+
this.startAuthGraceTimer();
|
|
12093
|
+
return { ended };
|
|
12094
|
+
} catch (err) {
|
|
12095
|
+
fireEnd({
|
|
12096
|
+
code: null,
|
|
12097
|
+
reason: `connect failed: ${err.message}`,
|
|
12098
|
+
httpStatus: err.httpStatus
|
|
12099
|
+
});
|
|
12100
|
+
throw new NetworkError(`relay connect failed: ${err.message}`, err);
|
|
12101
|
+
}
|
|
12102
|
+
}
|
|
12103
|
+
async withHandshakeTimeout(ready) {
|
|
12104
|
+
let timer;
|
|
12105
|
+
const timeout = new Promise((_, reject) => {
|
|
12106
|
+
timer = setTimeout(
|
|
12107
|
+
() => reject(new Error(`handshake timeout after ${this.handshakeTimeoutMs}ms`)),
|
|
12108
|
+
this.handshakeTimeoutMs
|
|
12109
|
+
);
|
|
12110
|
+
timer.unref?.();
|
|
12111
|
+
});
|
|
12112
|
+
try {
|
|
12113
|
+
await Promise.race([ready, timeout]);
|
|
12114
|
+
} finally {
|
|
12115
|
+
if (timer) clearTimeout(timer);
|
|
12116
|
+
}
|
|
12045
12117
|
}
|
|
12118
|
+
async runLoop(firstEnded) {
|
|
12119
|
+
let ended = firstEnded;
|
|
12120
|
+
while (true) {
|
|
12121
|
+
const end = await ended;
|
|
12122
|
+
this.stopHeartbeat();
|
|
12123
|
+
this.cancelAuthGraceTimer();
|
|
12124
|
+
this.transport = void 0;
|
|
12125
|
+
this.emit("disconnected", end.reason);
|
|
12126
|
+
if (this.stopped) return;
|
|
12127
|
+
const fatal = this.classifyFatal(end);
|
|
12128
|
+
if (fatal) {
|
|
12129
|
+
this.stopped = true;
|
|
12130
|
+
this.fatalState = fatal;
|
|
12131
|
+
this.emit("fatal", fatal);
|
|
12132
|
+
return;
|
|
12133
|
+
}
|
|
12134
|
+
this.throttled = end.code === 1013;
|
|
12135
|
+
for (; ; ) {
|
|
12136
|
+
await this.backoffDelay();
|
|
12137
|
+
if (this.stopped) return;
|
|
12138
|
+
try {
|
|
12139
|
+
({ ended } = await this.openConnection());
|
|
12140
|
+
break;
|
|
12141
|
+
} catch (err) {
|
|
12142
|
+
const status = err.httpStatus ?? err.cause?.httpStatus;
|
|
12143
|
+
if (status === 401 || status === 403) {
|
|
12144
|
+
const info = { reason: `upgrade rejected: HTTP ${status}`, code: null };
|
|
12145
|
+
this.stopped = true;
|
|
12146
|
+
this.fatalState = info;
|
|
12147
|
+
this.emit("fatal", info);
|
|
12148
|
+
return;
|
|
12149
|
+
}
|
|
12150
|
+
}
|
|
12151
|
+
}
|
|
12152
|
+
}
|
|
12153
|
+
}
|
|
12154
|
+
classifyFatal(end) {
|
|
12155
|
+
if (end.fatalFrameCode) {
|
|
12156
|
+
return { reason: `fatal error frame: ${end.fatalFrameCode}`, code: end.code };
|
|
12157
|
+
}
|
|
12158
|
+
if (end.code !== null && this.authFailureCloseCodes.has(end.code)) {
|
|
12159
|
+
return { reason: end.reason, code: end.code };
|
|
12160
|
+
}
|
|
12161
|
+
if (end.httpStatus === 401 || end.httpStatus === 403) {
|
|
12162
|
+
return { reason: `upgrade rejected: HTTP ${end.httpStatus}`, code: null };
|
|
12163
|
+
}
|
|
12164
|
+
return null;
|
|
12165
|
+
}
|
|
12166
|
+
async backoffDelay() {
|
|
12167
|
+
this.reconnectAttempt += 1;
|
|
12168
|
+
let base = Math.min(this.reconnectBaseMs * 2 ** (this.reconnectAttempt - 1), this.reconnectMaxMs);
|
|
12169
|
+
if (this.throttled) base = Math.min(base * 2, this.reconnectMaxMs * 2);
|
|
12170
|
+
const jitter = base * (0.5 + Math.random());
|
|
12171
|
+
await new Promise((r) => {
|
|
12172
|
+
const t = setTimeout(r, jitter);
|
|
12173
|
+
t.unref?.();
|
|
12174
|
+
});
|
|
12175
|
+
}
|
|
12176
|
+
// ------------------------------------------------------------------
|
|
12177
|
+
// Frames / heartbeat / grace (unchanged semantics)
|
|
12178
|
+
// ------------------------------------------------------------------
|
|
12046
12179
|
async sendIdentify() {
|
|
12047
12180
|
await this.send({
|
|
12048
12181
|
type: MessageType.IDENTIFY,
|
|
@@ -12077,33 +12210,30 @@ var RelayClient = class extends EventEmitter {
|
|
|
12077
12210
|
} catch {
|
|
12078
12211
|
return;
|
|
12079
12212
|
}
|
|
12213
|
+
if (frame.type === "error" && typeof frame.code === "string" && this.authFatalFrameCodes.has(frame.code)) {
|
|
12214
|
+
this.fireEnd?.({
|
|
12215
|
+
code: null,
|
|
12216
|
+
reason: `error frame: ${frame.code}`,
|
|
12217
|
+
fatalFrameCode: frame.code
|
|
12218
|
+
});
|
|
12219
|
+
}
|
|
12080
12220
|
this.emit("raw", frame);
|
|
12081
12221
|
const evt = parseInbound(frame);
|
|
12082
12222
|
if (evt) this.emit("event", evt);
|
|
12083
12223
|
}
|
|
12084
|
-
handleClose(code, reason) {
|
|
12085
|
-
this.stopHeartbeat();
|
|
12086
|
-
this.cancelAuthGraceTimer();
|
|
12087
|
-
this.transport = void 0;
|
|
12088
|
-
this.emit("disconnected", reason);
|
|
12089
|
-
if (this.stopped) return;
|
|
12090
|
-
if (code !== null && this.authFailureCloseCodes.has(code)) {
|
|
12091
|
-
this.stopped = true;
|
|
12092
|
-
this.fatalState = { reason, code };
|
|
12093
|
-
this.emit("fatal", { reason, code });
|
|
12094
|
-
return;
|
|
12095
|
-
}
|
|
12096
|
-
void this.scheduleReconnect();
|
|
12097
|
-
}
|
|
12098
12224
|
startAuthGraceTimer() {
|
|
12099
12225
|
this.cancelAuthGraceTimer();
|
|
12100
12226
|
if (this.authGraceMs <= 0) {
|
|
12101
12227
|
this.reconnectAttempt = 0;
|
|
12228
|
+
this.throttled = false;
|
|
12102
12229
|
return;
|
|
12103
12230
|
}
|
|
12104
12231
|
this.authGraceTimer = setTimeout(() => {
|
|
12105
12232
|
this.authGraceTimer = void 0;
|
|
12106
|
-
if (this.transport)
|
|
12233
|
+
if (this.transport) {
|
|
12234
|
+
this.reconnectAttempt = 0;
|
|
12235
|
+
this.throttled = false;
|
|
12236
|
+
}
|
|
12107
12237
|
}, this.authGraceMs);
|
|
12108
12238
|
if (typeof this.authGraceTimer.unref === "function") {
|
|
12109
12239
|
this.authGraceTimer.unref();
|
|
@@ -12115,30 +12245,15 @@ var RelayClient = class extends EventEmitter {
|
|
|
12115
12245
|
this.authGraceTimer = void 0;
|
|
12116
12246
|
}
|
|
12117
12247
|
}
|
|
12118
|
-
async scheduleReconnect() {
|
|
12119
|
-
this.reconnectAttempt += 1;
|
|
12120
|
-
const base = Math.min(
|
|
12121
|
-
this.reconnectBaseMs * 2 ** (this.reconnectAttempt - 1),
|
|
12122
|
-
this.reconnectMaxMs
|
|
12123
|
-
);
|
|
12124
|
-
const jitter = base * (0.5 + Math.random());
|
|
12125
|
-
await new Promise((r) => {
|
|
12126
|
-
const t = setTimeout(r, jitter);
|
|
12127
|
-
if (typeof t.unref === "function") {
|
|
12128
|
-
t.unref();
|
|
12129
|
-
}
|
|
12130
|
-
});
|
|
12131
|
-
if (this.stopped) return;
|
|
12132
|
-
try {
|
|
12133
|
-
await this.openOnce();
|
|
12134
|
-
} catch {
|
|
12135
|
-
if (!this.stopped) void this.scheduleReconnect();
|
|
12136
|
-
}
|
|
12137
|
-
}
|
|
12138
12248
|
};
|
|
12139
|
-
var nodeWsConnector = async (url) => {
|
|
12249
|
+
var nodeWsConnector = async (url, opts) => {
|
|
12140
12250
|
const { WebSocket: WebSocket2 } = await Promise.resolve().then(() => (init_wrapper(), wrapper_exports));
|
|
12141
|
-
const ws = new WebSocket2(url);
|
|
12251
|
+
const ws = new WebSocket2(url, { handshakeTimeout: opts?.handshakeTimeoutMs ?? 1e4 });
|
|
12252
|
+
ws.on("unexpected-response", (_req, res) => {
|
|
12253
|
+
const err = new Error(`unexpected server response: ${res.statusCode}`);
|
|
12254
|
+
err.httpStatus = res.statusCode;
|
|
12255
|
+
ws.emit("error", err);
|
|
12256
|
+
});
|
|
12142
12257
|
const transport = {
|
|
12143
12258
|
send: (data) => {
|
|
12144
12259
|
return new Promise((resolve, reject) => {
|
|
@@ -12318,6 +12433,8 @@ var DEFAULT_INVOKE_TIMEOUT_MS = 3e4;
|
|
|
12318
12433
|
var DEFAULT_SESSION_TURN_TIMEOUT_MS = 6e4;
|
|
12319
12434
|
var DEFAULT_GIG_TASK_OFFER_TIMEOUT_MS = 3e4;
|
|
12320
12435
|
var DEFAULT_GIG_TASK_EXECUTE_TIMEOUT_MS = 3e5;
|
|
12436
|
+
var DEFAULT_SESSION_IDLE_TIMEOUT_MS = 144e5;
|
|
12437
|
+
var DEFAULT_SESSION_REAPER_INTERVAL_MS = 3e5;
|
|
12321
12438
|
var GIG_TASK_SUBMIT_MAX_RETRIES = 3;
|
|
12322
12439
|
var GIG_TASK_SUBMIT_BASE_MS = 500;
|
|
12323
12440
|
var GIG_TASK_SUBMIT_CAP_MS = 8e3;
|
|
@@ -12335,6 +12452,7 @@ var ProviderRuntime = class {
|
|
|
12335
12452
|
running = false;
|
|
12336
12453
|
connected = false;
|
|
12337
12454
|
fatal = null;
|
|
12455
|
+
reaperTimer = null;
|
|
12338
12456
|
constructor(deps) {
|
|
12339
12457
|
this.cloud = deps.cloud;
|
|
12340
12458
|
this.relay = deps.relay;
|
|
@@ -12545,10 +12663,45 @@ var ProviderRuntime = class {
|
|
|
12545
12663
|
this.relay.on("event", (evt) => {
|
|
12546
12664
|
void this.dispatch(evt);
|
|
12547
12665
|
});
|
|
12666
|
+
const interval = this.config.sessionReaperIntervalMs ?? DEFAULT_SESSION_REAPER_INTERVAL_MS;
|
|
12667
|
+
this.reaperTimer = setInterval(() => {
|
|
12668
|
+
void this.reapIdleSessions();
|
|
12669
|
+
}, interval);
|
|
12670
|
+
this.reaperTimer.unref?.();
|
|
12548
12671
|
await this.relay.connect();
|
|
12549
12672
|
}
|
|
12673
|
+
/**
|
|
12674
|
+
* Evict sessions idle past the TTL (#28a). For each, run onSessionEnd(..., "idle_timeout")
|
|
12675
|
+
* so provider-side cleanup fires, emit `session_reaped` for observability, and free the
|
|
12676
|
+
* slot so a subsequent create succeeds where it would otherwise hit `provider_busy`.
|
|
12677
|
+
* Mirrors py `ProviderSkill._reaper_loop`.
|
|
12678
|
+
*/
|
|
12679
|
+
async reapIdleSessions() {
|
|
12680
|
+
const ttl = this.config.sessionIdleTimeoutMs ?? DEFAULT_SESSION_IDLE_TIMEOUT_MS;
|
|
12681
|
+
const now = performance.now();
|
|
12682
|
+
for (const sessionId of [...this.activeSessions.keys()]) {
|
|
12683
|
+
const session = this.activeSessions.get(sessionId);
|
|
12684
|
+
if (!session || now - session.lastActivity < ttl) continue;
|
|
12685
|
+
this.activeSessions.delete(sessionId);
|
|
12686
|
+
this.emitEvent("session_reaped", { session_id: sessionId });
|
|
12687
|
+
if (this.handler.onSessionEnd) {
|
|
12688
|
+
try {
|
|
12689
|
+
await this.handler.onSessionEnd({
|
|
12690
|
+
type: "session.end",
|
|
12691
|
+
session_id: sessionId,
|
|
12692
|
+
reason: "idle_timeout"
|
|
12693
|
+
});
|
|
12694
|
+
} catch {
|
|
12695
|
+
}
|
|
12696
|
+
}
|
|
12697
|
+
}
|
|
12698
|
+
}
|
|
12550
12699
|
async stop() {
|
|
12551
12700
|
this.running = false;
|
|
12701
|
+
if (this.reaperTimer !== null) {
|
|
12702
|
+
clearInterval(this.reaperTimer);
|
|
12703
|
+
this.reaperTimer = null;
|
|
12704
|
+
}
|
|
12552
12705
|
if (this.activeSessions.size > 0) {
|
|
12553
12706
|
this.emitEvent("draining", { live_sessions: this.activeSessions.size });
|
|
12554
12707
|
}
|
|
@@ -12656,7 +12809,9 @@ var ProviderRuntime = class {
|
|
|
12656
12809
|
const activeSession = {
|
|
12657
12810
|
requesterId: evt.requester_id,
|
|
12658
12811
|
capability: evt.capability,
|
|
12659
|
-
replySeq: 0
|
|
12812
|
+
replySeq: 0,
|
|
12813
|
+
lastActivity: performance.now()
|
|
12814
|
+
// monotonic — reaper parity (#28a)
|
|
12660
12815
|
};
|
|
12661
12816
|
const acceptExtras = {};
|
|
12662
12817
|
const reqEphB64 = evt.eph_enc_pub;
|
|
@@ -12677,6 +12832,7 @@ var ProviderRuntime = class {
|
|
|
12677
12832
|
async handleSessionMessage(evt) {
|
|
12678
12833
|
const session = this.activeSessions.get(evt.session_id);
|
|
12679
12834
|
if (!session) return;
|
|
12835
|
+
session.lastActivity = performance.now();
|
|
12680
12836
|
const timeout = this.config.sessionTurnTimeoutMs ?? DEFAULT_SESSION_TURN_TIMEOUT_MS;
|
|
12681
12837
|
let handlerEvt = evt;
|
|
12682
12838
|
if (session.K) {
|
|
@@ -12763,7 +12919,7 @@ var ProviderRuntime = class {
|
|
|
12763
12919
|
}
|
|
12764
12920
|
}
|
|
12765
12921
|
async handleSessionEnd(evt) {
|
|
12766
|
-
this.activeSessions.delete(evt.session_id);
|
|
12922
|
+
if (!this.activeSessions.delete(evt.session_id)) return;
|
|
12767
12923
|
if (this.handler.onSessionEnd) {
|
|
12768
12924
|
try {
|
|
12769
12925
|
await this.handler.onSessionEnd(evt);
|
|
@@ -13075,7 +13231,8 @@ function parseConfig(raw) {
|
|
|
13075
13231
|
autoStartProvider: raw["autoStartProvider"] !== false,
|
|
13076
13232
|
autoAcceptInvokes: raw["autoAcceptInvokes"] !== false,
|
|
13077
13233
|
autoAcceptSessions: raw["autoAcceptSessions"] !== false,
|
|
13078
|
-
autoAcceptGigTasks: raw["autoAcceptGigTasks"] === true
|
|
13234
|
+
autoAcceptGigTasks: raw["autoAcceptGigTasks"] === true,
|
|
13235
|
+
servingAgentId: typeof raw["servingAgentId"] === "string" && raw["servingAgentId"].trim() ? raw["servingAgentId"].trim() : "main"
|
|
13079
13236
|
};
|
|
13080
13237
|
}
|
|
13081
13238
|
|
|
@@ -13206,13 +13363,13 @@ var SubagentHandler = class {
|
|
|
13206
13363
|
}
|
|
13207
13364
|
// ───── keys ─────
|
|
13208
13365
|
sessionKey(id) {
|
|
13209
|
-
return `agent:
|
|
13366
|
+
return `agent:${this.config.servingAgentId}:subagent:linkedclaw-session-${id}`;
|
|
13210
13367
|
}
|
|
13211
13368
|
invokeKey(id) {
|
|
13212
|
-
return `agent:
|
|
13369
|
+
return `agent:${this.config.servingAgentId}:subagent:linkedclaw-invoke-${id}`;
|
|
13213
13370
|
}
|
|
13214
13371
|
gigTaskKey(id) {
|
|
13215
|
-
return `agent:
|
|
13372
|
+
return `agent:${this.config.servingAgentId}:subagent:linkedclaw-gig-task-${id}`;
|
|
13216
13373
|
}
|
|
13217
13374
|
};
|
|
13218
13375
|
function formatPayload(payload) {
|