@vicvic-im/agent-bot 0.1.2 → 0.1.4
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-X5QSWCDH.js → chunk-3FUDOPAV.js} +202 -74
- package/dist/chunk-3FUDOPAV.js.map +1 -0
- package/dist/{chunk-6CK4XIJB.js → chunk-X65ZARFF.js} +2 -2
- 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 +1 -1
- package/dist/chunk-X5QSWCDH.js.map +0 -1
- /package/dist/{chunk-6CK4XIJB.js.map → chunk-X65ZARFF.js.map} +0 -0
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
loadConfig,
|
|
9
9
|
normalizeConfig,
|
|
10
10
|
saveConfig
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-3FUDOPAV.js";
|
|
12
12
|
|
|
13
13
|
// src/commands/setup.ts
|
|
14
14
|
import { existsSync } from "fs";
|
|
@@ -89,4 +89,4 @@ async function ensureConfig(explicit) {
|
|
|
89
89
|
export {
|
|
90
90
|
ensureConfig
|
|
91
91
|
};
|
|
92
|
-
//# sourceMappingURL=chunk-
|
|
92
|
+
//# sourceMappingURL=chunk-X65ZARFF.js.map
|
package/dist/cli.cjs
CHANGED
|
@@ -362,6 +362,9 @@ var acp = __toESM(require("@agentclientprotocol/sdk"), 1);
|
|
|
362
362
|
// src/agents/types.ts
|
|
363
363
|
var EMPTY_USAGE = { used: 0, size: 0, cost: null };
|
|
364
364
|
|
|
365
|
+
// src/version.ts
|
|
366
|
+
var VBOT_VERSION = "0.1.4";
|
|
367
|
+
|
|
365
368
|
// src/agents/acp.ts
|
|
366
369
|
var AgentAbortError = class extends Error {
|
|
367
370
|
constructor() {
|
|
@@ -378,6 +381,14 @@ var AgentStartError = class extends Error {
|
|
|
378
381
|
stderr;
|
|
379
382
|
};
|
|
380
383
|
var STDERR_LIMIT = 4e3;
|
|
384
|
+
function flattenSelectOptions(options) {
|
|
385
|
+
return options.flatMap(
|
|
386
|
+
(entry) => "group" in entry ? entry.options.map((option) => ({ value: option.value, label: option.name })) : [{ value: entry.value, label: entry.name }]
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
function isModelOption(option) {
|
|
390
|
+
return option.type === "select" && (option.category === "model" || option.id === "model");
|
|
391
|
+
}
|
|
381
392
|
var AcpAgent = class {
|
|
382
393
|
constructor(name, config) {
|
|
383
394
|
this.name = name;
|
|
@@ -407,6 +418,14 @@ var AcpAgent = class {
|
|
|
407
418
|
sessionId() {
|
|
408
419
|
return this.session;
|
|
409
420
|
}
|
|
421
|
+
currentModel() {
|
|
422
|
+
const option = this.configOptions.find(isModelOption);
|
|
423
|
+
if (!option || option.type !== "select") return null;
|
|
424
|
+
const value = String(option.currentValue);
|
|
425
|
+
const options = flattenSelectOptions(option.options);
|
|
426
|
+
const label = options.find((entry) => entry.value === value)?.label ?? value;
|
|
427
|
+
return { value, label, options };
|
|
428
|
+
}
|
|
410
429
|
resetSession() {
|
|
411
430
|
this.session = null;
|
|
412
431
|
}
|
|
@@ -474,7 +493,7 @@ var AcpAgent = class {
|
|
|
474
493
|
const init = await this.ctx.request(acp.methods.agent.initialize, {
|
|
475
494
|
protocolVersion: 1,
|
|
476
495
|
clientCapabilities: {},
|
|
477
|
-
clientInfo: { name: "vbot", version:
|
|
496
|
+
clientInfo: { name: "vbot", version: VBOT_VERSION }
|
|
478
497
|
});
|
|
479
498
|
this.initCaps = init.agentCapabilities;
|
|
480
499
|
} catch (error) {
|
|
@@ -593,15 +612,14 @@ var AcpAgent = class {
|
|
|
593
612
|
this.pendingModel = model;
|
|
594
613
|
return true;
|
|
595
614
|
}
|
|
596
|
-
const option = this.configOptions.find(
|
|
597
|
-
(entry) => entry.type === "select" && (entry.id === "model" || entry.category === "model")
|
|
598
|
-
);
|
|
615
|
+
const option = this.configOptions.find(isModelOption);
|
|
599
616
|
if (!option) return false;
|
|
600
|
-
await this.ctx.request(acp.methods.agent.session.setConfigOption, {
|
|
617
|
+
const response = await this.ctx.request(acp.methods.agent.session.setConfigOption, {
|
|
601
618
|
sessionId: this.session,
|
|
602
619
|
configId: option.id,
|
|
603
620
|
value: model
|
|
604
621
|
});
|
|
622
|
+
if (response?.configOptions?.length) this.configOptions = response.configOptions;
|
|
605
623
|
this.pendingModel = null;
|
|
606
624
|
return true;
|
|
607
625
|
}
|
|
@@ -737,21 +755,29 @@ var BotQueue = class {
|
|
|
737
755
|
}
|
|
738
756
|
};
|
|
739
757
|
|
|
740
|
-
// src/version.ts
|
|
741
|
-
var VBOT_VERSION = "0.1.2";
|
|
742
|
-
|
|
743
758
|
// src/core/dispatcher.ts
|
|
744
|
-
var
|
|
745
|
-
|
|
746
|
-
/
|
|
747
|
-
/
|
|
748
|
-
/
|
|
749
|
-
/
|
|
750
|
-
/
|
|
751
|
-
/
|
|
752
|
-
/
|
|
753
|
-
|
|
754
|
-
|
|
759
|
+
var import_node_os2 = require("os");
|
|
760
|
+
var HELP_ROWS = [
|
|
761
|
+
["/new", "Start a new session"],
|
|
762
|
+
["/stop", "Abort the current request"],
|
|
763
|
+
["/status", "Show agent, session and queue status"],
|
|
764
|
+
["/agent [name]", "Show or switch agent backend"],
|
|
765
|
+
["/model [name]", "Show or switch model"],
|
|
766
|
+
["/cost", "Show context usage and cost"],
|
|
767
|
+
["/version", "Show vbot version"],
|
|
768
|
+
["/help", "Show this help"]
|
|
769
|
+
];
|
|
770
|
+
var HELP_FOOTER = "Other /commands are sent to the agent as prompts.";
|
|
771
|
+
var NEW_BUSY_TEXT = "Cannot reset the session while a request is running. Use /stop first.";
|
|
772
|
+
var MODEL_BUSY_TEXT = "Cannot switch model while a request is running. Use /stop first.";
|
|
773
|
+
var HELP_TEXT = [
|
|
774
|
+
table(
|
|
775
|
+
["Command", "Description"],
|
|
776
|
+
HELP_ROWS.map(([command, description]) => [command, description])
|
|
777
|
+
),
|
|
778
|
+
"",
|
|
779
|
+
HELP_FOOTER
|
|
780
|
+
].join("\n");
|
|
755
781
|
function createDispatcher(runtime) {
|
|
756
782
|
return (text, reply) => {
|
|
757
783
|
const send = (message) => {
|
|
@@ -765,11 +791,57 @@ function createDispatcher(runtime) {
|
|
|
765
791
|
});
|
|
766
792
|
};
|
|
767
793
|
}
|
|
794
|
+
function escapeCell(value) {
|
|
795
|
+
return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
796
|
+
}
|
|
797
|
+
function table(headers, rows) {
|
|
798
|
+
const head = `| ${headers.map(escapeCell).join(" | ")} |`;
|
|
799
|
+
const separator = `| ${headers.map(() => "---").join(" | ")} |`;
|
|
800
|
+
const body = rows.map((row) => `| ${row.map(escapeCell).join(" | ")} |`);
|
|
801
|
+
return [head, separator, ...body].join("\n");
|
|
802
|
+
}
|
|
803
|
+
function formatNumber(value) {
|
|
804
|
+
if (!Number.isFinite(value)) return String(value);
|
|
805
|
+
const negative = value < 0;
|
|
806
|
+
const digits = Math.abs(Math.trunc(value)).toString();
|
|
807
|
+
let out = "";
|
|
808
|
+
for (let i = 0; i < digits.length; i += 1) {
|
|
809
|
+
if (i > 0 && (digits.length - i) % 3 === 0) out += ",";
|
|
810
|
+
out += digits[i];
|
|
811
|
+
}
|
|
812
|
+
return negative ? "-" + out : out;
|
|
813
|
+
}
|
|
814
|
+
function percentOf(used, size) {
|
|
815
|
+
if (size <= 0) return null;
|
|
816
|
+
return `${(used / size * 100).toFixed(1)}%`;
|
|
817
|
+
}
|
|
818
|
+
function usageText(runtime) {
|
|
819
|
+
const { used, size } = runtime.state().usage;
|
|
820
|
+
if (size <= 0) return "not reported";
|
|
821
|
+
const base = `${formatNumber(used)} / ${formatNumber(size)}`;
|
|
822
|
+
const percent = percentOf(used, size);
|
|
823
|
+
return percent ? `${base} (${percent})` : base;
|
|
824
|
+
}
|
|
825
|
+
function compactPath(path) {
|
|
826
|
+
const home = (0, import_node_os2.homedir)();
|
|
827
|
+
if (!home) return path;
|
|
828
|
+
if (path === home) return "~";
|
|
829
|
+
const prefix = home + "/";
|
|
830
|
+
if (path.startsWith(prefix)) return "~" + path.slice(home.length);
|
|
831
|
+
return path;
|
|
832
|
+
}
|
|
833
|
+
function modelText(runtime) {
|
|
834
|
+
const current = runtime.agent().currentModel();
|
|
835
|
+
if (current) return current.label;
|
|
836
|
+
const configured = runtime.config().agent.model;
|
|
837
|
+
if (configured) return `${configured} (configured, not applied yet)`;
|
|
838
|
+
return "unknown (session not started)";
|
|
839
|
+
}
|
|
768
840
|
function handleSlashCommand(runtime, text, send) {
|
|
769
841
|
const [rawCommand, ...args] = text.split(/\s+/);
|
|
770
842
|
switch (rawCommand.toLowerCase()) {
|
|
771
843
|
case "/new":
|
|
772
|
-
handleNew(runtime, send);
|
|
844
|
+
void handleNew(runtime, send);
|
|
773
845
|
return null;
|
|
774
846
|
case "/stop":
|
|
775
847
|
handleStop(runtime, send);
|
|
@@ -781,7 +853,7 @@ function handleSlashCommand(runtime, text, send) {
|
|
|
781
853
|
handleAgent(runtime, args, send);
|
|
782
854
|
return null;
|
|
783
855
|
case "/model":
|
|
784
|
-
handleModel(runtime, args, send);
|
|
856
|
+
void handleModel(runtime, args, send);
|
|
785
857
|
return null;
|
|
786
858
|
case "/cost":
|
|
787
859
|
send(costText(runtime));
|
|
@@ -796,12 +868,18 @@ function handleSlashCommand(runtime, text, send) {
|
|
|
796
868
|
return text.slice(1);
|
|
797
869
|
}
|
|
798
870
|
}
|
|
799
|
-
function handleNew(runtime, send) {
|
|
800
|
-
runtime.
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
runtime.
|
|
871
|
+
async function handleNew(runtime, send) {
|
|
872
|
+
if (runtime.queue().status().busy) {
|
|
873
|
+
send(NEW_BUSY_TEXT);
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
await runtime.serialize(async () => {
|
|
877
|
+
runtime.agent().resetSession();
|
|
878
|
+
const state = runtime.state();
|
|
879
|
+
state.acpSessionId = null;
|
|
880
|
+
state.usage = { used: 0, size: 0, cost: null };
|
|
881
|
+
runtime.saveState();
|
|
882
|
+
});
|
|
805
883
|
send("Session reset. Starting a new conversation.");
|
|
806
884
|
}
|
|
807
885
|
function handleStop(runtime, send) {
|
|
@@ -817,12 +895,18 @@ function handleStop(runtime, send) {
|
|
|
817
895
|
}
|
|
818
896
|
function handleAgent(runtime, args, send) {
|
|
819
897
|
const name = args.join(" ").trim();
|
|
898
|
+
const current = runtime.config().agent.name;
|
|
820
899
|
if (!name) {
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
900
|
+
send(
|
|
901
|
+
table(
|
|
902
|
+
["Agent", "Backend", ""],
|
|
903
|
+
AGENT_NAMES.map((entry) => [
|
|
904
|
+
entry,
|
|
905
|
+
AGENTS[entry].label,
|
|
906
|
+
entry === current ? "\u2190 current" : ""
|
|
907
|
+
])
|
|
908
|
+
)
|
|
909
|
+
);
|
|
826
910
|
return;
|
|
827
911
|
}
|
|
828
912
|
if (!isAgentName(name)) {
|
|
@@ -838,56 +922,95 @@ ${list}`);
|
|
|
838
922
|
(error) => send(`Error: ${error instanceof Error ? error.message : String(error)}`)
|
|
839
923
|
);
|
|
840
924
|
}
|
|
841
|
-
function handleModel(runtime, args, send) {
|
|
925
|
+
async function handleModel(runtime, args, send) {
|
|
842
926
|
const model = args.join(" ").trim();
|
|
843
927
|
if (!model) {
|
|
844
|
-
send(
|
|
928
|
+
send(modelReport(runtime));
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
if (runtime.queue().status().busy) {
|
|
932
|
+
send(MODEL_BUSY_TEXT);
|
|
845
933
|
return;
|
|
846
934
|
}
|
|
847
935
|
const config = runtime.config();
|
|
848
936
|
const hadSession = runtime.agent().sessionId() !== null;
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
}
|
|
937
|
+
const supported = await runtime.serialize(async () => {
|
|
938
|
+
const accepted = await runtime.agent().setModel(model);
|
|
939
|
+
config.agent.model = model;
|
|
940
|
+
runtime.saveConfig();
|
|
941
|
+
return accepted;
|
|
942
|
+
});
|
|
943
|
+
const applied = runtime.agent().currentModel()?.label ?? model;
|
|
944
|
+
if (!supported) {
|
|
858
945
|
send(
|
|
859
|
-
|
|
946
|
+
`Model saved: ${model}. This agent does not expose a runtime model option; it will be used on the next session if supported.`
|
|
860
947
|
);
|
|
861
|
-
|
|
862
|
-
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
send(
|
|
951
|
+
hadSession ? `Model switched to: ${applied}` : `Model set to: ${applied}. It will apply when the session starts.`
|
|
863
952
|
);
|
|
864
953
|
}
|
|
954
|
+
function modelReport(runtime) {
|
|
955
|
+
const current = runtime.agent().currentModel();
|
|
956
|
+
if (!current) {
|
|
957
|
+
const configured = runtime.config().agent.model;
|
|
958
|
+
const hint = configured ? `Configured: ${configured}
|
|
959
|
+
|
|
960
|
+
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.";
|
|
961
|
+
return `Current: unknown
|
|
962
|
+
|
|
963
|
+
${hint}`;
|
|
964
|
+
}
|
|
965
|
+
const lines = [`Current: ${current.label}`];
|
|
966
|
+
if (current.options.length > 0) {
|
|
967
|
+
lines.push(
|
|
968
|
+
"",
|
|
969
|
+
table(
|
|
970
|
+
["Model", ""],
|
|
971
|
+
current.options.map((option) => [
|
|
972
|
+
option.label,
|
|
973
|
+
option.value === current.value ? "\u2190 current" : ""
|
|
974
|
+
])
|
|
975
|
+
)
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
lines.push("", "Switch: /model <name>");
|
|
979
|
+
return lines.join("\n");
|
|
980
|
+
}
|
|
865
981
|
function statusText(runtime) {
|
|
866
982
|
const config = runtime.config();
|
|
867
983
|
const agent = runtime.agent();
|
|
868
984
|
const state = runtime.state();
|
|
869
985
|
const queue = runtime.queue().status();
|
|
870
|
-
const
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
986
|
+
const { used, size } = state.usage;
|
|
987
|
+
const summary = [
|
|
988
|
+
`**${config.agent.name}**`,
|
|
989
|
+
queue.busy ? "busy" : "idle",
|
|
990
|
+
size > 0 ? `${formatNumber(used)} / ${formatNumber(size)}` : null
|
|
991
|
+
].filter(Boolean).join(" \xB7 ");
|
|
992
|
+
const rows = [
|
|
993
|
+
["Agent", `${config.agent.name} (${AGENTS[config.agent.name].label})`],
|
|
994
|
+
["Session", agent.sessionId() ?? "none"],
|
|
995
|
+
["Work dir", compactPath(config.agent.cwd)],
|
|
996
|
+
["Model", modelText(runtime)],
|
|
997
|
+
["Status", queue.busy ? "busy" : "idle"],
|
|
998
|
+
["Queue", String(queue.queued)],
|
|
999
|
+
["Usage", usageText(runtime)],
|
|
1000
|
+
["Capabilities", capabilitiesText(agent.capabilities())]
|
|
879
1001
|
];
|
|
880
|
-
return
|
|
1002
|
+
return [summary, "", table(["Field", "Value"], rows)].join("\n");
|
|
881
1003
|
}
|
|
882
1004
|
function costText(runtime) {
|
|
883
1005
|
const usage = runtime.state().usage;
|
|
884
|
-
const
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
1006
|
+
const cost = usage.cost ? `${usage.cost.amount} ${usage.cost.currency}` : "not reported by this agent";
|
|
1007
|
+
return table(
|
|
1008
|
+
["Field", "Value"],
|
|
1009
|
+
[
|
|
1010
|
+
["Context", usageText(runtime)],
|
|
1011
|
+
["Cost", cost]
|
|
1012
|
+
]
|
|
1013
|
+
);
|
|
891
1014
|
}
|
|
892
1015
|
function capabilitiesText(caps) {
|
|
893
1016
|
const enabled = [
|
|
@@ -942,10 +1065,10 @@ var import_node_path5 = require("path");
|
|
|
942
1065
|
// src/core/state.ts
|
|
943
1066
|
var import_node_crypto = require("crypto");
|
|
944
1067
|
var import_node_fs4 = require("fs");
|
|
945
|
-
var
|
|
1068
|
+
var import_node_os3 = require("os");
|
|
946
1069
|
var import_node_path4 = require("path");
|
|
947
1070
|
function vbotHome() {
|
|
948
|
-
return process.env.VBOT_HOME?.trim() || (0, import_node_path4.join)((0,
|
|
1071
|
+
return process.env.VBOT_HOME?.trim() || (0, import_node_path4.join)((0, import_node_os3.homedir)(), ".vbot");
|
|
949
1072
|
}
|
|
950
1073
|
function stateDir() {
|
|
951
1074
|
return (0, import_node_path4.join)(vbotHome(), "state");
|
|
@@ -1274,13 +1397,17 @@ async function startBot(configPath) {
|
|
|
1274
1397
|
saveConfig: () => saveConfig(config, configPath)
|
|
1275
1398
|
};
|
|
1276
1399
|
holder.queue = new BotQueue((item, signal) => gate(() => processPrompt(ctx, item, signal)));
|
|
1277
|
-
const runtime = createRuntime(
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
switching
|
|
1282
|
-
|
|
1283
|
-
|
|
1400
|
+
const runtime = createRuntime(
|
|
1401
|
+
ctx,
|
|
1402
|
+
(task) => gate(task),
|
|
1403
|
+
(name) => {
|
|
1404
|
+
if (switching) return Promise.reject(new Error("Agent switch already in progress."));
|
|
1405
|
+
switching = true;
|
|
1406
|
+
return gate(() => switchAgent(ctx, name)).finally(() => {
|
|
1407
|
+
switching = false;
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
);
|
|
1284
1411
|
const dispatch = createDispatcher(runtime);
|
|
1285
1412
|
let notifySignal = () => void 0;
|
|
1286
1413
|
const wire = new VicvicWire({
|
|
@@ -1341,7 +1468,7 @@ async function runBot(configPath) {
|
|
|
1341
1468
|
const bot = await startBot(configPath);
|
|
1342
1469
|
await bot.finished;
|
|
1343
1470
|
}
|
|
1344
|
-
function createRuntime(ctx, switchAgent2) {
|
|
1471
|
+
function createRuntime(ctx, gate, switchAgent2) {
|
|
1345
1472
|
return {
|
|
1346
1473
|
config: () => ctx.config,
|
|
1347
1474
|
agent: () => ctx.getAgent(),
|
|
@@ -1349,6 +1476,7 @@ function createRuntime(ctx, switchAgent2) {
|
|
|
1349
1476
|
state: () => ctx.state,
|
|
1350
1477
|
saveState: () => ctx.saveState(),
|
|
1351
1478
|
saveConfig: () => ctx.saveConfig(),
|
|
1479
|
+
serialize: (task) => gate(task),
|
|
1352
1480
|
switchAgent: switchAgent2
|
|
1353
1481
|
};
|
|
1354
1482
|
}
|