@femtomc/mu-agent 26.2.69 → 26.2.70

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 (52) hide show
  1. package/README.md +20 -1
  2. package/dist/backend.d.ts +1 -0
  3. package/dist/backend.d.ts.map +1 -1
  4. package/dist/backend.js +11 -2
  5. package/dist/extensions/activities.d.ts +4 -1
  6. package/dist/extensions/activities.d.ts.map +1 -1
  7. package/dist/extensions/activities.js +127 -16
  8. package/dist/extensions/branding.d.ts +2 -3
  9. package/dist/extensions/branding.d.ts.map +1 -1
  10. package/dist/extensions/branding.js +73 -58
  11. package/dist/extensions/cron.d.ts +4 -1
  12. package/dist/extensions/cron.d.ts.map +1 -1
  13. package/dist/extensions/cron.js +74 -14
  14. package/dist/extensions/heartbeats.d.ts +4 -1
  15. package/dist/extensions/heartbeats.d.ts.map +1 -1
  16. package/dist/extensions/heartbeats.js +60 -17
  17. package/dist/extensions/index.d.ts +13 -3
  18. package/dist/extensions/index.d.ts.map +1 -1
  19. package/dist/extensions/index.js +13 -3
  20. package/dist/extensions/messaging-setup.d.ts +4 -1
  21. package/dist/extensions/messaging-setup.d.ts.map +1 -1
  22. package/dist/extensions/messaging-setup.js +47 -10
  23. package/dist/extensions/mu-full-tools.d.ts +10 -0
  24. package/dist/extensions/mu-full-tools.d.ts.map +1 -0
  25. package/dist/extensions/mu-full-tools.js +25 -0
  26. package/dist/extensions/mu-operator.d.ts.map +1 -1
  27. package/dist/extensions/mu-operator.js +2 -6
  28. package/dist/extensions/mu-query-tools.d.ts +10 -0
  29. package/dist/extensions/mu-query-tools.d.ts.map +1 -0
  30. package/dist/extensions/mu-query-tools.js +11 -0
  31. package/dist/extensions/operator-command.d.ts.map +1 -1
  32. package/dist/extensions/operator-command.js +106 -6
  33. package/dist/extensions/orchestration-runs-readonly.d.ts.map +1 -1
  34. package/dist/extensions/orchestration-runs-readonly.js +180 -10
  35. package/dist/extensions/orchestration-runs.d.ts.map +1 -1
  36. package/dist/extensions/orchestration-runs.js +206 -14
  37. package/dist/extensions/server-tools.d.ts +10 -0
  38. package/dist/extensions/server-tools.d.ts.map +1 -1
  39. package/dist/extensions/server-tools.js +688 -290
  40. package/dist/extensions/shared.d.ts +11 -0
  41. package/dist/extensions/shared.d.ts.map +1 -1
  42. package/dist/extensions/shared.js +81 -0
  43. package/dist/session_factory.d.ts.map +1 -1
  44. package/dist/session_factory.js +3 -1
  45. package/dist/ui_defaults.d.ts +4 -0
  46. package/dist/ui_defaults.d.ts.map +1 -0
  47. package/dist/ui_defaults.js +18 -0
  48. package/package.json +4 -3
  49. package/prompts/roles/operator.md +5 -0
  50. package/prompts/roles/orchestrator.md +1 -0
  51. package/prompts/roles/worker.md +10 -4
  52. package/themes/mu-gruvbox-dark.json +90 -0
@@ -1,12 +1,138 @@
1
1
  import { StringEnum } from "@mariozechner/pi-ai";
2
2
  import { Type } from "@sinclair/typebox";
3
- import { clampInt, fetchMuJson, textResult, toJsonText } from "./shared.js";
3
+ import { asArray, asNumber, asRecord, asString, clampInt, fetchMuJson, parseFieldPaths, previewLines, previewText, selectFields, textResult, toJsonText, } from "./shared.js";
4
4
  function trimOrNull(value) {
5
5
  if (value == null)
6
6
  return null;
7
7
  const trimmed = value.trim();
8
8
  return trimmed.length > 0 ? trimmed : null;
9
9
  }
