@femtomc/mu-agent 26.2.74 → 26.2.76
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/backend.d.ts.map +1 -1
- package/dist/backend.js +27 -9
- package/dist/default_prompts.d.ts.map +1 -1
- package/dist/default_prompts.js +2 -1
- package/dist/extensions/event-log.js +1 -1
- package/dist/extensions/shared.js +5 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/operator.d.ts +34 -0
- package/dist/operator.d.ts.map +1 -1
- package/dist/operator.js +62 -4
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +2 -1
- package/dist/self_documentation.d.ts +7 -0
- package/dist/self_documentation.d.ts.map +1 -0
- package/dist/self_documentation.js +67 -0
- package/dist/session_turn.d.ts +37 -0
- package/dist/session_turn.d.ts.map +1 -0
- package/dist/session_turn.js +392 -0
- package/package.json +2 -2
- package/prompts/roles/operator.md +9 -1
- package/prompts/roles/orchestrator.md +3 -0
- package/prompts/roles/reviewer.md +2 -0
- package/prompts/roles/worker.md +3 -0
package/dist/backend.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEjD,OAAO,EACN,WAAW,EAOX,qBAAqB,EAGrB,eAAe,EACf,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAI5C,MAAM,MAAM,cAAc,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,WAAW,aAAa;IAC7B,GAAG,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3C;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CA4BpD;AAGD;;;;;GAKG;AACH,wBAAgB,YAAY,CAC3B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,WAAW,EACxB,kBAAkB,CAAC,EAAE,MAAM,GACzB,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CA6BxB;AAED;;;;GAIG;AACH,qBAAa,UAAW,YAAW,aAAa;IACzC,GAAG,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;CAoGhD;AAGD,MAAM,MAAM,0BAA0B,GAAG;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,0BAA0B,GAAG,qBAAqB,CA+C9F"}
|
package/dist/backend.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { mkdir, open } from "node:fs/promises";
|
|
3
3
|
import { basename, dirname, join } from "node:path";
|
|
4
|
+
import { findRepoRoot, getMuHomeDir, getStorePaths } from "@femtomc/mu-core/node";
|
|
4
5
|
import { getModels, getProviders } from "@mariozechner/pi-ai";
|
|
5
|
-
import { AuthStorage, createAgentSession, createBashTool, createEditTool, createReadTool, createWriteTool, DefaultResourceLoader, SessionManager, SettingsManager, } from "@mariozechner/pi-coding-agent";
|
|
6
|
+
import { AuthStorage, createAgentSession, createBashTool, createEditTool, createReadTool, createWriteTool, DefaultResourceLoader, getAgentDir, SessionManager, SettingsManager, } from "@mariozechner/pi-coding-agent";
|
|
6
7
|
import { orchestratorToolExtensionPaths, workerToolExtensionPaths } from "./extensions/index.js";
|
|
7
8
|
import { MU_DEFAULT_THEME_NAME, MU_DEFAULT_THEME_PATH } from "./ui_defaults.js";
|
|
8
9
|
export function streamHasError(line) {
|
|
@@ -159,25 +160,42 @@ export class SdkBackend {
|
|
|
159
160
|
}
|
|
160
161
|
}
|
|
161
162
|
export function createMuResourceLoader(opts) {
|
|
162
|
-
const
|
|
163
|
+
const repoRoot = findRepoRoot(opts.cwd);
|
|
164
|
+
const storePaths = getStorePaths(repoRoot);
|
|
165
|
+
const piAgentDir = opts.agentDir ?? getAgentDir();
|
|
166
|
+
const skillPaths = [];
|
|
167
|
+
const seenSkillPaths = new Set();
|
|
168
|
+
const addSkillPath = (path, requireExists) => {
|
|
169
|
+
if (requireExists && !existsSync(path)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (seenSkillPaths.has(path)) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
seenSkillPaths.add(path);
|
|
176
|
+
skillPaths.push(path);
|
|
177
|
+
};
|
|
178
|
+
// Preference order (first match wins on skill-name collisions):
|
|
179
|
+
// mu workspace -> mu global -> repo top-level -> explicit additions -> pi project -> pi global.
|
|
180
|
+
addSkillPath(join(storePaths.storeDir, "skills"), true);
|
|
181
|
+
addSkillPath(join(getMuHomeDir(), "skills"), true);
|
|
182
|
+
addSkillPath(join(repoRoot, "skills"), true);
|
|
163
183
|
for (const p of opts.additionalSkillPaths ?? []) {
|
|
164
|
-
|
|
184
|
+
addSkillPath(p, false);
|
|
165
185
|
}
|
|
186
|
+
addSkillPath(join(repoRoot, ".pi", "skills"), true);
|
|
187
|
+
addSkillPath(join(piAgentDir, "skills"), true);
|
|
166
188
|
const themePaths = new Set([MU_DEFAULT_THEME_PATH]);
|
|
167
189
|
for (const p of opts.additionalThemePaths ?? []) {
|
|
168
190
|
themePaths.add(p);
|
|
169
191
|
}
|
|
170
|
-
// If a repo has a top-level `skills/` dir (like workshop/), load it.
|
|
171
|
-
const repoSkills = join(opts.cwd, "skills");
|
|
172
|
-
if (existsSync(repoSkills)) {
|
|
173
|
-
skillPaths.add(repoSkills);
|
|
174
|
-
}
|
|
175
192
|
return new DefaultResourceLoader({
|
|
176
193
|
cwd: opts.cwd,
|
|
177
194
|
agentDir: opts.agentDir,
|
|
178
195
|
settingsManager: opts.settingsManager ?? SettingsManager.inMemory({ theme: MU_DEFAULT_THEME_NAME, quietStartup: true }),
|
|
179
196
|
additionalExtensionPaths: opts.additionalExtensionPaths,
|
|
180
|
-
|
|
197
|
+
noSkills: true,
|
|
198
|
+
additionalSkillPaths: skillPaths,
|
|
181
199
|
additionalThemePaths: [...themePaths],
|
|
182
200
|
systemPromptOverride: (_base) => opts.systemPrompt,
|
|
183
201
|
agentsFilesOverride: (base) => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default_prompts.d.ts","sourceRoot":"","sources":["../src/default_prompts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"default_prompts.d.ts","sourceRoot":"","sources":["../src/default_prompts.ts"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAStD;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAO/E;AAED,eAAO,MAAM,mBAAmB,QAAqC,CAAC;AAOtE,eAAO,MAAM,2BAA2B,QAAkE,CAAC;AAC3G,eAAO,MAAM,uBAAuB,QAA8D,CAAC;AACnG,eAAO,MAAM,qBAAqB,QAA4D,CAAC;AAC/F,eAAO,MAAM,8BAA8B,QAE1C,CAAC"}
|
package/dist/default_prompts.js
CHANGED
|
@@ -2,6 +2,7 @@ import { readFileSync } from "node:fs";
|
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { splitFrontmatter } from "./prompt.js";
|
|
5
|
+
import { appendMuDocumentationSection } from "./self_documentation.js";
|
|
5
6
|
function bundledPromptPath(name) {
|
|
6
7
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
7
8
|
return join(here, "..", "prompts", name);
|
|
@@ -38,4 +39,4 @@ const BASE_OPERATOR_SYSTEM_PROMPT = loadBundledPrompt("roles/operator.md");
|
|
|
38
39
|
export const DEFAULT_ORCHESTRATOR_PROMPT = appendSharedSoul(BASE_ORCHESTRATOR_PROMPT, DEFAULT_SOUL_PROMPT);
|
|
39
40
|
export const DEFAULT_REVIEWER_PROMPT = appendSharedSoul(BASE_REVIEWER_PROMPT, DEFAULT_SOUL_PROMPT);
|
|
40
41
|
export const DEFAULT_WORKER_PROMPT = appendSharedSoul(BASE_WORKER_PROMPT, DEFAULT_SOUL_PROMPT);
|
|
41
|
-
export const DEFAULT_OPERATOR_SYSTEM_PROMPT = appendSharedSoul(BASE_OPERATOR_SYSTEM_PROMPT, DEFAULT_SOUL_PROMPT);
|
|
42
|
+
export const DEFAULT_OPERATOR_SYSTEM_PROMPT = appendMuDocumentationSection(appendSharedSoul(BASE_OPERATOR_SYSTEM_PROMPT, DEFAULT_SOUL_PROMPT));
|
|
@@ -19,7 +19,7 @@ async function fetchTail(n) {
|
|
|
19
19
|
if (!muServerUrl())
|
|
20
20
|
return [];
|
|
21
21
|
try {
|
|
22
|
-
return await fetchMuJson(`/api/events/tail?n=${n}`, { timeoutMs: 6_000 });
|
|
22
|
+
return await fetchMuJson(`/api/control-plane/events/tail?n=${n}`, { timeoutMs: 6_000 });
|
|
23
23
|
}
|
|
24
24
|
catch {
|
|
25
25
|
return [];
|
|
@@ -42,25 +42,25 @@ export async function fetchMuJson(path, opts = {}) {
|
|
|
42
42
|
function ensureGenerationScopedStatus(status) {
|
|
43
43
|
const controlPlane = status.control_plane;
|
|
44
44
|
if (!controlPlane || typeof controlPlane !== "object") {
|
|
45
|
-
throw new Error("mu server /api/status missing control_plane payload (expected generation-scoped contract)");
|
|
45
|
+
throw new Error("mu server /api/control-plane/status missing control_plane payload (expected generation-scoped contract)");
|
|
46
46
|
}
|
|
47
47
|
const controlPlaneRecord = controlPlane;
|
|
48
48
|
if (!("generation" in controlPlaneRecord) || !controlPlaneRecord.generation) {
|
|
49
|
-
throw new Error("mu server /api/status missing control_plane.generation (expected generation-scoped contract)");
|
|
49
|
+
throw new Error("mu server /api/control-plane/status missing control_plane.generation (expected generation-scoped contract)");
|
|
50
50
|
}
|
|
51
51
|
if (!("observability" in controlPlaneRecord) || !controlPlaneRecord.observability) {
|
|
52
|
-
throw new Error("mu server /api/status missing control_plane.observability (expected generation-scoped contract)");
|
|
52
|
+
throw new Error("mu server /api/control-plane/status missing control_plane.observability (expected generation-scoped contract)");
|
|
53
53
|
}
|
|
54
54
|
const observability = controlPlaneRecord.observability;
|
|
55
55
|
if (typeof observability !== "object" ||
|
|
56
56
|
observability == null ||
|
|
57
57
|
!("counters" in observability) ||
|
|
58
58
|
!observability.counters) {
|
|
59
|
-
throw new Error("mu server /api/status missing control_plane.observability.counters (expected generation-scoped contract)");
|
|
59
|
+
throw new Error("mu server /api/control-plane/status missing control_plane.observability.counters (expected generation-scoped contract)");
|
|
60
60
|
}
|
|
61
61
|
return status;
|
|
62
62
|
}
|
|
63
63
|
export async function fetchMuStatus(timeoutMs) {
|
|
64
|
-
const status = await fetchMuJson("/api/status", { timeoutMs });
|
|
64
|
+
const status = await fetchMuJson("/api/control-plane/status", { timeoutMs });
|
|
65
65
|
return ensureGenerationScopedStatus(status);
|
|
66
66
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,OAAO,EACN,8BAA8B,EAC9B,2BAA2B,EAC3B,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,OAAO,EACN,8BAA8B,EAC9B,2BAA2B,EAC3B,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/operator.d.ts
CHANGED
|
@@ -48,6 +48,23 @@ export declare const OperatorApprovedCommandSchema: z.ZodDiscriminatedUnion<[z.Z
|
|
|
48
48
|
kind: z.ZodLiteral<"reload">;
|
|
49
49
|
}, z.core.$strip>, z.ZodObject<{
|
|
50
50
|
kind: z.ZodLiteral<"update">;
|
|
51
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
52
|
+
kind: z.ZodLiteral<"operator_config_get">;
|
|
53
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
54
|
+
kind: z.ZodLiteral<"operator_model_list">;
|
|
55
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
56
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
57
|
+
kind: z.ZodLiteral<"operator_thinking_list">;
|
|
58
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
59
|
+
model: z.ZodOptional<z.ZodString>;
|
|
60
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
61
|
+
kind: z.ZodLiteral<"operator_model_set">;
|
|
62
|
+
provider: z.ZodString;
|
|
63
|
+
model: z.ZodString;
|
|
64
|
+
thinking: z.ZodOptional<z.ZodString>;
|
|
65
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
66
|
+
kind: z.ZodLiteral<"operator_thinking_set">;
|
|
67
|
+
thinking: z.ZodString;
|
|
51
68
|
}, z.core.$strip>, z.ZodObject<{
|
|
52
69
|
kind: z.ZodLiteral<"run_start">;
|
|
53
70
|
prompt: z.ZodString;
|
|
@@ -88,6 +105,23 @@ export declare const OperatorBackendTurnResultSchema: z.ZodDiscriminatedUnion<[z
|
|
|
88
105
|
kind: z.ZodLiteral<"reload">;
|
|
89
106
|
}, z.core.$strip>, z.ZodObject<{
|
|
90
107
|
kind: z.ZodLiteral<"update">;
|
|
108
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
109
|
+
kind: z.ZodLiteral<"operator_config_get">;
|
|
110
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
111
|
+
kind: z.ZodLiteral<"operator_model_list">;
|
|
112
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
113
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
114
|
+
kind: z.ZodLiteral<"operator_thinking_list">;
|
|
115
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
116
|
+
model: z.ZodOptional<z.ZodString>;
|
|
117
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
118
|
+
kind: z.ZodLiteral<"operator_model_set">;
|
|
119
|
+
provider: z.ZodString;
|
|
120
|
+
model: z.ZodString;
|
|
121
|
+
thinking: z.ZodOptional<z.ZodString>;
|
|
122
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
123
|
+
kind: z.ZodLiteral<"operator_thinking_set">;
|
|
124
|
+
thinking: z.ZodString;
|
|
91
125
|
}, z.core.$strip>, z.ZodObject<{
|
|
92
126
|
kind: z.ZodLiteral<"run_start">;
|
|
93
127
|
prompt: z.ZodString;
|
package/dist/operator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../src/operator.ts"],"names":[],"mappings":"AAGA,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
|
|
1
|
+
{"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../src/operator.ts"],"names":[],"mappings":"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"}
|
package/dist/operator.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { appendJsonl, readJsonl } from "@femtomc/mu-core/node";
|
|
1
|
+
import { appendJsonl, getStorePaths, readJsonl } from "@femtomc/mu-core/node";
|
|
2
2
|
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { z } from "zod";
|
|
@@ -32,6 +32,26 @@ export const OperatorApprovedCommandSchema = z.discriminatedUnion("kind", [
|
|
|
32
32
|
}),
|
|
33
33
|
z.object({ kind: z.literal("reload") }),
|
|
34
34
|
z.object({ kind: z.literal("update") }),
|
|
35
|
+
z.object({ kind: z.literal("operator_config_get") }),
|
|
36
|
+
z.object({
|
|
37
|
+
kind: z.literal("operator_model_list"),
|
|
38
|
+
provider: z.string().trim().min(1).optional(),
|
|
39
|
+
}),
|
|
40
|
+
z.object({
|
|
41
|
+
kind: z.literal("operator_thinking_list"),
|
|
42
|
+
provider: z.string().trim().min(1).optional(),
|
|
43
|
+
model: z.string().trim().min(1).optional(),
|
|
44
|
+
}),
|
|
45
|
+
z.object({
|
|
46
|
+
kind: z.literal("operator_model_set"),
|
|
47
|
+
provider: z.string().trim().min(1),
|
|
48
|
+
model: z.string().trim().min(1),
|
|
49
|
+
thinking: z.string().trim().min(1).optional(),
|
|
50
|
+
}),
|
|
51
|
+
z.object({
|
|
52
|
+
kind: z.literal("operator_thinking_set"),
|
|
53
|
+
thinking: z.string().trim().min(1),
|
|
54
|
+
}),
|
|
35
55
|
z.object({
|
|
36
56
|
kind: z.literal("run_start"),
|
|
37
57
|
prompt: z.string().trim().min(1),
|
|
@@ -135,6 +155,43 @@ export class ApprovedCommandBroker {
|
|
|
135
155
|
args = [];
|
|
136
156
|
break;
|
|
137
157
|
}
|
|
158
|
+
case "operator_config_get": {
|
|
159
|
+
commandKey = "operator config get";
|
|
160
|
+
args = [];
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
case "operator_model_list": {
|
|
164
|
+
commandKey = "operator model list";
|
|
165
|
+
args = [];
|
|
166
|
+
if (opts.proposal.provider) {
|
|
167
|
+
args.push(normalizeArg(opts.proposal.provider));
|
|
168
|
+
}
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case "operator_thinking_list": {
|
|
172
|
+
commandKey = "operator thinking list";
|
|
173
|
+
args = [];
|
|
174
|
+
if (opts.proposal.provider) {
|
|
175
|
+
args.push(normalizeArg(opts.proposal.provider));
|
|
176
|
+
}
|
|
177
|
+
if (opts.proposal.model) {
|
|
178
|
+
args.push(normalizeArg(opts.proposal.model));
|
|
179
|
+
}
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
case "operator_model_set": {
|
|
183
|
+
commandKey = "operator model set";
|
|
184
|
+
args = [normalizeArg(opts.proposal.provider), normalizeArg(opts.proposal.model)];
|
|
185
|
+
if (opts.proposal.thinking) {
|
|
186
|
+
args.push(normalizeArg(opts.proposal.thinking));
|
|
187
|
+
}
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
case "operator_thinking_set": {
|
|
191
|
+
commandKey = "operator thinking set";
|
|
192
|
+
args = [normalizeArg(opts.proposal.thinking)];
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
138
195
|
case "run_start": {
|
|
139
196
|
if (!this.#runTriggersEnabled) {
|
|
140
197
|
return { kind: "reject", reason: "operator_action_disallowed", details: "run triggers disabled" };
|
|
@@ -216,7 +273,7 @@ function stringList(value) {
|
|
|
216
273
|
return out;
|
|
217
274
|
}
|
|
218
275
|
function sessionFlashPath(repoRoot) {
|
|
219
|
-
return join(repoRoot
|
|
276
|
+
return join(getStorePaths(repoRoot).storeDir, "control-plane", "session_flash.jsonl");
|
|
220
277
|
}
|
|
221
278
|
async function loadPendingSessionFlashes(opts) {
|
|
222
279
|
const rows = await readJsonl(sessionFlashPath(opts.repoRoot));
|
|
@@ -661,7 +718,8 @@ export class PiMessagingOperatorBackend {
|
|
|
661
718
|
this.#auditTurns = opts.auditTurns ?? true;
|
|
662
719
|
this.#persistSessions = opts.persistSessions ?? true;
|
|
663
720
|
this.#sessionDirForRepoRoot =
|
|
664
|
-
opts.sessionDirForRepoRoot ??
|
|
721
|
+
opts.sessionDirForRepoRoot ??
|
|
722
|
+
((repoRoot) => join(getStorePaths(repoRoot).storeDir, "control-plane", "operator-sessions"));
|
|
665
723
|
// Operator turns can emit structured command proposals captured from tool events.
|
|
666
724
|
}
|
|
667
725
|
#disposeSession(sessionId) {
|
|
@@ -766,7 +824,7 @@ export class PiMessagingOperatorBackend {
|
|
|
766
824
|
command: opts.command ?? null,
|
|
767
825
|
};
|
|
768
826
|
try {
|
|
769
|
-
const path = join(input.inbound.repo_root
|
|
827
|
+
const path = join(getStorePaths(input.inbound.repo_root).storeDir, "control-plane", "operator_turns.jsonl");
|
|
770
828
|
await appendJsonl(path, entry);
|
|
771
829
|
}
|
|
772
830
|
catch {
|
package/dist/prompt.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAyCjD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CA6BjF;AAYD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAW1G;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAItE;AAMD,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwCxE;AAED,wBAAsB,oBAAoB,CACzC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,OAAO,GAAG,MAAM,CAAC,EAC3C,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9B,OAAO,CAAC,MAAM,CAAC,CAmBjB;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAK9E"}
|
package/dist/prompt.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getStorePaths } from "@femtomc/mu-core/node";
|
|
1
2
|
import { readdir } from "node:fs/promises";
|
|
2
3
|
import { isAbsolute, join, relative } from "node:path";
|
|
3
4
|
function stripQuotes(s) {
|
|
@@ -96,7 +97,7 @@ function toPosixPath(path) {
|
|
|
96
97
|
return path.replaceAll("\\", "/");
|
|
97
98
|
}
|
|
98
99
|
export async function buildRoleCatalog(repoRoot) {
|
|
99
|
-
const rolesDir = join(repoRoot
|
|
100
|
+
const rolesDir = join(getStorePaths(repoRoot).storeDir, "roles");
|
|
100
101
|
let entries;
|
|
101
102
|
try {
|
|
102
103
|
entries = await readdir(rolesDir);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type MuDocumentation = {
|
|
2
|
+
readmePath?: string;
|
|
3
|
+
docsPath?: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function resolveMuDocumentation(): MuDocumentation;
|
|
6
|
+
export declare function appendMuDocumentationSection(basePrompt: string): string;
|
|
7
|
+
//# sourceMappingURL=self_documentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self_documentation.d.ts","sourceRoot":"","sources":["../src/self_documentation.ts"],"names":[],"mappings":"AA8BA,MAAM,MAAM,eAAe,GAAG;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,sBAAsB,IAAI,eAAe,CA2BxD;AAED,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAiBvE"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
function findPackageRoot(startDir) {
|
|
7
|
+
let dir = resolve(startDir);
|
|
8
|
+
while (true) {
|
|
9
|
+
if (existsSync(join(dir, "package.json"))) {
|
|
10
|
+
return dir;
|
|
11
|
+
}
|
|
12
|
+
const parent = dirname(dir);
|
|
13
|
+
if (parent === dir) {
|
|
14
|
+
return resolve(startDir);
|
|
15
|
+
}
|
|
16
|
+
dir = parent;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function firstExistingPath(candidates) {
|
|
20
|
+
for (const candidate of candidates) {
|
|
21
|
+
if (existsSync(candidate)) {
|
|
22
|
+
return candidate;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
export function resolveMuDocumentation() {
|
|
28
|
+
const thisModuleDir = dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
const agentPackageRoot = findPackageRoot(thisModuleDir);
|
|
30
|
+
let muPackageRoot;
|
|
31
|
+
try {
|
|
32
|
+
const muEntry = require.resolve("@femtomc/mu");
|
|
33
|
+
muPackageRoot = findPackageRoot(dirname(muEntry));
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
muPackageRoot = undefined;
|
|
37
|
+
}
|
|
38
|
+
const candidateRoots = [muPackageRoot, agentPackageRoot].filter((v) => Boolean(v));
|
|
39
|
+
const readmeCandidates = [];
|
|
40
|
+
const docsCandidates = [];
|
|
41
|
+
for (const root of candidateRoots) {
|
|
42
|
+
readmeCandidates.push(resolve(root, "..", "..", "README.md"));
|
|
43
|
+
readmeCandidates.push(join(root, "README.md"));
|
|
44
|
+
docsCandidates.push(resolve(root, "..", "..", "docs"));
|
|
45
|
+
docsCandidates.push(join(root, "docs"));
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
readmePath: firstExistingPath(readmeCandidates),
|
|
49
|
+
docsPath: firstExistingPath(docsCandidates),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export function appendMuDocumentationSection(basePrompt) {
|
|
53
|
+
const trimmed = basePrompt.trim();
|
|
54
|
+
const { readmePath, docsPath } = resolveMuDocumentation();
|
|
55
|
+
const lines = ["Mu documentation (for mu feature/configuration/setup questions):"];
|
|
56
|
+
if (readmePath) {
|
|
57
|
+
lines.push(`- Main documentation: ${readmePath}`);
|
|
58
|
+
}
|
|
59
|
+
if (docsPath) {
|
|
60
|
+
lines.push(`- Additional docs: ${docsPath}`);
|
|
61
|
+
}
|
|
62
|
+
if (!readmePath && !docsPath) {
|
|
63
|
+
lines.push("- Documentation path unavailable at runtime; use `mu --help` and package README files.");
|
|
64
|
+
}
|
|
65
|
+
lines.push("- Read these when users ask about mu capabilities, adapters, or operational setup.");
|
|
66
|
+
return `${trimmed}\n\n${lines.join("\n")}`;
|
|
67
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type CreateMuSessionOpts, type MuSession } from "./session_factory.js";
|
|
2
|
+
export type SessionTurnRequest = {
|
|
3
|
+
session_id: string;
|
|
4
|
+
session_kind: string | null;
|
|
5
|
+
body: string;
|
|
6
|
+
source: string | null;
|
|
7
|
+
provider: string | null;
|
|
8
|
+
model: string | null;
|
|
9
|
+
thinking: string | null;
|
|
10
|
+
session_file: string | null;
|
|
11
|
+
session_dir: string | null;
|
|
12
|
+
extension_profile: string | null;
|
|
13
|
+
};
|
|
14
|
+
export type SessionTurnResult = {
|
|
15
|
+
session_id: string;
|
|
16
|
+
session_kind: string | null;
|
|
17
|
+
session_file: string;
|
|
18
|
+
context_entry_id: string | null;
|
|
19
|
+
reply: string;
|
|
20
|
+
source: string | null;
|
|
21
|
+
completed_at_ms: number;
|
|
22
|
+
};
|
|
23
|
+
export declare class SessionTurnError extends Error {
|
|
24
|
+
readonly status: number;
|
|
25
|
+
constructor(status: number, message: string);
|
|
26
|
+
}
|
|
27
|
+
export declare function parseSessionTurnRequest(body: Record<string, unknown>): {
|
|
28
|
+
request: SessionTurnRequest | null;
|
|
29
|
+
error: string | null;
|
|
30
|
+
};
|
|
31
|
+
export declare function executeSessionTurn(opts: {
|
|
32
|
+
repoRoot: string;
|
|
33
|
+
request: SessionTurnRequest;
|
|
34
|
+
sessionFactory?: (opts: CreateMuSessionOpts) => Promise<MuSession>;
|
|
35
|
+
nowMs?: () => number;
|
|
36
|
+
}): Promise<SessionTurnResult>;
|
|
37
|
+
//# sourceMappingURL=session_turn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session_turn.d.ts","sourceRoot":"","sources":["../src/session_turn.ts"],"names":[],"mappings":"AAcA,OAAO,EAAmB,KAAK,mBAAmB,EAAE,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjG,MAAM,MAAM,kBAAkB,GAAG;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,qBAAa,gBAAiB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEL,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAIlD;AAoSD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACvE,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACnC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CA+BA;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACnE,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA+F7B"}
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { getStorePaths } from "@femtomc/mu-core/node";
|
|
2
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
|
+
import { DEFAULT_OPERATOR_SYSTEM_PROMPT, DEFAULT_ORCHESTRATOR_PROMPT, DEFAULT_REVIEWER_PROMPT, DEFAULT_WORKER_PROMPT, } from "./default_prompts.js";
|
|
5
|
+
import { operatorExtensionPaths, orchestratorToolExtensionPaths, workerToolExtensionPaths, } from "./extensions/index.js";
|
|
6
|
+
import { createMuSession } from "./session_factory.js";
|
|
7
|
+
export class SessionTurnError extends Error {
|
|
8
|
+
status;
|
|
9
|
+
constructor(status, message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.status = status;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function nonEmptyString(value) {
|
|
15
|
+
if (typeof value !== "string") {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const trimmed = value.trim();
|
|
19
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
20
|
+
}
|
|
21
|
+
function asRecord(value) {
|
|
22
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
function normalizeSessionKind(value) {
|
|
28
|
+
if (!value) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const normalized = value.trim().toLowerCase().replaceAll("-", "_");
|
|
32
|
+
if (normalized === "cpoperator" || normalized === "control_plane_operator") {
|
|
33
|
+
return "cp_operator";
|
|
34
|
+
}
|
|
35
|
+
return normalized;
|
|
36
|
+
}
|
|
37
|
+
function normalizeExtensionProfile(value) {
|
|
38
|
+
if (!value) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const normalized = value.trim().toLowerCase();
|
|
42
|
+
if (normalized === "operator" ||
|
|
43
|
+
normalized === "worker" ||
|
|
44
|
+
normalized === "orchestrator" ||
|
|
45
|
+
normalized === "reviewer" ||
|
|
46
|
+
normalized === "none") {
|
|
47
|
+
return normalized;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
function sessionFileStem(sessionId) {
|
|
52
|
+
const normalized = sessionId.trim().replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
53
|
+
const compact = normalized.replace(/-+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
|
|
54
|
+
return compact.length > 0 ? compact : "session";
|
|
55
|
+
}
|
|
56
|
+
function resolveRepoPath(repoRoot, candidate) {
|
|
57
|
+
return isAbsolute(candidate) ? resolve(candidate) : resolve(repoRoot, candidate);
|
|
58
|
+
}
|
|
59
|
+
function defaultSessionDirForKind(repoRoot, sessionKind) {
|
|
60
|
+
const storeDir = getStorePaths(repoRoot).storeDir;
|
|
61
|
+
switch (sessionKind) {
|
|
62
|
+
case "operator":
|
|
63
|
+
return join(storeDir, "operator", "sessions");
|
|
64
|
+
case "cp_operator":
|
|
65
|
+
return join(storeDir, "control-plane", "operator-sessions");
|
|
66
|
+
case "orchestrator":
|
|
67
|
+
return join(storeDir, "orchestrator", "sessions");
|
|
68
|
+
case "worker":
|
|
69
|
+
return join(storeDir, "worker", "sessions");
|
|
70
|
+
case "reviewer":
|
|
71
|
+
return join(storeDir, "reviewer", "sessions");
|
|
72
|
+
default:
|
|
73
|
+
return join(storeDir, "control-plane", "operator-sessions");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function pathExists(path) {
|
|
77
|
+
try {
|
|
78
|
+
await stat(path);
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function directoryExists(path) {
|
|
86
|
+
try {
|
|
87
|
+
const info = await stat(path);
|
|
88
|
+
return info.isDirectory();
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function readSessionHeaderId(sessionFile) {
|
|
95
|
+
let raw;
|
|
96
|
+
try {
|
|
97
|
+
raw = await readFile(sessionFile, "utf8");
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const firstLine = raw
|
|
103
|
+
.split("\n")
|
|
104
|
+
.map((line) => line.trim())
|
|
105
|
+
.find((line) => line.length > 0);
|
|
106
|
+
if (!firstLine) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const parsed = JSON.parse(firstLine);
|
|
111
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
const header = parsed;
|
|
115
|
+
if (header.type !== "session") {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
return nonEmptyString(header.id);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async function resolveSessionFileById(opts) {
|
|
125
|
+
const direct = join(opts.sessionDir, `${sessionFileStem(opts.sessionId)}.jsonl`);
|
|
126
|
+
if (await pathExists(direct)) {
|
|
127
|
+
const headerId = await readSessionHeaderId(direct);
|
|
128
|
+
if (headerId === opts.sessionId) {
|
|
129
|
+
return direct;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const entries = await readdir(opts.sessionDir, { withFileTypes: true });
|
|
133
|
+
for (const entry of entries) {
|
|
134
|
+
if (!entry.isFile() || !entry.name.endsWith(".jsonl")) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const filePath = join(opts.sessionDir, entry.name);
|
|
138
|
+
if (filePath === direct) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const headerId = await readSessionHeaderId(filePath);
|
|
142
|
+
if (headerId === opts.sessionId) {
|
|
143
|
+
return filePath;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
function extensionPathsForTurn(opts) {
|
|
149
|
+
if (opts.extensionProfile === "none") {
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
if (opts.extensionProfile === "operator") {
|
|
153
|
+
return [...operatorExtensionPaths];
|
|
154
|
+
}
|
|
155
|
+
if (opts.extensionProfile === "orchestrator") {
|
|
156
|
+
return [...orchestratorToolExtensionPaths];
|
|
157
|
+
}
|
|
158
|
+
if (opts.extensionProfile === "worker" || opts.extensionProfile === "reviewer") {
|
|
159
|
+
return [...workerToolExtensionPaths];
|
|
160
|
+
}
|
|
161
|
+
if (opts.sessionKind === "operator" || opts.sessionKind === "cp_operator") {
|
|
162
|
+
return [...operatorExtensionPaths];
|
|
163
|
+
}
|
|
164
|
+
if (opts.sessionKind === "orchestrator") {
|
|
165
|
+
return [...orchestratorToolExtensionPaths];
|
|
166
|
+
}
|
|
167
|
+
if (opts.sessionKind === "worker" || opts.sessionKind === "reviewer") {
|
|
168
|
+
return [...workerToolExtensionPaths];
|
|
169
|
+
}
|
|
170
|
+
return [...operatorExtensionPaths];
|
|
171
|
+
}
|
|
172
|
+
function systemPromptForTurn(opts) {
|
|
173
|
+
const role = opts.extensionProfile ?? opts.sessionKind;
|
|
174
|
+
if (role === "operator" || role === "cp_operator") {
|
|
175
|
+
return DEFAULT_OPERATOR_SYSTEM_PROMPT;
|
|
176
|
+
}
|
|
177
|
+
if (role === "orchestrator") {
|
|
178
|
+
return DEFAULT_ORCHESTRATOR_PROMPT;
|
|
179
|
+
}
|
|
180
|
+
if (role === "reviewer") {
|
|
181
|
+
return DEFAULT_REVIEWER_PROMPT;
|
|
182
|
+
}
|
|
183
|
+
if (role === "worker") {
|
|
184
|
+
return DEFAULT_WORKER_PROMPT;
|
|
185
|
+
}
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
function extractAssistantText(message) {
|
|
189
|
+
if (!message || typeof message !== "object") {
|
|
190
|
+
return "";
|
|
191
|
+
}
|
|
192
|
+
const record = message;
|
|
193
|
+
if (typeof record.text === "string") {
|
|
194
|
+
return record.text;
|
|
195
|
+
}
|
|
196
|
+
if (typeof record.content === "string") {
|
|
197
|
+
return record.content;
|
|
198
|
+
}
|
|
199
|
+
if (Array.isArray(record.content)) {
|
|
200
|
+
const parts = [];
|
|
201
|
+
for (const item of record.content) {
|
|
202
|
+
if (typeof item === "string") {
|
|
203
|
+
if (item.trim().length > 0) {
|
|
204
|
+
parts.push(item);
|
|
205
|
+
}
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (!item || typeof item !== "object") {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const text = nonEmptyString(item.text);
|
|
212
|
+
if (text) {
|
|
213
|
+
parts.push(text);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return parts.join("\n");
|
|
217
|
+
}
|
|
218
|
+
return "";
|
|
219
|
+
}
|
|
220
|
+
function safeLeafId(session) {
|
|
221
|
+
const manager = session.sessionManager;
|
|
222
|
+
if (!manager || typeof manager.getLeafId !== "function") {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
const value = manager.getLeafId();
|
|
226
|
+
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
227
|
+
}
|
|
228
|
+
function safeSessionId(session) {
|
|
229
|
+
const value = session.sessionId;
|
|
230
|
+
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
231
|
+
}
|
|
232
|
+
function safeSessionFile(session) {
|
|
233
|
+
const value = session.sessionFile;
|
|
234
|
+
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
235
|
+
}
|
|
236
|
+
async function resolveSessionTarget(opts) {
|
|
237
|
+
const sessionDir = opts.request.session_dir
|
|
238
|
+
? resolveRepoPath(opts.repoRoot, opts.request.session_dir)
|
|
239
|
+
: defaultSessionDirForKind(opts.repoRoot, opts.normalizedSessionKind);
|
|
240
|
+
if (opts.request.session_file) {
|
|
241
|
+
const sessionFile = resolveRepoPath(opts.repoRoot, opts.request.session_file);
|
|
242
|
+
if (!(await pathExists(sessionFile))) {
|
|
243
|
+
throw new SessionTurnError(404, `session_file not found: ${sessionFile}`);
|
|
244
|
+
}
|
|
245
|
+
const headerId = await readSessionHeaderId(sessionFile);
|
|
246
|
+
if (!headerId) {
|
|
247
|
+
throw new SessionTurnError(400, `session_file is missing a valid session header: ${sessionFile}`);
|
|
248
|
+
}
|
|
249
|
+
if (headerId !== opts.request.session_id) {
|
|
250
|
+
throw new SessionTurnError(409, `session_file header id mismatch (expected ${opts.request.session_id}, found ${headerId})`);
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
sessionFile,
|
|
254
|
+
sessionDir: opts.request.session_dir ? sessionDir : dirname(sessionFile),
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
if (!(await directoryExists(sessionDir))) {
|
|
258
|
+
throw new SessionTurnError(404, `session directory not found: ${sessionDir}`);
|
|
259
|
+
}
|
|
260
|
+
const sessionFile = await resolveSessionFileById({
|
|
261
|
+
sessionDir,
|
|
262
|
+
sessionId: opts.request.session_id,
|
|
263
|
+
});
|
|
264
|
+
if (!sessionFile) {
|
|
265
|
+
throw new SessionTurnError(404, `session_id not found in ${sessionDir}: ${opts.request.session_id}`);
|
|
266
|
+
}
|
|
267
|
+
return { sessionFile, sessionDir };
|
|
268
|
+
}
|
|
269
|
+
export function parseSessionTurnRequest(body) {
|
|
270
|
+
const sessionId = nonEmptyString(body.session_id);
|
|
271
|
+
if (!sessionId) {
|
|
272
|
+
return { request: null, error: "session_id is required" };
|
|
273
|
+
}
|
|
274
|
+
const messageBody = nonEmptyString(body.body) ?? nonEmptyString(body.message) ?? nonEmptyString(body.prompt);
|
|
275
|
+
if (!messageBody) {
|
|
276
|
+
return { request: null, error: "body (or message/prompt) is required" };
|
|
277
|
+
}
|
|
278
|
+
const extensionProfileRaw = nonEmptyString(body.extension_profile);
|
|
279
|
+
if (extensionProfileRaw && !normalizeExtensionProfile(extensionProfileRaw)) {
|
|
280
|
+
return {
|
|
281
|
+
request: null,
|
|
282
|
+
error: "extension_profile must be one of operator|worker|orchestrator|reviewer|none",
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
request: {
|
|
287
|
+
session_id: sessionId,
|
|
288
|
+
session_kind: nonEmptyString(body.session_kind),
|
|
289
|
+
body: messageBody,
|
|
290
|
+
source: nonEmptyString(body.source),
|
|
291
|
+
provider: nonEmptyString(body.provider),
|
|
292
|
+
model: nonEmptyString(body.model),
|
|
293
|
+
thinking: nonEmptyString(body.thinking),
|
|
294
|
+
session_file: nonEmptyString(body.session_file),
|
|
295
|
+
session_dir: nonEmptyString(body.session_dir),
|
|
296
|
+
extension_profile: extensionProfileRaw,
|
|
297
|
+
},
|
|
298
|
+
error: null,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
export async function executeSessionTurn(opts) {
|
|
302
|
+
const normalizedSessionKind = normalizeSessionKind(opts.request.session_kind);
|
|
303
|
+
const extensionProfile = normalizeExtensionProfile(opts.request.extension_profile);
|
|
304
|
+
const target = await resolveSessionTarget({
|
|
305
|
+
repoRoot: opts.repoRoot,
|
|
306
|
+
request: opts.request,
|
|
307
|
+
normalizedSessionKind,
|
|
308
|
+
});
|
|
309
|
+
const sessionFactory = opts.sessionFactory ?? createMuSession;
|
|
310
|
+
const session = await sessionFactory({
|
|
311
|
+
cwd: opts.repoRoot,
|
|
312
|
+
systemPrompt: systemPromptForTurn({
|
|
313
|
+
sessionKind: normalizedSessionKind,
|
|
314
|
+
extensionProfile,
|
|
315
|
+
}),
|
|
316
|
+
provider: opts.request.provider ?? undefined,
|
|
317
|
+
model: opts.request.model ?? undefined,
|
|
318
|
+
thinking: opts.request.thinking ?? undefined,
|
|
319
|
+
extensionPaths: extensionPathsForTurn({
|
|
320
|
+
sessionKind: normalizedSessionKind,
|
|
321
|
+
extensionProfile,
|
|
322
|
+
}),
|
|
323
|
+
session: {
|
|
324
|
+
mode: "open",
|
|
325
|
+
sessionDir: target.sessionDir,
|
|
326
|
+
sessionFile: target.sessionFile,
|
|
327
|
+
},
|
|
328
|
+
});
|
|
329
|
+
let assistantText = "";
|
|
330
|
+
let contextEntryId = null;
|
|
331
|
+
let resolvedSessionId = null;
|
|
332
|
+
let resolvedSessionFile = null;
|
|
333
|
+
const nowMs = opts.nowMs ?? Date.now;
|
|
334
|
+
try {
|
|
335
|
+
await session.bindExtensions({
|
|
336
|
+
commandContextActions: {
|
|
337
|
+
waitForIdle: () => session.agent.waitForIdle(),
|
|
338
|
+
newSession: async () => ({ cancelled: true }),
|
|
339
|
+
fork: async () => ({ cancelled: true }),
|
|
340
|
+
navigateTree: async () => ({ cancelled: true }),
|
|
341
|
+
switchSession: async () => ({ cancelled: true }),
|
|
342
|
+
reload: async () => { },
|
|
343
|
+
},
|
|
344
|
+
onError: () => { },
|
|
345
|
+
});
|
|
346
|
+
const unsubscribe = session.subscribe((event) => {
|
|
347
|
+
const rec = asRecord(event);
|
|
348
|
+
if (!rec || rec.type !== "message_end") {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const message = asRecord(rec.message);
|
|
352
|
+
if (!message || message.role !== "assistant") {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const text = extractAssistantText(message);
|
|
356
|
+
if (text.trim().length > 0) {
|
|
357
|
+
assistantText = text;
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
try {
|
|
361
|
+
await session.prompt(opts.request.body, { expandPromptTemplates: false });
|
|
362
|
+
await session.agent.waitForIdle();
|
|
363
|
+
}
|
|
364
|
+
finally {
|
|
365
|
+
unsubscribe();
|
|
366
|
+
}
|
|
367
|
+
contextEntryId = safeLeafId(session);
|
|
368
|
+
resolvedSessionId = safeSessionId(session) ?? opts.request.session_id;
|
|
369
|
+
resolvedSessionFile = safeSessionFile(session) ?? target.sessionFile;
|
|
370
|
+
}
|
|
371
|
+
finally {
|
|
372
|
+
try {
|
|
373
|
+
session.dispose();
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
// Best effort cleanup.
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
const reply = assistantText.trim();
|
|
380
|
+
if (reply.length === 0) {
|
|
381
|
+
throw new SessionTurnError(502, "session turn completed without an assistant reply");
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
session_id: resolvedSessionId ?? opts.request.session_id,
|
|
385
|
+
session_kind: normalizedSessionKind,
|
|
386
|
+
session_file: resolvedSessionFile ?? target.sessionFile,
|
|
387
|
+
context_entry_id: contextEntryId,
|
|
388
|
+
reply,
|
|
389
|
+
source: opts.request.source ?? null,
|
|
390
|
+
completed_at_ms: Math.trunc(nowMs()),
|
|
391
|
+
};
|
|
392
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@femtomc/mu-agent",
|
|
3
|
-
"version": "26.2.
|
|
3
|
+
"version": "26.2.76",
|
|
4
4
|
"description": "Shared agent runtime for mu chat, orchestration roles, and serve extensions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mu",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"themes/**"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@femtomc/mu-core": "26.2.
|
|
27
|
+
"@femtomc/mu-core": "26.2.76",
|
|
28
28
|
"@mariozechner/pi-agent-core": "^0.53.0",
|
|
29
29
|
"@mariozechner/pi-ai": "^0.53.0",
|
|
30
30
|
"@mariozechner/pi-coding-agent": "^0.53.0",
|
|
@@ -16,6 +16,8 @@ Available tools:
|
|
|
16
16
|
CLI-first workflow:
|
|
17
17
|
- Use `bash` + `mu ...` for issue/forum/run/control-plane state operations.
|
|
18
18
|
- Prefer `--pretty` (or `--json` + targeted parsing) for clear, auditable output.
|
|
19
|
+
- Use `mu memory search|timeline|stats` as the primary cross-store memory surface.
|
|
20
|
+
- Use `mu memory index status|rebuild` to inspect/refresh local memory index health when needed.
|
|
19
21
|
- Do not use bespoke query/command wrappers; call the CLI surface directly.
|
|
20
22
|
|
|
21
23
|
Example invocation patterns:
|
|
@@ -25,10 +27,16 @@ Example invocation patterns:
|
|
|
25
27
|
- `bash("mu runs start \"ship release\" --max-steps 25 --pretty")`
|
|
26
28
|
- `bash("mu issues close mu-abc123 --outcome success --pretty")`
|
|
27
29
|
- `bash("mu forum post issue:mu-abc123 -m \"done\" --author operator --pretty")`
|
|
30
|
+
- `bash("mu memory search --query reload --limit 20 --pretty")`
|
|
31
|
+
- `bash("mu memory timeline --issue-id mu-abc123 --order desc --limit 40 --pretty")`
|
|
32
|
+
- `bash("mu memory index status --pretty")`
|
|
33
|
+
- `bash("mu memory index rebuild --sources issues,forum,events --pretty")`
|
|
34
|
+
- `bash("mu control operator set openai-codex gpt-5.3-codex xhigh --pretty")`
|
|
35
|
+
- `bash("mu control operator thinking-set high --pretty")`
|
|
28
36
|
- `bash("mu control reload --pretty")`
|
|
29
37
|
|
|
30
38
|
Guardrails:
|
|
31
|
-
- Never hand-edit
|
|
39
|
+
- Never hand-edit workspace-store `*.jsonl` files for normal lifecycle actions; use `mu` CLI commands.
|
|
32
40
|
- Prefer bounded retrieval (`--limit`, scoped filters) before broad scans.
|
|
33
41
|
- Do NOT pre-fetch status/issues/events/runs at conversation start.
|
|
34
42
|
- Fetch only what the user request requires.
|
|
@@ -25,6 +25,9 @@ Workflow:
|
|
|
25
25
|
- `bash("mu issues get <id> --pretty")`
|
|
26
26
|
- `bash("mu forum read issue:<id> --limit 20 --pretty")`
|
|
27
27
|
- `bash("mu issues children <id> --pretty")` (or `mu issues list --root <id> --pretty`)
|
|
28
|
+
- `bash("mu memory search --query <keywords> --issue-id <id> --limit 20 --pretty")`
|
|
29
|
+
- `bash("mu memory timeline --issue-id <id> --order desc --limit 40 --pretty")`
|
|
30
|
+
- `bash("mu memory index status --pretty")` (rebuild when missing/stale if broader retrieval is needed)
|
|
28
31
|
2. Decompose into worker issues:
|
|
29
32
|
- `bash("mu issues create \"<title>\" --body \"<body>\" --tags \"node:agent,role:worker\" --parent <id> --pretty")`
|
|
30
33
|
3. Add ordering where needed:
|
|
@@ -19,6 +19,8 @@ Workflow:
|
|
|
19
19
|
1. Inspect:
|
|
20
20
|
- `bash("mu issues get <id> --pretty")`
|
|
21
21
|
- `bash("mu forum read issue:<id> --limit 20 --pretty")`
|
|
22
|
+
- `bash("mu memory search --query <keywords> --issue-id <id> --limit 20 --pretty")`
|
|
23
|
+
- `bash("mu memory timeline --issue-id <id> --order desc --limit 40 --pretty")`
|
|
22
24
|
2. Verify:
|
|
23
25
|
- Re-run relevant tests/checks, inspect changed files/logs.
|
|
24
26
|
3. Decide:
|
package/prompts/roles/worker.md
CHANGED
|
@@ -19,6 +19,9 @@ Workflow:
|
|
|
19
19
|
1. Inspect:
|
|
20
20
|
- `bash("mu issues get <id> --pretty")`
|
|
21
21
|
- `bash("mu forum read issue:<id> --limit 20 --pretty")`
|
|
22
|
+
- `bash("mu memory search --query <keywords> --issue-id <id> --limit 20 --pretty")`
|
|
23
|
+
- `bash("mu memory timeline --issue-id <id> --order desc --limit 40 --pretty")`
|
|
24
|
+
- `bash("mu memory index status --pretty")` (rebuild when missing/stale if context retrieval quality is poor)
|
|
22
25
|
2. Implement:
|
|
23
26
|
- Edit files and run commands needed for this issue only.
|
|
24
27
|
3. Verify:
|