volute 0.7.0 → 0.8.1

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.
Files changed (77) hide show
  1. package/README.md +16 -14
  2. package/dist/{agent-7JF7MT73.js → agent-YORVRB6I.js} +10 -10
  3. package/dist/{agent-manager-IMZ7ZMBF.js → agent-manager-CMMH5KQQ.js} +4 -4
  4. package/dist/{channel-SMCNOIVQ.js → channel-RDGHBFSI.js} +16 -56
  5. package/dist/{chunk-JR4UXCTO.js → chunk-23L3MKEV.js} +1 -1
  6. package/dist/{chunk-5SKQ6J7T.js → chunk-5C5JWR2L.js} +15 -7
  7. package/dist/{chunk-UWHWAPGO.js → chunk-DP2DX4WV.js} +9 -1
  8. package/dist/{chunk-7ACDT3P2.js → chunk-ECPQXRLB.js} +1 -2
  9. package/dist/{chunk-LLJNZPCU.js → chunk-HZ5LTOEJ.js} +1 -1
  10. package/dist/{chunk-W76KWE23.js → chunk-IQXBMFZG.js} +6 -4
  11. package/dist/{chunk-ZZOOTYXK.js → chunk-LIPPXNIE.js} +60 -74
  12. package/dist/{chunk-BX7KI4S3.js → chunk-N6MLQ26B.js} +23 -96
  13. package/dist/{chunk-H7AMDUIA.js → chunk-QF22MYDJ.js} +6 -5
  14. package/dist/{chunk-NKXULRSW.js → chunk-RT6Y7AR3.js} +1 -1
  15. package/dist/{chunk-62X577Y7.js → chunk-W6TMWYU3.js} +126 -73
  16. package/dist/{chunk-EG45HBSJ.js → chunk-XSJ27WEM.js} +1 -1
  17. package/dist/cli.js +22 -20
  18. package/dist/{connector-Y7JPNROO.js → connector-ZP6MEFF4.js} +3 -3
  19. package/dist/connectors/discord.js +18 -59
  20. package/dist/connectors/slack.js +21 -38
  21. package/dist/connectors/telegram.js +31 -49
  22. package/dist/{create-G525LWEA.js → create-HGJHLABX.js} +22 -17
  23. package/dist/{daemon-client-442IV43D.js → daemon-client-54J3EIZD.js} +2 -2
  24. package/dist/{daemon-restart-4HVEKYFY.js → daemon-restart-CPBLMMRI.js} +3 -3
  25. package/dist/daemon.js +342 -402
  26. package/dist/{delete-UOU4AFQN.js → delete-45TGQC4N.js} +10 -5
  27. package/dist/{down-AZVH5TCD.js → down-O4EWZTVA.js} +2 -2
  28. package/dist/{env-7GLUJCWS.js → env-KMNYGVZ2.js} +7 -9
  29. package/dist/{history-H72ZUIBN.js → history-PXJVYLVY.js} +2 -2
  30. package/dist/{import-AVKQJDYC.js → import-CNEDF3TD.js} +6 -6
  31. package/dist/{logs-EDGK26AK.js → logs-TZB3MTLZ.js} +5 -4
  32. package/dist/{package-T2WAVJOU.js → package-RJSONENE.js} +1 -1
  33. package/dist/{restart-O4ETYLJF.js → restart-KVH3TK5N.js} +2 -2
  34. package/dist/{schedule-S6QVC5ON.js → schedule-HCUCBNQI.js} +2 -2
  35. package/dist/send-BNC2S5BY.js +162 -0
  36. package/dist/{service-HZNIDNJF.js → service-XCADRKIS.js} +8 -1
  37. package/dist/{setup-F4TCWVSP.js → setup-32KH5KLN.js} +85 -26
  38. package/dist/{start-VHQ7LNWM.js → start-QU73YTJW.js} +2 -2
  39. package/dist/{status-QAJWXKMZ.js → status-Q6ZQJXNI.js} +2 -2
  40. package/dist/{stop-CAGCT5NI.js → stop-N7U5N6A7.js} +2 -2
  41. package/dist/{up-RWZF6MLT.js → up-V6EAA7OZ.js} +2 -2
  42. package/dist/{update-F7QWV2LB.js → update-EUCZ7XGG.js} +3 -3
  43. package/dist/{update-check-B4J6IEQ4.js → update-check-SM4244SU.js} +2 -2
  44. package/dist/{upgrade-YXKPWDRU.js → upgrade-CZF6PN7Y.js} +4 -4
  45. package/dist/{variant-4Z6W3PP6.js → variant-RKXPN5DH.js} +20 -46
  46. package/dist/web-assets/assets/index-D-3zx6vs.js +307 -0
  47. package/dist/web-assets/index.html +1 -1
  48. package/drizzle/0004_magical_silverclaw.sql +1 -0
  49. package/drizzle/meta/0004_snapshot.json +410 -0
  50. package/drizzle/meta/_journal.json +7 -0
  51. package/package.json +1 -1
  52. package/templates/_base/_skills/volute-agent/SKILL.md +32 -16
  53. package/templates/_base/home/.config/routes.json +4 -8
  54. package/templates/_base/home/VOLUTE.md +16 -14
  55. package/templates/_base/src/lib/auto-reply.ts +38 -0
  56. package/templates/_base/src/lib/daemon-client.ts +53 -0
  57. package/templates/_base/src/lib/router.ts +66 -14
  58. package/templates/_base/src/lib/routing.ts +48 -9
  59. package/templates/_base/src/lib/startup.ts +1 -25
  60. package/templates/_base/src/lib/types.ts +2 -1
  61. package/templates/_base/src/lib/volute-server.ts +29 -14
  62. package/templates/agent-sdk/src/agent.ts +53 -111
  63. package/templates/agent-sdk/src/lib/content.ts +41 -0
  64. package/templates/agent-sdk/src/lib/session-store.ts +43 -0
  65. package/templates/agent-sdk/src/lib/stream-consumer.ts +66 -0
  66. package/templates/agent-sdk/src/server.ts +5 -13
  67. package/templates/pi/.init/AGENTS.md +5 -5
  68. package/templates/pi/src/agent.ts +32 -84
  69. package/templates/pi/src/lib/content.ts +15 -0
  70. package/templates/pi/src/lib/event-handler.ts +74 -0
  71. package/templates/pi/src/lib/resolve-model.ts +21 -0
  72. package/templates/pi/src/server.ts +3 -7
  73. package/dist/chunk-B3R6L2GW.js +0 -24
  74. package/dist/chunk-ZYGKG6VC.js +0 -22
  75. package/dist/message-SCOQDR3P.js +0 -32
  76. package/dist/send-G7PE4DOJ.js +0 -72
  77. package/dist/web-assets/assets/index-B1CqjUYD.js +0 -308
