ocsmarttools 0.1.2 → 0.1.4
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 +22 -0
- package/README.md +11 -1
- package/openclaw.plugin.json +2 -0
- package/package.json +2 -2
- package/src/commands/chat.ts +6 -0
- package/src/commands/cli.ts +17 -10
- package/src/commands/operations.ts +48 -0
- package/src/lib/bootstrap.ts +16 -0
- package/src/lib/plugin-config.ts +6 -0
- package/src/lib/routing-guide.ts +97 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `ocsmarttools` are documented here.
|
|
4
4
|
|
|
5
|
+
## [0.1.4] - 2026-02-22
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- Broadened peer compatibility range to `openclaw >=2026.2.19` for easier installs across existing instances.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- Routing policy sync is now fail-safe on restricted/read-only environments (never breaks plugin startup).
|
|
12
|
+
- Setup/config flows now return clear messages when routing sync is skipped due to filesystem permissions/path issues.
|
|
13
|
+
|
|
14
|
+
## [0.1.3] - 2026-02-22
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- Plugin-native auto-routing guide sync for `AGENTS.md` with managed markers, enabled by default (`autoInjectRoutingGuide`).
|
|
18
|
+
- New chat and CLI sync commands (`/ocsmarttools sync`, `openclaw ocsmarttools sync`) to re-apply routing guidance instantly.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- `setup` now re-syncs the managed routing guide automatically.
|
|
22
|
+
- Added `autoInjectRoutingGuide` to config schema, status, config output, and editable keys.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- Removed CLI registration conflict by making `stats reset` a subcommand under `stats`.
|
|
26
|
+
|
|
5
27
|
## [0.1.2] - 2026-02-22
|
|
6
28
|
|
|
7
29
|
### Added
|
package/README.md
CHANGED
|
@@ -23,6 +23,10 @@ flowchart LR
|
|
|
23
23
|
|
|
24
24
|
## Install
|
|
25
25
|
|
|
26
|
+
Compatibility:
|
|
27
|
+
- OpenClaw: `>=2026.2.19`
|
|
28
|
+
- Works with existing installed instances (no core patch required)
|
|
29
|
+
|
|
26
30
|
### npm
|
|
27
31
|
|
|
28
32
|
```bash
|
|
@@ -43,7 +47,8 @@ openclaw gateway restart
|
|
|
43
47
|
|
|
44
48
|
1. Install + enable + restart.
|
|
45
49
|
2. Done. The plugin auto-bootstraps and starts working in background.
|
|
46
|
-
3.
|
|
50
|
+
3. It also auto-manages an OCSmartTools routing block in `AGENTS.md` (unless disabled).
|
|
51
|
+
4. Optional check:
|
|
47
52
|
|
|
48
53
|
```text
|
|
49
54
|
/ocsmarttools status
|
|
@@ -66,6 +71,7 @@ Model note:
|
|
|
66
71
|
| `/ocsmarttools stats reset` | Resets the stats window |
|
|
67
72
|
| `/ocsmarttools setup [safe\|standard]` | Applies recommended defaults for the selected mode |
|
|
68
73
|
| `/ocsmarttools mode <safe\|standard>` | Changes mode only |
|
|
74
|
+
| `/ocsmarttools sync` | Re-applies the auto-managed routing policy block in `AGENTS.md` |
|
|
69
75
|
| `/ocsmarttools config` | Shows effective plugin config |
|
|
70
76
|
| `/ocsmarttools config keys` | Lists editable config keys |
|
|
71
77
|
| `/ocsmarttools config set <key> <value>` | Updates one config key with validation |
|
|
@@ -82,6 +88,7 @@ Model note:
|
|
|
82
88
|
| `openclaw ocsmarttools stats reset` | Resets the stats window |
|
|
83
89
|
| `openclaw ocsmarttools setup [safe\|standard]` | Applies recommended defaults for the selected mode |
|
|
84
90
|
| `openclaw ocsmarttools mode <safe\|standard>` | Changes mode only |
|
|
91
|
+
| `openclaw ocsmarttools sync` | Re-applies the auto-managed routing policy block in `AGENTS.md` |
|
|
85
92
|
| `openclaw ocsmarttools config` | Shows effective plugin config |
|
|
86
93
|
| `openclaw ocsmarttools config keys` | Lists editable config keys |
|
|
87
94
|
| `openclaw ocsmarttools config set <key> <value>` | Updates one config key with validation |
|
|
@@ -96,6 +103,8 @@ Model note:
|
|
|
96
103
|
/ocsmarttools config set storeLargeResults true
|
|
97
104
|
/ocsmarttools config set toolSearch.useLiveRegistry true
|
|
98
105
|
/ocsmarttools config set toolSearch.liveTimeoutMs 1500
|
|
106
|
+
/ocsmarttools config set autoInjectRoutingGuide true
|
|
107
|
+
/ocsmarttools config set autoInjectRoutingGuide false
|
|
99
108
|
/ocsmarttools config reset maxResultChars
|
|
100
109
|
/ocsmarttools stats
|
|
101
110
|
```
|
|
@@ -143,6 +152,7 @@ If your instance uses strict `tools.allow`, include:
|
|
|
143
152
|
## Safety and Limits
|
|
144
153
|
|
|
145
154
|
- `ocsmarttools` does not bypass OpenClaw tool policy.
|
|
155
|
+
- Routing policy is auto-injected into `AGENTS.md` with managed markers; it can be re-synced via `/ocsmarttools sync`.
|
|
146
156
|
- `tool_batch` is intentionally bounded (`maxSteps`, `maxForEach`).
|
|
147
157
|
- Large-result handles are in-memory and expire by TTL.
|
|
148
158
|
- `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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ocsmarttools",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Provider-agnostic advanced tool orchestration plugin for OpenClaw with search, dispatch, and batching",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
],
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"openclaw": ">=2026.2.
|
|
27
|
+
"openclaw": ">=2026.2.19"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"typescript": "^5.8.0",
|
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,13 @@ 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
|
+
const sync = await syncRoutingGuide(api, next);
|
|
284
|
+
if (sync.error) {
|
|
285
|
+
return `Config updated: ${key}=${JSON.stringify(parsed.value)} (routing sync skipped: ${sync.error}).`;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
276
289
|
return `Config updated: ${key}=${JSON.stringify(parsed.value)}.`;
|
|
277
290
|
}
|
|
278
291
|
|
|
@@ -288,6 +301,12 @@ export async function resetConfig(api: OpenClawPluginApi, key?: string): Promise
|
|
|
288
301
|
setValueAtPath(pluginCfg, cfgKey, DEFAULT_BY_KEY[cfgKey]);
|
|
289
302
|
}
|
|
290
303
|
await writeConfig(api, next);
|
|
304
|
+
if (DEFAULT_SETTINGS.autoInjectRoutingGuide) {
|
|
305
|
+
const sync = await syncRoutingGuide(api, next);
|
|
306
|
+
if (sync.error) {
|
|
307
|
+
return `Config reset to plugin defaults (routing sync skipped: ${sync.error}).`;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
291
310
|
return "Config reset to plugin defaults.";
|
|
292
311
|
}
|
|
293
312
|
|
|
@@ -297,6 +316,12 @@ export async function resetConfig(api: OpenClawPluginApi, key?: string): Promise
|
|
|
297
316
|
|
|
298
317
|
setValueAtPath(pluginCfg, key, DEFAULT_BY_KEY[key]);
|
|
299
318
|
await writeConfig(api, next);
|
|
319
|
+
if (key === "autoInjectRoutingGuide" && DEFAULT_BY_KEY[key] === true) {
|
|
320
|
+
const sync = await syncRoutingGuide(api, next);
|
|
321
|
+
if (sync.error) {
|
|
322
|
+
return `Config key reset: ${key}=${JSON.stringify(DEFAULT_BY_KEY[key])} (routing sync skipped: ${sync.error}).`;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
300
325
|
return `Config key reset: ${key}=${JSON.stringify(DEFAULT_BY_KEY[key])}.`;
|
|
301
326
|
}
|
|
302
327
|
|
|
@@ -320,6 +345,7 @@ export async function applySetup(api: OpenClawPluginApi, mode: AdvToolsMode): Pr
|
|
|
320
345
|
|
|
321
346
|
pluginCfg.enabled = true;
|
|
322
347
|
pluginCfg.mode = mode;
|
|
348
|
+
pluginCfg.autoInjectRoutingGuide = true;
|
|
323
349
|
pluginCfg.maxSteps = DEFAULT_SETTINGS.maxSteps;
|
|
324
350
|
pluginCfg.maxForEach = DEFAULT_SETTINGS.maxForEach;
|
|
325
351
|
pluginCfg.maxResultChars = DEFAULT_SETTINGS.maxResultChars;
|
|
@@ -344,10 +370,16 @@ export async function applySetup(api: OpenClawPluginApi, mode: AdvToolsMode): Pr
|
|
|
344
370
|
);
|
|
345
371
|
|
|
346
372
|
await writeConfig(api, next);
|
|
373
|
+
const sync = await syncRoutingGuide(api, next);
|
|
374
|
+
const syncLine = sync.error
|
|
375
|
+
? `- routing guide sync skipped: ${sync.error}`
|
|
376
|
+
: `- routing guide ${sync.changed ? "synced" : "already up to date"} (${sync.filePath ?? "AGENTS.md"})`;
|
|
347
377
|
|
|
348
378
|
return [
|
|
349
379
|
"OCSmartTools setup applied.",
|
|
350
380
|
`- mode: ${mode}`,
|
|
381
|
+
"- autoInjectRoutingGuide: true",
|
|
382
|
+
syncLine,
|
|
351
383
|
`- ensured tools.allow includes: ${ADVTOOLS_TOOL_NAMES.join(", ")}`,
|
|
352
384
|
"- config written via runtime config writer",
|
|
353
385
|
"If your gateway does not hot-apply this change, run: openclaw gateway restart",
|
|
@@ -368,3 +400,19 @@ export async function updateMode(api: OpenClawPluginApi, mode: AdvToolsMode): Pr
|
|
|
368
400
|
await writeConfig(api, next);
|
|
369
401
|
return `Mode updated to ${mode}.`;
|
|
370
402
|
}
|
|
403
|
+
|
|
404
|
+
export async function syncManagedRouting(api: OpenClawPluginApi): Promise<string> {
|
|
405
|
+
const loaded = api.runtime.config.loadConfig();
|
|
406
|
+
const settings = resolveSettings(api, loaded);
|
|
407
|
+
if (!settings.autoInjectRoutingGuide) {
|
|
408
|
+
return "Routing guide sync skipped: autoInjectRoutingGuide=false.";
|
|
409
|
+
}
|
|
410
|
+
const result = await syncRoutingGuide(api, loaded);
|
|
411
|
+
if (result.error) {
|
|
412
|
+
return `Routing guide sync skipped: ${result.error}`;
|
|
413
|
+
}
|
|
414
|
+
if (!result.changed) {
|
|
415
|
+
return `Routing guide already up to date (${result.filePath ?? "AGENTS.md"}).`;
|
|
416
|
+
}
|
|
417
|
+
return `Routing guide synced (${result.filePath ?? "AGENTS.md"}).`;
|
|
418
|
+
}
|
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,19 @@ 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.error) {
|
|
123
|
+
notes.push(`routing guide skipped: ${sync.error}`);
|
|
124
|
+
} else if (sync.changed) {
|
|
125
|
+
notes.push(`synced routing guide (${sync.filePath ?? "AGENTS.md"})`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
113
129
|
return { changed, notes };
|
|
114
130
|
}
|
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,97 @@
|
|
|
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
|
+
error?: string;
|
|
64
|
+
}> {
|
|
65
|
+
const workspaceDir = resolveWorkspaceDir(cfg);
|
|
66
|
+
const filePath = path.join(workspaceDir, "AGENTS.md");
|
|
67
|
+
let current = "";
|
|
68
|
+
try {
|
|
69
|
+
current = await fs.readFile(filePath, "utf8");
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
72
|
+
return {
|
|
73
|
+
changed: false,
|
|
74
|
+
filePath,
|
|
75
|
+
error: `read failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const next = upsertRoutingBlock(current);
|
|
81
|
+
if (next === current) {
|
|
82
|
+
return { changed: false, filePath };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
await fs.mkdir(workspaceDir, { recursive: true });
|
|
87
|
+
await fs.writeFile(filePath, next, "utf8");
|
|
88
|
+
} catch (error) {
|
|
89
|
+
return {
|
|
90
|
+
changed: false,
|
|
91
|
+
filePath,
|
|
92
|
+
error: `write failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
api.logger.info(`[ocsmarttools] routing policy synced: ${filePath}`);
|
|
96
|
+
return { changed: true, filePath };
|
|
97
|
+
}
|