10
+ function summarizeRun(run) {
11
+ return {
12
+ job_id: asString(run.job_id),
13
+ root_issue_id: asString(run.root_issue_id),
14
+ status: asString(run.status),
15
+ source: asString(run.source),
16
+ started_at_ms: asNumber(run.started_at_ms),
17
+ finished_at_ms: asNumber(run.finished_at_ms),
18
+ exit_code: asNumber(run.exit_code),
19
+ provider: asString(run.provider),
20
+ model: asString(run.model),
21
+ reasoning: asString(run.reasoning),
22
+ prompt_preview: previewText(run.prompt, 140),
23
+ };
24
+ }
25
+ function summarizeTrace(trace, lineLimit) {
26
+ const run = asRecord(trace.run);
27
+ return {
28
+ run: run ? summarizeRun(run) : null,
29
+ stdout: previewLines(trace.stdout, { maxLines: lineLimit, maxCharsPerLine: 220 }),
30
+ stderr: previewLines(trace.stderr, { maxLines: lineLimit, maxCharsPerLine: 220 }),
31
+ log_hints: asArray(trace.log_hints).slice(0, 20),
32
+ trace_files: asArray(trace.trace_files).slice(0, 20),
33
+ };
34
+ }
35
+ function runFromStartEvent(event) {
36
+ const runId = asString(event.run_id);
37
+ if (!runId) {
38
+ return null;
39
+ }
40
+ const payload = asRecord(event.payload);
41
+ const issueId = asString(event.issue_id);
42
+ const role = payload ? asString(payload.role) : null;
43
+ const explicitRoot = payload ? asString(payload.root_issue_id) : null;
44
+ const rootIssueId = explicitRoot ?? (role === "orchestrator" ? issueId : null);
45
+ return {
46
+ job_id: runId,
47
+ root_issue_id: rootIssueId,
48
+ issue_id: issueId,
49
+ role,
50
+ status: "history",
51
+ source: "event_log",
52
+ started_at_ms: asNumber(event.ts_ms),
53
+ finished_at_ms: null,
54
+ exit_code: null,
55
+ provider: payload ? asString(payload.provider) : null,
56
+ model: payload ? asString(payload.model) : null,
57
+ reasoning: payload ? asString(payload.reasoning) : null,
58
+ prompt: payload ? asString(payload.prompt) : null,
59
+ };
60
+ }
61
+ async function fetchHistoricalRuns(limit) {
62
+ const payload = await fetchMuJson(`/api/events?type=backend.run.start&limit=${Math.max(limit * 4, 80)}`);
63
+ const payloadRecord = asRecord(payload);
64
+ const events = Array.isArray(payload) ? payload : asArray(payloadRecord?.events);
65
+ const runIndex = new Map();
66
+ const runs = [];
67
+ for (let index = events.length - 1; index >= 0; index -= 1) {
68
+ const event = asRecord(events[index]);
69
+ if (!event) {
70
+ continue;
71
+ }
72
+ const run = runFromStartEvent(event);
73
+ if (!run) {
74
+ continue;
75
+ }
76
+ const runId = asString(run.job_id);
77
+ if (!runId) {
78
+ continue;
79
+ }
80
+ const existingIdx = runIndex.get(runId);
81
+ if (existingIdx == null) {
82
+ if (runs.length >= limit) {
83
+ continue;
84
+ }
85
+ runIndex.set(runId, runs.length);
86
+ runs.push(run);
87
+ continue;
88
+ }
89
+ const existing = runs[existingIdx];
90
+ if (!asString(existing.root_issue_id)) {
91
+ existing.root_issue_id = asString(run.root_issue_id) ?? asString(run.issue_id);
92
+ }
93
+ if (!asString(existing.provider)) {
94
+ existing.provider = asString(run.provider);
95
+ }
96
+ if (!asString(existing.model)) {
97
+ existing.model = asString(run.model);
98
+ }
99
+ if (!asString(existing.reasoning)) {
100
+ existing.reasoning = asString(run.reasoning);
101
+ }
102
+ if (!asString(existing.prompt)) {
103
+ existing.prompt = asString(run.prompt);
104
+ }
105
+ }
106
+ return runs;
107
+ }
108
+ async function findHistoricalRun(idOrRoot) {
109
+ const payload = await fetchMuJson("/api/events?type=backend.run.start&limit=200");
110
+ const payloadRecord = asRecord(payload);
111
+ const events = Array.isArray(payload) ? payload : asArray(payloadRecord?.events);
112
+ for (let index = events.length - 1; index >= 0; index -= 1) {
113
+ const event = asRecord(events[index]);
114
+ if (!event) {
115
+ continue;
116
+ }
117
+ const run = runFromStartEvent(event);
118
+ if (!run) {
119
+ continue;
120
+ }
121
+ const runId = asString(run.job_id);
122
+ const rootIssueId = asString(run.root_issue_id);
123
+ if (runId === idOrRoot || rootIssueId === idOrRoot) {
124
+ return run;
125
+ }
126
+ }
127
+ return null;
128
+ }
129
+ function isRunNotFoundError(error) {
130
+ if (!(error instanceof Error)) {
131
+ return false;
132
+ }
133
+ const message = error.message.toLowerCase();
134
+ return message.includes("mu server 404") || message.includes("run not found");
135
+ }
10
136
  export function orchestrationRunsExtension(pi) {
11
137
  const RunsParams = Type.Object({
12
138
  action: StringEnum(["list", "status", "start", "resume", "interrupt", "heartbeat", "trace"]),
@@ -14,14 +140,17 @@ export function orchestrationRunsExtension(pi) {
14
140
  root_issue_id: Type.Optional(Type.String({ description: "Run root issue ID (mu-...)" })),
15
141
  prompt: Type.Optional(Type.String({ description: "Prompt for run start" })),
16
142
  max_steps: Type.Optional(Type.Number({ description: "Optional max steps for start/resume" })),
17
- limit: Type.Optional(Type.Number({ description: "Optional limit (list/trace)" })),
143
+ limit: Type.Optional(Type.Number({ description: "Optional limit (list/trace). Defaults to 20 for list and 40 lines for trace." })),
18
144
  status: Type.Optional(Type.String({ description: "Optional status filter for list" })),
145
+ fields: Type.Optional(Type.String({
146
+ description: "Comma-separated fields for status/trace selection (e.g. status,exit_code,prompt)",
147
+ })),
19
148
  reason: Type.Optional(Type.String({ description: "Optional heartbeat reason (default: manual)" })),
20
149
  });
21
150
  pi.registerTool({
22
151
  name: "mu_runs",
23
152
  label: "Runs",
24
- description: "Manage orchestration runs. Actions: list, status, start, resume, interrupt, heartbeat, trace (stdout/stderr + .mu/log hints).",
153
+ description: "Manage orchestration runs. Actions: list, status, start, resume, interrupt, heartbeat, trace. List/trace return compact summaries; use fields for precise retrieval.",
25
154
  parameters: RunsParams,
26
155
  async execute(_toolCallId, params) {
27
156
  switch (params.action) {
@@ -30,17 +159,54 @@ export function orchestrationRunsExtension(pi) {
30
159
  const status = trimOrNull(params.status);
31
160
  if (status)
32
161
  query.set("status", status);
33
- const limit = clampInt(params.limit, 50, 1, 500);
162
+ const limit = clampInt(params.limit, 20, 1, 500);
34
163
  query.set("limit", String(limit));
35
164
  const payload = await fetchMuJson(`/api/runs?${query.toString()}`);
36
- return textResult(toJsonText(payload), { action: "list", status, limit });
165
+ let records = asArray(payload.runs)
166
+ .map((run) => asRecord(run))
167
+ .filter((run) => run != null);
168
+ let source = "run_supervisor";
169
+ if (records.length === 0 && (status == null || status === "history")) {
170
+ records = await fetchHistoricalRuns(limit);
171
+ source = "event_log";
172
+ }
173
+ const runs = records.map((run) => summarizeRun(run));
174
+ return textResult(toJsonText({ count: runs.length, source, runs }), {
175
+ action: "list",
176
+ status,
177
+ limit,
178
+ source,
179
+ payload,
180
+ runs: records,
181
+ });
37
182
  }
38
183
  case "status": {
39
184
  const id = trimOrNull(params.job_id) ?? trimOrNull(params.root_issue_id);
40
185
  if (!id)
41
186
  return textResult("status requires job_id or root_issue_id");
42
- const payload = await fetchMuJson(`/api/runs/${encodeURIComponent(id)}`);
43
- return textResult(toJsonText(payload), { action: "status", id });
187
+ let payload = null;
188
+ let source = "run_supervisor";
189
+ try {
190
+ payload = await fetchMuJson(`/api/runs/${encodeURIComponent(id)}`);
191
+ }
192
+ catch (err) {
193
+ if (!isRunNotFoundError(err)) {
194
+ throw err;
195
+ }
196
+ payload = await findHistoricalRun(id);
197
+ source = "event_log";
198
+ if (!payload) {
199
+ throw err;
200
+ }
201
+ }
202
+ if (!payload) {
203
+ return textResult(`run not found: ${id}`);
204
+ }
205
+ const fields = parseFieldPaths(trimOrNull(params.fields) ?? undefined);
206
+ const content = fields.length > 0
207
+ ? { id, source, selected: selectFields(payload, fields) }
208
+ : { source, run: summarizeRun(payload) };
209
+ return textResult(toJsonText(content), { action: "status", id, source, fields, payload });
44
210
  }
45
211
  case "start": {
46
212
  const prompt = trimOrNull(params.prompt);
@@ -56,7 +222,13 @@ export function orchestrationRunsExtension(pi) {
56
222
  max_steps: maxSteps,
57
223
  },
58
224
  });
59
- return textResult(toJsonText(payload), { action: "start", prompt, maxSteps });
225
+ const run = asRecord(payload.run);
226
+ return textResult(toJsonText({ ok: payload.ok ?? true, run: run ? summarizeRun(run) : null }), {
227
+ action: "start",
228
+ prompt,
229
+ maxSteps,
230
+ payload,
231
+ });
60
232
  }
61
233
  case "resume": {
62
234
  const rootIssueId = trimOrNull(params.root_issue_id);
@@ -72,7 +244,13 @@ export function orchestrationRunsExtension(pi) {
72
244
  max_steps: maxSteps,
73
245
  },
74
246
  });
75
- return textResult(toJsonText(payload), { action: "resume", rootIssueId, maxSteps });
247
+ const run = asRecord(payload.run);
248
+ return textResult(toJsonText({ ok: payload.ok ?? true, run: run ? summarizeRun(run) : null }), {
249
+ action: "resume",
250
+ rootIssueId,
251
+ maxSteps,
252
+ payload,
253
+ });
76
254
  }
77
255
  case "interrupt": {
78
256
  const jobId = trimOrNull(params.job_id);
@@ -87,7 +265,12 @@ export function orchestrationRunsExtension(pi) {
87
265
  root_issue_id: rootIssueId,
88
266
  },
89
267
  });
90
- return textResult(toJsonText(payload), { action: "interrupt", jobId, rootIssueId });
268
+ const run = asRecord(payload.run);
269
+ return textResult(toJsonText({
270
+ ok: payload.ok ?? null,
271
+ reason: payload.reason ?? null,
272
+ run: run ? summarizeRun(run) : null,
273
+ }), { action: "interrupt", jobId, rootIssueId, payload });
91
274
  }
