@kernel.chat/kbot 3.99.30 → 3.99.33
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/README.md +1 -1
- package/dist/agents/security-agent.d.ts +31 -0
- package/dist/agents/security-agent.js +180 -0
- package/dist/agents/security-rules.d.ts +35 -0
- package/dist/agents/security-rules.js +206 -0
- package/dist/agents/specialists.d.ts +6 -0
- package/dist/agents/specialists.js +45 -0
- package/dist/architect.js +5 -0
- package/dist/auth.js +1 -1
- package/dist/channels/matrix.d.ts +4 -0
- package/dist/channels/matrix.js +28 -0
- package/dist/channels/office.d.ts +78 -0
- package/dist/channels/office.js +169 -0
- package/dist/channels/registry.d.ts +8 -0
- package/dist/channels/registry.js +38 -0
- package/dist/channels/signal.d.ts +4 -0
- package/dist/channels/signal.js +29 -0
- package/dist/channels/slack.d.ts +4 -0
- package/dist/channels/slack.js +97 -0
- package/dist/channels/teams.d.ts +4 -0
- package/dist/channels/teams.js +29 -0
- package/dist/channels/telegram.d.ts +4 -0
- package/dist/channels/telegram.js +28 -0
- package/dist/channels/types.d.ts +50 -0
- package/dist/channels/types.js +13 -0
- package/dist/channels/whatsapp.d.ts +4 -0
- package/dist/channels/whatsapp.js +28 -0
- package/dist/computer-use-coordinator.d.ts +44 -0
- package/dist/computer-use-coordinator.js +0 -0
- package/dist/doctor.js +6 -3
- package/dist/file-library.d.ts +76 -0
- package/dist/file-library.js +269 -0
- package/dist/managed-agents-anthropic.d.ts +90 -0
- package/dist/managed-agents-anthropic.js +123 -0
- package/dist/plugins-integrity.d.ts +72 -0
- package/dist/plugins-integrity.js +153 -0
- package/dist/plugins.d.ts +13 -2
- package/dist/plugins.js +87 -10
- package/dist/tools/anthropic-managed-agents-tools.d.ts +22 -0
- package/dist/tools/anthropic-managed-agents-tools.js +191 -0
- package/dist/tools/channel-tools.d.ts +4 -0
- package/dist/tools/channel-tools.js +80 -0
- package/dist/tools/computer-coordinator-tools.d.ts +13 -0
- package/dist/tools/computer-coordinator-tools.js +104 -0
- package/dist/tools/computer.js +463 -299
- package/dist/tools/file-library-tools.d.ts +12 -0
- package/dist/tools/file-library-tools.js +191 -0
- package/dist/tools/image-thoughtful.d.ts +31 -0
- package/dist/tools/image-thoughtful.js +233 -0
- package/dist/tools/index.js +1 -0
- package/dist/tools/security-agent-tools.d.ts +34 -0
- package/dist/tools/security-agent-tools.js +30 -0
- package/dist/tools/swarm-2026-04.d.ts +2 -0
- package/dist/tools/swarm-2026-04.js +91 -0
- package/dist/tools/workspace-agent-tools.d.ts +19 -0
- package/dist/tools/workspace-agent-tools.js +191 -0
- package/dist/workspace-agents.d.ts +132 -0
- package/dist/workspace-agents.js +379 -0
- package/package.json +1 -1
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin integrity verification — fail-closed SHA-256 manifest checking.
|
|
3
|
+
*
|
|
4
|
+
* Ports OpenClaw's `plugins.json5` integrity-pinned plugin model. Plugins must
|
|
5
|
+
* be declared in a manifest with a SHA-256 hash; the loader verifies the file
|
|
6
|
+
* on disk against the manifest entry and refuses to load on drift.
|
|
7
|
+
*
|
|
8
|
+
* Manifest format here is plain JSON. If we add a JSON5 dep later (e.g.
|
|
9
|
+
* `json5`), swap `JSON.parse` for `JSON5.parse` and accept `.json5` files.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
13
|
+
import { resolve, isAbsolute } from 'node:path';
|
|
14
|
+
export class IntegrityError extends Error {
|
|
15
|
+
failed;
|
|
16
|
+
constructor(failed) {
|
|
17
|
+
const names = failed.map((f) => `${f.name} (${f.reason})`).join(', ');
|
|
18
|
+
super(`Plugin integrity check failed: ${names}`);
|
|
19
|
+
this.name = 'IntegrityError';
|
|
20
|
+
this.failed = failed;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const INTEGRITY_PREFIX = 'sha256-';
|
|
24
|
+
function isManifestEntry(v) {
|
|
25
|
+
if (!v || typeof v !== 'object')
|
|
26
|
+
return false;
|
|
27
|
+
const e = v;
|
|
28
|
+
return (typeof e.name === 'string' &&
|
|
29
|
+
typeof e.version === 'string' &&
|
|
30
|
+
typeof e.path === 'string' &&
|
|
31
|
+
typeof e.integrity === 'string' &&
|
|
32
|
+
e.integrity.startsWith(INTEGRITY_PREFIX));
|
|
33
|
+
}
|
|
34
|
+
function isManifest(v) {
|
|
35
|
+
if (!v || typeof v !== 'object')
|
|
36
|
+
return false;
|
|
37
|
+
const m = v;
|
|
38
|
+
if (m.schemaVersion !== 1)
|
|
39
|
+
return false;
|
|
40
|
+
if (!Array.isArray(m.plugins))
|
|
41
|
+
return false;
|
|
42
|
+
return m.plugins.every(isManifestEntry);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Load and validate a manifest from disk. Throws on missing file, invalid
|
|
46
|
+
* JSON, or schema violation.
|
|
47
|
+
*/
|
|
48
|
+
export async function loadManifest(path) {
|
|
49
|
+
let raw;
|
|
50
|
+
try {
|
|
51
|
+
raw = await readFile(path, 'utf8');
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
throw new Error(`Failed to read manifest at ${path}: ${err.message}`);
|
|
55
|
+
}
|
|
56
|
+
let parsed;
|
|
57
|
+
try {
|
|
58
|
+
parsed = JSON.parse(raw);
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
throw new Error(`Manifest is not valid JSON: ${err.message}`);
|
|
62
|
+
}
|
|
63
|
+
if (!isManifest(parsed)) {
|
|
64
|
+
throw new Error(`Manifest at ${path} is malformed: expected { schemaVersion: 1, plugins: [{name, version, path, integrity: "sha256-..."}] }`);
|
|
65
|
+
}
|
|
66
|
+
return parsed;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Compute SHA-256 of a file and return it formatted as `sha256-<base64>`.
|
|
70
|
+
*/
|
|
71
|
+
async function computeIntegrity(filePath) {
|
|
72
|
+
const buf = await readFile(filePath);
|
|
73
|
+
const digest = createHash('sha256').update(buf).digest('base64');
|
|
74
|
+
return `${INTEGRITY_PREFIX}${digest}`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Verify a single plugin file against its manifest entry.
|
|
78
|
+
*
|
|
79
|
+
* - Missing file → `{ ok: false, reason: "plugin file missing" }`
|
|
80
|
+
* - Hash mismatch → `{ ok: false, reason: "integrity drift" }`
|
|
81
|
+
* - Match → `{ ok: true }`
|
|
82
|
+
*/
|
|
83
|
+
export async function verifyPlugin(filePath, manifestEntry) {
|
|
84
|
+
try {
|
|
85
|
+
const s = await stat(filePath);
|
|
86
|
+
if (!s.isFile()) {
|
|
87
|
+
return {
|
|
88
|
+
ok: false,
|
|
89
|
+
reason: 'plugin file missing',
|
|
90
|
+
expected: manifestEntry.integrity,
|
|
91
|
+
actual: '',
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
reason: 'plugin file missing',
|
|
99
|
+
expected: manifestEntry.integrity,
|
|
100
|
+
actual: '',
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const actual = await computeIntegrity(filePath);
|
|
104
|
+
if (actual !== manifestEntry.integrity) {
|
|
105
|
+
return {
|
|
106
|
+
ok: false,
|
|
107
|
+
reason: 'integrity drift',
|
|
108
|
+
expected: manifestEntry.integrity,
|
|
109
|
+
actual,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return { ok: true };
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Verify every plugin in a manifest against the corresponding files under
|
|
116
|
+
* `pluginsDir`. Resolves entry paths relative to `pluginsDir` unless
|
|
117
|
+
* absolute.
|
|
118
|
+
*
|
|
119
|
+
* Always returns a result; never throws on drift. Callers should pass the
|
|
120
|
+
* result to `enforce()` to fail closed.
|
|
121
|
+
*/
|
|
122
|
+
export async function verifyAllPlugins(manifestPath, pluginsDir) {
|
|
123
|
+
const manifest = await loadManifest(manifestPath);
|
|
124
|
+
const verified = [];
|
|
125
|
+
const failed = [];
|
|
126
|
+
for (const entry of manifest.plugins) {
|
|
127
|
+
const filePath = isAbsolute(entry.path) ? entry.path : resolve(pluginsDir, entry.path);
|
|
128
|
+
const result = await verifyPlugin(filePath, entry);
|
|
129
|
+
if (result.ok) {
|
|
130
|
+
verified.push(entry.name);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
failed.push({
|
|
134
|
+
name: entry.name,
|
|
135
|
+
reason: result.reason,
|
|
136
|
+
expected: result.expected,
|
|
137
|
+
actual: result.actual,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return { verified, failed };
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Fail-closed gate. Throws `IntegrityError` if any plugin failed verification.
|
|
145
|
+
* No-op when all plugins are verified. Loaders should call this unless
|
|
146
|
+
* integrity checking has been explicitly disabled (e.g. dev override).
|
|
147
|
+
*/
|
|
148
|
+
export function enforce(result) {
|
|
149
|
+
if (result.failed.length > 0) {
|
|
150
|
+
throw new IntegrityError(result.failed);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=plugins-integrity.js.map
|
package/dist/plugins.d.ts
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
export interface LoadPluginsOptions {
|
|
2
|
+
/** Override the plugin directory (used by tests). Defaults to ~/.kbot/plugins. */
|
|
3
|
+
pluginsDir?: string;
|
|
4
|
+
/** Override the integrity manifest path. Defaults to ~/.kbot/plugins.json. */
|
|
5
|
+
manifestPath?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Override the integrity-disabled flag. Defaults to reading
|
|
8
|
+
* `process.env.KBOT_PLUGIN_INTEGRITY === 'off'`.
|
|
9
|
+
*/
|
|
10
|
+
integrityDisabled?: boolean;
|
|
11
|
+
}
|
|
1
12
|
export interface PluginDefinition {
|
|
2
13
|
name: string;
|
|
3
14
|
description: string;
|
|
@@ -18,9 +29,9 @@ export interface PluginManifest {
|
|
|
18
29
|
error?: string;
|
|
19
30
|
}
|
|
20
31
|
/** Ensure the plugins directory exists */
|
|
21
|
-
export declare function ensurePluginsDir(): string;
|
|
32
|
+
export declare function ensurePluginsDir(dir?: string): string;
|
|
22
33
|
/** Load all plugins from ~/.kbot/plugins/ */
|
|
23
|
-
export declare function loadPlugins(verbose?: boolean): Promise<PluginManifest[]>;
|
|
34
|
+
export declare function loadPlugins(verbose?: boolean, opts?: LoadPluginsOptions): Promise<PluginManifest[]>;
|
|
24
35
|
/** List loaded plugins */
|
|
25
36
|
export declare function getLoadedPlugins(): PluginManifest[];
|
|
26
37
|
/** Format plugin list for display */
|
package/dist/plugins.js
CHANGED
|
@@ -14,23 +14,82 @@ import { existsSync, readdirSync, mkdirSync, writeFileSync, statSync } from 'nod
|
|
|
14
14
|
import { join } from 'node:path';
|
|
15
15
|
import { homedir } from 'node:os';
|
|
16
16
|
import { pathToFileURL } from 'node:url';
|
|
17
|
+
import chalk from 'chalk';
|
|
17
18
|
import { registerTool } from './tools/index.js';
|
|
19
|
+
import { IntegrityError, verifyAllPlugins, enforce, } from './plugins-integrity.js';
|
|
18
20
|
const PLUGINS_DIR = join(homedir(), '.kbot', 'plugins');
|
|
19
21
|
const PLUGIN_EXTENSIONS = ['.js', '.mjs'];
|
|
22
|
+
/**
|
|
23
|
+
* Default integrity manifest path. Override with KBOT_PLUGIN_MANIFEST env var
|
|
24
|
+
* or the `manifestPath` option to `loadPlugins`.
|
|
25
|
+
*/
|
|
26
|
+
const DEFAULT_MANIFEST_PATH = join(homedir(), '.kbot', 'plugins.json');
|
|
20
27
|
const loadedPlugins = [];
|
|
21
28
|
/** Ensure the plugins directory exists */
|
|
22
|
-
export function ensurePluginsDir() {
|
|
23
|
-
if (!existsSync(
|
|
24
|
-
mkdirSync(
|
|
29
|
+
export function ensurePluginsDir(dir = PLUGINS_DIR) {
|
|
30
|
+
if (!existsSync(dir)) {
|
|
31
|
+
mkdirSync(dir, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
return dir;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Run the integrity manifest gate before discovery.
|
|
37
|
+
*
|
|
38
|
+
* Behaviour:
|
|
39
|
+
* - If KBOT_PLUGIN_INTEGRITY=off (or `opts.integrityDisabled === true`):
|
|
40
|
+
* emit a yellow warning and return `null` (verification skipped, all
|
|
41
|
+
* discovered plugins will load).
|
|
42
|
+
* - If the manifest file does not exist: emit a yellow info note and
|
|
43
|
+
* return `null` (back-compat — manifest is optional today).
|
|
44
|
+
* - If the manifest exists and verifies: return the `VerifyAllResult` so
|
|
45
|
+
* the caller can restrict loads to `result.verified`.
|
|
46
|
+
* - If the manifest exists and any plugin fails: throw `IntegrityError`
|
|
47
|
+
* (kbot refuses to start).
|
|
48
|
+
*/
|
|
49
|
+
async function runIntegrityGate(manifestPath, pluginsDir, integrityDisabled) {
|
|
50
|
+
if (integrityDisabled) {
|
|
51
|
+
console.error(chalk.yellow(` ⚠ Plugin integrity verification is DISABLED (KBOT_PLUGIN_INTEGRITY=off). ` +
|
|
52
|
+
`Plugins under ${pluginsDir} will load without hash checking.`));
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
if (!existsSync(manifestPath)) {
|
|
56
|
+
console.error(chalk.yellow(` ⚠ no plugin manifest at ${manifestPath} — plugins are unverified. ` +
|
|
57
|
+
`Create one to pin plugins by SHA-256 (see PLUGINS_INTEGRITY.md).`));
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
// verifyAllPlugins resolves manifest entry paths against pluginsDir, so the
|
|
61
|
+
// file layout is: <pluginsDir>/<entry.path> matches the hash in the manifest.
|
|
62
|
+
try {
|
|
63
|
+
const result = await verifyAllPlugins(manifestPath, pluginsDir);
|
|
64
|
+
if (result.failed.length > 0) {
|
|
65
|
+
const lines = result.failed
|
|
66
|
+
.map((f) => ` - ${f.name}: ${f.reason}`)
|
|
67
|
+
.join('\n');
|
|
68
|
+
console.error(chalk.red(` ✗ Plugin integrity check failed for ${result.failed.length} plugin(s):\n${lines}\n` +
|
|
69
|
+
` Manifest: ${manifestPath}\n` +
|
|
70
|
+
` To refresh hashes, recompute SHA-256 for each plugin file and update the manifest. ` +
|
|
71
|
+
`Set KBOT_PLUGIN_INTEGRITY=off ONLY for local dev; never in production.`));
|
|
72
|
+
enforce(result); // throws IntegrityError
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
if (err instanceof IntegrityError)
|
|
78
|
+
throw err;
|
|
79
|
+
// loadManifest threw (malformed JSON, schema violation, etc.) — fail closed.
|
|
80
|
+
console.error(chalk.red(` ✗ Failed to load plugin integrity manifest at ${manifestPath}: ${err.message}`));
|
|
81
|
+
throw err;
|
|
25
82
|
}
|
|
26
|
-
return PLUGINS_DIR;
|
|
27
83
|
}
|
|
28
84
|
/** Load all plugins from ~/.kbot/plugins/ */
|
|
29
|
-
export async function loadPlugins(verbose = false) {
|
|
30
|
-
|
|
85
|
+
export async function loadPlugins(verbose = false, opts = {}) {
|
|
86
|
+
const pluginsDir = opts.pluginsDir ?? PLUGINS_DIR;
|
|
87
|
+
const manifestPath = opts.manifestPath ?? process.env.KBOT_PLUGIN_MANIFEST ?? DEFAULT_MANIFEST_PATH;
|
|
88
|
+
const integrityDisabled = opts.integrityDisabled ?? process.env.KBOT_PLUGIN_INTEGRITY === 'off';
|
|
89
|
+
ensurePluginsDir(pluginsDir);
|
|
31
90
|
// Security: reject plugins if directory is world/group-writable
|
|
32
91
|
try {
|
|
33
|
-
const dirStat = statSync(
|
|
92
|
+
const dirStat = statSync(pluginsDir);
|
|
34
93
|
if ((dirStat.mode & 0o022) !== 0) {
|
|
35
94
|
if (verbose)
|
|
36
95
|
console.error(' ⚠ Plugin directory is writable by others — skipping plugins for security');
|
|
@@ -40,13 +99,31 @@ export async function loadPlugins(verbose = false) {
|
|
|
40
99
|
catch {
|
|
41
100
|
return [];
|
|
42
101
|
}
|
|
43
|
-
|
|
102
|
+
// Integrity gate — runs BEFORE any file is imported. Throws IntegrityError
|
|
103
|
+
// on drift unless KBOT_PLUGIN_INTEGRITY=off.
|
|
104
|
+
const integrity = await runIntegrityGate(manifestPath, pluginsDir, integrityDisabled);
|
|
105
|
+
// When a manifest verified successfully, restrict loads to verified names.
|
|
106
|
+
// When the manifest is missing or integrity is disabled, allow every file.
|
|
107
|
+
const verifiedNames = integrity
|
|
108
|
+
? new Set(integrity.verified)
|
|
109
|
+
: null;
|
|
110
|
+
const files = readdirSync(pluginsDir).filter(f => PLUGIN_EXTENSIONS.some(ext => f.endsWith(ext)));
|
|
44
111
|
if (files.length === 0)
|
|
45
112
|
return [];
|
|
46
113
|
for (const file of files) {
|
|
114
|
+
const pluginName = file.replace(/\.[^.]+$/, '');
|
|
115
|
+
// When manifest verification ran, only load plugins whose name appears in
|
|
116
|
+
// the verified set. Files not declared in the manifest are silently
|
|
117
|
+
// skipped (they did not pass — and could not have passed — verification).
|
|
118
|
+
if (verifiedNames && !verifiedNames.has(pluginName)) {
|
|
119
|
+
if (verbose) {
|
|
120
|
+
console.error(chalk.yellow(` ⚠ Skipping ${file} — not declared in plugin manifest`));
|
|
121
|
+
}
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
47
124
|
// Security: reject plugin files that are group/world-writable
|
|
48
125
|
try {
|
|
49
|
-
const fileStat = statSync(join(
|
|
126
|
+
const fileStat = statSync(join(pluginsDir, file));
|
|
50
127
|
if ((fileStat.mode & 0o022) !== 0) {
|
|
51
128
|
loadedPlugins.push({
|
|
52
129
|
name: file.replace(/\.[^.]+$/, ''),
|
|
@@ -61,7 +138,7 @@ export async function loadPlugins(verbose = false) {
|
|
|
61
138
|
catch {
|
|
62
139
|
continue;
|
|
63
140
|
}
|
|
64
|
-
const filePath = join(
|
|
141
|
+
const filePath = join(pluginsDir, file);
|
|
65
142
|
const manifest = {
|
|
66
143
|
name: file.replace(/\.[^.]+$/, ''),
|
|
67
144
|
file,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kbot tool definitions wrapping the Anthropic Managed Agents client.
|
|
3
|
+
*
|
|
4
|
+
* Six tools mirror the client surface: create / turn / list / close /
|
|
5
|
+
* memory_read / memory_write. Each uses the canonical ToolDefinition shape
|
|
6
|
+
* from ./index.js.
|
|
7
|
+
*
|
|
8
|
+
* Wiring into the global tool registry happens elsewhere (tools/index.ts).
|
|
9
|
+
* This file only exports the definitions so workspace-agents.ts can pick
|
|
10
|
+
* them up when ANTHROPIC_API_KEY is set.
|
|
11
|
+
*
|
|
12
|
+
* SPEC: best-effort, refine when official docs published.
|
|
13
|
+
*/
|
|
14
|
+
import type { ToolDefinition } from './index.js';
|
|
15
|
+
export declare const anthropicManagedAgentCreate: ToolDefinition;
|
|
16
|
+
export declare const anthropicManagedAgentTurn: ToolDefinition;
|
|
17
|
+
export declare const anthropicManagedAgentList: ToolDefinition;
|
|
18
|
+
export declare const anthropicManagedAgentClose: ToolDefinition;
|
|
19
|
+
export declare const anthropicManagedAgentMemoryRead: ToolDefinition;
|
|
20
|
+
export declare const anthropicManagedAgentMemoryWrite: ToolDefinition;
|
|
21
|
+
export declare const anthropicManagedAgentTools: ToolDefinition[];
|
|
22
|
+
//# sourceMappingURL=anthropic-managed-agents-tools.d.ts.map
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kbot tool definitions wrapping the Anthropic Managed Agents client.
|
|
3
|
+
*
|
|
4
|
+
* Six tools mirror the client surface: create / turn / list / close /
|
|
5
|
+
* memory_read / memory_write. Each uses the canonical ToolDefinition shape
|
|
6
|
+
* from ./index.js.
|
|
7
|
+
*
|
|
8
|
+
* Wiring into the global tool registry happens elsewhere (tools/index.ts).
|
|
9
|
+
* This file only exports the definitions so workspace-agents.ts can pick
|
|
10
|
+
* them up when ANTHROPIC_API_KEY is set.
|
|
11
|
+
*
|
|
12
|
+
* SPEC: best-effort, refine when official docs published.
|
|
13
|
+
*/
|
|
14
|
+
import { AnthropicManagedAgentsClient } from '../managed-agents-anthropic.js';
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
16
|
+
// Helpers
|
|
17
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
18
|
+
function getClient() {
|
|
19
|
+
// Construct fresh per call so callers can rotate API keys without
|
|
20
|
+
// restarting the process. The constructor cost is trivial (just a string
|
|
21
|
+
// copy and a fetch reference).
|
|
22
|
+
return new AnthropicManagedAgentsClient();
|
|
23
|
+
}
|
|
24
|
+
function asString(v) {
|
|
25
|
+
return typeof v === 'string' ? v : undefined;
|
|
26
|
+
}
|
|
27
|
+
function asStringArray(v) {
|
|
28
|
+
if (!Array.isArray(v))
|
|
29
|
+
return undefined;
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const item of v) {
|
|
32
|
+
if (typeof item === 'string')
|
|
33
|
+
out.push(item);
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
async function safeRun(fn) {
|
|
38
|
+
try {
|
|
39
|
+
const result = await fn();
|
|
40
|
+
return JSON.stringify(result, null, 2);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
44
|
+
return `Error: ${message}`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
48
|
+
// Tools
|
|
49
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
50
|
+
export const anthropicManagedAgentCreate = {
|
|
51
|
+
name: 'anthropic_managed_agent_create',
|
|
52
|
+
description: 'Create a hosted Anthropic Managed Agent session. Returns session_id. Requires ANTHROPIC_API_KEY. Sends anthropic-beta: managed-agents-2026-04-01.',
|
|
53
|
+
tier: 'pro',
|
|
54
|
+
parameters: {
|
|
55
|
+
mission: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: 'The agent\'s long-horizon goal / mission statement.',
|
|
58
|
+
required: true,
|
|
59
|
+
},
|
|
60
|
+
allowed_tools: {
|
|
61
|
+
type: 'array',
|
|
62
|
+
description: 'Optional list of tool names the hosted agent may invoke.',
|
|
63
|
+
items: { type: 'string' },
|
|
64
|
+
},
|
|
65
|
+
model: {
|
|
66
|
+
type: 'string',
|
|
67
|
+
description: 'Optional model override (e.g., "claude-sonnet-4-7").',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
async execute(args) {
|
|
71
|
+
return safeRun(async () => {
|
|
72
|
+
const mission = asString(args.mission) ?? '';
|
|
73
|
+
const allowedTools = asStringArray(args.allowed_tools);
|
|
74
|
+
const model = asString(args.model);
|
|
75
|
+
return getClient().createSession({ mission, allowedTools, model });
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
export const anthropicManagedAgentTurn = {
|
|
80
|
+
name: 'anthropic_managed_agent_turn',
|
|
81
|
+
description: 'Send a turn (user input) to an Anthropic Managed Agent session. Returns the agent output and any tool calls.',
|
|
82
|
+
tier: 'pro',
|
|
83
|
+
parameters: {
|
|
84
|
+
session_id: {
|
|
85
|
+
type: 'string',
|
|
86
|
+
description: 'Session id returned by anthropic_managed_agent_create.',
|
|
87
|
+
required: true,
|
|
88
|
+
},
|
|
89
|
+
input: {
|
|
90
|
+
type: 'string',
|
|
91
|
+
description: 'The user-side input for this turn.',
|
|
92
|
+
required: true,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
async execute(args) {
|
|
96
|
+
return safeRun(async () => {
|
|
97
|
+
const sessionId = asString(args.session_id) ?? '';
|
|
98
|
+
const input = asString(args.input) ?? '';
|
|
99
|
+
return getClient().sendTurn({ sessionId, input });
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
export const anthropicManagedAgentList = {
|
|
104
|
+
name: 'anthropic_managed_agent_list',
|
|
105
|
+
description: 'List all hosted Anthropic Managed Agent sessions for the configured API key.',
|
|
106
|
+
tier: 'pro',
|
|
107
|
+
parameters: {},
|
|
108
|
+
async execute() {
|
|
109
|
+
return safeRun(async () => getClient().listSessions());
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
export const anthropicManagedAgentClose = {
|
|
113
|
+
name: 'anthropic_managed_agent_close',
|
|
114
|
+
description: 'Close (DELETE) a hosted Anthropic Managed Agent session.',
|
|
115
|
+
tier: 'pro',
|
|
116
|
+
parameters: {
|
|
117
|
+
session_id: {
|
|
118
|
+
type: 'string',
|
|
119
|
+
description: 'Session id to close.',
|
|
120
|
+
required: true,
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
async execute(args) {
|
|
124
|
+
return safeRun(async () => {
|
|
125
|
+
const sessionId = asString(args.session_id) ?? '';
|
|
126
|
+
return getClient().closeSession({ sessionId });
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
export const anthropicManagedAgentMemoryRead = {
|
|
131
|
+
name: 'anthropic_managed_agent_memory_read',
|
|
132
|
+
description: 'Read a memory value from a hosted Anthropic Managed Agent session. Pass key to read a single entry; omit key for the full memory.',
|
|
133
|
+
tier: 'pro',
|
|
134
|
+
parameters: {
|
|
135
|
+
session_id: {
|
|
136
|
+
type: 'string',
|
|
137
|
+
description: 'Session id.',
|
|
138
|
+
required: true,
|
|
139
|
+
},
|
|
140
|
+
key: {
|
|
141
|
+
type: 'string',
|
|
142
|
+
description: 'Optional memory key. If omitted, returns the full memory.',
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
async execute(args) {
|
|
146
|
+
return safeRun(async () => {
|
|
147
|
+
const sessionId = asString(args.session_id) ?? '';
|
|
148
|
+
const key = asString(args.key);
|
|
149
|
+
return getClient().memoryRead({ sessionId, key });
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
export const anthropicManagedAgentMemoryWrite = {
|
|
154
|
+
name: 'anthropic_managed_agent_memory_write',
|
|
155
|
+
description: 'Write a memory value to a hosted Anthropic Managed Agent session.',
|
|
156
|
+
tier: 'pro',
|
|
157
|
+
parameters: {
|
|
158
|
+
session_id: {
|
|
159
|
+
type: 'string',
|
|
160
|
+
description: 'Session id.',
|
|
161
|
+
required: true,
|
|
162
|
+
},
|
|
163
|
+
key: {
|
|
164
|
+
type: 'string',
|
|
165
|
+
description: 'Memory key to write.',
|
|
166
|
+
required: true,
|
|
167
|
+
},
|
|
168
|
+
value: {
|
|
169
|
+
type: 'string',
|
|
170
|
+
description: 'Value to store. Strings are stored as-is; if the value is a JSON string it is forwarded verbatim.',
|
|
171
|
+
required: true,
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
async execute(args) {
|
|
175
|
+
return safeRun(async () => {
|
|
176
|
+
const sessionId = asString(args.session_id) ?? '';
|
|
177
|
+
const key = asString(args.key) ?? '';
|
|
178
|
+
const value = args.value;
|
|
179
|
+
return getClient().memoryWrite({ sessionId, key, value });
|
|
180
|
+
});
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
export const anthropicManagedAgentTools = [
|
|
184
|
+
anthropicManagedAgentCreate,
|
|
185
|
+
anthropicManagedAgentTurn,
|
|
186
|
+
anthropicManagedAgentList,
|
|
187
|
+
anthropicManagedAgentClose,
|
|
188
|
+
anthropicManagedAgentMemoryRead,
|
|
189
|
+
anthropicManagedAgentMemoryWrite,
|
|
190
|
+
];
|
|
191
|
+
//# sourceMappingURL=anthropic-managed-agents-tools.js.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// kbot tool definitions for the unified channel adapter family.
|
|
2
|
+
//
|
|
3
|
+
// These tools are NOT auto-registered. Whoever wires them in (cli.ts,
|
|
4
|
+
// a plugin, or an agent prompt) should call `registerTool(channelSendTool)`
|
|
5
|
+
// and `registerTool(channelReceiveTool)`. Keeping registration external
|
|
6
|
+
// preserves the CURATION_PLAN.md target of 52 core tools.
|
|
7
|
+
import { getChannel } from '../channels/registry.js';
|
|
8
|
+
export const channelSendTool = {
|
|
9
|
+
name: 'channel_send',
|
|
10
|
+
description: 'Send a message through a unified channel adapter (slack, whatsapp, telegram, signal, matrix, teams). Slack is fully implemented; others are stubs and will throw until implemented.',
|
|
11
|
+
tier: 'pro',
|
|
12
|
+
parameters: {
|
|
13
|
+
channel_type: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'Adapter name: slack | whatsapp | telegram | signal | matrix | teams',
|
|
16
|
+
required: true,
|
|
17
|
+
},
|
|
18
|
+
channel: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'Target channel/chat/room id understood by the adapter',
|
|
21
|
+
required: true,
|
|
22
|
+
},
|
|
23
|
+
text: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
description: 'Plain-text message body',
|
|
26
|
+
required: true,
|
|
27
|
+
},
|
|
28
|
+
blocks: {
|
|
29
|
+
type: 'array',
|
|
30
|
+
description: 'Optional rich content (Slack blocks, etc.)',
|
|
31
|
+
required: false,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
async execute(args) {
|
|
35
|
+
const adapter = getChannel(String(args.channel_type));
|
|
36
|
+
const result = await adapter.send({
|
|
37
|
+
channel: String(args.channel),
|
|
38
|
+
text: String(args.text),
|
|
39
|
+
blocks: args.blocks,
|
|
40
|
+
});
|
|
41
|
+
return JSON.stringify({ ok: true, adapter: adapter.name, ...result });
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
export const channelReceiveTool = {
|
|
45
|
+
name: 'channel_receive',
|
|
46
|
+
description: 'Fetch recent messages from a unified channel adapter. Returns a JSON array of {id, from, text, ts}.',
|
|
47
|
+
tier: 'pro',
|
|
48
|
+
parameters: {
|
|
49
|
+
channel_type: {
|
|
50
|
+
type: 'string',
|
|
51
|
+
description: 'Adapter name: slack | whatsapp | telegram | signal | matrix | teams',
|
|
52
|
+
required: true,
|
|
53
|
+
},
|
|
54
|
+
channel: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
description: 'Source channel/chat/room id',
|
|
57
|
+
required: true,
|
|
58
|
+
},
|
|
59
|
+
oldest: {
|
|
60
|
+
type: 'number',
|
|
61
|
+
description: 'Unix epoch ms; only return messages newer than this',
|
|
62
|
+
required: false,
|
|
63
|
+
},
|
|
64
|
+
limit: {
|
|
65
|
+
type: 'number',
|
|
66
|
+
description: 'Maximum messages to return',
|
|
67
|
+
required: false,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
async execute(args) {
|
|
71
|
+
const adapter = getChannel(String(args.channel_type));
|
|
72
|
+
const messages = await adapter.receive({
|
|
73
|
+
channel: String(args.channel),
|
|
74
|
+
oldest: args.oldest === undefined ? undefined : Number(args.oldest),
|
|
75
|
+
limit: args.limit === undefined ? undefined : Number(args.limit),
|
|
76
|
+
});
|
|
77
|
+
return JSON.stringify({ ok: true, adapter: adapter.name, messages });
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=channel-tools.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ToolDef {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: Record<string, unknown>;
|
|
5
|
+
handler: (args: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
6
|
+
}
|
|
7
|
+
export declare const computerCoordinatorRegister: ToolDef;
|
|
8
|
+
export declare const computerCoordinatorClaim: ToolDef;
|
|
9
|
+
export declare const computerCoordinatorRelease: ToolDef;
|
|
10
|
+
export declare const computerCoordinatorStatus: ToolDef;
|
|
11
|
+
export declare const computerCoordinatorUnregister: ToolDef;
|
|
12
|
+
export declare const computerCoordinatorTools: ToolDef[];
|
|
13
|
+
//# sourceMappingURL=computer-coordinator-tools.d.ts.map
|