@@ -0,0 +1,74 @@
1
+ import { commitFileChange } from "./auto-commit.js";
2
+ import type { AutoReplyTracker, MessageChannelInfo } from "./auto-reply.js";
3
+ import { log, logText, logThinking, logToolResult, logToolUse } from "./logger.js";
4
+ import type { VoluteEvent } from "./types.js";
5
+
6
+ export type EventSession = {
7
+ name: string;
8
+ messageIds: (string | undefined)[];
9
+ currentMessageId?: string;
10
+ messageChannels: Map<string, MessageChannelInfo>;
11
+ autoReply: AutoReplyTracker;
12
+ };
13
+
14
+ export type EventHandlerOptions = {
15
+ cwd: string;
16
+ broadcast: (event: VoluteEvent) => void;
17
+ };
18
+
19
+ export function createEventHandler(session: EventSession, options: EventHandlerOptions) {
20
+ const toolArgs = new Map<string, any>();
21
+
22
+ return (event: any) => {
23
+ try {
24
+ if (session.currentMessageId === undefined) {
25
+ session.currentMessageId = session.messageIds.shift();
26
+ session.autoReply.reset();
27
+ }
28
+
29
+ if (event.type === "message_update") {
30
+ const ae = event.assistantMessageEvent;
31
+ if (ae.type === "text_delta") {
32
+ logText(ae.delta);
33
+ session.autoReply.accumulate(ae.delta);
34
+ } else if (ae.type === "thinking_delta") {
35
+ logThinking(ae.delta);
36
+ }
37
+ }
38
+
39
+ if (event.type === "tool_execution_start") {
40
+ session.autoReply.flush(session.currentMessageId);
41
+ toolArgs.set(event.toolCallId, event.args);
42
+ logToolUse(event.toolName, event.args);
43
+ }
44
+
45
+ if (event.type === "tool_execution_end") {
46
+ const output =
47
+ typeof event.result === "string" ? event.result : JSON.stringify(event.result);
48
+ logToolResult(event.toolName, output, event.isError);
49
+
50
+ // Auto-commit file changes in home/
51
+ if ((event.toolName === "edit" || event.toolName === "write") && !event.isError) {
52
+ const args = toolArgs.get(event.toolCallId);
53
+ const filePath = (args as { path?: string })?.path;
54
+ if (filePath) {
55
+ commitFileChange(filePath, options.cwd);
56
+ }
57
+ }
58
+ toolArgs.delete(event.toolCallId);
59
+ }
60
+
61
+ if (event.type === "agent_end") {
62
+ session.autoReply.flush(session.currentMessageId);
63
+ if (session.currentMessageId) {
64
+ session.messageChannels.delete(session.currentMessageId);
65
+ }
66
+ log("agent", `session "${session.name}": turn done`);
67
+ options.broadcast({ type: "done" });
68
+ session.currentMessageId = undefined;
69
+ }
70
+ } catch (err) {
71
+ log("agent", `session "${session.name}": event handler error:`, err);
72
+ }
73
+ };
74
+ }
@@ -0,0 +1,21 @@
1
+ import { getModel, getModels } from "@mariozechner/pi-ai";
2
+
3
+ export function resolveModel(modelStr: string) {
4
+ const [provider, ...rest] = modelStr.split(":");
5
+ const modelId = rest.join(":");
6
+
7
+ // Try exact match first, then prefix match against available models
8
+ let model = getModel(provider as any, modelId as any);
9
+ if (!model) {
10
+ const available = getModels(provider as any);
11
+ const found = available.find((m) => m.id.startsWith(modelId));
12
+ if (found) model = found;
13
+ }
14
+ if (!model) {
15
+ const available = getModels(provider as any);
16
+ throw new Error(
17
+ `Model not found: ${modelStr}\nAvailable ${provider} models: ${available.map((m) => m.id).join(", ")}`,
18
+ );
19
+ }
20
+ return model;
21
+ }
@@ -4,7 +4,6 @@ import { createFileHandlerResolver } from "./lib/file-handler.js";
4
4
  import { log } from "./lib/logger.js";
