@shipers-dev/multi 0.46.0 → 0.47.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 (2) hide show
  1. package/dist/index.js +124 -89
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -36725,6 +36725,7 @@ async function processUserMessage(chat2, userMsg, peer, ctx) {
36725
36725
  let buffered = "";
36726
36726
  let lastFlush = Date.now();
36727
36727
  let agentReplyText = "";
36728
+ const fullReplyParts = [];
36728
36729
  const toolMsgByCallId = new Map;
36729
36730
  let planContainerId = null;
36730
36731
  const flushText = (force = false) => {
@@ -36794,92 +36795,98 @@ async function processUserMessage(chat2, userMsg, peer, ctx) {
36794
36795
  };
36795
36796
  const preamble = buildChatPreamble({ projectId: chat2.project_id, agents: allAgents });
36796
36797
  peer.markDelivered(userMsg.id);
36797
- await new Promise((resolve2) => {
36798
- handleChatTurn({
36799
- chatId: chat2.id,
36800
- prompt: userMsg.text,
36801
- preferredRuntime: runtime4,
36802
- cwd,
36803
- systemPreamble: preamble,
36804
- log: log4,
36805
- onChunk: (text) => {
36806
- ensureTextOpen();
36807
- buffered += text;
36808
- agentReplyText += text;
36809
- flushText();
36810
- },
36811
- onToolCall: (ev) => {
36812
- closeText();
36813
- const partial2 = ev.status !== "completed" && ev.status !== "failed";
36814
- const status3 = ev.status || "in_progress";
36815
- if (ev.id) {
36816
- const existing = toolMsgByCallId.get(ev.id);
36817
- if (existing) {
36818
- peer.patchMessage(existing, {
36819
- partial: partial2,
36820
- status: status3,
36821
- tool: ev.tool,
36822
- tool_kind: mapToolKind(ev.kind),
36823
- input: summarizeInput(ev.input)
36824
- });
36825
- return;
36798
+ const runOneTurn = async (prompt, sendPreamble) => {
36799
+ agentReplyText = "";
36800
+ await new Promise((resolve2) => {
36801
+ handleChatTurn({
36802
+ chatId: chat2.id,
36803
+ prompt,
36804
+ preferredRuntime: runtime4,
36805
+ cwd,
36806
+ systemPreamble: sendPreamble ? preamble : undefined,
36807
+ log: log4,
36808
+ onChunk: (text) => {
36809
+ ensureTextOpen();
36810
+ buffered += text;
36811
+ agentReplyText += text;
36812
+ flushText();
36813
+ },
36814
+ onToolCall: (ev) => {
36815
+ closeText();
36816
+ const partial2 = ev.status !== "completed" && ev.status !== "failed";
36817
+ const status3 = ev.status || "in_progress";
36818
+ if (ev.id) {
36819
+ const existing = toolMsgByCallId.get(ev.id);
36820
+ if (existing) {
36821
+ peer.patchMessage(existing, {
36822
+ partial: partial2,
36823
+ status: status3,
36824
+ tool: ev.tool,
36825
+ tool_kind: mapToolKind(ev.kind),
36826
+ input: summarizeInput(ev.input)
36827
+ });
36828
+ return;
36829
+ }
36826
36830
  }
36831
+ const id3 = `tc_${ev.id || Math.random().toString(36).slice(2)}`;
36832
+ const containerId = peer.appendStructured({
36833
+ id: id3,
36834
+ author: { kind: "agent", id: agentAuthorId, name: agentDisplayName },
36835
+ kind: "tool_call",
36836
+ text: "",
36837
+ ts: Math.floor(Date.now() / 1000),
36838
+ mentions: [],
36839
+ attachments: [],
36840
+ partial: partial2,
36841
+ tool: ev.tool,
36842
+ tool_kind: mapToolKind(ev.kind),
36843
+ status: status3,
36844
+ input: summarizeInput(ev.input),
36845
+ tool_call_id: ev.id
36846
+ });
36847
+ if (ev.id)
36848
+ toolMsgByCallId.set(ev.id, containerId);
36849
+ },
36850
+ onToolResult: (ev) => {
36851
+ closeText();
36852
+ const summary5 = summarizeContent(ev.content);
36853
+ peer.appendStructured({
36854
+ id: `tr_${ev.tool_call_id || Math.random().toString(36).slice(2)}_${Date.now()}`,
36855
+ author: { kind: "agent", id: agentAuthorId, name: agentDisplayName },
36856
+ kind: "tool_result",
36857
+ text: `${summary5.lines} lines · ${summary5.bytes} bytes`,
36858
+ ts: Math.floor(Date.now() / 1000),
36859
+ mentions: [],
36860
+ attachments: [],
36861
+ partial: false,
36862
+ tool_call_id: ev.tool_call_id,
36863
+ content: summary5.content
36864
+ });
36865
+ const cid = ev.tool_call_id ? toolMsgByCallId.get(ev.tool_call_id) : undefined;
36866
+ if (cid)
36867
+ peer.patchMessage(cid, { partial: false, status: "completed" });
36868
+ },
36869
+ onPlanUpdate: (entries2) => {
36870
+ closeText();
36871
+ planContainerId = peer.upsertPlan(agentAuthorId, agentDisplayName, entries2, planContainerId);
36872
+ },
36873
+ onDone: (stopReason) => {
36874
+ closeText();
36875
+ for (const cid of toolMsgByCallId.values()) {
36876
+ peer.patchMessage(cid, { partial: false, status: "completed" });
36877
+ }
36878
+ log4(`[chat ${chat2.id}] done: ${stopReason}`);
36879
+ resolve2();
36827
36880
  }
36828
- const id3 = `tc_${ev.id || Math.random().toString(36).slice(2)}`;
36829
- const containerId = peer.appendStructured({
36830
- id: id3,
36831
- author: { kind: "agent", id: agentAuthorId, name: agentDisplayName },
36832
- kind: "tool_call",
36833
- text: "",
36834
- ts: Math.floor(Date.now() / 1000),
36835
- mentions: [],
36836
- attachments: [],
36837
- partial: partial2,
36838
- tool: ev.tool,
36839
- tool_kind: mapToolKind(ev.kind),
36840
- status: status3,
36841
- input: summarizeInput(ev.input),
36842
- tool_call_id: ev.id
36843
- });
36844
- if (ev.id)
36845
- toolMsgByCallId.set(ev.id, containerId);
36846
- },
36847
- onToolResult: (ev) => {
36848
- closeText();
36849
- const summary5 = summarizeContent(ev.content);
36850
- peer.appendStructured({
36851
- id: `tr_${ev.tool_call_id || Math.random().toString(36).slice(2)}_${Date.now()}`,
36852
- author: { kind: "agent", id: agentAuthorId, name: agentDisplayName },
36853
- kind: "tool_result",
36854
- text: `${summary5.lines} lines · ${summary5.bytes} bytes`,
36855
- ts: Math.floor(Date.now() / 1000),
36856
- mentions: [],
36857
- attachments: [],
36858
- partial: false,
36859
- tool_call_id: ev.tool_call_id,
36860
- content: summary5.content
36861
- });
36862
- const cid = ev.tool_call_id ? toolMsgByCallId.get(ev.tool_call_id) : undefined;
36863
- if (cid)
36864
- peer.patchMessage(cid, { partial: false, status: "completed" });
36865
- },
36866
- onPlanUpdate: (entries2) => {
36867
- closeText();
36868
- planContainerId = peer.upsertPlan(agentAuthorId, agentDisplayName, entries2, planContainerId);
36869
- },
36870
- onDone: (stopReason) => {
36871
- closeText();
36872
- for (const cid of toolMsgByCallId.values()) {
36873
- peer.patchMessage(cid, { partial: false, status: "completed" });
36874
- }
36875
- log4(`[chat ${chat2.id}] done: ${stopReason}`);
36876
- resolve2();
36877
- }
36881
+ });
36878
36882
  });
36879
- });
36880
- try {
36881
- const { actions, errors: errors3 } = parsePlanBlocks(agentReplyText);
36882
- if (actions.length || errors3.length) {
36883
+ fullReplyParts.push(agentReplyText);
36884
+ };
36885
+ const execAndPostPlan = async () => {
36886
+ try {
36887
+ const { actions, errors: errors3 } = parsePlanBlocks(agentReplyText);
36888
+ if (!actions.length && !errors3.length)
36889
+ return null;
36883
36890
  const res = await executeChatPlanActions(actions, errors3, {
36884
36891
  apiUrl,
36885
36892
  wsId: workspaceId,
@@ -36902,17 +36909,44 @@ async function processUserMessage(chat2, userMsg, peer, ctx) {
36902
36909
  });
36903
36910
  }
36904
36911
  log4(`[chat ${chat2.id}] plan exec: ${res.ok} ok, ${res.fail} fail, ${errors3.length} parse-err`);
36912
+ return { ok: res.ok, fail: res.fail, lines: res.lines };
36913
+ } catch (e) {
36914
+ log4(`[chat ${chat2.id}] post-turn err: ${e.message}`);
36915
+ return null;
36905
36916
  }
36906
- const ui = parseUiBlocks(agentReplyText);
36917
+ };
36918
+ await runOneTurn(userMsg.text, true);
36919
+ const firstPlan = await execAndPostPlan();
36920
+ if (firstPlan && firstPlan.ok > 0) {
36921
+ const resultText = firstPlan.lines.join(`
36922
+ `).slice(0, 6000);
36923
+ const followupPrompt = `[multi system note — auto-injected, not from the user]
36924
+
36925
+ ` + `Your previous multi-plan block was executed. Results below:
36926
+
36927
+ ` + `${resultText}
36928
+
36929
+ ` + `If these results need a follow-up multi-plan action (e.g. commenting on a newly-created issue using its returned KEY, or chaining work that depends on freshly-created ids), append ONE more multi-plan block now. Otherwise reply with a short confirmation to the user that summarises the outcome. Do NOT repeat actions you already ran successfully.`;
36930
+ await runOneTurn(followupPrompt, false);
36931
+ await execAndPostPlan();
36932
+ }
36933
+ try {
36934
+ const combined = fullReplyParts.join(`
36935
+
36936
+ `);
36937
+ const ui = parseUiBlocks(combined);
36907
36938
  if (ui.blocks.length)
36908
36939
  log4(`[chat ${chat2.id}] ui blocks: ${ui.blocks.length}`);
36909
36940
  if (ui.errors.length)
36910
36941
  log4(`[chat ${chat2.id}] ui parse err: ${ui.errors.length}`);
36911
36942
  } catch (e) {
36912
- log4(`[chat ${chat2.id}] post-turn err: ${e.message}`);
36943
+ log4(`[chat ${chat2.id}] ui parse err: ${e.message}`);
36913
36944
  }
36914
- if (/^new chat$/i.test(chat2.title) && agentReplyText.trim()) {
36915
- autoTitle(chat2, userMsg.text, agentReplyText, ctx).catch((e) => log4(`[chat ${chat2.id}] auto-title failed: ${e.message}`));
36945
+ const fullReply = fullReplyParts.join(`
36946
+
36947
+ `);
36948
+ if (/^new chat$/i.test(chat2.title) && fullReply.trim()) {
36949
+ autoTitle(chat2, userMsg.text, fullReply, ctx).catch((e) => log4(`[chat ${chat2.id}] auto-title failed: ${e.message}`));
36916
36950
  }
36917
36951
  }
36918
36952
  async function autoTitle(chat2, userMsg, agentReply, ctx) {
@@ -36963,7 +36997,7 @@ ${args2.agents.slice(0, 30).map((a) => `- \`${a.id}\` (${a.name})`).join(`
36963
36997
  ` : "";
36964
36998
  return `# multi platform — tool surface
36965
36999
 
36966
- You are running inside the multi platform. To create issues, agents, skills, or sessions, append ONE fenced \`multi-plan\` block at the end of your reply (JSON; either an array of actions, or {"actions":[...]}). The host parses it and executes immediately. Do NOT call \`gh\`, GitHub APIs, Linear, Jira, or any external tracker unless the user explicitly names that platform — multi is the default.
37000
+ You are running inside the multi platform. To create issues, agents, skills, or sessions, append ONE fenced \`multi-plan\` block at the end of your reply (JSON; either an array of actions, or {"actions":[...]}). The host parses it and executes immediately. Do NOT call \`gh\`, GitHub APIs, Linear, Jira, or any external tracker unless the user explicitly names that platform — multi is the default. In prose, refer to these as "issues" or by their KEY (e.g. \`ABC-12\`). Never call them "GitHub issues", "Linear issues", or "Jira tickets".
36967
37001
 
36968
37002
  ${projectLine}
36969
37003
 
@@ -36993,6 +37027,7 @@ Rules:
36993
37027
  - Max 10 actions per turn. Sub-caps: agent.create=2, skill.create=3, agent.update=5, skill.attach/detach=5, session.create=3, issue.comment=5.
36994
37028
  - Chat-initiated agent.create / agent.update / skill.attach are auto-approved (the user is reading this reply right now). skill.create still queues for human review.
36995
37029
  - Use \`issue.comment\` with \`@<agent name>\` mention to dispatch an agent on an existing issue. Plain comments without an @mention are recorded but do not trigger a run. Issues whose autonomy is \`manual\` will not dispatch.
37030
+ - To create an issue AND assign/dispatch it to an agent in the same turn, set \`assignee_type\` + \`assignee_id\` directly on the \`create\` action. Do NOT emit a separate \`delegate\` or \`issue.comment\` action referring to a brand-new issue in the same plan block — actions execute as a flat list and the new issue's id/key is not available to later actions in the same block. \`delegate\` and \`issue.comment\` are for issues that already exist before this turn.
36996
37031
  - \`allowed_tools\` on a new agent must be a subset of generally available tools.
36997
37032
 
36998
37033
  To draw an inline panel for the user, append a separate fenced \`multi-ui\` block. The host uploads it to a Cloudflare Worker (24h TTL), serves the rendered HTML at a public URL, and embeds it in a sandboxed iframe (\`allow-scripts allow-forms\`). No reactive runtime — write plain HTML with optional inline \`<script>\` for interactivity. \`window.data\` inside your script is the JSON you sent.
@@ -37763,7 +37798,7 @@ import { parseArgs } from "util";
37763
37798
  // package.json
37764
37799
  var package_default = {
37765
37800
  name: "@shipers-dev/multi",
37766
- version: "0.46.0",
37801
+ version: "0.47.1",
37767
37802
  type: "module",
37768
37803
  bin: {
37769
37804
  "multi-agent": "./dist/index.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipers-dev/multi",
3
- "version": "0.46.0",
3
+ "version": "0.47.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "multi-agent": "./dist/index.js"