@vicvic-im/agent-bot 0.1.2 → 0.1.3
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 +8 -2
- package/dist/agents/acp.d.ts +2 -1
- package/dist/agents/acp.d.ts.map +1 -1
- package/dist/agents/types.d.ts +16 -0
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/bin-server.cjs +201 -71
- package/dist/bin-server.cjs.map +1 -1
- package/dist/bin-server.js +1 -1
- package/dist/{chunk-6CK4XIJB.js → chunk-CDBYOHVL.js} +2 -2
- package/dist/{chunk-X5QSWCDH.js → chunk-ELLWQDOY.js} +202 -74
- package/dist/chunk-ELLWQDOY.js.map +1 -0
- package/dist/cli.cjs +201 -73
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/core/dispatcher.d.ts +3 -1
- package/dist/core/dispatcher.d.ts.map +1 -1
- package/dist/index.cjs +201 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/server.cjs +201 -73
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +10 -10
- package/dist/chunk-X5QSWCDH.js.map +0 -1
- /package/dist/{chunk-6CK4XIJB.js.map → chunk-CDBYOHVL.js.map} +0 -0
package/README.md
CHANGED
|
@@ -75,10 +75,17 @@ Chat commands:
|
|
|
75
75
|
| `/agent [name]` | List or switch the agent backend |
|
|
76
76
|
| `/model [name]` | Show or switch the model (if the agent exposes it) |
|
|
77
77
|
| `/cost` | Show context usage and optional cost |
|
|
78
|
+
| `/version` | Show the vbot version |
|
|
78
79
|
| `/help` | Show commands |
|
|
79
80
|
|
|
80
81
|
Unknown `/commands` are forwarded to the agent as prompts.
|
|
81
82
|
|
|
83
|
+
Output notes:
|
|
84
|
+
|
|
85
|
+
- `/status`, `/agent`, `/model`, `/cost` and `/help` render Markdown tables; the vicvic.im Web and RN clients already render GFM tables. `/status` starts with a one-line summary because conversation previews and push notifications only show the first line.
|
|
86
|
+
- `/model` with no argument reports the model the ACP session actually selected (`currentValue` mapped to its option name) and lists the available options. It shows `unknown (session not started)` before the first message instead of a misleading `default`.
|
|
87
|
+
- `/new` and `/model <name>` are rejected while a request is running (`Use /stop first`): resetting the session mid-turn drops the streamed reply and switches the model under a running turn.
|
|
88
|
+
|
|
82
89
|
## Configuration
|
|
83
90
|
|
|
84
91
|
`vbot.json` in the current directory, or `~/.vbot/config.json` as a fallback:
|
|
@@ -119,13 +126,12 @@ The pairing token is a long-lived credential. Do not commit `vbot.json`; the fil
|
|
|
119
126
|
- Session state is persisted; restarting `vbot` can resume the ACP session when the backend supports it.
|
|
120
127
|
- `/cost` reports ACP `usage_update` values (`used` / `size` / optional `cost`), not Claude's dollar cost.
|
|
121
128
|
- New config file (`vbot.json`) and pm2 process names (`vbot-*`); it does not read or migrate `ccbot.json`.
|
|
122
|
-
- The App
|
|
129
|
+
- The App onboarding now points to `npm i -g @vicvic-im/agent-bot` and `vbot start`.
|
|
123
130
|
|
|
124
131
|
## Known limitations
|
|
125
132
|
|
|
126
133
|
- No streaming/progress messages yet: only `Processing...` and the final reply.
|
|
127
134
|
- Text only. Image and file messages are not supported by the vicvic.im bot conversation.
|
|
128
|
-
- The server's offline notice still mentions `ccbot` (the server is unchanged in this phase).
|
|
129
135
|
- Windows is not officially verified; the adapters and pm2 may need extra setup.
|
|
130
136
|
- Chat CLI messages are English, matching the existing `@ccbot/cli` developer tooling; App UI i18n is unaffected.
|
|
131
137
|
|
package/dist/agents/acp.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentBackend, AgentCapabilities, AgentName, AgentRunRequest, AgentRunResult } from "./types.js";
|
|
1
|
+
import type { AgentBackend, AgentCapabilities, AgentModelState, AgentName, AgentRunRequest, AgentRunResult } from "./types.js";
|
|
2
2
|
import type { AgentConfig } from "../config.js";
|
|
3
3
|
export declare class AgentAbortError extends Error {
|
|
4
4
|
constructor();
|
|
@@ -25,6 +25,7 @@ export declare class AcpAgent implements AgentBackend {
|
|
|
25
25
|
constructor(name: AgentName, config: AgentConfig);
|
|
26
26
|
capabilities(): AgentCapabilities;
|
|
27
27
|
sessionId(): string | null;
|
|
28
|
+
currentModel(): AgentModelState | null;
|
|
28
29
|
resetSession(): void;
|
|
29
30
|
start(): Promise<void>;
|
|
30
31
|
private doStart;
|
package/dist/agents/acp.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acp.d.ts","sourceRoot":"","sources":["../../src/agents/acp.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"acp.d.ts","sourceRoot":"","sources":["../../src/agents/acp.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EAEjB,eAAe,EACf,SAAS,EACT,eAAe,EACf,cAAc,EAEf,MAAM,YAAY,CAAC;AAIpB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,qBAAa,eAAgB,SAAQ,KAAK;;CAKzC;AAED,qBAAa,eAAgB,SAAQ,KAAK;IAGtC,QAAQ,CAAC,MAAM,EAAE,MAAM;gBADvB,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,MAAM;CAK1B;AAyBD,0CAA0C;AAC1C,qBAAa,QAAS,YAAW,YAAY;IAczC,QAAQ,CAAC,IAAI,EAAE,SAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAdzB,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,UAAU,CAAqC;IACvD,OAAO,CAAC,GAAG,CAAkC;IAC7C,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,YAAY,CAAuB;gBAGhC,IAAI,EAAE,SAAS,EACP,MAAM,EAAE,WAAW;IAGtC,YAAY,IAAI,iBAAiB;IASjC,SAAS,IAAI,MAAM,GAAG,IAAI;IAI1B,YAAY,IAAI,eAAe,GAAG,IAAI;IAStC,YAAY,IAAI,IAAI;IAId,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YASd,OAAO;YA8EP,aAAa;IA+CrB,GAAG,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAkEtD,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IASvB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmBzC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB5B,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,cAAc;IAyBtB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,UAAU;CAWnB"}
|
package/dist/agents/types.d.ts
CHANGED
|
@@ -45,6 +45,20 @@ export interface AgentRunResult {
|
|
|
45
45
|
/** true 表示本次是新会话(用于提示用户上下文已重置)。 */
|
|
46
46
|
newSession: boolean;
|
|
47
47
|
}
|
|
48
|
+
/** 一个可选的模型(ACP session config 的 select 值)。 */
|
|
49
|
+
export interface AgentModelOption {
|
|
50
|
+
value: string;
|
|
51
|
+
label: string;
|
|
52
|
+
}
|
|
53
|
+
/** 当前模型状态,从 ACP session config 推导;未建立会话时为 null。 */
|
|
54
|
+
export interface AgentModelState {
|
|
55
|
+
/** 当前生效模型的 ACP 值(/model 切换时使用)。 */
|
|
56
|
+
value: string;
|
|
57
|
+
/** 当前生效模型的可读名(优先 option.name,回退 value)。 */
|
|
58
|
+
label: string;
|
|
59
|
+
/** 可选模型列表;后端不暴露时为空数组。 */
|
|
60
|
+
options: AgentModelOption[];
|
|
61
|
+
}
|
|
48
62
|
export interface AgentCapabilities {
|
|
49
63
|
resume: boolean;
|
|
50
64
|
load: boolean;
|
|
@@ -68,5 +82,7 @@ export interface AgentBackend {
|
|
|
68
82
|
capabilities(): AgentCapabilities;
|
|
69
83
|
/** 当前 ACP session id(可能为空)。 */
|
|
70
84
|
sessionId(): string | null;
|
|
85
|
+
/** 当前模型;后端未暴露模型配置项或会话未建立时返回 null。 */
|
|
86
|
+
currentModel(): AgentModelState | null;
|
|
71
87
|
}
|
|
72
88
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,IAAI,CAAC;AAE/D,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,KAAK;IACpB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACnD;AAED,eAAO,MAAM,WAAW,EAAE,KAAwC,CAAC;AAEnE,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAEpC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;IACb,mCAAmC;IACnC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,2CAA2C;IAC3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,sCAAsC;IACtC,GAAG,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACvD,mBAAmB;IACnB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,+BAA+B;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,sCAAsC;IACtC,YAAY,IAAI,IAAI,CAAC;IACrB,kBAAkB;IAClB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,YAAY,IAAI,iBAAiB,CAAC;IAClC,+BAA+B;IAC/B,SAAS,IAAI,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,IAAI,CAAC;AAE/D,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,KAAK;IACpB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACnD;AAED,eAAO,MAAM,WAAW,EAAE,KAAwC,CAAC;AAEnE,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAEpC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;IACb,mCAAmC;IACnC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,mDAAmD;AACnD,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,2CAA2C;IAC3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,sCAAsC;IACtC,GAAG,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACvD,mBAAmB;IACnB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,+BAA+B;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,sCAAsC;IACtC,YAAY,IAAI,IAAI,CAAC;IACrB,kBAAkB;IAClB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,YAAY,IAAI,iBAAiB,CAAC;IAClC,+BAA+B;IAC/B,SAAS,IAAI,MAAM,GAAG,IAAI,CAAC;IAC3B,qCAAqC;IACrC,YAAY,IAAI,eAAe,GAAG,IAAI,CAAC;CACxC"}
|
package/dist/bin-server.cjs
CHANGED
|
@@ -363,6 +363,11 @@ function releaseLock(token) {
|
|
|
363
363
|
var import_node_child_process = require("child_process");
|
|
364
364
|
var import_node_stream = require("stream");
|
|
365
365
|
var acp = __toESM(require("@agentclientprotocol/sdk"), 1);
|
|
366
|
+
|
|
367
|
+
// src/version.ts
|
|
368
|
+
var VBOT_VERSION = "0.1.3";
|
|
369
|
+
|
|
370
|
+
// src/agents/acp.ts
|
|
366
371
|
var AgentAbortError = class extends Error {
|
|
367
372
|
constructor() {
|
|
368
373
|
super("Aborted");
|
|
@@ -378,6 +383,14 @@ var AgentStartError = class extends Error {
|
|
|
378
383
|
stderr;
|
|
379
384
|
};
|
|
380
385
|
var STDERR_LIMIT = 4e3;
|
|
386
|
+
function flattenSelectOptions(options) {
|
|
387
|
+
return options.flatMap(
|
|
388
|
+
(entry) => "group" in entry ? entry.options.map((option) => ({ value: option.value, label: option.name })) : [{ value: entry.value, label: entry.name }]
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
function isModelOption(option) {
|
|
392
|
+
return option.type === "select" && (option.category === "model" || option.id === "model");
|
|
393
|
+
}
|
|
381
394
|
var AcpAgent = class {
|
|
382
395
|
constructor(name, config) {
|
|
383
396
|
this.name = name;
|
|
@@ -407,6 +420,14 @@ var AcpAgent = class {
|
|
|
407
420
|
sessionId() {
|
|
408
421
|
return this.session;
|
|
409
422
|
}
|
|
423
|
+
currentModel() {
|
|
424
|
+
const option = this.configOptions.find(isModelOption);
|
|
425
|
+
if (!option || option.type !== "select") return null;
|
|
426
|
+
const value = String(option.currentValue);
|
|
427
|
+
const options = flattenSelectOptions(option.options);
|
|
428
|
+
const label = options.find((entry) => entry.value === value)?.label ?? value;
|
|
429
|
+
return { value, label, options };
|
|
430
|
+
}
|
|
410
431
|
resetSession() {
|
|
411
432
|
this.session = null;
|
|
412
433
|
}
|
|
@@ -474,7 +495,7 @@ var AcpAgent = class {
|
|
|
474
495
|
const init = await this.ctx.request(acp.methods.agent.initialize, {
|
|
475
496
|
protocolVersion: 1,
|
|
476
497
|
clientCapabilities: {},
|
|
477
|
-
clientInfo: { name: "vbot", version:
|
|
498
|
+
clientInfo: { name: "vbot", version: VBOT_VERSION }
|
|
478
499
|
});
|
|
479
500
|
this.initCaps = init.agentCapabilities;
|
|
480
501
|
} catch (error) {
|
|
@@ -593,15 +614,14 @@ var AcpAgent = class {
|
|
|
593
614
|
this.pendingModel = model;
|
|
594
615
|
return true;
|
|
595
616
|
}
|
|
596
|
-
const option = this.configOptions.find(
|
|
597
|
-
(entry) => entry.type === "select" && (entry.id === "model" || entry.category === "model")
|
|
598
|
-
);
|
|
617
|
+
const option = this.configOptions.find(isModelOption);
|
|
599
618
|
if (!option) return false;
|
|
600
|
-
await this.ctx.request(acp.methods.agent.session.setConfigOption, {
|
|
619
|
+
const response = await this.ctx.request(acp.methods.agent.session.setConfigOption, {
|
|
601
620
|
sessionId: this.session,
|
|
602
621
|
configId: option.id,
|
|
603
622
|
value: model
|
|
604
623
|
});
|
|
624
|
+
if (response?.configOptions?.length) this.configOptions = response.configOptions;
|
|
605
625
|
this.pendingModel = null;
|
|
606
626
|
return true;
|
|
607
627
|
}
|
|
@@ -737,21 +757,29 @@ var BotQueue = class {
|
|
|
737
757
|
}
|
|
738
758
|
};
|
|
739
759
|
|
|
740
|
-
// src/version.ts
|
|
741
|
-
var VBOT_VERSION = "0.1.2";
|
|
742
|
-
|
|
743
760
|
// src/core/dispatcher.ts
|
|
744
|
-
var
|
|
745
|
-
|
|
746
|
-
/
|
|
747
|
-
/
|
|
748
|
-
/
|
|
749
|
-
/
|
|
750
|
-
/
|
|
751
|
-
/
|
|
752
|
-
/
|
|
753
|
-
|
|
754
|
-
|
|
761
|
+
var import_node_os3 = require("os");
|
|
762
|
+
var HELP_ROWS = [
|
|
763
|
+
["/new", "Start a new session"],
|
|
764
|
+
["/stop", "Abort the current request"],
|
|
765
|
+
["/status", "Show agent, session and queue status"],
|
|
766
|
+
["/agent [name]", "Show or switch agent backend"],
|
|
767
|
+
["/model [name]", "Show or switch model"],
|
|
768
|
+
["/cost", "Show context usage and cost"],
|
|
769
|
+
["/version", "Show vbot version"],
|
|
770
|
+
["/help", "Show this help"]
|
|
771
|
+
];
|
|
772
|
+
var HELP_FOOTER = "Other /commands are sent to the agent as prompts.";
|
|
773
|
+
var NEW_BUSY_TEXT = "Cannot reset the session while a request is running. Use /stop first.";
|
|
774
|
+
var MODEL_BUSY_TEXT = "Cannot switch model while a request is running. Use /stop first.";
|
|
775
|
+
var HELP_TEXT = [
|
|
776
|
+
table(
|
|
777
|
+
["Command", "Description"],
|
|
778
|
+
HELP_ROWS.map(([command, description]) => [command, description])
|
|
779
|
+
),
|
|
780
|
+
"",
|
|
781
|
+
HELP_FOOTER
|
|
782
|
+
].join("\n");
|
|
755
783
|
function createDispatcher(runtime) {
|
|
756
784
|
return (text, reply) => {
|
|
757
785
|
const send = (message) => {
|
|
@@ -765,11 +793,57 @@ function createDispatcher(runtime) {
|
|
|
765
793
|
});
|
|
766
794
|
};
|
|
767
795
|
}
|
|
796
|
+
function escapeCell(value) {
|
|
797
|
+
return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
798
|
+
}
|
|
799
|
+
function table(headers, rows) {
|
|
800
|
+
const head = `| ${headers.map(escapeCell).join(" | ")} |`;
|
|
801
|
+
const separator = `| ${headers.map(() => "---").join(" | ")} |`;
|
|
802
|
+
const body = rows.map((row) => `| ${row.map(escapeCell).join(" | ")} |`);
|
|
803
|
+
return [head, separator, ...body].join("\n");
|
|
804
|
+
}
|
|
805
|
+
function formatNumber(value) {
|
|
806
|
+
if (!Number.isFinite(value)) return String(value);
|
|
807
|
+
const negative = value < 0;
|
|
808
|
+
const digits = Math.abs(Math.trunc(value)).toString();
|
|
809
|
+
let out = "";
|
|
810
|
+
for (let i = 0; i < digits.length; i += 1) {
|
|
811
|
+
if (i > 0 && (digits.length - i) % 3 === 0) out += ",";
|
|
812
|
+
out += digits[i];
|
|
813
|
+
}
|
|
814
|
+
return negative ? "-" + out : out;
|
|
815
|
+
}
|
|
816
|
+
function percentOf(used, size) {
|
|
817
|
+
if (size <= 0) return null;
|
|
818
|
+
return `${(used / size * 100).toFixed(1)}%`;
|
|
819
|
+
}
|
|
820
|
+
function usageText(runtime) {
|
|
821
|
+
const { used, size } = runtime.state().usage;
|
|
822
|
+
if (size <= 0) return "not reported";
|
|
823
|
+
const base = `${formatNumber(used)} / ${formatNumber(size)}`;
|
|
824
|
+
const percent = percentOf(used, size);
|
|
825
|
+
return percent ? `${base} (${percent})` : base;
|
|
826
|
+
}
|
|
827
|
+
function compactPath(path) {
|
|
828
|
+
const home = (0, import_node_os3.homedir)();
|
|
829
|
+
if (!home) return path;
|
|
830
|
+
if (path === home) return "~";
|
|
831
|
+
const prefix = home + "/";
|
|
832
|
+
if (path.startsWith(prefix)) return "~" + path.slice(home.length);
|
|
833
|
+
return path;
|
|
834
|
+
}
|
|
835
|
+
function modelText(runtime) {
|
|
836
|
+
const current = runtime.agent().currentModel();
|
|
837
|
+
if (current) return current.label;
|
|
838
|
+
const configured = runtime.config().agent.model;
|
|
839
|
+
if (configured) return `${configured} (configured, not applied yet)`;
|
|
840
|
+
return "unknown (session not started)";
|
|
841
|
+
}
|
|
768
842
|
function handleSlashCommand(runtime, text, send) {
|
|
769
843
|
const [rawCommand, ...args] = text.split(/\s+/);
|
|
770
844
|
switch (rawCommand.toLowerCase()) {
|
|
771
845
|
case "/new":
|
|
772
|
-
handleNew(runtime, send);
|
|
846
|
+
void handleNew(runtime, send);
|
|
773
847
|
return null;
|
|
774
848
|
case "/stop":
|
|
775
849
|
handleStop(runtime, send);
|
|
@@ -781,7 +855,7 @@ function handleSlashCommand(runtime, text, send) {
|
|
|
781
855
|
handleAgent(runtime, args, send);
|
|
782
856
|
return null;
|
|
783
857
|
case "/model":
|
|
784
|
-
handleModel(runtime, args, send);
|
|
858
|
+
void handleModel(runtime, args, send);
|
|
785
859
|
return null;
|
|
786
860
|
case "/cost":
|
|
787
861
|
send(costText(runtime));
|
|
@@ -796,12 +870,18 @@ function handleSlashCommand(runtime, text, send) {
|
|
|
796
870
|
return text.slice(1);
|
|
797
871
|
}
|
|
798
872
|
}
|
|
799
|
-
function handleNew(runtime, send) {
|
|
800
|
-
runtime.
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
runtime.
|
|
873
|
+
async function handleNew(runtime, send) {
|
|
874
|
+
if (runtime.queue().status().busy) {
|
|
875
|
+
send(NEW_BUSY_TEXT);
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
await runtime.serialize(async () => {
|
|
879
|
+
runtime.agent().resetSession();
|
|
880
|
+
const state = runtime.state();
|
|
881
|
+
state.acpSessionId = null;
|
|
882
|
+
state.usage = { used: 0, size: 0, cost: null };
|
|
883
|
+
runtime.saveState();
|
|
884
|
+
});
|
|
805
885
|
send("Session reset. Starting a new conversation.");
|
|
806
886
|
}
|
|
807
887
|
function handleStop(runtime, send) {
|
|
@@ -817,12 +897,18 @@ function handleStop(runtime, send) {
|
|
|
817
897
|
}
|
|
818
898
|
function handleAgent(runtime, args, send) {
|
|
819
899
|
const name = args.join(" ").trim();
|
|
900
|
+
const current = runtime.config().agent.name;
|
|
820
901
|
if (!name) {
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
902
|
+
send(
|
|
903
|
+
table(
|
|
904
|
+
["Agent", "Backend", ""],
|
|
905
|
+
AGENT_NAMES.map((entry) => [
|
|
906
|
+
entry,
|
|
907
|
+
AGENTS[entry].label,
|
|
908
|
+
entry === current ? "\u2190 current" : ""
|
|
909
|
+
])
|
|
910
|
+
)
|
|
911
|
+
);
|
|
826
912
|
return;
|
|
827
913
|
}
|
|
828
914
|
if (!isAgentName(name)) {
|
|
@@ -838,56 +924,95 @@ ${list}`);
|
|
|
838
924
|
(error) => send(`Error: ${error instanceof Error ? error.message : String(error)}`)
|
|
839
925
|
);
|
|
840
926
|
}
|
|
841
|
-
function handleModel(runtime, args, send) {
|
|
927
|
+
async function handleModel(runtime, args, send) {
|
|
842
928
|
const model = args.join(" ").trim();
|
|
843
929
|
if (!model) {
|
|
844
|
-
send(
|
|
930
|
+
send(modelReport(runtime));
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
if (runtime.queue().status().busy) {
|
|
934
|
+
send(MODEL_BUSY_TEXT);
|
|
845
935
|
return;
|
|
846
936
|
}
|
|
847
937
|
const config = runtime.config();
|
|
848
938
|
const hadSession = runtime.agent().sessionId() !== null;
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
}
|
|
939
|
+
const supported = await runtime.serialize(async () => {
|
|
940
|
+
const accepted = await runtime.agent().setModel(model);
|
|
941
|
+
config.agent.model = model;
|
|
942
|
+
runtime.saveConfig();
|
|
943
|
+
return accepted;
|
|
944
|
+
});
|
|
945
|
+
const applied = runtime.agent().currentModel()?.label ?? model;
|
|
946
|
+
if (!supported) {
|
|
858
947
|
send(
|
|
859
|
-
|
|
948
|
+
`Model saved: ${model}. This agent does not expose a runtime model option; it will be used on the next session if supported.`
|
|
860
949
|
);
|
|
861
|
-
|
|
862
|
-
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
send(
|
|
953
|
+
hadSession ? `Model switched to: ${applied}` : `Model set to: ${applied}. It will apply when the session starts.`
|
|
863
954
|
);
|
|
864
955
|
}
|
|
956
|
+
function modelReport(runtime) {
|
|
957
|
+
const current = runtime.agent().currentModel();
|
|
958
|
+
if (!current) {
|
|
959
|
+
const configured = runtime.config().agent.model;
|
|
960
|
+
const hint = configured ? `Configured: ${configured}
|
|
961
|
+
|
|
962
|
+
The agent has not reported a model yet; it becomes visible after the first message.` : "This agent does not expose a runtime model option, or the session has not started.";
|
|
963
|
+
return `Current: unknown
|
|
964
|
+
|
|
965
|
+
${hint}`;
|
|
966
|
+
}
|
|
967
|
+
const lines = [`Current: ${current.label}`];
|
|
968
|
+
if (current.options.length > 0) {
|
|
969
|
+
lines.push(
|
|
970
|
+
"",
|
|
971
|
+
table(
|
|
972
|
+
["Model", ""],
|
|
973
|
+
current.options.map((option) => [
|
|
974
|
+
option.label,
|
|
975
|
+
option.value === current.value ? "\u2190 current" : ""
|
|
976
|
+
])
|
|
977
|
+
)
|
|
978
|
+
);
|
|
979
|
+
}
|
|
980
|
+
lines.push("", "Switch: /model <name>");
|
|
981
|
+
return lines.join("\n");
|
|
982
|
+
}
|
|
865
983
|
function statusText(runtime) {
|
|
866
984
|
const config = runtime.config();
|
|
867
985
|
const agent = runtime.agent();
|
|
868
986
|
const state = runtime.state();
|
|
869
987
|
const queue = runtime.queue().status();
|
|
870
|
-
const
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
988
|
+
const { used, size } = state.usage;
|
|
989
|
+
const summary = [
|
|
990
|
+
`**${config.agent.name}**`,
|
|
991
|
+
queue.busy ? "busy" : "idle",
|
|
992
|
+
size > 0 ? `${formatNumber(used)} / ${formatNumber(size)}` : null
|
|
993
|
+
].filter(Boolean).join(" \xB7 ");
|
|
994
|
+
const rows = [
|
|
995
|
+
["Agent", `${config.agent.name} (${AGENTS[config.agent.name].label})`],
|
|
996
|
+
["Session", agent.sessionId() ?? "none"],
|
|
997
|
+
["Work dir", compactPath(config.agent.cwd)],
|
|
998
|
+
["Model", modelText(runtime)],
|
|
999
|
+
["Status", queue.busy ? "busy" : "idle"],
|
|
1000
|
+
["Queue", String(queue.queued)],
|
|
1001
|
+
["Usage", usageText(runtime)],
|
|
1002
|
+
["Capabilities", capabilitiesText(agent.capabilities())]
|
|
879
1003
|
];
|
|
880
|
-
return
|
|
1004
|
+
return [summary, "", table(["Field", "Value"], rows)].join("\n");
|
|
881
1005
|
}
|
|
882
1006
|
function costText(runtime) {
|
|
883
1007
|
const usage = runtime.state().usage;
|
|
884
|
-
const
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
1008
|
+
const cost = usage.cost ? `${usage.cost.amount} ${usage.cost.currency}` : "not reported by this agent";
|
|
1009
|
+
return table(
|
|
1010
|
+
["Field", "Value"],
|
|
1011
|
+
[
|
|
1012
|
+
["Context", usageText(runtime)],
|
|
1013
|
+
["Cost", cost]
|
|
1014
|
+
]
|
|
1015
|
+
);
|
|
891
1016
|
}
|
|
892
1017
|
function capabilitiesText(caps) {
|
|
893
1018
|
const enabled = [
|
|
@@ -1151,13 +1276,17 @@ async function startBot(configPath2) {
|
|
|
1151
1276
|
saveConfig: () => saveConfig(config, configPath2)
|
|
1152
1277
|
};
|
|
1153
1278
|
holder.queue = new BotQueue((item, signal) => gate(() => processPrompt(ctx, item, signal)));
|
|
1154
|
-
const runtime = createRuntime(
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
switching
|
|
1159
|
-
|
|
1160
|
-
|
|
1279
|
+
const runtime = createRuntime(
|
|
1280
|
+
ctx,
|
|
1281
|
+
(task) => gate(task),
|
|
1282
|
+
(name) => {
|
|
1283
|
+
if (switching) return Promise.reject(new Error("Agent switch already in progress."));
|
|
1284
|
+
switching = true;
|
|
1285
|
+
return gate(() => switchAgent(ctx, name)).finally(() => {
|
|
1286
|
+
switching = false;
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
);
|
|
1161
1290
|
const dispatch = createDispatcher(runtime);
|
|
1162
1291
|
let notifySignal = () => void 0;
|
|
1163
1292
|
const wire = new VicvicWire({
|
|
@@ -1218,7 +1347,7 @@ async function runBot(configPath2) {
|
|
|
1218
1347
|
const bot = await startBot(configPath2);
|
|
1219
1348
|
await bot.finished;
|
|
1220
1349
|
}
|
|
1221
|
-
function createRuntime(ctx, switchAgent2) {
|
|
1350
|
+
function createRuntime(ctx, gate, switchAgent2) {
|
|
1222
1351
|
return {
|
|
1223
1352
|
config: () => ctx.config,
|
|
1224
1353
|
agent: () => ctx.getAgent(),
|
|
@@ -1226,6 +1355,7 @@ function createRuntime(ctx, switchAgent2) {
|
|
|
1226
1355
|
state: () => ctx.state,
|
|
1227
1356
|
saveState: () => ctx.saveState(),
|
|
1228
1357
|
saveConfig: () => ctx.saveConfig(),
|
|
1358
|
+
serialize: (task) => gate(task),
|
|
1229
1359
|
switchAgent: switchAgent2
|
|
1230
1360
|
};
|
|
1231
1361
|
}
|