@shipers-dev/multi 0.51.0 → 0.52.0

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 +133 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -34148,7 +34148,7 @@ function parsePlanBlocks(text) {
34148
34148
  }
34149
34149
  return { actions, errors: errors3 };
34150
34150
  }
34151
- var PLAN_SCHEMA_VERSION = 6, Priority, AssigneeType, IssueStatus, SessionRole, SkillFile, EvalPolicy, PlanActionSchema, PlanEnvelopeSchema, UiBlockSchema, UI_FENCE_RE, FENCE_RE;
34151
+ var PLAN_SCHEMA_VERSION = 7, Priority, AssigneeType, IssueStatus, SessionRole, SkillFile, EvalPolicy, PlanActionSchema, PlanEnvelopeSchema, UiBlockSchema, UI_FENCE_RE, FENCE_RE;
34152
34152
  var init_plans = __esm(() => {
34153
34153
  init_zod();
34154
34154
  Priority = exports_external.enum(["low", "medium", "high"]);
@@ -34268,6 +34268,20 @@ var init_plans = __esm(() => {
34268
34268
  score: exports_external.number().min(0).max(1),
34269
34269
  feedback: exports_external.string().min(1).max(8000),
34270
34270
  scores: exports_external.record(exports_external.string(), exports_external.number().min(0).max(1)).optional()
34271
+ }),
34272
+ exports_external.object({
34273
+ type: exports_external.literal("memory.search"),
34274
+ project_id: exports_external.string().optional(),
34275
+ query: exports_external.string().min(1).max(1000),
34276
+ limit: exports_external.number().int().min(1).max(50).optional()
34277
+ }),
34278
+ exports_external.object({
34279
+ type: exports_external.literal("memory.write"),
34280
+ project_id: exports_external.string().optional(),
34281
+ text: exports_external.string().min(1).max(20000),
34282
+ summary: exports_external.string().max(2000).optional(),
34283
+ kind: exports_external.string().min(1).max(64).optional(),
34284
+ source_id: exports_external.string().min(1).max(256).optional()
34271
34285
  })
34272
34286
  ]);
34273
34287
  PlanEnvelopeSchema = exports_external.object({
@@ -35366,7 +35380,9 @@ Issue actions:
35366
35380
  {"type":"issue.delete","id":"<issue id or key>"},
35367
35381
  {"type":"issue.delete_where","status":"todo"},
35368
35382
  {"type":"issue.list","status":"todo","assignee_id":"<agent id>","limit":20},
35369
- {"type":"issue.search","query":"flaky tests","limit":10}
35383
+ {"type":"issue.search","query":"flaky tests","limit":10},
35384
+ {"type":"memory.search","query":"how does the deploy pipeline work","limit":10},
35385
+ {"type":"memory.write","text":"Long-form note worth remembering across sessions...","summary":"short index hint","kind":"agent_note"}
35370
35386
  ]}
