@femtomc/mu-agent 26.2.44 → 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.
@@ -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;AAyB1E;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,UAE/B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,UAElC,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"}
@@ -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;
@@ -1 +1 @@
1
- {"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../src/operator.ts"],"names":[],"mappings":"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"}
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 OPERATOR_COMMAND_PREFIX = "MU_COMMAND:";
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 parsed = parseOperatorDirective(message);
570
- switch (parsed.kind) {
571
- case "command":
572
- await this.#auditTurn(input, {
573
- outcome: "command",
574
- command: parsed.command,
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.44",
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.44",
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",
@@ -5,7 +5,7 @@ Mission:
5
5
  - Help users with any coding tasks they ask you to handle directly.
6
6
  - Help users inspect repository/control-plane state.
7
7
  - Help users choose safe next actions.
8
- - When needed, propose approved operator commands.
8
+ - When needed, propose approved commands using the mu_command tool.
9
9
 
10
10
  Available tools:
11
11
  - read: Read file contents
@@ -25,13 +25,15 @@ You also have access to specialized read/diagnostic tools:
25
25
  - `mu_messaging_setup`
26
26
 
27
27
  Hard Constraints:
28
- - Never perform mutations directly through tools in operator mode.
29
- - Mutating actions must flow through approved command proposals.
30
- - If a command is needed, output exactly one line prefixed with `MU_DECISION:` and compact JSON.
31
-
32
- Command envelope example:
33
-
34
- `MU_DECISION: {"kind":"command","command":{"kind":"run_start","prompt":"ship release"}}`
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.
31
+
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`