92
275
  case "heartbeat": {
93
276
  const jobId = trimOrNull(params.job_id);
@@ -104,15 +287,24 @@ export function orchestrationRunsExtension(pi) {
104
287
  reason,
105
288
  },
106
289
  });
107
- return textResult(toJsonText(payload), { action: "heartbeat", jobId, rootIssueId, reason });
290
+ const run = asRecord(payload.run);
291
+ return textResult(toJsonText({
292
+ ok: payload.ok ?? null,
293
+ reason: payload.reason ?? null,
294
+ run: run ? summarizeRun(run) : null,
295
+ }), { action: "heartbeat", jobId, rootIssueId, reason, payload });
108
296
  }
109
297
  case "trace": {
110
298
  const id = trimOrNull(params.job_id) ?? trimOrNull(params.root_issue_id);
111
299
  if (!id)
112
300
  return textResult("trace requires job_id or root_issue_id");
113
- const limit = clampInt(params.limit, 200, 1, 2_000);
114
- const payload = await fetchMuJson(`/api/runs/${encodeURIComponent(id)}/trace?limit=${limit}`);
115
- return textResult(toJsonText(payload), { action: "trace", id, limit });
301
+ const lineLimit = clampInt(params.limit, 40, 1, 200);
302
+ const payload = await fetchMuJson(`/api/runs/${encodeURIComponent(id)}/trace?limit=${Math.max(lineLimit, 80)}`);
303
+ const fields = parseFieldPaths(trimOrNull(params.fields) ?? undefined);
304
+ const content = fields.length > 0
305
+ ? { id, selected: selectFields(payload, fields) }
306
+ : summarizeTrace(payload, lineLimit);
307
+ return textResult(toJsonText(content), { action: "trace", id, lineLimit, fields, payload });
116
308
  }