35371
35387
  \`\`\`
35372
35388
 
@@ -35374,7 +35390,9 @@ Status values: \`todo\` | \`in_progress\` | \`blocked\` | \`done\` | \`archived\
35374
35390
 
35375
35391
  Prefer the bulk \`issue.delete_where\` over \`issue.list\` + per-issue \`issue.delete\` when the user's intent matches a filter ("delete all todo issues", "remove anything assigned to agent X"). It runs in one turn instead of two.
35376
35392
 
35377
- Read actions (\`issue.list\`, \`issue.search\`) return the matched rows in the action summary comment. Use them to look up issue ids/keys before \`update\` / \`delegate\` / \`issue.delete\` ONLY when the per-row filter isn't enough (e.g. you need to inspect titles before acting).
35393
+ Read actions (\`issue.list\`, \`issue.search\`, \`memory.search\`) return the matched rows in the action summary comment. Use them to look up issue ids/keys before \`update\` / \`delegate\` / \`issue.delete\` ONLY when the per-row filter isn't enough (e.g. you need to inspect titles before acting).
35394
+
35395
+ Memory actions are project-scoped persistent storage (FTS5 + vector). Use \`memory.search\` to recall facts learned in past sessions; the hits land in the next-turn context like \`issue.search\`. Use \`memory.write\` sparingly to record durable notes (decisions, gotchas, references) that will be useful to future agents on this project — not transient task state. \`kind\` defaults to \`agent_note\`; use a stable kind string (e.g. \`decision\`, \`gotcha\`) if you want to filter later.
35378
35396
 
35379
35397
  Agent + skill self-service (use sparingly — only when you genuinely need a new capability that isn't covered by an existing agent or skill):
35380
35398
 
@@ -35424,7 +35442,7 @@ async function executePlanActions(apiUrl, parentTask, actions, ctx, parseErrors
35424
35442
  results.push({ type: "note", status: "note", message: `${blocked3} non-update action(s) blocked (planning depth limit ${PLANNING_DEPTH_LIMIT})` });
35425
35443
  }
35426
35444
  }
35427
- const SUBCAPS = { "agent.create": 2, "skill.create": 3, "skill.attach": 5, "skill.detach": 5, "agent.update": 5, "session.create": 3 };
35445
+ const SUBCAPS = { "agent.create": 2, "skill.create": 3, "skill.attach": 5, "skill.detach": 5, "agent.update": 5, "session.create": 3, "memory.search": 5, "memory.write": 5 };
35428
35446
  const counts = {};
35429
35447
  actions = actions.filter((a) => {
35430
35448
  const cap = SUBCAPS[a.type];
@@ -35606,6 +35624,57 @@ async function executePlanActions(apiUrl, parentTask, actions, ctx, parseErrors
35606
35624
  lines.push(` - **${r.key}** [${r.status}] ${r.title}`);
35607
35625
  }
35608
35626
  results.push({ type: "issue.search", status: "ok", count: rows.length, query: a.query });
35627
+ } else if (a.type === "memory.search") {
35628
+ const projectId = a.project_id || parentProjectId;
35629
+ if (!projectId) {
35630
+ lines.push(`- [err] memory.search "${a.query}": no project_id`);
35631
+ results.push({ type: "memory.search", status: "error", error: "no project_id", label: a.query });
35632
+ continue;
35633
+ }
35634
+ const limit = a.limit ?? 10;
35635
+ const qs = new URLSearchParams({ project_id: projectId, q: a.query, limit: String(limit) });
35636
+ const res = await apiClient.get(`${apiUrl}/api/memory/search?${qs.toString()}`);
35637
+ if (!res.success) {
35638
+ lines.push(`- [err] memory.search "${a.query}": ${res.error || res.status}`);
35639
+ results.push({ type: "memory.search", status: "error", error: String(res.error || res.status), label: a.query });
35640
+ continue;
35641
+ }
35642
+ const rows = Array.isArray(res.data?.rows) ? res.data.rows : [];
35643
+ if (!rows.length) {
35644
+ lines.push(`- [ok] memory.search "${a.query}": 0 hits`);
35645
+ results.push({ type: "memory.search", status: "ok", count: 0, query: a.query });
35646
+ continue;
35647
+ }
35648
+ lines.push(`- [ok] memory.search "${a.query}": ${rows.length} hit(s)`);
35649
+ for (const r of rows) {
35650
+ const summary5 = (r.summary || r.text || "").replace(/\s+/g, " ").slice(0, 200);
35651
+ lines.push(` - [${r.source_kind || "memory"}] ${summary5}`);
35652
+ }
35653
+ results.push({ type: "memory.search", status: "ok", count: rows.length, query: a.query });
35654
+ } else if (a.type === "memory.write") {
35655
+ const projectId = a.project_id || parentProjectId;
35656
+ if (!projectId) {
35657
+ lines.push(`- [err] memory.write: no project_id`);
35658
+ results.push({ type: "memory.write", status: "error", error: "no project_id" });
35659
+ continue;
35660
+ }
35661
+ const body = {
35662
+ project_id: projectId,
35663
+ source_kind: a.kind || "agent_note",
35664
+ source_id: a.source_id || `${parentTask.agent_id || "agent"}:${parentTask.issue_id || ""}:${Date.now()}`,
35665
+ agent_id: parentTask.agent_id || null,
35666
+ text: a.text,
35667
+ summary: a.summary || null
35668
+ };
35669
+ const res = await apiClient.post(`${apiUrl}/api/memory/write`, body);
35670
+ if (!res.success) {
35671
+ lines.push(`- [err] memory.write: ${res.error || res.status}`);
35672
+ results.push({ type: "memory.write", status: "error", error: String(res.error || res.status) });
35673
+ continue;
35674
+ }
35675
+ const row = res.data?.row || {};
35676
+ lines.push(`- [ok] memory.write -> ${row.id || "(no id)"}${row.embedding_id ? " (embedded)" : ""}`);
35677
+ results.push({ type: "memory.write", status: "ok", memory_id: row.id, embedded: !!row.embedding_id });
35609
35678
  } else if (a.type === "agent.create") {
35610
35679
  if (!parentWsId) {
35611
35680
  lines.push(`- [err] agent.create "${a.name}": no tenant workspace id`);
@@ -36837,6 +36906,58 @@ async function executeChatPlanActions(actionsIn, parseErrors, ctx) {
36837
36906
  lines.push(` - **${r.key}** [${r.status}] ${r.title}`);
36838
36907
  results.push({ type: "issue.search", status: "ok", count: rows.length, query: a.query });
36839
36908
  tally(true);
36909
+ } else if (a.type === "memory.search") {
36910
+ const project_id = a.project_id || ctx.projectId;
36911
+ if (!project_id) {
36912
+ lines.push(`- [err] memory.search "${a.query}": project_id required (chat has no pinned project)`);
36913
+ results.push({ type: "memory.search", status: "error", error: "project_id required (chat has no pinned project)", label: a.query });
36914
+ tally(false);
36915
+ continue;
36916
+ }
36917
+ const limit = a.limit ?? 10;
36918
+ const qs = new URLSearchParams({ project_id, q: a.query, limit: String(limit) });
36919
+ const res = await apiClient.get(`${ctx.apiUrl}/api/memory/search?${qs.toString()}`);
36920
+ if (!res.success) {
36921
+ lines.push(`- [err] memory.search "${a.query}": ${res.error || res.status}`);
36922
+ results.push({ type: "memory.search", status: "error", error: String(res.error || res.status), label: a.query });
36923
+ tally(false);
36924
+ continue;
36925
+ }
36926
+ const rows = Array.isArray(res.data?.rows) ? res.data.rows : [];
36927
+ lines.push(`- [ok] memory.search "${a.query}": ${rows.length} hit(s)`);
36928
+ for (const r of rows) {
36929
+ const summary5 = (r.summary || r.text || "").replace(/\s+/g, " ").slice(0, 200);
36930
+ lines.push(` - [${r.source_kind || "memory"}] ${summary5}`);
36931
+ }
36932
+ results.push({ type: "memory.search", status: "ok", count: rows.length, query: a.query });
36933
+ tally(true);
36934
+ } else if (a.type === "memory.write") {
36935
+ const project_id = a.project_id || ctx.projectId;
36936
+ if (!project_id) {
36937
+ lines.push(`- [err] memory.write: project_id required (chat has no pinned project)`);
36938
+ results.push({ type: "memory.write", status: "error", error: "project_id required (chat has no pinned project)" });
36939
+ tally(false);
36940
+ continue;
36941
+ }
36942
+ const body = {
36943
+ project_id,
36944
+ source_kind: a.kind || "agent_note",
36945
+ source_id: a.source_id || `chat:${ctx.chatId}:${Date.now()}`,
36946
+ agent_id: ctx.agentId || null,
36947
+ text: a.text,
36948
+ summary: a.summary || null
36949
+ };
36950
+ const res = await apiClient.post(`${ctx.apiUrl}/api/memory/write`, body);
36951
+ if (!res.success) {
36952
+ lines.push(`- [err] memory.write: ${res.error || res.status}`);
36953
+ results.push({ type: "memory.write", status: "error", error: String(res.error || res.status) });
36954
+ tally(false);
36955
+ continue;
36956
+ }
36957
+ const row = res.data?.row || {};
36958
+ lines.push(`- [ok] memory.write -> ${row.id || "(no id)"}${row.embedding_id ? " (embedded)" : ""}`);
36959
+ results.push({ type: "memory.write", status: "ok", memory_id: row.id, embedded: !!row.embedding_id });
36960
+ tally(true);
36840
36961
  } else if (a.type === "agent.create") {
36841
36962
  const res = await apiClient.post(agentsMutateUrl, {
36842
36963
  action: "create",
@@ -36952,7 +37073,9 @@ var init_chat_plan_actions = __esm(() => {
36952
37073
  "skill.detach": 5,
36953
37074
  "agent.update": 5,
36954
37075
  "session.create": 3,
36955
- "issue.comment": 5
37076
+ "issue.comment": 5,
37077
+ "memory.search": 5,
37078
+ "memory.write": 5
36956
37079
  };
36957
37080
  });
36958
37081
 
@@ -37330,6 +37453,8 @@ Action vocabulary:
37330
37453
  {"type":"issue.delete_where","status":"todo","limit":50},
37331
37454
  {"type":"issue.list","status":"todo","limit":20},
37332
37455
  {"type":"issue.search","query":"flaky tests","limit":10},
37456
+ {"type":"memory.search","query":"deploy pipeline","limit":10},
37457
+ {"type":"memory.write","text":"durable note worth recalling next session","summary":"short hint","kind":"agent_note"},
37333
37458
  {"type":"agent.create","name":"refactor-bot","prompt":"...","allowed_tools":["Read","Edit","Bash"]},
37334
37459
  {"type":"agent.update","id":"ag_xxx","prompt":"..."},
37335
37460
  {"type":"skill.create","name":"run-tests","description":"...","body":"---\\nname: run-tests\\n---\\n..."},
@@ -37341,7 +37466,8 @@ Action vocabulary:
37341
37466
  Rules:
37342
37467
  - Omit the block entirely if no actions are needed. Don't emit empty arrays.
37343
37468
  - Status values for \`update\`: \`todo\` | \`in_progress\` | \`blocked\` | \`done\` | \`archived\` | \`failed\`. **Use \`blocked\` (NOT \`done\`) when the issue is paused waiting on a human decision** — confirmation, choice, or missing context. Marking such an issue \`done\` misrepresents finished work. Use \`archived\` to hide a completed/abandoned issue from default views.
37344
- - 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.
37469
+ - 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, memory.search=5, memory.write=5.
37470
+ - Memory actions are project-scoped persistent notes (FTS5 + vector). \`memory.search\` returns hits in the action summary; the agent reads them next turn. \`memory.write\` records durable facts for future sessions — use sparingly, not for transient task state. Both require a pinned project.
37345
37471
  - 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.
37346
37472
  - 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.
37347
37473
  - 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.
@@ -38115,7 +38241,7 @@ import { parseArgs } from "util";
38115
38241
  // package.json
38116
38242
  var package_default = {
38117
38243
  name: "@shipers-dev/multi",
38118
- version: "0.51.0",
38244
+ version: "0.52.0",
38119
38245
  type: "module",
38120
38246
  bin: {
38121
38247
  "multi-agent": "./dist/index.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipers-dev/multi",
3
- "version": "0.51.0",
3
+ "version": "0.52.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "multi-agent": "./dist/index.js"