ocsmarttools 0.1.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/CHANGELOG.md ADDED
@@ -0,0 +1,35 @@
1
+ # Changelog
2
+
3
+ All notable changes to `ocsmarttools` are documented here.
4
+
5
+ ## [0.1.2] - 2026-02-22
6
+
7
+ ### Added
8
+ - Lightweight metrics tracking for tool invocations: success/failure/timeout, latency, shaped-result rate, and approximate token savings.
9
+ - Chat and CLI stats commands (`/ocsmarttools stats`, `/ocsmarttools stats reset`, `openclaw ocsmarttools stats`, `openclaw ocsmarttools stats reset`).
10
+
11
+ ### Changed
12
+ - `tool_search` now tries live gateway registry endpoints first and falls back to policy/static catalog automatically.
13
+ - Added `toolSearch.useLiveRegistry` and `toolSearch.liveTimeoutMs` config options.
14
+
15
+ ## [0.1.1] - 2026-02-22
16
+
17
+ ### Added
18
+ - `version` commands in chat and CLI (`/ocsmarttools version`, `openclaw ocsmarttools version`).
19
+ - Version control scripts in `package.json` (`version:show`, `version:bump:*`, `release:check`).
20
+ - `CHANGELOG.md` for release notes tracking.
21
+
22
+ ### Changed
23
+ - `setup` default mode now aligns with zero-touch defaults (`standard`).
24
+
25
+ ### Fixed
26
+ - Blocked `tool_dispatch` from dispatching internal orchestration tools (`tool_dispatch`, `tool_batch`) to avoid nested orchestration loops.
27
+
28
+ ## [0.1.0] - 2026-02-22
29
+
30
+ ### Added
31
+ - Provider-agnostic tool orchestration tools: `tool_search`, `tool_dispatch`, `tool_batch`, `tool_result_get`.
32
+ - Zero-touch auto-bootstrap on plugin start.
33
+ - Chat and CLI setup/status/mode/config commands.
34
+ - Help commands in chat and CLI.
35
+ - Adaptive large-result shaping with handle-based retrieval.
package/README.md ADDED
@@ -0,0 +1,169 @@
1
+ # OCSmartTools for OpenClaw
2
+
3
+ Provider-agnostic tool orchestration for lower latency and lower token cost.
4
+
5
+ `ocsmarttools` is designed to work immediately after install, with safe defaults and minimal setup.
6
+
7
+ ## What It Adds
8
+
9
+ - `tool_search`: finds relevant tools quickly
10
+ - `tool_dispatch`: runs one tool call through normal OpenClaw policy checks
11
+ - `tool_batch`: runs bounded multi-step workflows (`call` + `foreach`)
12
+ - `tool_result_get`: retrieves large stored outputs by handle
13
+
14
+ ## Why It Helps
15
+
16
+ ```mermaid
17
+ flowchart LR
18
+ A["Traditional"] --> B["Model -> tool -> model -> tool"] --> C["More turns + repeated context"]
19
+ D["ocsmarttools"] --> E["Batch + shaped results"] --> F["Fewer turns + smaller context"]
20
+ C --> G["Higher cost/latency"]
21
+ F --> H["Lower cost/latency"]
22
+ ```
23
+
24
+ ## Install
25
+
26
+ ### npm
27
+
28
+ ```bash
29
+ openclaw plugins install ocsmarttools --pin
30
+ openclaw plugins enable ocsmarttools
31
+ openclaw gateway restart
32
+ ```
33
+
34
+ ### Local folder
35
+
36
+ ```bash
37
+ openclaw plugins install /absolute/path/to/OpenClaw-SmartToolCalls
38
+ openclaw plugins enable ocsmarttools
39
+ openclaw gateway restart
40
+ ```
41
+
42
+ ## Quick Start
43
+
44
+ 1. Install + enable + restart.
45
+ 2. Done. The plugin auto-bootstraps and starts working in background.
46
+ 3. Optional check:
47
+
48
+ ```text
49
+ /ocsmarttools status
50
+ ```
51
+
52
+ Model note:
53
+ - No model setup is required in this plugin.
54
+ - It automatically uses the model OpenClaw is already using.
55
+
56
+ ## Commands
57
+
58
+ ### Chat Commands
59
+
60
+ | Command | What it does |
61
+ |---|---|
62
+ | `/ocsmarttools version` | Shows installed plugin version |
63
+ | `/ocsmarttools help` | Shows simple help and examples |
64
+ | `/ocsmarttools status` | Shows current mode, limits, and safety flags |
65
+ | `/ocsmarttools stats` | Shows live usage metrics (success/failure/timeout, latency, shaping, savings) |
66
+ | `/ocsmarttools stats reset` | Resets the stats window |
67
+ | `/ocsmarttools setup [safe\|standard]` | Applies recommended defaults for the selected mode |
68
+ | `/ocsmarttools mode <safe\|standard>` | Changes mode only |
69
+ | `/ocsmarttools config` | Shows effective plugin config |
70
+ | `/ocsmarttools config keys` | Lists editable config keys |
71
+ | `/ocsmarttools config set <key> <value>` | Updates one config key with validation |
72
+ | `/ocsmarttools config reset [key]` | Resets one key (or all keys) to defaults |
73
+
74
+ ### CLI Commands
75
+
76
+ | Command | What it does |
77
+ |---|---|
78
+ | `openclaw ocsmarttools version` | Shows installed plugin version |
79
+ | `openclaw ocsmarttools help` | Shows simple help and examples |
80
+ | `openclaw ocsmarttools status` | Shows current mode, limits, and safety flags |
81
+ | `openclaw ocsmarttools stats` | Shows live usage metrics (success/failure/timeout, latency, shaping, savings) |
82
+ | `openclaw ocsmarttools stats reset` | Resets the stats window |
83
+ | `openclaw ocsmarttools setup [safe\|standard]` | Applies recommended defaults for the selected mode |
84
+ | `openclaw ocsmarttools mode <safe\|standard>` | Changes mode only |
85
+ | `openclaw ocsmarttools config` | Shows effective plugin config |
86
+ | `openclaw ocsmarttools config keys` | Lists editable config keys |
87
+ | `openclaw ocsmarttools config set <key> <value>` | Updates one config key with validation |
88
+ | `openclaw ocsmarttools config reset [key]` | Resets one key (or all keys) to defaults |
89
+
90
+ ## Common Config Actions
91
+
92
+ ```text
93
+ /ocsmarttools config
94
+ /ocsmarttools config keys
95
+ /ocsmarttools config set maxResultChars 120000
96
+ /ocsmarttools config set storeLargeResults true
97
+ /ocsmarttools config set toolSearch.useLiveRegistry true
98
+ /ocsmarttools config set toolSearch.liveTimeoutMs 1500
99
+ /ocsmarttools config reset maxResultChars
100
+ /ocsmarttools stats
101
+ ```
102
+
103
+ Config path:
104
+ - `plugins.entries.ocsmarttools.config`
105
+
106
+ ## Modes
107
+
108
+ - `standard` (default): zero-touch mode, no sandbox requirement, control-plane dispatch still blocked
109
+ - `safe`: requires sandboxed execution and blocks control-plane dispatch (`gateway`, `cron`)
110
+
111
+ Setup default:
112
+ - `/ocsmarttools setup` and `openclaw ocsmarttools setup` default to `standard`.
113
+
114
+ ## Recommended Defaults
115
+
116
+ For mixed daily usage (research + writing + coding):
117
+
118
+ - `maxResultChars`: `120000`
119
+ - `storeLargeResults`: `true`
120
+ - `resultStoreTtlSec`: `3600`
121
+ - `resultSampleItems`: `10`
122
+
123
+ Example:
124
+
125
+ ```text
126
+ /ocsmarttools config set maxResultChars 120000
127
+ /ocsmarttools config set resultStoreTtlSec 3600
128
+ /ocsmarttools config set resultSampleItems 10
129
+ ```
130
+
131
+ ## Strict Policy Note
132
+
133
+ If your instance uses strict `tools.allow`, include:
134
+
135
+ ```json5
136
+ {
137
+ tools: {
138
+ allow: ["tool_search", "tool_dispatch", "tool_batch", "tool_result_get"]
139
+ }
140
+ }
141
+ ```
142
+
143
+ ## Safety and Limits
144
+
145
+ - `ocsmarttools` does not bypass OpenClaw tool policy.
146
+ - `tool_batch` is intentionally bounded (`maxSteps`, `maxForEach`).
147
+ - Large-result handles are in-memory and expire by TTL.
148
+ - `tool_result_get` works only while handle is still valid.
149
+ - `tool_search` tries live registry endpoints first, then automatically falls back to policy/static catalog.
150
+
151
+ ## Development
152
+
153
+ ```bash
154
+ npm install
155
+ npm run typecheck
156
+ ```
157
+
158
+ ## Versioning
159
+
160
+ ```bash
161
+ npm run version:show
162
+ npm run version:bump:patch
163
+ npm run version:bump:minor
164
+ npm run version:bump:major
165
+ npm run release:check
166
+ ```
167
+
168
+ - Version source of truth: `package.json`.
169
+ - Release notes: `CHANGELOG.md`.
@@ -0,0 +1,48 @@
1
+ {
2
+ "id": "ocsmarttools",
3
+ "name": "OCSmartTools",
4
+ "description": "Provider-agnostic advanced tool orchestration with adaptive large-result handling and zero-touch startup.",
5
+ "configSchema": {
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "enabled": { "type": "boolean" },
10
+ "mode": { "type": "string", "enum": ["safe", "standard"] },
11
+ "maxSteps": { "type": "integer", "minimum": 1, "maximum": 200 },
12
+ "maxForEach": { "type": "integer", "minimum": 1, "maximum": 200 },
13
+ "maxResultChars": { "type": "integer", "minimum": 500, "maximum": 500000 },
14
+ "invokeTimeoutMs": { "type": "integer", "minimum": 0, "maximum": 1800000 },
15
+ "storeLargeResults": { "type": "boolean" },
16
+ "resultStoreTtlSec": { "type": "integer", "minimum": 60, "maximum": 86400 },
17
+ "resultSampleItems": { "type": "integer", "minimum": 1, "maximum": 50 },
18
+ "requireSandbox": { "type": "boolean" },
19
+ "denyControlPlane": { "type": "boolean" },
20
+ "toolSearch": {
21
+ "type": "object",
22
+ "additionalProperties": false,
23
+ "properties": {
24
+ "enabled": { "type": "boolean" },
25
+ "defaultLimit": { "type": "integer", "minimum": 1, "maximum": 50 },
26
+ "useLiveRegistry": { "type": "boolean" },
27
+ "liveTimeoutMs": { "type": "integer", "minimum": 250, "maximum": 10000 }
28
+ }
29
+ }
30
+ }
31
+ },
32
+ "uiHints": {
33
+ "mode": { "label": "Mode" },
34
+ "maxSteps": { "label": "Max Steps", "advanced": true },
35
+ "maxForEach": { "label": "Max ForEach", "advanced": true },
36
+ "maxResultChars": { "label": "Max Result Chars", "advanced": true },
37
+ "invokeTimeoutMs": { "label": "Invoke Timeout (ms)", "advanced": true },
38
+ "storeLargeResults": { "label": "Store Large Results", "advanced": true },
39
+ "resultStoreTtlSec": { "label": "Result Store TTL (sec)", "advanced": true },
40
+ "resultSampleItems": { "label": "Result Sample Items", "advanced": true },
41
+ "requireSandbox": { "label": "Require Sandbox", "advanced": true },
42
+ "denyControlPlane": { "label": "Deny Control Plane", "advanced": true },
43
+ "toolSearch.enabled": { "label": "Enable Tool Search" },
44
+ "toolSearch.defaultLimit": { "label": "Tool Search Default Limit", "advanced": true },
45
+ "toolSearch.useLiveRegistry": { "label": "Use Live Tool Registry", "advanced": true },
46
+ "toolSearch.liveTimeoutMs": { "label": "Live Tool Registry Timeout (ms)", "advanced": true }
47
+ }
48
+ }
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "ocsmarttools",
3
+ "version": "0.1.2",
4
+ "description": "Provider-agnostic advanced tool orchestration plugin for OpenClaw with search, dispatch, and batching",
5
+ "type": "module",
6
+ "scripts": {
7
+ "typecheck": "tsc --noEmit",
8
+ "release:check": "npm run typecheck && npm pack --dry-run",
9
+ "version:show": "node -p \"require('./package.json').version\"",
10
+ "version:bump:patch": "npm version patch --no-git-tag-version",
11
+ "version:bump:minor": "npm version minor --no-git-tag-version",
12
+ "version:bump:major": "npm version major --no-git-tag-version"
13
+ },
14
+ "openclaw": {
15
+ "extensions": [
16
+ "./src/index.ts"
17
+ ]
18
+ },
19
+ "keywords": [
20
+ "openclaw",
21
+ "plugin",
22
+ "tools",
23
+ "agent"
24
+ ],
25
+ "license": "MIT",
26
+ "peerDependencies": {
27
+ "openclaw": ">=2026.2.21"
28
+ },
29
+ "devDependencies": {
30
+ "typescript": "^5.8.0",
31
+ "@types/node": "^22.10.0"
32
+ }
33
+ }
@@ -0,0 +1,123 @@
1
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
2
+ import {
3
+ applySetup,
4
+ canEditConfigKey,
5
+ normalizeConfigKey,
6
+ renderConfig,
7
+ renderConfigKeys,
8
+ renderHelp,
9
+ renderStatus,
10
+ renderStats,
11
+ renderVersion,
12
+ resetStats,
13
+ resetConfig,
14
+ setConfigKey,
15
+ updateMode,
16
+ } from "./operations.js";
17
+ import type { AdvToolsMode } from "../lib/plugin-config.js";
18
+ import type { MetricsStore } from "../lib/metrics-store.js";
19
+
20
+ function parseMode(value: string | undefined): AdvToolsMode | null {
21
+ if (value === "safe" || value === "standard") {
22
+ return value;
23
+ }
24
+ return null;
25
+ }
26
+
27
+ export function registerChatCommands(api: OpenClawPluginApi, metrics: MetricsStore): void {
28
+ api.registerCommand({
29
+ name: "ocsmarttools",
30
+ description: "OCSmartTools setup/status helper.",
31
+ acceptsArgs: true,
32
+ handler: async (ctx) => {
33
+ const args = (ctx.args ?? "").trim();
34
+ if (!args) {
35
+ return { text: renderHelp() };
36
+ }
37
+
38
+ const parts = args.split(/\s+/);
39
+ const cmd = parts[0]?.toLowerCase();
40
+
41
+ try {
42
+ if (cmd === "status") {
43
+ return { text: renderStatus(api) };
44
+ }
45
+
46
+ if (cmd === "version") {
47
+ return { text: renderVersion(api) };
48
+ }
49
+
50
+ if (cmd === "help") {
51
+ return { text: renderHelp() };
52
+ }
53
+
54
+ if (cmd === "stats") {
55
+ const action = (parts[1] ?? "").toLowerCase();
56
+ if (action === "reset") {
57
+ return { text: resetStats(metrics) };
58
+ }
59
+ return { text: renderStats(metrics) };
60
+ }
61
+
62
+ if (cmd === "setup") {
63
+ const mode = parseMode(parts[1]) ?? "standard";
64
+ return { text: await applySetup(api, mode) };
65
+ }
66
+
67
+ if (cmd === "mode") {
68
+ const mode = parseMode(parts[1]);
69
+ if (!mode) {
70
+ return { text: "Usage: /ocsmarttools mode <safe|standard>" };
71
+ }
72
+ return { text: await updateMode(api, mode) };
73
+ }
74
+
75
+ if (cmd === "config") {
76
+ const action = (parts[1] ?? "get").toLowerCase();
77
+ if (action === "get") {
78
+ return { text: renderConfig(api) };
79
+ }
80
+ if (action === "keys") {
81
+ return { text: renderConfigKeys() };
82
+ }
83
+ if (action === "set") {
84
+ const key = normalizeConfigKey(parts[2] ?? "");
85
+ const valueRaw = parts.slice(3).join(" ").trim();
86
+ if (!key || !valueRaw) {
87
+ return { text: "Usage: /ocsmarttools config set <key> <value>" };
88
+ }
89
+ if (!canEditConfigKey(key)) {
90
+ return { text: `Unknown key: ${key}. Use \`/ocsmarttools config keys\`.` };
91
+ }
92
+ return { text: await setConfigKey(api, key, valueRaw) };
93
+ }
94
+ if (action === "reset") {
95
+ const key = normalizeConfigKey(parts[2] ?? "");
96
+ if (key && !canEditConfigKey(key)) {
97
+ return { text: `Unknown key: ${key}. Use \`/ocsmarttools config keys\`.` };
98
+ }
99
+ return { text: await resetConfig(api, key || undefined) };
100
+ }
101
+ return {
102
+ text: [
103
+ "Usage:",
104
+ "/ocsmarttools config",
105
+ "/ocsmarttools config get",
106
+ "/ocsmarttools config keys",
107
+ "/ocsmarttools config set <key> <value>",
108
+ "/ocsmarttools config reset [key]",
109
+ ].join("\n"),
110
+ };
111
+ }
112
+
113
+ return {
114
+ text: "Unknown subcommand. Use `/ocsmarttools help`.",
115
+ };
116
+ } catch (error) {
117
+ return {
118
+ text: `ocsmarttools error: ${error instanceof Error ? error.message : String(error)}`,
119
+ };
120
+ }
121
+ },
122
+ });
123
+ }
@@ -0,0 +1,130 @@
1
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
2
+ import {
3
+ applySetup,
4
+ renderConfig,
5
+ renderConfigKeys,
6
+ renderHelp,
7
+ renderStatus,
8
+ renderStats,
9
+ renderVersion,
10
+ resetStats,
11
+ resetConfig,
12
+ setConfigKey,
13
+ updateMode,
14
+ } from "./operations.js";
15
+ import type { AdvToolsMode } from "../lib/plugin-config.js";
16
+ import type { MetricsStore } from "../lib/metrics-store.js";
17
+
18
+ function parseMode(value: string | undefined): AdvToolsMode | null {
19
+ if (value === "safe" || value === "standard") {
20
+ return value;
21
+ }
22
+ return null;
23
+ }
24
+
25
+ export function registerCliCommands(api: OpenClawPluginApi, metrics: MetricsStore): void {
26
+ api.registerCli(
27
+ ({ program }) => {
28
+ const adv = program.command("ocsmarttools").description("OCSmartTools plugin commands");
29
+ adv.addHelpCommand(false);
30
+
31
+ adv
32
+ .command("help")
33
+ .description("Show simple command guide")
34
+ .action(() => {
35
+ // eslint-disable-next-line no-console
36
+ console.log(renderHelp());
37
+ });
38
+
39
+ adv
40
+ .command("version")
41
+ .description("Show installed plugin version")
42
+ .action(() => {
43
+ // eslint-disable-next-line no-console
44
+ console.log(renderVersion(api));
45
+ });
46
+
47
+ adv
48
+ .command("status")
49
+ .description("Show plugin status")
50
+ .action(() => {
51
+ // eslint-disable-next-line no-console
52
+ console.log(renderStatus(api));
53
+ });
54
+
55
+ adv
56
+ .command("stats")
57
+ .description("Show usage/savings metrics")
58
+ .action(() => {
59
+ // eslint-disable-next-line no-console
60
+ console.log(renderStats(metrics));
61
+ });
62
+
63
+ adv
64
+ .command("stats reset")
65
+ .description("Reset usage/savings metrics window")
66
+ .action(() => {
67
+ // eslint-disable-next-line no-console
68
+ console.log(resetStats(metrics));
69
+ });
70
+
71
+ adv
72
+ .command("setup [mode]")
73
+ .description("Apply recommended setup (default mode: standard)")
74
+ .action(async (modeRaw?: string) => {
75
+ const mode = parseMode(modeRaw) ?? "standard";
76
+ const text = await applySetup(api, mode);
77
+ // eslint-disable-next-line no-console
78
+ console.log(text);
79
+ });
80
+
81
+ adv
82
+ .command("mode <mode>")
83
+ .description("Set plugin mode")
84
+ .action(async (modeRaw: string) => {
85
+ const mode = parseMode(modeRaw);
86
+ if (!mode) {
87
+ throw new Error("mode must be one of: safe, standard");
88
+ }
89
+ const text = await updateMode(api, mode);
90
+ // eslint-disable-next-line no-console
91
+ console.log(text);
92
+ });
93
+
94
+ adv
95
+ .command("config")
96
+ .description("Show effective plugin config")
97
+ .action(() => {
98
+ // eslint-disable-next-line no-console
99
+ console.log(renderConfig(api));
100
+ });
101
+
102
+ adv
103
+ .command("config keys")
104
+ .description("List editable plugin config keys")
105
+ .action(() => {
106
+ // eslint-disable-next-line no-console
107
+ console.log(renderConfigKeys());
108
+ });
109
+
110
+ adv
111
+ .command("config set <key> <value>")
112
+ .description("Set one plugin config key")
113
+ .action(async (key: string, value: string) => {
114
+ const text = await setConfigKey(api, key, value);
115
+ // eslint-disable-next-line no-console
116
+ console.log(text);
117
+ });
118
+
119
+ adv
120
+ .command("config reset [key]")
121
+ .description("Reset all plugin config to defaults or reset one key")
122
+ .action(async (key?: string) => {
123
+ const text = await resetConfig(api, key);
124
+ // eslint-disable-next-line no-console
125
+ console.log(text);
126
+ });
127
+ },
128
+ { commands: ["ocsmarttools"] },
129
+ );
130
+ }