@cabane/companion 0.6.23 → 0.6.25
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 +49 -5
- package/dist/runtime.js +49 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6835,6 +6835,22 @@ function checkoutState(cwd) {
|
|
|
6835
6835
|
function runKey(conversationId, agentId) {
|
|
6836
6836
|
return `${conversationId}|${agentId}`;
|
|
6837
6837
|
}
|
|
6838
|
+
var ERROR_BODY_LOG_CAP = 2e3;
|
|
6839
|
+
function describeErrorBody(body) {
|
|
6840
|
+
if (body === void 0 || body === null) return void 0;
|
|
6841
|
+
let text;
|
|
6842
|
+
if (typeof body === "string") {
|
|
6843
|
+
text = body;
|
|
6844
|
+
} else {
|
|
6845
|
+
try {
|
|
6846
|
+
text = JSON.stringify(body);
|
|
6847
|
+
} catch {
|
|
6848
|
+
text = String(body);
|
|
6849
|
+
}
|
|
6850
|
+
}
|
|
6851
|
+
if (text.length === 0) return void 0;
|
|
6852
|
+
return text.length > ERROR_BODY_LOG_CAP ? `${text.slice(0, ERROR_BODY_LOG_CAP)}\u2026` : text;
|
|
6853
|
+
}
|
|
6838
6854
|
function describeSubAgentError(status2, body) {
|
|
6839
6855
|
const code = body && typeof body === "object" && "error" in body ? String(body.error) : void 0;
|
|
6840
6856
|
switch (code) {
|
|
@@ -6860,6 +6876,13 @@ var Dispatcher = class {
|
|
|
6860
6876
|
opts;
|
|
6861
6877
|
// SJ383: per-(conversation, agent) abort registry.
|
|
6862
6878
|
aborts;
|
|
6879
|
+
// CT1109: pairs already told, in the conversation, that their session state is
|
|
6880
|
+
// being refused. The failure repeats every single turn until someone fixes the
|
|
6881
|
+
// payload, so without this the notice would be a per-turn drumbeat; one notice
|
|
6882
|
+
// is the signal and the rest is noise. Deliberately in-memory and unbounded-free:
|
|
6883
|
+
// a companion restart re-arms it, which is the behaviour we want — a restart is
|
|
6884
|
+
// exactly when it's worth re-stating that memory is still being lost.
|
|
6885
|
+
sessionWriteNotified = /* @__PURE__ */ new Set();
|
|
6863
6886
|
notifyStart(info) {
|
|
6864
6887
|
try {
|
|
6865
6888
|
this.opts.observer?.onStart(info);
|
|
@@ -7430,6 +7453,7 @@ ${reason}`,
|
|
|
7430
7453
|
) : null;
|
|
7431
7454
|
let sessionWritten = false;
|
|
7432
7455
|
let sessionDegraded = false;
|
|
7456
|
+
let sessionWriteRejected = false;
|
|
7433
7457
|
let okResult = false;
|
|
7434
7458
|
let resultReason;
|
|
7435
7459
|
const turnRuntime = turnContext.runtime;
|
|
@@ -7550,10 +7574,25 @@ ${reason}`,
|
|
|
7550
7574
|
{ agentSessionId: event.state }
|
|
7551
7575
|
);
|
|
7552
7576
|
} catch (err) {
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7577
|
+
const status2 = err instanceof ApiError ? err.status : void 0;
|
|
7578
|
+
if (status2 !== void 0 && status2 >= 400 && status2 < 500) {
|
|
7579
|
+
sessionWriteRejected = true;
|
|
7580
|
+
turnLog.error(
|
|
7581
|
+
{
|
|
7582
|
+
err: err instanceof Error ? err.message : String(err),
|
|
7583
|
+
status: status2,
|
|
7584
|
+
responseBody: describeErrorBody(err instanceof ApiError ? err.body : void 0),
|
|
7585
|
+
stateLength: event.state.length,
|
|
7586
|
+
runtime: turnRuntime
|
|
7587
|
+
},
|
|
7588
|
+
"dispatcher: session-state write REJECTED (4xx) \u2014 this turn is not resumable and the next turn starts with no memory of it"
|
|
7589
|
+
);
|
|
7590
|
+
} else {
|
|
7591
|
+
turnLog.warn(
|
|
7592
|
+
{ err: err instanceof Error ? err.message : String(err) },
|
|
7593
|
+
"dispatcher: session-id write failed (will retry next turn)"
|
|
7594
|
+
);
|
|
7595
|
+
}
|
|
7557
7596
|
}
|
|
7558
7597
|
}
|
|
7559
7598
|
} else if (event.type === "result") {
|
|
@@ -7680,6 +7719,10 @@ ${reason}`,
|
|
|
7680
7719
|
if (sessionDegraded) {
|
|
7681
7720
|
body.degraded = true;
|
|
7682
7721
|
}
|
|
7722
|
+
if (sessionWriteRejected && !this.sessionWriteNotified.has(key)) {
|
|
7723
|
+
body.sessionWriteRejected = true;
|
|
7724
|
+
this.sessionWriteNotified.add(key);
|
|
7725
|
+
}
|
|
7683
7726
|
this.opts.connectorHealth?.recordSettle(turnRuntime, {
|
|
7684
7727
|
ok: okResult,
|
|
7685
7728
|
errorReason: body.errorReason ?? null
|
|
@@ -8235,7 +8278,8 @@ var SseSubscriber = class {
|
|
|
8235
8278
|
}
|
|
8236
8279
|
async connect() {
|
|
8237
8280
|
const base = this.opts.baseUrl.endsWith("/") ? this.opts.baseUrl.slice(0, -1) : this.opts.baseUrl;
|
|
8238
|
-
const
|
|
8281
|
+
const query = this.lastEventId ? "" : "?replayPending=1";
|
|
8282
|
+
const url = `${base}/api/workspaces/${this.opts.workspaceId}/events${query}`;
|
|
8239
8283
|
this.controller = new AbortController();
|
|
8240
8284
|
const headers = {
|
|
8241
8285
|
Authorization: `Bearer ${this.opts.token}`,
|
package/dist/runtime.js
CHANGED
|
@@ -6454,6 +6454,22 @@ function checkoutState(cwd) {
|
|
|
6454
6454
|
function runKey(conversationId, agentId) {
|
|
6455
6455
|
return `${conversationId}|${agentId}`;
|
|
6456
6456
|
}
|
|
6457
|
+
var ERROR_BODY_LOG_CAP = 2e3;
|
|
6458
|
+
function describeErrorBody(body) {
|
|
6459
|
+
if (body === void 0 || body === null) return void 0;
|
|
6460
|
+
let text;
|
|
6461
|
+
if (typeof body === "string") {
|
|
6462
|
+
text = body;
|
|
6463
|
+
} else {
|
|
6464
|
+
try {
|
|
6465
|
+
text = JSON.stringify(body);
|
|
6466
|
+
} catch {
|
|
6467
|
+
text = String(body);
|
|
6468
|
+
}
|
|
6469
|
+
}
|
|
6470
|
+
if (text.length === 0) return void 0;
|
|
6471
|
+
return text.length > ERROR_BODY_LOG_CAP ? `${text.slice(0, ERROR_BODY_LOG_CAP)}\u2026` : text;
|
|
6472
|
+
}
|
|
6457
6473
|
function describeSubAgentError(status, body) {
|
|
6458
6474
|
const code = body && typeof body === "object" && "error" in body ? String(body.error) : void 0;
|
|
6459
6475
|
switch (code) {
|
|
@@ -6479,6 +6495,13 @@ var Dispatcher = class {
|
|
|
6479
6495
|
opts;
|
|
6480
6496
|
// SJ383: per-(conversation, agent) abort registry.
|
|
6481
6497
|
aborts;
|
|
6498
|
+
// CT1109: pairs already told, in the conversation, that their session state is
|
|
6499
|
+
// being refused. The failure repeats every single turn until someone fixes the
|
|
6500
|
+
// payload, so without this the notice would be a per-turn drumbeat; one notice
|
|
6501
|
+
// is the signal and the rest is noise. Deliberately in-memory and unbounded-free:
|
|
6502
|
+
// a companion restart re-arms it, which is the behaviour we want — a restart is
|
|
6503
|
+
// exactly when it's worth re-stating that memory is still being lost.
|
|
6504
|
+
sessionWriteNotified = /* @__PURE__ */ new Set();
|
|
6482
6505
|
notifyStart(info) {
|
|
6483
6506
|
try {
|
|
6484
6507
|
this.opts.observer?.onStart(info);
|
|
@@ -7049,6 +7072,7 @@ ${reason}`,
|
|
|
7049
7072
|
) : null;
|
|
7050
7073
|
let sessionWritten = false;
|
|
7051
7074
|
let sessionDegraded = false;
|
|
7075
|
+
let sessionWriteRejected = false;
|
|
7052
7076
|
let okResult = false;
|
|
7053
7077
|
let resultReason;
|
|
7054
7078
|
const turnRuntime = turnContext.runtime;
|
|
@@ -7169,10 +7193,25 @@ ${reason}`,
|
|
|
7169
7193
|
{ agentSessionId: event.state }
|
|
7170
7194
|
);
|
|
7171
7195
|
} catch (err) {
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7196
|
+
const status = err instanceof ApiError ? err.status : void 0;
|
|
7197
|
+
if (status !== void 0 && status >= 400 && status < 500) {
|
|
7198
|
+
sessionWriteRejected = true;
|
|
7199
|
+
turnLog.error(
|
|
7200
|
+
{
|
|
7201
|
+
err: err instanceof Error ? err.message : String(err),
|
|
7202
|
+
status,
|
|
7203
|
+
responseBody: describeErrorBody(err instanceof ApiError ? err.body : void 0),
|
|
7204
|
+
stateLength: event.state.length,
|
|
7205
|
+
runtime: turnRuntime
|
|
7206
|
+
},
|
|
7207
|
+
"dispatcher: session-state write REJECTED (4xx) \u2014 this turn is not resumable and the next turn starts with no memory of it"
|
|
7208
|
+
);
|
|
7209
|
+
} else {
|
|
7210
|
+
turnLog.warn(
|
|
7211
|
+
{ err: err instanceof Error ? err.message : String(err) },
|
|
7212
|
+
"dispatcher: session-id write failed (will retry next turn)"
|
|
7213
|
+
);
|
|
7214
|
+
}
|
|
7176
7215
|
}
|
|
7177
7216
|
}
|
|
7178
7217
|
} else if (event.type === "result") {
|
|
@@ -7299,6 +7338,10 @@ ${reason}`,
|
|
|
7299
7338
|
if (sessionDegraded) {
|
|
7300
7339
|
body.degraded = true;
|
|
7301
7340
|
}
|
|
7341
|
+
if (sessionWriteRejected && !this.sessionWriteNotified.has(key)) {
|
|
7342
|
+
body.sessionWriteRejected = true;
|
|
7343
|
+
this.sessionWriteNotified.add(key);
|
|
7344
|
+
}
|
|
7302
7345
|
this.opts.connectorHealth?.recordSettle(turnRuntime, {
|
|
7303
7346
|
ok: okResult,
|
|
7304
7347
|
errorReason: body.errorReason ?? null
|
|
@@ -7854,7 +7897,8 @@ var SseSubscriber = class {
|
|
|
7854
7897
|
}
|
|
7855
7898
|
async connect() {
|
|
7856
7899
|
const base = this.opts.baseUrl.endsWith("/") ? this.opts.baseUrl.slice(0, -1) : this.opts.baseUrl;
|
|
7857
|
-
const
|
|
7900
|
+
const query = this.lastEventId ? "" : "?replayPending=1";
|
|
7901
|
+
const url = `${base}/api/workspaces/${this.opts.workspaceId}/events${query}`;
|
|
7858
7902
|
this.controller = new AbortController();
|
|
7859
7903
|
const headers = {
|
|
7860
7904
|
Authorization: `Bearer ${this.opts.token}`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cabane/companion",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.25",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The Cabane Companion (headless): connect a coding agent on your machine to your Cabane workspace as a responder — drive work against your own codebase, files, and MCP servers without putting any of it in Cabane.",
|
|
6
6
|
"license": "UNLICENSED",
|