mu-harness 0.17.0 → 0.17.2
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/esm/harness/create.js +20 -4
- package/esm/harness/environment.d.ts +10 -0
- package/esm/harness/environment.js +14 -0
- package/esm/harness/types.d.ts +1 -0
- package/esm/tui/chat/ChatApp.d.ts +5 -5
- package/esm/tui/chat/ChatApp.js +0 -2
- package/package.json +3 -3
- package/script/harness/create.js +20 -4
- package/script/harness/environment.d.ts +10 -0
- package/script/harness/environment.js +17 -0
- package/script/harness/types.d.ts +1 -0
- package/script/tui/chat/ChatApp.d.ts +5 -5
- package/script/tui/chat/ChatApp.js +0 -2
package/esm/harness/create.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
1
2
|
import { join } from 'node:path';
|
|
2
3
|
import process from 'node:process';
|
|
3
4
|
import { createAgentRegistry, grantArg, loadAgents, toolDecision, toolNames } from '../agents/index.js';
|
|
@@ -10,6 +11,7 @@ import { createScheduler, createScheduleTaskTool, createTasksCommand, createTask
|
|
|
10
11
|
import { createAgentSession, createSessionCatalog, createSessionManager, createSessionStore, persistTo, runTitler, } from '../session/index.js';
|
|
11
12
|
import { createRunSkillTool, createSkillRegistry, createSkillTool, createSkillWriterTool, loadSkills, runSkill, } from '../skills/index.js';
|
|
12
13
|
import { createSubAgentRegistry, createSubAgentTool, runSubAgent } from '../subAgents/index.js';
|
|
14
|
+
import { environmentBlock } from './environment.js';
|
|
13
15
|
import { createModelRegistry } from './models.js';
|
|
14
16
|
const TITLE_AGENT = {
|
|
15
17
|
name: 'title',
|
|
@@ -22,13 +24,27 @@ export const createHarness = async (options) => {
|
|
|
22
24
|
const cwd = options.cwd ?? process.cwd();
|
|
23
25
|
const config = createHarnessConfig({ hostName, xdg });
|
|
24
26
|
const models = createModelRegistry({ providers, default: model });
|
|
25
|
-
const
|
|
27
|
+
const pluginsDir = join(config.configDir, 'plugins');
|
|
28
|
+
const agentsDir = join(config.configDir, 'agents');
|
|
29
|
+
const plugins = createPluginStore({ dir: pluginsDir });
|
|
26
30
|
const newId = () => crypto.randomUUID();
|
|
27
31
|
const pluginAgents = (sessionDefaults.plugins ?? []).flatMap((plugin) => plugin.agents ?? []);
|
|
28
|
-
const diskAgents = await loadAgents(
|
|
32
|
+
const diskAgents = await loadAgents(agentsDir);
|
|
29
33
|
const agents = createAgentRegistry([...hostAgents, ...pluginAgents, ...diskAgents]);
|
|
30
34
|
const skillsDir = join(config.configDir, 'skills');
|
|
31
35
|
const cwdSkillsDir = join(cwd, 'skills');
|
|
36
|
+
const envBlock = environmentBlock({
|
|
37
|
+
os: `${os.platform()} ${os.release()} (${os.arch()})`,
|
|
38
|
+
configDir: config.configDir,
|
|
39
|
+
pluginsDir,
|
|
40
|
+
skillsDir,
|
|
41
|
+
agentsDir,
|
|
42
|
+
hostName,
|
|
43
|
+
hostSourceUrl: options.sourceUrl,
|
|
44
|
+
});
|
|
45
|
+
const envHook = {
|
|
46
|
+
prepareRequest: ({ system }) => ({ system: system ? `${system}\n\n${envBlock}` : envBlock }),
|
|
47
|
+
};
|
|
32
48
|
const pluginSkills = (sessionDefaults.plugins ?? []).flatMap((plugin) => plugin.skills ?? []);
|
|
33
49
|
const cwdSkills = await loadSkills(cwdSkillsDir);
|
|
34
50
|
const diskSkills = await loadSkills(skillsDir);
|
|
@@ -77,7 +93,7 @@ export const createHarness = async (options) => {
|
|
|
77
93
|
});
|
|
78
94
|
const spawn = (agent) => persistTo(store, persona(agent, {
|
|
79
95
|
tools: sessionTools(agent),
|
|
80
|
-
hooks: mergeHooks([sessionDefaults.hooks, allowList(toolNames(agent)), approvalHook(() => agent)]),
|
|
96
|
+
hooks: mergeHooks([sessionDefaults.hooks, allowList(toolNames(agent)), approvalHook(() => agent), envHook]),
|
|
81
97
|
}));
|
|
82
98
|
const scheduler = enableScheduler && tasks
|
|
83
99
|
? createScheduler({
|
|
@@ -125,7 +141,7 @@ export const createHarness = async (options) => {
|
|
|
125
141
|
},
|
|
126
142
|
revive: ({ id, model: ref, messages }) => createAgentSession({
|
|
127
143
|
...sessionDefaults,
|
|
128
|
-
hooks: mergeHooks([sessionDefaults.hooks, approvalHook(() => approvals?.activeAgent())]),
|
|
144
|
+
hooks: mergeHooks([sessionDefaults.hooks, approvalHook(() => approvals?.activeAgent()), envHook]),
|
|
129
145
|
tools: sessionTools(undefined, [createSubAgentTool({ registry: agents, spawn, runs, parentId: id })]),
|
|
130
146
|
...models.resolve(ref),
|
|
131
147
|
id,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const HARNESS_SOURCE_URL = 'https://github.com/gaetan-puleo/mu-ai';
|
|
2
|
+
export function environmentBlock(info) {
|
|
3
|
+
const lines = [
|
|
4
|
+
`Operating system: ${info.os}`,
|
|
5
|
+
`Config directory: ${info.configDir}`,
|
|
6
|
+
`Plugins directory: ${info.pluginsDir}`,
|
|
7
|
+
`Skills directory: ${info.skillsDir}`,
|
|
8
|
+
`Sub-agents directory: ${info.agentsDir}`,
|
|
9
|
+
`Harness (mu) source code: ${HARNESS_SOURCE_URL}`,
|
|
10
|
+
];
|
|
11
|
+
if (info.hostSourceUrl)
|
|
12
|
+
lines.push(`${info.hostName} source code: ${info.hostSourceUrl}`);
|
|
13
|
+
return `<env>\n${lines.join('\n')}\n</env>`;
|
|
14
|
+
}
|
package/esm/harness/types.d.ts
CHANGED
|
@@ -54,12 +54,12 @@ export interface ChatHost {
|
|
|
54
54
|
*/
|
|
55
55
|
banner?: string;
|
|
56
56
|
/**
|
|
57
|
-
* Lean input presentation:
|
|
58
|
-
* model/provider/agent footer inside the input
|
|
59
|
-
* the status bar — leaving a
|
|
57
|
+
* Lean input presentation: keep the surface-background input frame but drop
|
|
58
|
+
* the model/provider/agent footer inside the input and the context readout on
|
|
59
|
+
* the status bar — leaving a framed prompt + editor. The {@link ChatHost.banner}
|
|
60
60
|
* splash is independent and still shown if set. Hosts that want the full
|
|
61
|
-
* information-rich input (
|
|
62
|
-
*
|
|
61
|
+
* information-rich input (model · provider · @agent footer, token/context usage
|
|
62
|
+
* in the status line) leave this unset (the default).
|
|
63
63
|
*/
|
|
64
64
|
minimal?: boolean;
|
|
65
65
|
onExit(code: number): void;
|
package/esm/tui/chat/ChatApp.js
CHANGED
|
@@ -1116,8 +1116,6 @@ export class ChatApp {
|
|
|
1116
1116
|
}
|
|
1117
1117
|
inputPanel() {
|
|
1118
1118
|
const inner = this.approvalView() ?? this.editorInner();
|
|
1119
|
-
if (this.minimal)
|
|
1120
|
-
return box(inner, { padding: 0 });
|
|
1121
1119
|
return box(inner, { background: this.theme().colors.surface, padding: 1 });
|
|
1122
1120
|
}
|
|
1123
1121
|
editorInner() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mu-harness",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.2",
|
|
4
4
|
"description": "Agent harness: createHarness wires mu-core into a host — XDG paths, model registry, plugins, disk-loaded agents & skills, sub-agents, sessions (JSONL + SQLite catalog), slash commands, permission/approval hooks, an optional scheduler, and a composable TUI chat app",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./script/index.js",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"@swc/wasm-typescript": "^1.15.0",
|
|
24
24
|
"cli-highlight": "^2.1.11",
|
|
25
25
|
"croner": "^9.0.0",
|
|
26
|
-
"mu-core": "^0.17.
|
|
27
|
-
"mu-tui": "^0.17.
|
|
26
|
+
"mu-core": "^0.17.2",
|
|
27
|
+
"mu-tui": "^0.17.2"
|
|
28
28
|
},
|
|
29
29
|
"_generatedBy": "dnt@dev",
|
|
30
30
|
"types": "./esm/index.d.ts"
|
package/script/harness/create.js
CHANGED
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createHarness = void 0;
|
|
7
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
7
8
|
const node_path_1 = require("node:path");
|
|
8
9
|
const node_process_1 = __importDefault(require("node:process"));
|
|
9
10
|
const index_js_1 = require("../agents/index.js");
|
|
@@ -16,6 +17,7 @@ const index_js_7 = require("../scheduler/index.js");
|
|
|
16
17
|
const index_js_8 = require("../session/index.js");
|
|
17
18
|
const index_js_9 = require("../skills/index.js");
|
|
18
19
|
const index_js_10 = require("../subAgents/index.js");
|
|
20
|
+
const environment_js_1 = require("./environment.js");
|
|
19
21
|
const models_js_1 = require("./models.js");
|
|
20
22
|
const TITLE_AGENT = {
|
|
21
23
|
name: 'title',
|
|
@@ -28,13 +30,27 @@ const createHarness = async (options) => {
|
|
|
28
30
|
const cwd = options.cwd ?? node_process_1.default.cwd();
|
|
29
31
|
const config = (0, index_js_3.createHarnessConfig)({ hostName, xdg });
|
|
30
32
|
const models = (0, models_js_1.createModelRegistry)({ providers, default: model });
|
|
31
|
-
const
|
|
33
|
+
const pluginsDir = (0, node_path_1.join)(config.configDir, 'plugins');
|
|
34
|
+
const agentsDir = (0, node_path_1.join)(config.configDir, 'agents');
|
|
35
|
+
const plugins = (0, index_js_6.createPluginStore)({ dir: pluginsDir });
|
|
32
36
|
const newId = () => crypto.randomUUID();
|
|
33
37
|
const pluginAgents = (sessionDefaults.plugins ?? []).flatMap((plugin) => plugin.agents ?? []);
|
|
34
|
-
const diskAgents = await (0, index_js_1.loadAgents)(
|
|
38
|
+
const diskAgents = await (0, index_js_1.loadAgents)(agentsDir);
|
|
35
39
|
const agents = (0, index_js_1.createAgentRegistry)([...hostAgents, ...pluginAgents, ...diskAgents]);
|
|
36
40
|
const skillsDir = (0, node_path_1.join)(config.configDir, 'skills');
|
|
37
41
|
const cwdSkillsDir = (0, node_path_1.join)(cwd, 'skills');
|
|
42
|
+
const envBlock = (0, environment_js_1.environmentBlock)({
|
|
43
|
+
os: `${node_os_1.default.platform()} ${node_os_1.default.release()} (${node_os_1.default.arch()})`,
|
|
44
|
+
configDir: config.configDir,
|
|
45
|
+
pluginsDir,
|
|
46
|
+
skillsDir,
|
|
47
|
+
agentsDir,
|
|
48
|
+
hostName,
|
|
49
|
+
hostSourceUrl: options.sourceUrl,
|
|
50
|
+
});
|
|
51
|
+
const envHook = {
|
|
52
|
+
prepareRequest: ({ system }) => ({ system: system ? `${system}\n\n${envBlock}` : envBlock }),
|
|
53
|
+
};
|
|
38
54
|
const pluginSkills = (sessionDefaults.plugins ?? []).flatMap((plugin) => plugin.skills ?? []);
|
|
39
55
|
const cwdSkills = await (0, index_js_9.loadSkills)(cwdSkillsDir);
|
|
40
56
|
const diskSkills = await (0, index_js_9.loadSkills)(skillsDir);
|
|
@@ -83,7 +99,7 @@ const createHarness = async (options) => {
|
|
|
83
99
|
});
|
|
84
100
|
const spawn = (agent) => (0, index_js_8.persistTo)(store, persona(agent, {
|
|
85
101
|
tools: sessionTools(agent),
|
|
86
|
-
hooks: (0, index_js_4.mergeHooks)([sessionDefaults.hooks, (0, index_js_5.allowList)((0, index_js_1.toolNames)(agent)), approvalHook(() => agent)]),
|
|
102
|
+
hooks: (0, index_js_4.mergeHooks)([sessionDefaults.hooks, (0, index_js_5.allowList)((0, index_js_1.toolNames)(agent)), approvalHook(() => agent), envHook]),
|
|
87
103
|
}));
|
|
88
104
|
const scheduler = enableScheduler && tasks
|
|
89
105
|
? (0, index_js_7.createScheduler)({
|
|
@@ -131,7 +147,7 @@ const createHarness = async (options) => {
|
|
|
131
147
|
},
|
|
132
148
|
revive: ({ id, model: ref, messages }) => (0, index_js_8.createAgentSession)({
|
|
133
149
|
...sessionDefaults,
|
|
134
|
-
hooks: (0, index_js_4.mergeHooks)([sessionDefaults.hooks, approvalHook(() => approvals?.activeAgent())]),
|
|
150
|
+
hooks: (0, index_js_4.mergeHooks)([sessionDefaults.hooks, approvalHook(() => approvals?.activeAgent()), envHook]),
|
|
135
151
|
tools: sessionTools(undefined, [(0, index_js_10.createSubAgentTool)({ registry: agents, spawn, runs, parentId: id })]),
|
|
136
152
|
...models.resolve(ref),
|
|
137
153
|
id,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.environmentBlock = environmentBlock;
|
|
4
|
+
const HARNESS_SOURCE_URL = 'https://github.com/gaetan-puleo/mu-ai';
|
|
5
|
+
function environmentBlock(info) {
|
|
6
|
+
const lines = [
|
|
7
|
+
`Operating system: ${info.os}`,
|
|
8
|
+
`Config directory: ${info.configDir}`,
|
|
9
|
+
`Plugins directory: ${info.pluginsDir}`,
|
|
10
|
+
`Skills directory: ${info.skillsDir}`,
|
|
11
|
+
`Sub-agents directory: ${info.agentsDir}`,
|
|
12
|
+
`Harness (mu) source code: ${HARNESS_SOURCE_URL}`,
|
|
13
|
+
];
|
|
14
|
+
if (info.hostSourceUrl)
|
|
15
|
+
lines.push(`${info.hostName} source code: ${info.hostSourceUrl}`);
|
|
16
|
+
return `<env>\n${lines.join('\n')}\n</env>`;
|
|
17
|
+
}
|
|
@@ -54,12 +54,12 @@ export interface ChatHost {
|
|
|
54
54
|
*/
|
|
55
55
|
banner?: string;
|
|
56
56
|
/**
|
|
57
|
-
* Lean input presentation:
|
|
58
|
-
* model/provider/agent footer inside the input
|
|
59
|
-
* the status bar — leaving a
|
|
57
|
+
* Lean input presentation: keep the surface-background input frame but drop
|
|
58
|
+
* the model/provider/agent footer inside the input and the context readout on
|
|
59
|
+
* the status bar — leaving a framed prompt + editor. The {@link ChatHost.banner}
|
|
60
60
|
* splash is independent and still shown if set. Hosts that want the full
|
|
61
|
-
* information-rich input (
|
|
62
|
-
*
|
|
61
|
+
* information-rich input (model · provider · @agent footer, token/context usage
|
|
62
|
+
* in the status line) leave this unset (the default).
|
|
63
63
|
*/
|
|
64
64
|
minimal?: boolean;
|
|
65
65
|
onExit(code: number): void;
|
|
@@ -1119,8 +1119,6 @@ class ChatApp {
|
|
|
1119
1119
|
}
|
|
1120
1120
|
inputPanel() {
|
|
1121
1121
|
const inner = this.approvalView() ?? this.editorInner();
|
|
1122
|
-
if (this.minimal)
|
|
1123
|
-
return (0, mu_tui_1.box)(inner, { padding: 0 });
|
|
1124
1122
|
return (0, mu_tui_1.box)(inner, { background: this.theme().colors.surface, padding: 1 });
|
|
1125
1123
|
}
|
|
1126
1124
|
editorInner() {
|