@femtomc/mu-agent 26.2.43 → 26.2.45
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/dist/extensions/index.d.ts +1 -0
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/extensions/index.js +2 -0
- package/dist/extensions/operator-command.d.ts +14 -0
- package/dist/extensions/operator-command.d.ts.map +1 -0
- package/dist/extensions/operator-command.js +52 -0
- package/dist/operator.d.ts.map +1 -1
- package/dist/operator.js +26 -156
- package/package.json +2 -2
- package/prompts/operator.md +20 -19
- package/prompts/orchestrator.md +8 -13
- package/prompts/worker.md +10 -10
|
@@ -3,6 +3,7 @@ export { brandingExtension } from "./branding.js";
|
|
|
3
3
|
export { eventLogExtension } from "./event-log.js";
|
|
4
4
|
export { heartbeatsExtension } from "./heartbeats.js";
|
|
5
5
|
export { messagingSetupExtension } from "./messaging-setup.js";
|
|
6
|
+
export { operatorCommandExtension } from "./operator-command.js";
|
|
6
7
|
export { orchestrationRunsExtension } from "./orchestration-runs.js";
|
|
7
8
|
export { orchestrationRunsReadOnlyExtension } from "./orchestration-runs-readonly.js";
|
|
8
9
|
export { serverToolsExtension, serverToolsReadOnlyExtension } from "./server-tools.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/extensions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,kCAAkC,EAAE,MAAM,kCAAkC,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/extensions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,kCAAkC,EAAE,MAAM,kCAAkC,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AA0B1E;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,UAE/B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,UAElC,CAAC"}
|
package/dist/extensions/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { brandingExtension } from "./branding.js";
|
|
|
3
3
|
export { eventLogExtension } from "./event-log.js";
|
|
4
4
|
export { heartbeatsExtension } from "./heartbeats.js";
|
|
5
5
|
export { messagingSetupExtension } from "./messaging-setup.js";
|
|
6
|
+
export { operatorCommandExtension } from "./operator-command.js";
|
|
6
7
|
export { orchestrationRunsExtension } from "./orchestration-runs.js";
|
|
7
8
|
export { orchestrationRunsReadOnlyExtension } from "./orchestration-runs-readonly.js";
|
|
8
9
|
export { serverToolsExtension, serverToolsReadOnlyExtension } from "./server-tools.js";
|
|
@@ -22,6 +23,7 @@ const OPERATOR_EXTENSION_MODULE_BASENAMES = [
|
|
|
22
23
|
"event-log",
|
|
23
24
|
"messaging-setup",
|
|
24
25
|
"orchestration-runs-readonly",
|
|
26
|
+
"operator-command",
|
|
25
27
|
];
|
|
26
28
|
const RUNTIME_EXTENSION = import.meta.url.endsWith(".ts") ? "ts" : "js";
|
|
27
29
|
function resolveBundledExtensionPath(moduleBasename) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mu_command — Operator mutation tool.
|
|
3
|
+
*
|
|
4
|
+
* Registered only in operator sessions. The LLM calls this tool with a
|
|
5
|
+
* structured command proposal instead of emitting fragile text directives.
|
|
6
|
+
* The tool itself does nothing except confirm receipt — the actual command
|
|
7
|
+
* is captured by the PiMessagingOperatorBackend subscriber on
|
|
8
|
+
* tool_execution_start and routed through the existing broker/audit pipeline.
|
|
9
|
+
*/
|
|
10
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
11
|
+
export declare const MU_COMMAND_TOOL_NAME = "mu_command";
|
|
12
|
+
export declare function operatorCommandExtension(pi: ExtensionAPI): void;
|
|
13
|
+
export default operatorCommandExtension;
|
|
14
|
+
//# sourceMappingURL=operator-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operator-command.d.ts","sourceRoot":"","sources":["../../src/extensions/operator-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAGlE,eAAO,MAAM,oBAAoB,eAAe,CAAC;AAEjD,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,YAAY,QAuCxD;AAED,eAAe,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mu_command — Operator mutation tool.
|
|
3
|
+
*
|
|
4
|
+
* Registered only in operator sessions. The LLM calls this tool with a
|
|
5
|
+
* structured command proposal instead of emitting fragile text directives.
|
|
6
|
+
* The tool itself does nothing except confirm receipt — the actual command
|
|
7
|
+
* is captured by the PiMessagingOperatorBackend subscriber on
|
|
8
|
+
* tool_execution_start and routed through the existing broker/audit pipeline.
|
|
9
|
+
*/
|
|
10
|
+
import { StringEnum } from "@mariozechner/pi-ai";
|
|
11
|
+
import { Type } from "@sinclair/typebox";
|
|
12
|
+
export const MU_COMMAND_TOOL_NAME = "mu_command";
|
|
13
|
+
export function operatorCommandExtension(pi) {
|
|
14
|
+
const CommandParams = Type.Object({
|
|
15
|
+
kind: StringEnum([
|
|
16
|
+
"status",
|
|
17
|
+
"ready",
|
|
18
|
+
"issue_list",
|
|
19
|
+
"issue_get",
|
|
20
|
+
"forum_read",
|
|
21
|
+
"run_list",
|
|
22
|
+
"run_status",
|
|
23
|
+
"run_start",
|
|
24
|
+
"run_resume",
|
|
25
|
+
"run_interrupt",
|
|
26
|
+
]),
|
|
27
|
+
prompt: Type.Optional(Type.String({ description: "Prompt for run_start" })),
|
|
28
|
+
issue_id: Type.Optional(Type.String({ description: "Issue ID for issue_get" })),
|
|
29
|
+
topic: Type.Optional(Type.String({ description: "Topic for forum_read" })),
|
|
30
|
+
limit: Type.Optional(Type.Number({ description: "Limit for forum_read / run_resume" })),
|
|
31
|
+
root_issue_id: Type.Optional(Type.String({ description: "Root issue ID for run_status / run_resume / run_interrupt" })),
|
|
32
|
+
max_steps: Type.Optional(Type.Number({ description: "Max steps for run_start / run_resume" })),
|
|
33
|
+
});
|
|
34
|
+
pi.registerTool({
|
|
35
|
+
name: MU_COMMAND_TOOL_NAME,
|
|
36
|
+
label: "Command",
|
|
37
|
+
description: [
|
|
38
|
+
"Propose an approved mu command for execution.",
|
|
39
|
+
"This is the ONLY way to trigger mutations (starting runs, resuming runs, interrupting runs).",
|
|
40
|
+
"Read-only queries (status, issue_list, etc.) can also be proposed here.",
|
|
41
|
+
"The command will be validated and executed through the control-plane pipeline.",
|
|
42
|
+
].join(" "),
|
|
43
|
+
parameters: CommandParams,
|
|
44
|
+
async execute(_toolCallId, params) {
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: "text", text: `Command proposal accepted: ${params.kind}` }],
|
|
47
|
+
details: { kind: params.kind },
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
export default operatorCommandExtension;
|
package/dist/operator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../src/operator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAmB,KAAK,mBAAmB,EAAE,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjG,OAAO,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAC;AAEtE,MAAM,MAAM,gCAAgC,GAAG;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uBAAuB,EAAE,MAAM,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,gCAAgC,GAAG;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,KAAK,eAAe,GAAG,gCAAgC,CAAC;AACxD,KAAK,eAAe,GAAG,gCAAgC,CAAC;AAIxD,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BA6BxC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAG1C,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../src/operator.ts"],"names":[],"mappings":"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"}
|
package/dist/operator.js
CHANGED
|
@@ -39,10 +39,6 @@ export const OperatorBackendTurnResultSchema = z.discriminatedUnion("kind", [
|
|
|
39
39
|
z.object({ kind: z.literal("respond"), message: z.string().trim().min(1).max(2000) }),
|
|
40
40
|
z.object({ kind: z.literal("command"), command: OperatorApprovedCommandSchema }),
|
|
41
41
|
]);
|
|
42
|
-
const OperatorDecisionEnvelopeSchema = z.discriminatedUnion("kind", [
|
|
43
|
-
z.object({ kind: z.literal("respond"), message: z.string().trim().min(1).max(2000) }),
|
|
44
|
-
z.object({ kind: z.literal("command"), command: OperatorApprovedCommandSchema }),
|
|
45
|
-
]);
|
|
46
42
|
function splitPromptIntoTokens(prompt) {
|
|
47
43
|
return prompt
|
|
48
44
|
.split(/\s+/)
|
|
@@ -279,107 +275,7 @@ export class MessagingOperatorRuntime {
|
|
|
279
275
|
}
|
|
280
276
|
}
|
|
281
277
|
export { DEFAULT_OPERATOR_SYSTEM_PROMPT };
|
|
282
|
-
const
|
|
283
|
-
const OPERATOR_DECISION_PREFIX = "MU_DECISION:";
|
|
284
|
-
function stripOperatorDirectiveLines(text) {
|
|
285
|
-
return text
|
|
286
|
-
.split(/\r?\n/)
|
|
287
|
-
.filter((line) => {
|
|
288
|
-
const trimmed = line.trim();
|
|
289
|
-
return !(trimmed.startsWith(OPERATOR_COMMAND_PREFIX) || trimmed.startsWith(OPERATOR_DECISION_PREFIX));
|
|
290
|
-
})
|
|
291
|
-
.join("\n")
|
|
292
|
-
.trim();
|
|
293
|
-
}
|
|
294
|
-
function parseOperatorDirective(text) {
|
|
295
|
-
const whole = text.trim();
|
|
296
|
-
if (whole.startsWith("{") && whole.endsWith("}")) {
|
|
297
|
-
try {
|
|
298
|
-
const parsed = JSON.parse(whole);
|
|
299
|
-
const envelope = OperatorDecisionEnvelopeSchema.safeParse(parsed);
|
|
300
|
-
if (envelope.success) {
|
|
301
|
-
return envelope.data.kind === "command"
|
|
302
|
-
? { kind: "command", command: envelope.data.command }
|
|
303
|
-
: { kind: "respond", message: envelope.data.message };
|
|
304
|
-
}
|
|
305
|
-
const legacy = OperatorApprovedCommandSchema.safeParse(parsed);
|
|
306
|
-
if (legacy.success) {
|
|
307
|
-
return { kind: "command", command: legacy.data };
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
catch {
|
|
311
|
-
// fall through to line-based directives / plain text fallback.
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
const lines = text.split(/\r?\n/);
|
|
315
|
-
for (const line of lines) {
|
|
316
|
-
const trimmed = line.trim();
|
|
317
|
-
if (trimmed.startsWith(OPERATOR_DECISION_PREFIX)) {
|
|
318
|
-
const payloadText = trimmed.slice(OPERATOR_DECISION_PREFIX.length).trim();
|
|
319
|
-
if (payloadText.length === 0) {
|
|
320
|
-
return {
|
|
321
|
-
kind: "invalid",
|
|
322
|
-
reason: "operator_decision_directive_missing_payload",
|
|
323
|
-
fallbackMessage: stripOperatorDirectiveLines(text),
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
let parsed;
|
|
327
|
-
try {
|
|
328
|
-
parsed = JSON.parse(payloadText);
|
|
329
|
-
}
|
|
330
|
-
catch (err) {
|
|
331
|
-
return {
|
|
332
|
-
kind: "invalid",
|
|
333
|
-
reason: `operator_decision_directive_invalid_json: ${err instanceof Error ? err.message : String(err)}`,
|
|
334
|
-
fallbackMessage: stripOperatorDirectiveLines(text),
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
const envelope = OperatorDecisionEnvelopeSchema.safeParse(parsed);
|
|
338
|
-
if (!envelope.success) {
|
|
339
|
-
return {
|
|
340
|
-
kind: "invalid",
|
|
341
|
-
reason: `operator_decision_directive_invalid_payload: ${envelope.error.message}`,
|
|
342
|
-
fallbackMessage: stripOperatorDirectiveLines(text),
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
return envelope.data.kind === "command"
|
|
346
|
-
? { kind: "command", command: envelope.data.command }
|
|
347
|
-
: { kind: "respond", message: envelope.data.message };
|
|
348
|
-
}
|
|
349
|
-
if (!trimmed.startsWith(OPERATOR_COMMAND_PREFIX)) {
|
|
350
|
-
continue;
|
|
351
|
-
}
|
|
352
|
-
const payloadText = trimmed.slice(OPERATOR_COMMAND_PREFIX.length).trim();
|
|
353
|
-
if (payloadText.length === 0) {
|
|
354
|
-
return {
|
|
355
|
-
kind: "invalid",
|
|
356
|
-
reason: "operator_command_directive_missing_payload",
|
|
357
|
-
fallbackMessage: stripOperatorDirectiveLines(text),
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
let parsed;
|
|
361
|
-
try {
|
|
362
|
-
parsed = JSON.parse(payloadText);
|
|
363
|
-
}
|
|
364
|
-
catch (err) {
|
|
365
|
-
return {
|
|
366
|
-
kind: "invalid",
|
|
367
|
-
reason: `operator_command_directive_invalid_json: ${err instanceof Error ? err.message : String(err)}`,
|
|
368
|
-
fallbackMessage: stripOperatorDirectiveLines(text),
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
const command = OperatorApprovedCommandSchema.safeParse(parsed);
|
|
372
|
-
if (!command.success) {
|
|
373
|
-
return {
|
|
374
|
-
kind: "invalid",
|
|
375
|
-
reason: `operator_command_directive_invalid_payload: ${command.error.message}`,
|
|
376
|
-
fallbackMessage: stripOperatorDirectiveLines(text),
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
return { kind: "command", command: command.data };
|
|
380
|
-
}
|
|
381
|
-
return { kind: "none" };
|
|
382
|
-
}
|
|
278
|
+
const MU_COMMAND_TOOL_NAME = "mu_command";
|
|
383
279
|
function buildOperatorPrompt(input) {
|
|
384
280
|
return [
|
|
385
281
|
`[Messaging context]`,
|
|
@@ -516,7 +412,9 @@ export class PiMessagingOperatorBackend {
|
|
|
516
412
|
const sessionRecord = await this.#resolveSession(input.sessionId, input.inbound.repo_root);
|
|
517
413
|
const session = sessionRecord.session;
|
|
518
414
|
let assistantText = "";
|
|
415
|
+
let capturedCommand = null;
|
|
519
416
|
const unsub = session.subscribe((event) => {
|
|
417
|
+
// Capture assistant text for fallback responses.
|
|
520
418
|
if (event?.type === "message_end" && event?.message?.role === "assistant") {
|
|
521
419
|
const msg = event.message;
|
|
522
420
|
if (typeof msg.text === "string") {
|
|
@@ -536,6 +434,13 @@ export class PiMessagingOperatorBackend {
|
|
|
536
434
|
assistantText = parts.join("\n");
|
|
537
435
|
}
|
|
538
436
|
}
|
|
437
|
+
// Capture mu_command tool calls — structured command proposals.
|
|
438
|
+
if (event?.type === "tool_execution_start" && event?.toolName === MU_COMMAND_TOOL_NAME) {
|
|
439
|
+
const parsed = OperatorApprovedCommandSchema.safeParse(event.args);
|
|
440
|
+
if (parsed.success) {
|
|
441
|
+
capturedCommand = parsed.data;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
539
444
|
});
|
|
540
445
|
const timeoutPromise = new Promise((_, reject) => {
|
|
541
446
|
setTimeout(() => reject(new Error("pi operator timeout")), this.#timeoutMs);
|
|
@@ -558,6 +463,16 @@ export class PiMessagingOperatorBackend {
|
|
|
558
463
|
unsub();
|
|
559
464
|
sessionRecord.lastUsedAtMs = Math.trunc(this.#nowMs());
|
|
560
465
|
}
|
|
466
|
+
// If the operator called mu_command, use the captured structured command.
|
|
467
|
+
if (capturedCommand) {
|
|
468
|
+
await this.#auditTurn(input, {
|
|
469
|
+
outcome: "command",
|
|
470
|
+
command: capturedCommand,
|
|
471
|
+
messagePreview: assistantText,
|
|
472
|
+
});
|
|
473
|
+
return { kind: "command", command: capturedCommand };
|
|
474
|
+
}
|
|
475
|
+
// Otherwise treat the assistant text as a plain response.
|
|
561
476
|
const message = assistantText.trim();
|
|
562
477
|
if (!message) {
|
|
563
478
|
await this.#auditTurn(input, {
|
|
@@ -566,57 +481,12 @@ export class PiMessagingOperatorBackend {
|
|
|
566
481
|
});
|
|
567
482
|
throw new Error("operator_empty_response");
|
|
568
483
|
}
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
messagePreview: message,
|
|
576
|
-
});
|
|
577
|
-
return {
|
|
578
|
-
kind: "command",
|
|
579
|
-
command: parsed.command,
|
|
580
|
-
};
|
|
581
|
-
case "respond": {
|
|
582
|
-
const responseMessage = parsed.message.trim().slice(0, 2000);
|
|
583
|
-
if (!SAFE_RESPONSE_RE.test(responseMessage)) {
|
|
584
|
-
const fallback = buildOperatorFailureFallbackMessage("operator_invalid_response_payload");
|
|
585
|
-
await this.#auditTurn(input, {
|
|
586
|
-
outcome: "invalid_directive",
|
|
587
|
-
reason: "operator_invalid_response_payload",
|
|
588
|
-
messagePreview: message,
|
|
589
|
-
});
|
|
590
|
-
return { kind: "respond", message: fallback };
|
|
591
|
-
}
|
|
592
|
-
await this.#auditTurn(input, {
|
|
593
|
-
outcome: "respond",
|
|
594
|
-
messagePreview: responseMessage,
|
|
595
|
-
});
|
|
596
|
-
return { kind: "respond", message: responseMessage };
|
|
597
|
-
}
|
|
598
|
-
case "invalid": {
|
|
599
|
-
const fallbackMessage = parsed.fallbackMessage.trim();
|
|
600
|
-
const responseMessage = fallbackMessage.length > 0
|
|
601
|
-
? fallbackMessage.slice(0, 2000)
|
|
602
|
-
: buildOperatorFailureFallbackMessage("operator_invalid_command_directive");
|
|
603
|
-
await this.#auditTurn(input, {
|
|
604
|
-
outcome: "invalid_directive",
|
|
605
|
-
reason: parsed.reason,
|
|
606
|
-
messagePreview: message,
|
|
607
|
-
});
|
|
608
|
-
return { kind: "respond", message: responseMessage };
|
|
609
|
-
}
|
|
610
|
-
case "none":
|
|
611
|
-
default: {
|
|
612
|
-
const responseMessage = message.slice(0, 2000);
|
|
613
|
-
await this.#auditTurn(input, {
|
|
614
|
-
outcome: "respond",
|
|
615
|
-
messagePreview: responseMessage,
|
|
616
|
-
});
|
|
617
|
-
return { kind: "respond", message: responseMessage };
|
|
618
|
-
}
|
|
619
|
-
}
|
|
484
|
+
const responseMessage = message.slice(0, 2000);
|
|
485
|
+
await this.#auditTurn(input, {
|
|
486
|
+
outcome: "respond",
|
|
487
|
+
messagePreview: responseMessage,
|
|
488
|
+
});
|
|
489
|
+
return { kind: "respond", message: responseMessage };
|
|
620
490
|
}
|
|
621
491
|
dispose() {
|
|
622
492
|
for (const sessionId of [...this.#sessions.keys()]) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@femtomc/mu-agent",
|
|
3
|
-
"version": "26.2.
|
|
3
|
+
"version": "26.2.45",
|
|
4
4
|
"description": "Shared agent runtime for mu chat, orchestration roles, and serve extensions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mu",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"prompts/**"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@femtomc/mu-core": "26.2.
|
|
26
|
+
"@femtomc/mu-core": "26.2.45",
|
|
27
27
|
"@mariozechner/pi-agent-core": "^0.52.12",
|
|
28
28
|
"@mariozechner/pi-ai": "^0.52.12",
|
|
29
29
|
"@mariozechner/pi-coding-agent": "^0.52.12",
|
package/prompts/operator.md
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
You are mu, the operator assistant for the mu orchestration platform.
|
|
4
|
-
|
|
5
|
-
## Mission
|
|
1
|
+
You are an operator: you help users interact with and utilize all the capabilities that mu has to offer.
|
|
6
2
|
|
|
3
|
+
Mission:
|
|
4
|
+
- Free flowing discussion with users about their interests.
|
|
5
|
+
- Help users with any coding tasks they ask you to handle directly.
|
|
7
6
|
- Help users inspect repository/control-plane state.
|
|
8
7
|
- Help users choose safe next actions.
|
|
9
|
-
- When needed, propose approved
|
|
8
|
+
- When needed, propose approved commands using the mu_command tool.
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
Available tools:
|
|
11
|
+
- read: Read file contents
|
|
12
|
+
- bash: Execute bash commands
|
|
13
|
+
- edit: Make surgical edits to files
|
|
14
|
+
- write: Create or overwrite files
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
You also have access to specialized read/diagnostic tools:
|
|
14
17
|
- `mu_status`
|
|
15
18
|
- `mu_control_plane`
|
|
16
19
|
- `mu_issues`
|
|
@@ -21,17 +24,16 @@ Use available read/diagnostic tools:
|
|
|
21
24
|
- `mu_heartbeats`
|
|
22
25
|
- `mu_messaging_setup`
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
- If a command is needed, output exactly one line prefixed with `MU_DECISION:` and compact JSON.
|
|
29
|
-
|
|
30
|
-
## Output Contract
|
|
31
|
-
|
|
32
|
-
Command envelope example:
|
|
27
|
+
Hard Constraints:
|
|
28
|
+
- Never perform mutations directly through read/write tools.
|
|
29
|
+
- Mutating actions must flow through the `mu_command` tool.
|
|
30
|
+
- Use the `mu_command` tool to propose commands. It accepts structured parameters — do NOT emit raw JSON directives in your text output.
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
mu_command tool usage:
|
|
33
|
+
- Call `mu_command` with `kind` set to the command type and relevant parameters.
|
|
34
|
+
- Example: `mu_command({ kind: "run_start", prompt: "ship release" })`
|
|
35
|
+
- Example: `mu_command({ kind: "status" })`
|
|
36
|
+
- Example: `mu_command({ kind: "issue_get", issue_id: "mu-abc123" })`
|
|
35
37
|
|
|
36
38
|
Allowed command kinds:
|
|
37
39
|
- `status`
|
|
@@ -47,4 +49,3 @@ Allowed command kinds:
|
|
|
47
49
|
|
|
48
50
|
For normal answers:
|
|
49
51
|
- Respond in plain text (no directive prefix).
|
|
50
|
-
- Be concise, practical, and actionable.
|
package/prompts/orchestrator.md
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
You are an orchestrator: you help by engaging in planning and review as part of the orchestration engine within mu.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- Decompose assigned issues into executable worker issues.
|
|
3
|
+
Mission:
|
|
4
|
+
- Read and think carefully about the issue assigned to you. Use mu's CLI to explore related issues, and the forum for relevant conversation.
|
|
5
|
+
- Decompose your assigned issue into executable worker issues, or further orchestrator issues if multi-layer decomposition is appropriate.
|
|
8
6
|
- Define ordering via dependencies.
|
|
9
7
|
- Move planning state forward by closing expanded planning nodes.
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
Hard Constraints:
|
|
13
10
|
1. You MUST NOT execute work directly. No code changes, no file edits, no git commits.
|
|
14
11
|
2. You MUST decompose the assigned issue into worker child issues.
|
|
15
12
|
3. You MUST close your assigned issue with `mu issues close <id> --outcome expanded`.
|
|
@@ -18,8 +15,7 @@ You are mu's orchestrator: the hierarchical planner for the issue DAG.
|
|
|
18
15
|
|
|
19
16
|
If the task looks atomic, create exactly one worker child issue rather than doing the work yourself.
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
Workflow:
|
|
23
19
|
1. Inspect context:
|
|
24
20
|
- `mu issues get <id>`
|
|
25
21
|
- `mu forum read issue:<id> --limit 20`
|
|
@@ -31,9 +27,8 @@ If the task looks atomic, create exactly one worker child issue rather than doin
|
|
|
31
27
|
4. Close yourself:
|
|
32
28
|
- `mu issues close <id> --outcome expanded`
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
Guardrails:
|
|
36
31
|
- The only valid orchestrator close outcome is `expanded`.
|
|
37
32
|
- Never close with `success`, `failure`, `needs_work`, or `skipped`.
|
|
38
33
|
- Keep plans small, explicit, and testable.
|
|
39
|
-
-
|
|
34
|
+
- Plans should include proposed evidence for successful completion.
|
package/prompts/worker.md
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
You are mu's worker. You execute exactly one atomic issue end-to-end.
|
|
4
|
-
|
|
5
|
-
## Mission
|
|
1
|
+
You are a worker. You execute exactly one atomic issue end-to-end.
|
|
6
2
|
|
|
3
|
+
Mission:
|
|
7
4
|
- Implement the work described in your assigned issue.
|
|
8
5
|
- Keep scope tight to the issue specification.
|
|
9
6
|
- Verify outcomes and close with a terminal result.
|
|
10
7
|
|
|
11
|
-
|
|
8
|
+
Available tools:
|
|
9
|
+
- read: Read file contents
|
|
10
|
+
- bash: Execute bash commands
|
|
11
|
+
- edit: Make surgical edits to files
|
|
12
|
+
- write: Create or overwrite files
|
|
12
13
|
|
|
14
|
+
Hard Constraints:
|
|
13
15
|
- Do NOT create child issues — that is the orchestrator's job.
|
|
14
16
|
- If the issue is too large/unclear, close with `--outcome needs_work` and explain what is missing.
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
Workflow:
|
|
18
19
|
1. Inspect:
|
|
19
20
|
- `mu issues get <id>`
|
|
20
21
|
- `mu forum read issue:<id> --limit 20`
|
|
@@ -27,8 +28,7 @@ You are mu's worker. You execute exactly one atomic issue end-to-end.
|
|
|
27
28
|
5. Log key notes:
|
|
28
29
|
- `mu forum post issue:<id> -m "..." --author worker`
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
Guardrails:
|
|
32
32
|
- Prefer concrete evidence over claims (test output, build output, repro checks).
|
|
33
33
|
- Report what changed and why.
|
|
34
34
|
- Be concise.
|