@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.
- package/README.md +20 -1
- package/dist/backend.d.ts +1 -0
- package/dist/backend.d.ts.map +1 -1
- package/dist/backend.js +11 -2
- package/dist/extensions/activities.d.ts +4 -1
- package/dist/extensions/activities.d.ts.map +1 -1
- package/dist/extensions/activities.js +127 -16
- package/dist/extensions/branding.d.ts +2 -3
- package/dist/extensions/branding.d.ts.map +1 -1
- package/dist/extensions/branding.js +73 -58
- package/dist/extensions/cron.d.ts +4 -1
- package/dist/extensions/cron.d.ts.map +1 -1
- package/dist/extensions/cron.js +74 -14
- package/dist/extensions/heartbeats.d.ts +4 -1
- package/dist/extensions/heartbeats.d.ts.map +1 -1
- package/dist/extensions/heartbeats.js +60 -17
- package/dist/extensions/index.d.ts +13 -3
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/extensions/index.js +13 -3
- package/dist/extensions/messaging-setup.d.ts +4 -1
- package/dist/extensions/messaging-setup.d.ts.map +1 -1
- package/dist/extensions/messaging-setup.js +47 -10
- package/dist/extensions/mu-full-tools.d.ts +10 -0
- package/dist/extensions/mu-full-tools.d.ts.map +1 -0
- package/dist/extensions/mu-full-tools.js +25 -0
- package/dist/extensions/mu-operator.d.ts.map +1 -1
- package/dist/extensions/mu-operator.js +2 -6
- package/dist/extensions/mu-query-tools.d.ts +10 -0
- package/dist/extensions/mu-query-tools.d.ts.map +1 -0
- package/dist/extensions/mu-query-tools.js +11 -0
- package/dist/extensions/operator-command.d.ts.map +1 -1
- package/dist/extensions/operator-command.js +106 -6
- package/dist/extensions/orchestration-runs-readonly.d.ts.map +1 -1
- package/dist/extensions/orchestration-runs-readonly.js +180 -10
- package/dist/extensions/orchestration-runs.d.ts.map +1 -1
- package/dist/extensions/orchestration-runs.js +206 -14
- package/dist/extensions/server-tools.d.ts +10 -0
- package/dist/extensions/server-tools.d.ts.map +1 -1
- package/dist/extensions/server-tools.js +688 -290
- package/dist/extensions/shared.d.ts +11 -0
- package/dist/extensions/shared.d.ts.map +1 -1
- package/dist/extensions/shared.js +81 -0
- package/dist/session_factory.d.ts.map +1 -1
- package/dist/session_factory.js +3 -1
- package/dist/ui_defaults.d.ts +4 -0
- package/dist/ui_defaults.d.ts.map +1 -0
- package/dist/ui_defaults.js +18 -0
- package/package.json +4 -3
- package/prompts/roles/operator.md +5 -0
- package/prompts/roles/orchestrator.md +1 -0
- package/prompts/roles/worker.md +10 -4
- 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
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
43
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
114
|
-
const payload = await fetchMuJson(`/api/runs/${encodeURIComponent(id)}/trace?limit=${
|
|
115
|
-
|
|
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;
|
|
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"}
|