@hmharness/agent 0.19.7 → 0.19.9
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/rlm-tool.d.ts +14 -0
- package/dist/rlm-tool.js +89 -0
- package/dist/tools.js +2 -1
- package/package.json +8 -8
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hmharness/agent - RLM workspace tool (blueprint M5 / RLM-001..010 live)
|
|
3
|
+
*
|
|
4
|
+
* Gives the LIVE model a persistent, programmable cognitive workspace for
|
|
5
|
+
* the duration of a task: set/get variables, eval sandboxed code against
|
|
6
|
+
* them, checkpoint/restore, fork. The runtime enforces the budget and
|
|
7
|
+
* freezes its governance state — the model composes context, it can never
|
|
8
|
+
* rewrite the meter (no hidden unsafe self-modification, RLM-008).
|
|
9
|
+
*
|
|
10
|
+
* One workspace per session (spawned subagents share the parent's by home
|
|
11
|
+
* key — deliberately: delegation sees the same whiteboard).
|
|
12
|
+
*/
|
|
13
|
+
import type { Tool } from '@hmharness/kernel';
|
|
14
|
+
export declare const rlmWorkspaceTool: Tool;
|
package/dist/rlm-tool.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { RLMRuntime } from '@hmharness/cognitive';
|
|
2
|
+
const workspaces = new Map();
|
|
3
|
+
function wsFor(home) {
|
|
4
|
+
let ws = workspaces.get(home);
|
|
5
|
+
if (!ws) {
|
|
6
|
+
ws = new RLMRuntime({ maxEvals: 200, maxWallMs: 30 * 60_000, maxSubagents: 0 });
|
|
7
|
+
workspaces.set(home, ws);
|
|
8
|
+
}
|
|
9
|
+
return ws;
|
|
10
|
+
}
|
|
11
|
+
export const rlmWorkspaceTool = {
|
|
12
|
+
name: 'rlm_workspace',
|
|
13
|
+
description: 'Persistent structured workspace for THIS task: variables survive between calls (unlike your context window). ' +
|
|
14
|
+
'Actions: set(name,value) / get(name) / list() / eval(code — JS, `ctx.vars` holds the variables, return a value) / ' +
|
|
15
|
+
'checkpoint(label?) / restore(checkpointId) / reset(). Use it to accumulate findings, counts, plans, intermediate ' +
|
|
16
|
+
'results across many tool calls, then eval a composition over them. eval is sandboxed and budget-metered.',
|
|
17
|
+
parameters: {
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
action: { type: 'string', description: 'set | get | list | eval | checkpoint | restore | reset' },
|
|
21
|
+
name: { type: 'string', description: 'variable name (set/get)' },
|
|
22
|
+
value: { type: 'string', description: 'value to set (stored as string; eval can JSON.parse)' },
|
|
23
|
+
code: { type: 'string', description: 'eval body: `return ...` over ctx.vars' },
|
|
24
|
+
checkpointId: { type: 'string', description: 'restore target (from checkpoint result)' },
|
|
25
|
+
label: { type: 'string', description: 'checkpoint label' },
|
|
26
|
+
},
|
|
27
|
+
required: ['action'],
|
|
28
|
+
},
|
|
29
|
+
async execute(args, ctx) {
|
|
30
|
+
const action = String(args.action ?? '');
|
|
31
|
+
const ws = wsFor(ctx.home);
|
|
32
|
+
try {
|
|
33
|
+
switch (action) {
|
|
34
|
+
case 'set': {
|
|
35
|
+
const name = String(args.name ?? '');
|
|
36
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
|
|
37
|
+
return { output: `invalid variable name '${name}'`, isError: true };
|
|
38
|
+
ws.set(name, String(args.value ?? ''));
|
|
39
|
+
return { output: `set ${name} (${String(args.value ?? '').length} chars)` };
|
|
40
|
+
}
|
|
41
|
+
case 'get': {
|
|
42
|
+
const v = ws.get(String(args.name ?? ''));
|
|
43
|
+
if (v === undefined)
|
|
44
|
+
return { output: `undefined`, isError: true };
|
|
45
|
+
return { output: typeof v === 'string' ? v : JSON.stringify(v) };
|
|
46
|
+
}
|
|
47
|
+
case 'list':
|
|
48
|
+
return { output: ws.names().length ? ws.names().join(', ') : '(empty)' };
|
|
49
|
+
case 'eval': {
|
|
50
|
+
const code = String(args.code ?? '');
|
|
51
|
+
if (!code.trim())
|
|
52
|
+
return { output: 'code required', isError: true };
|
|
53
|
+
const r = await ws.eval(code);
|
|
54
|
+
if (!r.ok)
|
|
55
|
+
return { output: `eval failed [${r.error?.code}]: ${r.error?.message}`, isError: true };
|
|
56
|
+
const text = r.value === undefined ? 'undefined' : typeof r.value === 'string' ? r.value : JSON.stringify(r.value);
|
|
57
|
+
return { output: text.length > 8_000 ? text.slice(0, 8_000) + '…[truncated]' : text };
|
|
58
|
+
}
|
|
59
|
+
case 'checkpoint': {
|
|
60
|
+
const cp = ws.checkpoint(args.label ? String(args.label) : undefined);
|
|
61
|
+
checkpoints.set(`${ctx.home}::${cp.id}`, cp);
|
|
62
|
+
return { output: `checkpoint ${cp.id}${cp.label ? ` (${cp.label})` : ''} — restore with checkpointId=${cp.id}` };
|
|
63
|
+
}
|
|
64
|
+
case 'restore': {
|
|
65
|
+
const id = String(args.checkpointId ?? '');
|
|
66
|
+
if (!id)
|
|
67
|
+
return { output: 'checkpointId required', isError: true };
|
|
68
|
+
// restore needs the checkpoint object; keep an id->cp map on the tool side
|
|
69
|
+
const cp = checkpoints.get(`${ctx.home}::${id}`);
|
|
70
|
+
if (!cp)
|
|
71
|
+
return { output: `unknown checkpoint ${id} (checkpoints live in-process)`, isError: true };
|
|
72
|
+
ws.restore(cp);
|
|
73
|
+
return { output: `restored ${id}` };
|
|
74
|
+
}
|
|
75
|
+
case 'reset': {
|
|
76
|
+
workspaces.delete(ctx.home);
|
|
77
|
+
checkpoints.delete(ctx.home);
|
|
78
|
+
return { output: 'workspace cleared' };
|
|
79
|
+
}
|
|
80
|
+
default:
|
|
81
|
+
return { output: `unknown action '${action}' (set|get|list|eval|checkpoint|restore|reset)`, isError: true };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
return { output: 'rlm_workspace failed: ' + String(err).slice(0, 200), isError: true };
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
const checkpoints = new Map();
|
package/dist/tools.js
CHANGED
|
@@ -10,6 +10,7 @@ import { isAbsolute, join, resolve } from 'node:path';
|
|
|
10
10
|
import { promisify } from 'node:util';
|
|
11
11
|
import { chatVision, homeDir, isBareProbe, isVisionRefusal, loadConfig, visionProviderChain } from '@hmharness/kernel';
|
|
12
12
|
import { cognitiveQueryTool } from "./cognitive-tools.js";
|
|
13
|
+
import { rlmWorkspaceTool } from "./rlm-tool.js";
|
|
13
14
|
const execCb = promisify(exec);
|
|
14
15
|
const DENY_PATTERNS = [
|
|
15
16
|
// recursive deletes aimed at ROOT/HOME/SYSTEM targets only - relative
|
|
@@ -663,5 +664,5 @@ export const seeImageTool = {
|
|
|
663
664
|
export const baseTools = [
|
|
664
665
|
readFileTool, editFileTool, writeFileTool, listDirTool, runCommandTool, rememberTool, seeImageTool,
|
|
665
666
|
webSearchTool, webFetchTool, browserOpenTool, desktopScreenshotTool, desktopClickTool, desktopTypeTool, sshRunTool,
|
|
666
|
-
cognitiveQueryTool,
|
|
667
|
+
cognitiveQueryTool, rlmWorkspaceTool,
|
|
667
668
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hmharness/agent",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.9",
|
|
4
4
|
"description": "hmharness agent execution layer: base tools, system prompt, sub-agent spawn, and the shared task runner that frontends (cli, web) drive.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
"build": "tsc -p tsconfig.build.json"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@hmharness/cognitive": "0.19.
|
|
19
|
-
"@hmharness/domain-harmony": "0.19.
|
|
20
|
-
"@hmharness/domain-ops": "0.19.
|
|
21
|
-
"@hmharness/evolution": "0.19.
|
|
22
|
-
"@hmharness/kernel": "0.19.
|
|
23
|
-
"@hmharness/observability": "0.19.
|
|
24
|
-
"@hmharness/sandbox": "0.19.
|
|
18
|
+
"@hmharness/cognitive": "0.19.9",
|
|
19
|
+
"@hmharness/domain-harmony": "0.19.9",
|
|
20
|
+
"@hmharness/domain-ops": "0.19.9",
|
|
21
|
+
"@hmharness/evolution": "0.19.9",
|
|
22
|
+
"@hmharness/kernel": "0.19.9",
|
|
23
|
+
"@hmharness/observability": "0.19.9",
|
|
24
|
+
"@hmharness/sandbox": "0.19.9"
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
27
|
"dist"
|