5
5
  import { createRouter } from "./lib/router.js";
6
6
  import {
7
- handleMergeContext,
8
7
  handleStartupContext,
9
8
  loadConfig,
10
9
  loadPackageInfo,
@@ -17,6 +16,7 @@ import { createVoluteServer } from "./lib/volute-server.js";
17
16
  const { port } = parseArgs();
18
17
  const config = loadConfig();
19
18
  if (config.model) log("server", `using model: ${config.model}`);
19
+ if (config.thinkingLevel) log("server", `thinking level: ${config.thinkingLevel}`);
20
20
 
21
21
  const systemPrompt = loadSystemPrompt();
22
22
  const pkg = loadPackageInfo();
@@ -25,6 +25,7 @@ const agent = createAgent({
25
25
  systemPrompt,
26
26
  cwd: resolve("home"),
27
27
  model: config.model,
28
+ thinkingLevel: config.thinkingLevel,
28
29
  compactionMessage: config.compactionMessage,
29
30
  });
30
31
 
@@ -45,14 +46,9 @@ server.listen(port, async () => {
45
46
  const addr = server.address();
46
47
  const actualPort = typeof addr === "object" && addr ? addr.port : port;
47
48
  log("server", `listening on :${actualPort}`);
48
- const hasMerge = handleMergeContext((content) =>
49
+ await handleStartupContext((content) =>
49
50
  router.route([{ type: "text", text: content }], { channel: "system" }),
50
51
  );
51
- if (!hasMerge) {
52
- await handleStartupContext((content) =>
53
- router.route([{ type: "text", text: content }], { channel: "system" }),
54
- );
55
- }
56
52
  });
57
53
 
58
54
  setupShutdown();
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/lib/format-tool.ts
4
- function summarizeTool(name, input) {
5
- if (input && typeof input === "object") {
6
- const args = input;
7
- const val = args.path ?? args.command ?? args.query ?? args.url;
8
- if (typeof val === "string") {
9
- const brief = val.length > 60 ? `${val.slice(0, 57)}...` : val;
10
- return `[${name} ${brief}]`;
11
- }
12
- }
13
- return `[${name}]`;
14
- }
15
- function collectPart(event) {
16
- if (event.type === "text") return event.content ?? "";
17
- if (event.type === "tool_use") return summarizeTool(event.name ?? "", event.input);
18
- return null;
19
- }
20
-
21
- export {
22
- summarizeTool,
23
- collectPart
24
- };
@@ -1,22 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/lib/read-stdin.ts
4
- import { isatty } from "tty";
5
- async function readStdin() {
6
- if (isatty(0)) return void 0;
7
- const chunks = [];
8
- try {
9
- for await (const chunk of process.stdin) {
10
- chunks.push(chunk);
11
- }
12
- } catch (err) {
13
- console.error(`Failed to read from stdin: ${err instanceof Error ? err.message : String(err)}`);
14
- process.exit(1);
15
- }
16
- const text = Buffer.concat(chunks).toString().replace(/\r?\n$/, "");
17
- return text || void 0;
18
- }
19
-
20
- export {
21
- readStdin
22
- };
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./chunk-K3NQKI34.js";
3
-
4
- // src/commands/message.ts
5
- async function run(args) {
6
- const subcommand = args[0];
7
- switch (subcommand) {
8
- case "send":
9
- await import("./send-G7PE4DOJ.js").then((m) => m.run(args.slice(1)));
10
- break;
11
- case "history":
12
- await import("./history-H72ZUIBN.js").then((m) => m.run(args.slice(1)));
13
- break;
14
- case "--help":
15
- case "-h":
16
- case void 0:
17
- printUsage();
18
- break;
19
- default:
20
- printUsage();
21
- process.exit(1);
22
- }
23
- }
24
- function printUsage() {
25
- console.log(`Usage:
26
- volute message send <name> "<msg>"
27
- echo "msg" | volute message send <name>
28
- volute message history [--agent <name>] [--channel <ch>] [--limit N]`);
29
- }
30
- export {
31
- run
32
- };
@@ -1,72 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- readStdin
4
- } from "./chunk-ZYGKG6VC.js";
5
- import {
6
- summarizeTool
7
- } from "./chunk-B3R6L2GW.js";
8
- import {
9
- getChannelDriver
10
- } from "./chunk-ZZOOTYXK.js";
11
- import "./chunk-BX7KI4S3.js";
12
- import {
13
- daemonFetch
14
- } from "./chunk-JR4UXCTO.js";
15
- import "./chunk-UWHWAPGO.js";
16
- import "./chunk-K3NQKI34.js";
17
-
18
- // src/commands/send.ts
19
- import { userInfo } from "os";
20
- async function run(args) {
21
- const name = args[0];
22
- const message = args[1] ?? await readStdin();
23
- if (!name || !message) {
24
- console.error('Usage: volute message send <name> "<message>"');
25
- console.error(' echo "message" | volute message send <name>');
26
- process.exit(1);
27
- }
28
- const agentSelf = process.env.VOLUTE_AGENT;
29
- const sender = agentSelf || userInfo().username;
30
- const driver = getChannelDriver("volute");
31
- if (!driver?.sendAndStream || !driver.createConversation) {
32
- console.error("Volute driver not available");
33
- process.exit(1);
34
- }
35
- const env = { VOLUTE_AGENT: name, VOLUTE_SENDER: sender };
36
- let conversationId;
37
- try {
38
- conversationId = await driver.createConversation(env, [sender]);
39
- } catch (err) {
40
- console.error(err instanceof Error ? err.message : String(err));
41
- process.exit(1);
42
- }
43
- try {
44
- for await (const event of driver.sendAndStream(env, conversationId, message)) {
45
- if (event.type === "text") {
46
- process.stdout.write(event.content);
47
- } else if (event.type === "tool_use") {
48
- process.stderr.write(`${summarizeTool(event.name, event.input)}
49
- `);
50
- }
51
- if (event.type === "done") break;
52
- }
53
- process.stdout.write("\n");
54
- } catch (err) {
55
- console.error(err instanceof Error ? err.message : String(err));
56
- process.exit(1);
57
- }
58
- if (agentSelf) {
59
- try {
60
- await daemonFetch(`/api/agents/${encodeURIComponent(agentSelf)}/history`, {
61
- method: "POST",
62
- headers: { "Content-Type": "application/json" },
63
- body: JSON.stringify({ channel: conversationId, content: message })
64
- });
65
- } catch (err) {
66
- console.error(`Failed to persist to history: ${err instanceof Error ? err.message : err}`);
67
- }
68
- }
69
- }
70
- export {
71
- run
72
- };