117
309
  default:
118
310
  return textResult(`unknown action: ${params.action}`);
@@ -6,10 +6,20 @@
6
6
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
7
7
  export type ServerToolsExtensionOpts = {
8
8
  allowForumPost?: boolean;
9
+ allowIssueMutations?: boolean;
10
+ allowIdentityMutations?: boolean;
11
+ includeStatusTool?: boolean;
12
+ includeControlPlaneTool?: boolean;
13
+ includeIssuesTool?: boolean;
14
+ includeForumTool?: boolean;
15
+ includeEventsTool?: boolean;
16
+ includeIdentityTool?: boolean;
9
17
  toolIntroLine?: string;
18
+ usageLine?: string;
10
19
  extraSystemPromptLines?: string[];
11
20
  };
12
21
  export declare function serverToolsExtension(pi: ExtensionAPI, opts?: ServerToolsExtensionOpts): void;
13
22
  export declare function serverToolsReadOnlyExtension(pi: ExtensionAPI): void;
23
+ export declare function serverToolsIssueForumExtension(pi: ExtensionAPI): void;
14
24
  export default serverToolsExtension;
15
25
  //# sourceMappingURL=server-tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-tools.d.ts","sourceRoot":"","sources":["../../src/extensions/server-tools.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAqFlE,MAAM,MAAM,wBAAwB,GAAG;IACtC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC,CAAC;AA2XF,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,GAAE,wBAA6B,QAQzF;AAED,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,YAAY,QAS5D;AAED,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"server-tools.d.ts","sourceRoot":"","sources":["../../src/extensions/server-tools.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAqMlE,MAAM,MAAM,wBAAwB,GAAG;IACtC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC,CAAC;AAmqBF,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,GAAE,wBAA6B,QAmBzF;AAED,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,YAAY,QAkB5D;AAED,wBAAgB,8BAA8B,CAAC,EAAE,EAAE,YAAY,QAe9D;AAED,eAAe,oBAAoB,CAAC"}