@cabane/companion 0.6.198 → 0.6.200
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 +24 -6
- package/dist/runtime.js +24 -6
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2616,7 +2616,7 @@ var init_descriptions = __esm({
|
|
|
2616
2616
|
"withdraw_ask"
|
|
2617
2617
|
];
|
|
2618
2618
|
TURN_CONTROL_TOOL_DESCRIPTIONS = {
|
|
2619
|
-
ask: `Ask a person a structured question you need answered to continue, then end your turn; don't wait for the reply. \`targetUserId\` is a person on your roster, by their \`@handle\`; to bring in an agent, name
|
|
2619
|
+
ask: `Ask a person a structured question you need answered to continue, then end your turn; don't wait for the reply. \`targetUserId\` is a person on your roster, by their \`@handle\`; to bring in an agent, name them with \`@handle\` in your reply.
|
|
2620
2620
|
- Form: one question (\`headline\`, optional \`question\` body, \`options\`) or \`questions\`, 1\u2013${MAX_ASK_ITEMS} \`{ headline, body?, options? }\`; never both. Decisions that arise together go in ONE call, in the order you want them answered. A second \`ask\` is a separate item, never an edit; raise one only for a genuinely new question.
|
|
2621
2621
|
- \`headline\`: one sentence ending in \`?\`. Body (\`question\` or each item's \`body\`): a sentence or two of framing, not a report; inline Markdown only, no lists or headings. \`options\`: ${MIN_ASK_OPTIONS}\u2013${MAX_ASK_OPTIONS} one-click answers (always for a yes/no go-ahead), each a distinct course of action you can carry out without asking back.
|
|
2622
2622
|
- Voice, in headline, body and options: "I" for yourself, never your own name; name everyone else who decides or acts, as on your roster. Never "you", "your", "we", "us", "our" or their contractions, nor "he", "she" or "they" for a named actor. Each option reads correctly alone. A quotation stays accurate: say who said it.
|
|
@@ -12686,7 +12686,7 @@ function turnFailureCopy(reason, runtime) {
|
|
|
12686
12686
|
if (reason === "timeout_total")
|
|
12687
12687
|
return "The turn ran longer than expected and was stopped. Reply in Cabane to continue.";
|
|
12688
12688
|
if (reason === "result_error:error_max_turns")
|
|
12689
|
-
return "The agent reached
|
|
12689
|
+
return "The agent reached their step limit. Reply in Cabane to continue.";
|
|
12690
12690
|
if (reason === "no_result" || reason === "empty_result" || reason === "empty_result_unverified")
|
|
12691
12691
|
return "The agent finished without a response. Reply in Cabane to try again.";
|
|
12692
12692
|
if (reason === "session_start_failed")
|
|
@@ -12700,11 +12700,11 @@ function turnFailureCopy(reason, runtime) {
|
|
|
12700
12700
|
if (reason?.startsWith("seq_floor_unavailable:"))
|
|
12701
12701
|
return "The interrupted turn could not safely continue. Reply in Cabane to continue.";
|
|
12702
12702
|
if (reason === "result_error:error_max_budget_usd")
|
|
12703
|
-
return "The agent reached
|
|
12703
|
+
return "The agent reached their spending limit. Check their budget settings before trying again in Cabane.";
|
|
12704
12704
|
if (reason === "result_error:error_max_structured_output_retries")
|
|
12705
12705
|
return "The agent could not produce the requested response format. Check the requested format, then reply in Cabane to try again.";
|
|
12706
12706
|
if (reason?.startsWith("result_error:"))
|
|
12707
|
-
return "The agent stopped with an error while running. Check
|
|
12707
|
+
return "The agent stopped with an error while running. Check their transcript, then reply in Cabane to try again.";
|
|
12708
12708
|
if (reason === "setup_failed")
|
|
12709
12709
|
return "The turn could not be set up. Check the agent setup on this device, then reply in Cabane to try again.";
|
|
12710
12710
|
if (reason === "unexpected_role")
|
|
@@ -14179,6 +14179,10 @@ var CompanionSupervisor = class {
|
|
|
14179
14179
|
// Whether the device stream is open, which is what every workspace's link on
|
|
14180
14180
|
// the dashboard reports.
|
|
14181
14181
|
deviceConnected = false;
|
|
14182
|
+
// Set when the device stream ended on a 403: the device was deactivated, not
|
|
14183
|
+
// unpaired. The next accepted heartbeat proves it was reactivated, and
|
|
14184
|
+
// reopens the stream.
|
|
14185
|
+
deviceStreamDeactivated = false;
|
|
14182
14186
|
recoveryChecked = false;
|
|
14183
14187
|
recovering = false;
|
|
14184
14188
|
heartbeated = false;
|
|
@@ -14314,7 +14318,15 @@ var CompanionSupervisor = class {
|
|
|
14314
14318
|
}
|
|
14315
14319
|
if (ev.event === "message") await this.handleDeviceMessage(ev);
|
|
14316
14320
|
},
|
|
14317
|
-
onAuthFailure: () => {
|
|
14321
|
+
onAuthFailure: (status2) => {
|
|
14322
|
+
if (status2 === 403) {
|
|
14323
|
+
this.deviceStreamDeactivated = true;
|
|
14324
|
+
this.heartbeatTimer?.ref();
|
|
14325
|
+
this.log.warn(
|
|
14326
|
+
"This device was deactivated in Cabane. The companion will reconnect once it is reactivated."
|
|
14327
|
+
);
|
|
14328
|
+
return;
|
|
14329
|
+
}
|
|
14318
14330
|
this.log.error(
|
|
14319
14331
|
`Cabane no longer accepts this device. Run ${cabane("logout")}, then ${cabane("setup")} to pair again.`
|
|
14320
14332
|
);
|
|
@@ -14404,6 +14416,12 @@ var CompanionSupervisor = class {
|
|
|
14404
14416
|
lastAcknowledgedDevice: view.success ? view.data : null,
|
|
14405
14417
|
lastHeartbeatRefused: false
|
|
14406
14418
|
};
|
|
14419
|
+
if (this.deviceStreamDeactivated && this.deviceSub && !this.stopped) {
|
|
14420
|
+
this.deviceStreamDeactivated = false;
|
|
14421
|
+
this.heartbeatTimer?.unref();
|
|
14422
|
+
this.log.info("This device was reactivated; reconnecting to Cabane.");
|
|
14423
|
+
this.deviceSub.start();
|
|
14424
|
+
}
|
|
14407
14425
|
void this.recoverRuns();
|
|
14408
14426
|
void this.updater?.onHeartbeat(res.companion, this.deviceConnected).catch(
|
|
14409
14427
|
(err) => this.log.warn(
|
|
@@ -14586,7 +14604,7 @@ var CompanionSupervisor = class {
|
|
|
14586
14604
|
if (!credential) {
|
|
14587
14605
|
this.log.error(
|
|
14588
14606
|
{ workspaceId, agentId: it.agentId, username: it.agentUsername },
|
|
14589
|
-
`Cannot run ${it.agentDisplayName}:
|
|
14607
|
+
`Cannot run ${it.agentDisplayName}: their sign-in to Cabane is missing and Cabane didn't send a new one. Asking again on the next check.`
|
|
14590
14608
|
);
|
|
14591
14609
|
this.removeAgent(wr, it.agentId);
|
|
14592
14610
|
this.hub.setAgent(workspaceId, {
|
package/dist/runtime.js
CHANGED
|
@@ -1756,7 +1756,7 @@ function turnFailureCopy(reason, runtime) {
|
|
|
1756
1756
|
if (reason === "timeout_total")
|
|
1757
1757
|
return "The turn ran longer than expected and was stopped. Reply in Cabane to continue.";
|
|
1758
1758
|
if (reason === "result_error:error_max_turns")
|
|
1759
|
-
return "The agent reached
|
|
1759
|
+
return "The agent reached their step limit. Reply in Cabane to continue.";
|
|
1760
1760
|
if (reason === "no_result" || reason === "empty_result" || reason === "empty_result_unverified")
|
|
1761
1761
|
return "The agent finished without a response. Reply in Cabane to try again.";
|
|
1762
1762
|
if (reason === "session_start_failed")
|
|
@@ -1770,11 +1770,11 @@ function turnFailureCopy(reason, runtime) {
|
|
|
1770
1770
|
if (reason?.startsWith("seq_floor_unavailable:"))
|
|
1771
1771
|
return "The interrupted turn could not safely continue. Reply in Cabane to continue.";
|
|
1772
1772
|
if (reason === "result_error:error_max_budget_usd")
|
|
1773
|
-
return "The agent reached
|
|
1773
|
+
return "The agent reached their spending limit. Check their budget settings before trying again in Cabane.";
|
|
1774
1774
|
if (reason === "result_error:error_max_structured_output_retries")
|
|
1775
1775
|
return "The agent could not produce the requested response format. Check the requested format, then reply in Cabane to try again.";
|
|
1776
1776
|
if (reason?.startsWith("result_error:"))
|
|
1777
|
-
return "The agent stopped with an error while running. Check
|
|
1777
|
+
return "The agent stopped with an error while running. Check their transcript, then reply in Cabane to try again.";
|
|
1778
1778
|
if (reason === "setup_failed")
|
|
1779
1779
|
return "The turn could not be set up. Check the agent setup on this device, then reply in Cabane to try again.";
|
|
1780
1780
|
if (reason === "unexpected_role")
|
|
@@ -3079,7 +3079,7 @@ var TURN_CONTROL_TOOLS = [
|
|
|
3079
3079
|
"withdraw_ask"
|
|
3080
3080
|
];
|
|
3081
3081
|
var TURN_CONTROL_TOOL_DESCRIPTIONS = {
|
|
3082
|
-
ask: `Ask a person a structured question you need answered to continue, then end your turn; don't wait for the reply. \`targetUserId\` is a person on your roster, by their \`@handle\`; to bring in an agent, name
|
|
3082
|
+
ask: `Ask a person a structured question you need answered to continue, then end your turn; don't wait for the reply. \`targetUserId\` is a person on your roster, by their \`@handle\`; to bring in an agent, name them with \`@handle\` in your reply.
|
|
3083
3083
|
- Form: one question (\`headline\`, optional \`question\` body, \`options\`) or \`questions\`, 1\u2013${MAX_ASK_ITEMS} \`{ headline, body?, options? }\`; never both. Decisions that arise together go in ONE call, in the order you want them answered. A second \`ask\` is a separate item, never an edit; raise one only for a genuinely new question.
|
|
3084
3084
|
- \`headline\`: one sentence ending in \`?\`. Body (\`question\` or each item's \`body\`): a sentence or two of framing, not a report; inline Markdown only, no lists or headings. \`options\`: ${MIN_ASK_OPTIONS}\u2013${MAX_ASK_OPTIONS} one-click answers (always for a yes/no go-ahead), each a distinct course of action you can carry out without asking back.
|
|
3085
3085
|
- Voice, in headline, body and options: "I" for yourself, never your own name; name everyone else who decides or acts, as on your roster. Never "you", "your", "we", "us", "our" or their contractions, nor "he", "she" or "they" for a named actor. Each option reads correctly alone. A quotation stays accurate: say who said it.
|
|
@@ -9789,6 +9789,10 @@ var CompanionSupervisor = class {
|
|
|
9789
9789
|
// Whether the device stream is open, which is what every workspace's link on
|
|
9790
9790
|
// the dashboard reports.
|
|
9791
9791
|
deviceConnected = false;
|
|
9792
|
+
// Set when the device stream ended on a 403: the device was deactivated, not
|
|
9793
|
+
// unpaired. The next accepted heartbeat proves it was reactivated, and
|
|
9794
|
+
// reopens the stream.
|
|
9795
|
+
deviceStreamDeactivated = false;
|
|
9792
9796
|
recoveryChecked = false;
|
|
9793
9797
|
recovering = false;
|
|
9794
9798
|
heartbeated = false;
|
|
@@ -9924,7 +9928,15 @@ var CompanionSupervisor = class {
|
|
|
9924
9928
|
}
|
|
9925
9929
|
if (ev.event === "message") await this.handleDeviceMessage(ev);
|
|
9926
9930
|
},
|
|
9927
|
-
onAuthFailure: () => {
|
|
9931
|
+
onAuthFailure: (status) => {
|
|
9932
|
+
if (status === 403) {
|
|
9933
|
+
this.deviceStreamDeactivated = true;
|
|
9934
|
+
this.heartbeatTimer?.ref();
|
|
9935
|
+
this.log.warn(
|
|
9936
|
+
"This device was deactivated in Cabane. The companion will reconnect once it is reactivated."
|
|
9937
|
+
);
|
|
9938
|
+
return;
|
|
9939
|
+
}
|
|
9928
9940
|
this.log.error(
|
|
9929
9941
|
`Cabane no longer accepts this device. Run ${cabane("logout")}, then ${cabane("setup")} to pair again.`
|
|
9930
9942
|
);
|
|
@@ -10014,6 +10026,12 @@ var CompanionSupervisor = class {
|
|
|
10014
10026
|
lastAcknowledgedDevice: view.success ? view.data : null,
|
|
10015
10027
|
lastHeartbeatRefused: false
|
|
10016
10028
|
};
|
|
10029
|
+
if (this.deviceStreamDeactivated && this.deviceSub && !this.stopped) {
|
|
10030
|
+
this.deviceStreamDeactivated = false;
|
|
10031
|
+
this.heartbeatTimer?.unref();
|
|
10032
|
+
this.log.info("This device was reactivated; reconnecting to Cabane.");
|
|
10033
|
+
this.deviceSub.start();
|
|
10034
|
+
}
|
|
10017
10035
|
void this.recoverRuns();
|
|
10018
10036
|
void this.updater?.onHeartbeat(res.companion, this.deviceConnected).catch(
|
|
10019
10037
|
(err) => this.log.warn(
|
|
@@ -10196,7 +10214,7 @@ var CompanionSupervisor = class {
|
|
|
10196
10214
|
if (!credential) {
|
|
10197
10215
|
this.log.error(
|
|
10198
10216
|
{ workspaceId, agentId: it.agentId, username: it.agentUsername },
|
|
10199
|
-
`Cannot run ${it.agentDisplayName}:
|
|
10217
|
+
`Cannot run ${it.agentDisplayName}: their sign-in to Cabane is missing and Cabane didn't send a new one. Asking again on the next check.`
|
|
10200
10218
|
);
|
|
10201
10219
|
this.removeAgent(wr, it.agentId);
|
|
10202
10220
|
this.hub.setAgent(workspaceId, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cabane/companion",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.200",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The Cabane Companion (headless): connect an 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",
|