ocsmarttools 0.1.2 → 0.1.3
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/CHANGELOG.md +13 -0
- package/README.md +7 -1
- package/openclaw.plugin.json +2 -0
- package/package.json +1 -1
- package/src/commands/chat.ts +6 -0
- package/src/commands/cli.ts +17 -10
- package/src/commands/operations.ts +32 -0
- package/src/lib/bootstrap.ts +14 -0
- package/src/lib/plugin-config.ts +6 -0
- package/src/lib/routing-guide.ts +84 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `ocsmarttools` are documented here.
|
|
4
4
|
|
|
5
|
+
## [0.1.3] - 2026-02-22
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Plugin-native auto-routing guide sync for `AGENTS.md` with managed markers, enabled by default (`autoInjectRoutingGuide`).
|
|
9
|
+
- New chat and CLI sync commands (`/ocsmarttools sync`, `openclaw ocsmarttools sync`) to re-apply routing guidance instantly.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- `setup` now re-syncs the managed routing guide automatically.
|
|
13
|
+
- Added `autoInjectRoutingGuide` to config schema, status, config output, and editable keys.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- Removed CLI registration conflict by making `stats reset` a subcommand under `stats`.
|
|
17
|
+
|
|
5
18
|
## [0.1.2] - 2026-02-22
|
|
6
19
|
|
|
7
20
|
### Added
|
package/README.md
CHANGED
|
@@ -43,7 +43,8 @@ openclaw gateway restart
|
|
|
43
43
|
|
|
44
44
|
1. Install + enable + restart.
|
|
45
45
|
2. Done. The plugin auto-bootstraps and starts working in background.
|
|
46
|
-
3.
|
|
46
|
+
3. It also auto-manages an OCSmartTools routing block in `AGENTS.md` (unless disabled).
|
|
47
|
+
4. Optional check:
|
|
47
48
|
|
|
48
49
|
```text
|
|
49
50
|
/ocsmarttools status
|
|
@@ -66,6 +67,7 @@ Model note:
|
|
|
66
67
|
| `/ocsmarttools stats reset` | Resets the stats window |
|
|
67
68
|
| `/ocsmarttools setup [safe\|standard]` | Applies recommended defaults for the selected mode |
|
|
68
69
|
| `/ocsmarttools mode <safe\|standard>` | Changes mode only |
|
|
70
|
+
| `/ocsmarttools sync` | Re-applies the auto-managed routing policy block in `AGENTS.md` |
|
|
69
71
|
| `/ocsmarttools config` | Shows effective plugin config |
|
|
70
72
|
| `/ocsmarttools config keys` | Lists editable config keys |
|
|
71
73
|
| `/ocsmarttools config set <key> <value>` | Updates one config key with validation |
|
|
@@ -82,6 +84,7 @@ Model note:
|
|
|
82
84
|
| `openclaw ocsmarttools stats reset` | Resets the stats window |
|
|
83
85
|
| `openclaw ocsmarttools setup [safe\|standard]` | Applies recommended defaults for the selected mode |
|
|
84
86
|
| `openclaw ocsmarttools mode <safe\|standard>` | Changes mode only |
|
|
87
|
+
| `openclaw ocsmarttools sync` | Re-applies the auto-managed routing policy block in `AGENTS.md` |
|
|
85
88
|
| `openclaw ocsmarttools config` | Shows effective plugin config |
|
|
86
89
|
| `openclaw ocsmarttools config keys` | Lists editable config keys |
|
|
87
90
|
| `openclaw ocsmarttools config set <key> <value>` | Updates one config key with validation |
|
|
@@ -96,6 +99,8 @@ Model note:
|
|
|
96
99
|
/ocsmarttools config set storeLargeResults true
|
|
97
100
|
/ocsmarttools config set toolSearch.useLiveRegistry true
|
|
98
101
|
/ocsmarttools config set toolSearch.liveTimeoutMs 1500
|
|
102
|
+
/ocsmarttools config set autoInjectRoutingGuide true
|
|
103
|
+
/ocsmarttools config set autoInjectRoutingGuide false
|
|
99
104
|
/ocsmarttools config reset maxResultChars
|
|
100
105
|
/ocsmarttools stats
|
|
101
106
|
```
|
|
@@ -143,6 +148,7 @@ If your instance uses strict `tools.allow`, include:
|
|
|
143
148
|
## Safety and Limits
|
|
144
149
|
|
|
145
150
|
- `ocsmarttools` does not bypass OpenClaw tool policy.
|
|
151
|
+
- Routing policy is auto-injected into `AGENTS.md` with managed markers; it can be re-synced via `/ocsmarttools sync`.
|
|
146
152
|
- `tool_batch` is intentionally bounded (`maxSteps`, `maxForEach`).
|
|
147
153
|
- Large-result handles are in-memory and expire by TTL.
|
|
148
154
|
- `tool_result_get` works only while handle is still valid.
|
package/openclaw.plugin.json
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"properties": {
|
|
9
9
|
"enabled": { "type": "boolean" },
|
|
10
10
|
"mode": { "type": "string", "enum": ["safe", "standard"] },
|
|
11
|
+
"autoInjectRoutingGuide": { "type": "boolean" },
|
|
11
12
|
"maxSteps": { "type": "integer", "minimum": 1, "maximum": 200 },
|
|
12
13
|
"maxForEach": { "type": "integer", "minimum": 1, "maximum": 200 },
|
|
13
14
|
"maxResultChars": { "type": "integer", "minimum": 500, "maximum": 500000 },
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
},
|
|
32
33
|
"uiHints": {
|
|
33
34
|
"mode": { "label": "Mode" },
|
|
35
|
+
"autoInjectRoutingGuide": { "label": "Auto Inject Routing Guide" },
|
|
34
36
|
"maxSteps": { "label": "Max Steps", "advanced": true },
|
|
35
37
|
"maxForEach": { "label": "Max ForEach", "advanced": true },
|
|
36
38
|
"maxResultChars": { "label": "Max Result Chars", "advanced": true },
|
package/package.json
CHANGED
package/src/commands/chat.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
resetStats,
|
|
13
13
|
resetConfig,
|
|
14
14
|
setConfigKey,
|
|
15
|
+
syncManagedRouting,
|
|
15
16
|
updateMode,
|
|
16
17
|
} from "./operations.js";
|
|
17
18
|
import type { AdvToolsMode } from "../lib/plugin-config.js";
|
|
@@ -72,6 +73,10 @@ export function registerChatCommands(api: OpenClawPluginApi, metrics: MetricsSto
|
|
|
72
73
|
return { text: await updateMode(api, mode) };
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
if (cmd === "sync") {
|
|
77
|
+
return { text: await syncManagedRouting(api) };
|
|
78
|
+
}
|
|
79
|
+
|
|
75
80
|
if (cmd === "config") {
|
|
76
81
|
const action = (parts[1] ?? "get").toLowerCase();
|
|
77
82
|
if (action === "get") {
|
|
@@ -106,6 +111,7 @@ export function registerChatCommands(api: OpenClawPluginApi, metrics: MetricsSto
|
|
|
106
111
|
"/ocsmarttools config keys",
|
|
107
112
|
"/ocsmarttools config set <key> <value>",
|
|
108
113
|
"/ocsmarttools config reset [key]",
|
|
114
|
+
"/ocsmarttools sync",
|
|
109
115
|
].join("\n"),
|
|
110
116
|
};
|
|
111
117
|
}
|
package/src/commands/cli.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
resetStats,
|
|
11
11
|
resetConfig,
|
|
12
12
|
setConfigKey,
|
|
13
|
+
syncManagedRouting,
|
|
13
14
|
updateMode,
|
|
14
15
|
} from "./operations.js";
|
|
15
16
|
import type { AdvToolsMode } from "../lib/plugin-config.js";
|
|
@@ -52,16 +53,13 @@ export function registerCliCommands(api: OpenClawPluginApi, metrics: MetricsStor
|
|
|
52
53
|
console.log(renderStatus(api));
|
|
53
54
|
});
|
|
54
55
|
|
|
55
|
-
adv
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
adv
|
|
64
|
-
.command("stats reset")
|
|
56
|
+
const statsCmd = adv.command("stats").description("Show usage/savings metrics");
|
|
57
|
+
statsCmd.action(() => {
|
|
58
|
+
// eslint-disable-next-line no-console
|
|
59
|
+
console.log(renderStats(metrics));
|
|
60
|
+
});
|
|
61
|
+
statsCmd
|
|
62
|
+
.command("reset")
|
|
65
63
|
.description("Reset usage/savings metrics window")
|
|
66
64
|
.action(() => {
|
|
67
65
|
// eslint-disable-next-line no-console
|
|
@@ -91,6 +89,15 @@ export function registerCliCommands(api: OpenClawPluginApi, metrics: MetricsStor
|
|
|
91
89
|
console.log(text);
|
|
92
90
|
});
|
|
93
91
|
|
|
92
|
+
adv
|
|
93
|
+
.command("sync")
|
|
94
|
+
.description("Re-apply auto-managed routing policy to AGENTS.md")
|
|
95
|
+
.action(async () => {
|
|
96
|
+
const text = await syncManagedRouting(api);
|
|
97
|
+
// eslint-disable-next-line no-console
|
|
98
|
+
console.log(text);
|
|
99
|
+
});
|
|
100
|
+
|
|
94
101
|
adv
|
|
95
102
|
.command("config")
|
|
96
103
|
.description("Show effective plugin config")
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
writeConfig,
|
|
10
10
|
} from "../lib/plugin-config.js";
|
|
11
11
|
import type { MetricsStore } from "../lib/metrics-store.js";
|
|
12
|
+
import { syncRoutingGuide } from "../lib/routing-guide.js";
|
|
12
13
|
|
|
13
14
|
const ADVTOOLS_TOOL_NAMES = ["tool_search", "tool_dispatch", "tool_batch", "tool_result_get"];
|
|
14
15
|
type ConfigKind = "boolean" | "integer" | "enum";
|
|
@@ -20,6 +21,7 @@ type ConfigSpec =
|
|
|
20
21
|
const CONFIG_SPECS: Record<string, ConfigSpec> = {
|
|
21
22
|
enabled: { kind: "boolean" },
|
|
22
23
|
mode: { kind: "enum", values: ["safe", "standard"] },
|
|
24
|
+
autoInjectRoutingGuide: { kind: "boolean" },
|
|
23
25
|
maxSteps: { kind: "integer", min: 1, max: 200 },
|
|
24
26
|
maxForEach: { kind: "integer", min: 1, max: 200 },
|
|
25
27
|
maxResultChars: { kind: "integer", min: 500, max: 500000 },
|
|
@@ -38,6 +40,7 @@ const CONFIG_SPECS: Record<string, ConfigSpec> = {
|
|
|
38
40
|
const DEFAULT_BY_KEY: Record<string, boolean | number | string> = {
|
|
39
41
|
enabled: DEFAULT_SETTINGS.enabled,
|
|
40
42
|
mode: DEFAULT_SETTINGS.mode,
|
|
43
|
+
autoInjectRoutingGuide: DEFAULT_SETTINGS.autoInjectRoutingGuide,
|
|
41
44
|
maxSteps: DEFAULT_SETTINGS.maxSteps,
|
|
42
45
|
maxForEach: DEFAULT_SETTINGS.maxForEach,
|
|
43
46
|
maxResultChars: DEFAULT_SETTINGS.maxResultChars,
|
|
@@ -140,6 +143,7 @@ export function renderStatus(api: OpenClawPluginApi): string {
|
|
|
140
143
|
"OCSmartTools Status",
|
|
141
144
|
`- plugin: ${api.id}`,
|
|
142
145
|
`- mode: ${s.mode}`,
|
|
146
|
+
`- autoInjectRoutingGuide: ${s.autoInjectRoutingGuide}`,
|
|
143
147
|
`- tool_search enabled: ${s.toolSearch.enabled}`,
|
|
144
148
|
`- maxSteps: ${s.maxSteps}`,
|
|
145
149
|
`- maxForEach: ${s.maxForEach}`,
|
|
@@ -165,6 +169,7 @@ export function renderHelp(): string {
|
|
|
165
169
|
"- /ocsmarttools stats reset: Reset metrics window",
|
|
166
170
|
"- /ocsmarttools setup [safe|standard]: Apply recommended defaults (default: standard)",
|
|
167
171
|
"- /ocsmarttools mode <safe|standard>: Switch only the operating mode",
|
|
172
|
+
"- /ocsmarttools sync: Re-apply auto-managed routing policy to AGENTS.md",
|
|
168
173
|
"- /ocsmarttools config: Show effective plugin config",
|
|
169
174
|
"- /ocsmarttools config keys: List editable config keys",
|
|
170
175
|
"- /ocsmarttools config set <key> <value>: Update one config key",
|
|
@@ -229,6 +234,7 @@ export function renderConfig(api: OpenClawPluginApi): string {
|
|
|
229
234
|
"OCSmartTools Config",
|
|
230
235
|
`- enabled: ${s.enabled}`,
|
|
231
236
|
`- mode: ${s.mode}`,
|
|
237
|
+
`- autoInjectRoutingGuide: ${s.autoInjectRoutingGuide}`,
|
|
232
238
|
`- maxSteps: ${s.maxSteps}`,
|
|
233
239
|
`- maxForEach: ${s.maxForEach}`,
|
|
234
240
|
`- maxResultChars: ${s.maxResultChars}`,
|
|
@@ -273,6 +279,10 @@ export async function setConfigKey(
|
|
|
273
279
|
setValueAtPath(pluginCfg, key, parsed.value);
|
|
274
280
|
await writeConfig(api, next);
|
|
275
281
|
|
|
282
|
+
if (key === "autoInjectRoutingGuide" && parsed.value === true) {
|
|
283
|
+
await syncRoutingGuide(api, next);
|
|
284
|
+
}
|
|
285
|
+
|
|
276
286
|
return `Config updated: ${key}=${JSON.stringify(parsed.value)}.`;
|
|
277
287
|
}
|
|
278
288
|
|
|
@@ -288,6 +298,9 @@ export async function resetConfig(api: OpenClawPluginApi, key?: string): Promise
|
|
|
288
298
|
setValueAtPath(pluginCfg, cfgKey, DEFAULT_BY_KEY[cfgKey]);
|
|
289
299
|
}
|
|
290
300
|
await writeConfig(api, next);
|
|
301
|
+
if (DEFAULT_SETTINGS.autoInjectRoutingGuide) {
|
|
302
|
+
await syncRoutingGuide(api, next);
|
|
303
|
+
}
|
|
291
304
|
return "Config reset to plugin defaults.";
|
|
292
305
|
}
|
|
293
306
|
|
|
@@ -297,6 +310,9 @@ export async function resetConfig(api: OpenClawPluginApi, key?: string): Promise
|
|
|
297
310
|
|
|
298
311
|
setValueAtPath(pluginCfg, key, DEFAULT_BY_KEY[key]);
|
|
299
312
|
await writeConfig(api, next);
|
|
313
|
+
if (key === "autoInjectRoutingGuide" && DEFAULT_BY_KEY[key] === true) {
|
|
314
|
+
await syncRoutingGuide(api, next);
|
|
315
|
+
}
|
|
300
316
|
return `Config key reset: ${key}=${JSON.stringify(DEFAULT_BY_KEY[key])}.`;
|
|
301
317
|
}
|
|
302
318
|
|
|
@@ -320,6 +336,7 @@ export async function applySetup(api: OpenClawPluginApi, mode: AdvToolsMode): Pr
|
|
|
320
336
|
|
|
321
337
|
pluginCfg.enabled = true;
|
|
322
338
|
pluginCfg.mode = mode;
|
|
339
|
+
pluginCfg.autoInjectRoutingGuide = true;
|
|
323
340
|
pluginCfg.maxSteps = DEFAULT_SETTINGS.maxSteps;
|
|
324
341
|
pluginCfg.maxForEach = DEFAULT_SETTINGS.maxForEach;
|
|
325
342
|
pluginCfg.maxResultChars = DEFAULT_SETTINGS.maxResultChars;
|
|
@@ -344,10 +361,12 @@ export async function applySetup(api: OpenClawPluginApi, mode: AdvToolsMode): Pr
|
|
|
344
361
|
);
|
|
345
362
|
|
|
346
363
|
await writeConfig(api, next);
|
|
364
|
+
await syncRoutingGuide(api, next);
|
|
347
365
|
|
|
348
366
|
return [
|
|
349
367
|
"OCSmartTools setup applied.",
|
|
350
368
|
`- mode: ${mode}`,
|
|
369
|
+
"- autoInjectRoutingGuide: true",
|
|
351
370
|
`- ensured tools.allow includes: ${ADVTOOLS_TOOL_NAMES.join(", ")}`,
|
|
352
371
|
"- config written via runtime config writer",
|
|
353
372
|
"If your gateway does not hot-apply this change, run: openclaw gateway restart",
|
|
@@ -368,3 +387,16 @@ export async function updateMode(api: OpenClawPluginApi, mode: AdvToolsMode): Pr
|
|
|
368
387
|
await writeConfig(api, next);
|
|
369
388
|
return `Mode updated to ${mode}.`;
|
|
370
389
|
}
|
|
390
|
+
|
|
391
|
+
export async function syncManagedRouting(api: OpenClawPluginApi): Promise<string> {
|
|
392
|
+
const loaded = api.runtime.config.loadConfig();
|
|
393
|
+
const settings = resolveSettings(api, loaded);
|
|
394
|
+
if (!settings.autoInjectRoutingGuide) {
|
|
395
|
+
return "Routing guide sync skipped: autoInjectRoutingGuide=false.";
|
|
396
|
+
}
|
|
397
|
+
const result = await syncRoutingGuide(api, loaded);
|
|
398
|
+
if (!result.changed) {
|
|
399
|
+
return `Routing guide already up to date (${result.filePath ?? "AGENTS.md"}).`;
|
|
400
|
+
}
|
|
401
|
+
return `Routing guide synced (${result.filePath ?? "AGENTS.md"}).`;
|
|
402
|
+
}
|
package/src/lib/bootstrap.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
mergeUniqueStrings,
|
|
7
7
|
writeConfig,
|
|
8
8
|
} from "./plugin-config.js";
|
|
9
|
+
import { syncRoutingGuide } from "./routing-guide.js";
|
|
9
10
|
|
|
10
11
|
const TOOL_NAMES = ["tool_search", "tool_dispatch", "tool_batch", "tool_result_get"];
|
|
11
12
|
|
|
@@ -45,6 +46,7 @@ export async function autoBootstrap(api: OpenClawPluginApi): Promise<{ changed:
|
|
|
45
46
|
|
|
46
47
|
setDefault("enabled", true);
|
|
47
48
|
setDefault("mode", DEFAULT_SETTINGS.mode);
|
|
49
|
+
setDefault("autoInjectRoutingGuide", DEFAULT_SETTINGS.autoInjectRoutingGuide);
|
|
48
50
|
setDefault("maxSteps", DEFAULT_SETTINGS.maxSteps);
|
|
49
51
|
setDefault("maxForEach", DEFAULT_SETTINGS.maxForEach);
|
|
50
52
|
setDefault("maxResultChars", DEFAULT_SETTINGS.maxResultChars);
|
|
@@ -110,5 +112,17 @@ export async function autoBootstrap(api: OpenClawPluginApi): Promise<{ changed:
|
|
|
110
112
|
if (changed) {
|
|
111
113
|
await writeConfig(api, next);
|
|
112
114
|
}
|
|
115
|
+
|
|
116
|
+
const routingGuideEnabled =
|
|
117
|
+
typeof pluginCfg.autoInjectRoutingGuide === "boolean"
|
|
118
|
+
? pluginCfg.autoInjectRoutingGuide
|
|
119
|
+
: DEFAULT_SETTINGS.autoInjectRoutingGuide;
|
|
120
|
+
if (routingGuideEnabled) {
|
|
121
|
+
const sync = await syncRoutingGuide(api, next);
|
|
122
|
+
if (sync.changed) {
|
|
123
|
+
notes.push(`synced routing guide (${sync.filePath ?? "AGENTS.md"})`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
113
127
|
return { changed, notes };
|
|
114
128
|
}
|
package/src/lib/plugin-config.ts
CHANGED
|
@@ -5,6 +5,7 @@ export type AdvToolsMode = "safe" | "standard";
|
|
|
5
5
|
export type AdvToolsSettings = {
|
|
6
6
|
enabled: boolean;
|
|
7
7
|
mode: AdvToolsMode;
|
|
8
|
+
autoInjectRoutingGuide: boolean;
|
|
8
9
|
maxSteps: number;
|
|
9
10
|
maxForEach: number;
|
|
10
11
|
maxResultChars: number;
|
|
@@ -25,6 +26,7 @@ export type AdvToolsSettings = {
|
|
|
25
26
|
export const DEFAULT_SETTINGS: AdvToolsSettings = {
|
|
26
27
|
enabled: true,
|
|
27
28
|
mode: "standard",
|
|
29
|
+
autoInjectRoutingGuide: true,
|
|
28
30
|
maxSteps: 25,
|
|
29
31
|
maxForEach: 20,
|
|
30
32
|
maxResultChars: 40000,
|
|
@@ -73,6 +75,10 @@ export function resolveSettings(api: OpenClawPluginApi, cfg: OpenClawConfig = ap
|
|
|
73
75
|
return {
|
|
74
76
|
enabled: asBool(pluginCfg.enabled, DEFAULT_SETTINGS.enabled),
|
|
75
77
|
mode: asMode(pluginCfg.mode, DEFAULT_SETTINGS.mode),
|
|
78
|
+
autoInjectRoutingGuide: asBool(
|
|
79
|
+
pluginCfg.autoInjectRoutingGuide,
|
|
80
|
+
DEFAULT_SETTINGS.autoInjectRoutingGuide,
|
|
81
|
+
),
|
|
76
82
|
maxSteps: asInt(pluginCfg.maxSteps, DEFAULT_SETTINGS.maxSteps, 1, 200),
|
|
77
83
|
maxForEach: asInt(pluginCfg.maxForEach, DEFAULT_SETTINGS.maxForEach, 1, 200),
|
|
78
84
|
maxResultChars: asInt(pluginCfg.maxResultChars, DEFAULT_SETTINGS.maxResultChars, 500, 500000),
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import type { OpenClawConfig, OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
5
|
+
|
|
6
|
+
const BLOCK_START = "<!-- OCSMARTTOOLS_ROUTING_START -->";
|
|
7
|
+
const BLOCK_END = "<!-- OCSMARTTOOLS_ROUTING_END -->";
|
|
8
|
+
|
|
9
|
+
const ROUTING_BLOCK = `${BLOCK_START}
|
|
10
|
+
## OCSmartTools Routing Policy (Auto-Managed)
|
|
11
|
+
|
|
12
|
+
Default objective: preserve answer quality while reducing token and latency cost.
|
|
13
|
+
|
|
14
|
+
1. If tool usage is needed and result size is uncertain, use \`tool_dispatch\`.
|
|
15
|
+
2. If the task needs 2+ related tool calls, use \`tool_batch\`.
|
|
16
|
+
3. Use \`tool_search\` only when tool choice is unclear.
|
|
17
|
+
4. Prefer compact/tool-shaped outputs; use \`tool_result_get\` only when more detail is required.
|
|
18
|
+
5. Use direct native tool calls only for simple one-shot small-output actions.
|
|
19
|
+
|
|
20
|
+
Common large/noisy tools: \`web_fetch\`, \`read\` (large files), \`exec\`, \`process\`, \`browser\`, \`nodes\`.
|
|
21
|
+
${BLOCK_END}
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
function asObj(value: unknown): Record<string, unknown> {
|
|
25
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
26
|
+
? (value as Record<string, unknown>)
|
|
27
|
+
: {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function resolveWorkspaceDir(cfg: OpenClawConfig): string {
|
|
31
|
+
const root = cfg as Record<string, unknown>;
|
|
32
|
+
const agents = asObj(root.agents);
|
|
33
|
+
const defaults = asObj(agents.defaults);
|
|
34
|
+
const configured = defaults.workspace;
|
|
35
|
+
if (typeof configured === "string" && configured.trim()) {
|
|
36
|
+
return configured.trim();
|
|
37
|
+
}
|
|
38
|
+
if (typeof process.env.OPENCLAW_WORKSPACE === "string" && process.env.OPENCLAW_WORKSPACE.trim()) {
|
|
39
|
+
return process.env.OPENCLAW_WORKSPACE.trim();
|
|
40
|
+
}
|
|
41
|
+
return path.join(os.homedir(), ".openclaw", "workspace");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function upsertRoutingBlock(raw: string): string {
|
|
45
|
+
const source = raw.trim()
|
|
46
|
+
? raw
|
|
47
|
+
: "# AGENTS.md - Workspace Directives\n\nAdd local operating preferences below.\n";
|
|
48
|
+
|
|
49
|
+
const start = source.indexOf(BLOCK_START);
|
|
50
|
+
const end = source.indexOf(BLOCK_END);
|
|
51
|
+
if (start >= 0 && end > start) {
|
|
52
|
+
const before = source.slice(0, start).replace(/\s*$/, "");
|
|
53
|
+
const after = source.slice(end + BLOCK_END.length).replace(/^\s*/, "");
|
|
54
|
+
return `${before}\n\n${ROUTING_BLOCK}\n${after}`.replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
|
|
55
|
+
}
|
|
56
|
+
const joined = `${source.replace(/\s*$/, "")}\n\n${ROUTING_BLOCK}\n`;
|
|
57
|
+
return joined.replace(/\n{3,}/g, "\n\n");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function syncRoutingGuide(api: OpenClawPluginApi, cfg: OpenClawConfig): Promise<{
|
|
61
|
+
changed: boolean;
|
|
62
|
+
filePath?: string;
|
|
63
|
+
}> {
|
|
64
|
+
const workspaceDir = resolveWorkspaceDir(cfg);
|
|
65
|
+
const filePath = path.join(workspaceDir, "AGENTS.md");
|
|
66
|
+
let current = "";
|
|
67
|
+
try {
|
|
68
|
+
current = await fs.readFile(filePath, "utf8");
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const next = upsertRoutingBlock(current);
|
|
76
|
+
if (next === current) {
|
|
77
|
+
return { changed: false, filePath };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
await fs.mkdir(workspaceDir, { recursive: true });
|
|
81
|
+
await fs.writeFile(filePath, next, "utf8");
|
|
82
|
+
api.logger.info(`[ocsmarttools] routing policy synced: ${filePath}`);
|
|
83
|
+
return { changed: true, filePath };
|
|
84
|
+
}
|