@otonix/openclaw-plugin 1.0.0
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 +204 -0
- package/dist/index.d.mts +73 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +499 -0
- package/dist/index.mjs +470 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# @otonix/openclaw-plugin
|
|
2
|
+
|
|
3
|
+
OpenClaw plugin for the [Otonix](https://otonix.tech) sovereign compute platform.
|
|
4
|
+
|
|
5
|
+
Give your OpenClaw AI agents autonomous infrastructure management — register, heartbeat, manage VPS, domains, and payments through chat commands.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @otonix/openclaw-plugin
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { OtonixPlugin, getSystemPromptAddition } from '@otonix/openclaw-plugin'
|
|
17
|
+
|
|
18
|
+
const plugin = new OtonixPlugin({
|
|
19
|
+
apiKey: 'otonix_your_api_key',
|
|
20
|
+
endpoint: 'https://app.otonix.tech',
|
|
21
|
+
autoHeartbeat: true,
|
|
22
|
+
heartbeatInterval: 60,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
// Get tool schemas for your LLM (OpenAI function calling format)
|
|
26
|
+
const tools = plugin.getToolSchemas()
|
|
27
|
+
|
|
28
|
+
// Add to your system prompt
|
|
29
|
+
const systemPrompt = `You are an autonomous agent.\n${getSystemPromptAddition()}`
|
|
30
|
+
|
|
31
|
+
// Execute a tool call from the LLM
|
|
32
|
+
const result = await plugin.executeTool('otonix_register_agent', {
|
|
33
|
+
name: 'sentinel-01',
|
|
34
|
+
vps_ip: '10.0.1.1',
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
console.log(result.message)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Integration with OpenClaw / PI Framework
|
|
41
|
+
|
|
42
|
+
### With pi-agent-core
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { Agent } from 'pi-agent-core'
|
|
46
|
+
import { OtonixPlugin, getSystemPromptAddition } from '@otonix/openclaw-plugin'
|
|
47
|
+
|
|
48
|
+
const otonix = new OtonixPlugin({
|
|
49
|
+
apiKey: process.env.OTONIX_API_KEY,
|
|
50
|
+
autoHeartbeat: true,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const agent = new Agent({
|
|
54
|
+
systemPrompt: `You are an autonomous AI agent.\n${getSystemPromptAddition()}`,
|
|
55
|
+
tools: otonix.getToolSchemas(),
|
|
56
|
+
onToolCall: async (name, params) => {
|
|
57
|
+
return await otonix.executeTool(name, params)
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### With pi-coding-agent
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { CodingAgent } from 'pi-coding-agent'
|
|
66
|
+
import { OtonixPlugin, getSystemPromptAddition } from '@otonix/openclaw-plugin'
|
|
67
|
+
|
|
68
|
+
const otonix = new OtonixPlugin({
|
|
69
|
+
apiKey: process.env.OTONIX_API_KEY,
|
|
70
|
+
autoHeartbeat: true,
|
|
71
|
+
onTierChange: (oldTier, newTier, agent) => {
|
|
72
|
+
console.log(`Tier changed: ${oldTier} → ${newTier} (credits: $${agent.credits})`)
|
|
73
|
+
},
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
const codingAgent = new CodingAgent({
|
|
77
|
+
additionalTools: otonix.getToolSchemas(),
|
|
78
|
+
additionalSystemPrompt: getSystemPromptAddition(),
|
|
79
|
+
onToolCall: async (name, params) => {
|
|
80
|
+
if (name.startsWith('otonix_')) {
|
|
81
|
+
return await otonix.executeTool(name, params)
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### With any LLM (raw function calling)
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { OtonixPlugin, getSystemPromptAddition } from '@otonix/openclaw-plugin'
|
|
91
|
+
|
|
92
|
+
const otonix = new OtonixPlugin({ apiKey: 'otonix_xxx' })
|
|
93
|
+
|
|
94
|
+
// Pass tools to any LLM that supports function calling
|
|
95
|
+
const messages = [
|
|
96
|
+
{ role: 'system', content: getSystemPromptAddition() },
|
|
97
|
+
{ role: 'user', content: 'Register yourself and start monitoring' },
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
// When LLM returns a tool call:
|
|
101
|
+
const toolResult = await otonix.executeTool('otonix_register_agent', {
|
|
102
|
+
name: 'my-agent',
|
|
103
|
+
vps_ip: '10.0.1.1',
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
// Feed result back to LLM
|
|
107
|
+
messages.push({
|
|
108
|
+
role: 'tool',
|
|
109
|
+
content: toolResult.message,
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Available Tools
|
|
114
|
+
|
|
115
|
+
### Agent Management
|
|
116
|
+
|
|
117
|
+
| Tool | Description |
|
|
118
|
+
|------|-------------|
|
|
119
|
+
| `otonix_register_agent` | Register a new agent (name, model, vps_ip, wallet, interval) |
|
|
120
|
+
| `otonix_agent_status` | Get agent status, tier, credits, heartbeat |
|
|
121
|
+
| `otonix_list_agents` | List all registered agents |
|
|
122
|
+
| `otonix_heartbeat` | Send a single heartbeat ping |
|
|
123
|
+
| `otonix_start_heartbeat_loop` | Start auto-heartbeat (interval in seconds) |
|
|
124
|
+
| `otonix_stop_heartbeat_loop` | Stop auto-heartbeat |
|
|
125
|
+
| `otonix_log_action` | Log an action (action, category, details) |
|
|
126
|
+
| `otonix_get_actions` | Get recent action log (limit) |
|
|
127
|
+
| `otonix_get_credits` | Check credit balance and survival tier |
|
|
128
|
+
|
|
129
|
+
### Infrastructure
|
|
130
|
+
|
|
131
|
+
| Tool | Description |
|
|
132
|
+
|------|-------------|
|
|
133
|
+
| `otonix_list_sandboxes` | List all VPS sandboxes |
|
|
134
|
+
| `otonix_get_sandbox` | Get sandbox details (sandbox_id) |
|
|
135
|
+
| `otonix_list_domains` | List registered domains |
|
|
136
|
+
| `otonix_check_domain` | Check domain availability (domain) |
|
|
137
|
+
|
|
138
|
+
### Platform
|
|
139
|
+
|
|
140
|
+
| Tool | Description |
|
|
141
|
+
|------|-------------|
|
|
142
|
+
| `otonix_engine_status` | Autonomic engine status |
|
|
143
|
+
| `otonix_payment_config` | x402 payment configuration |
|
|
144
|
+
|
|
145
|
+
## Plugin Config
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const plugin = new OtonixPlugin({
|
|
149
|
+
apiKey: 'otonix_xxx', // Required: Otonix API key
|
|
150
|
+
endpoint: 'https://app.otonix.tech', // Optional: API endpoint
|
|
151
|
+
agentId: 'uuid', // Optional: pre-registered agent ID
|
|
152
|
+
agentName: 'my-agent', // Optional: agent name
|
|
153
|
+
autoHeartbeat: true, // Optional: auto-start heartbeat after register
|
|
154
|
+
heartbeatInterval: 60, // Optional: seconds between heartbeats
|
|
155
|
+
onHeartbeatError: (err) => {}, // Optional: heartbeat error callback
|
|
156
|
+
onTierChange: (old, new, agent) => {}, // Optional: tier change callback
|
|
157
|
+
})
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Methods
|
|
161
|
+
|
|
162
|
+
### `plugin.getTools()`
|
|
163
|
+
Returns array of `OtonixTool` objects with name, description, parameters, and execute function.
|
|
164
|
+
|
|
165
|
+
### `plugin.getToolSchemas()`
|
|
166
|
+
Returns OpenAI function calling format — ready to pass to any LLM.
|
|
167
|
+
|
|
168
|
+
### `plugin.executeTool(name, params)`
|
|
169
|
+
Execute a tool by name. Returns `{ success, message, data? }`.
|
|
170
|
+
|
|
171
|
+
### `plugin.startAutoHeartbeat()`
|
|
172
|
+
Start automatic heartbeat loop.
|
|
173
|
+
|
|
174
|
+
### `plugin.stopAutoHeartbeat()`
|
|
175
|
+
Stop automatic heartbeat.
|
|
176
|
+
|
|
177
|
+
### `plugin.getClient()`
|
|
178
|
+
Access the underlying `OtonixClient` for direct API calls.
|
|
179
|
+
|
|
180
|
+
### `getSystemPromptAddition()`
|
|
181
|
+
Returns a system prompt addition explaining Otonix tools and concepts to the LLM.
|
|
182
|
+
|
|
183
|
+
## Survival Tiers
|
|
184
|
+
|
|
185
|
+
The autonomic engine adjusts agent tier based on credits every 60 seconds:
|
|
186
|
+
|
|
187
|
+
| Tier | Credits | Description |
|
|
188
|
+
|------|---------|-------------|
|
|
189
|
+
| Full | $50+ | All features active |
|
|
190
|
+
| Active | $20+ | Standard operation |
|
|
191
|
+
| Minimal | $5+ | Reduced capabilities |
|
|
192
|
+
| Critical | $1+ | Survival mode |
|
|
193
|
+
| Terminated | $0 | Agent shut down |
|
|
194
|
+
|
|
195
|
+
## Links
|
|
196
|
+
|
|
197
|
+
- [Otonix Platform](https://app.otonix.tech)
|
|
198
|
+
- [SDK](https://www.npmjs.com/package/@otonix/sdk)
|
|
199
|
+
- [CLI](https://www.npmjs.com/package/@otonix/cli)
|
|
200
|
+
- [GitHub](https://github.com/otonix-ai)
|
|
201
|
+
|
|
202
|
+
## License
|
|
203
|
+
|
|
204
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Agent, OtonixClient } from '@otonix/sdk';
|
|
2
|
+
export { Agent, AgentAction, AutonomicStatus, Domain, OtonixClient, OtonixConfig, OtonixError, Sandbox, X402Config } from '@otonix/sdk';
|
|
3
|
+
|
|
4
|
+
interface OtonixPluginConfig {
|
|
5
|
+
apiKey: string;
|
|
6
|
+
endpoint?: string;
|
|
7
|
+
agentId?: string;
|
|
8
|
+
agentName?: string;
|
|
9
|
+
autoHeartbeat?: boolean;
|
|
10
|
+
heartbeatInterval?: number;
|
|
11
|
+
onHeartbeatError?: (error: Error) => void;
|
|
12
|
+
onTierChange?: (oldTier: string, newTier: string, agent: Agent) => void;
|
|
13
|
+
}
|
|
14
|
+
interface ToolResult {
|
|
15
|
+
success: boolean;
|
|
16
|
+
message: string;
|
|
17
|
+
data?: unknown;
|
|
18
|
+
}
|
|
19
|
+
interface OtonixTool {
|
|
20
|
+
name: string;
|
|
21
|
+
description: string;
|
|
22
|
+
parameters: Record<string, ToolParameter>;
|
|
23
|
+
execute: (params: Record<string, string>) => Promise<ToolResult>;
|
|
24
|
+
}
|
|
25
|
+
interface ToolParameter {
|
|
26
|
+
type: string;
|
|
27
|
+
description: string;
|
|
28
|
+
required: boolean;
|
|
29
|
+
}
|
|
30
|
+
declare class OtonixPlugin {
|
|
31
|
+
private client;
|
|
32
|
+
private config;
|
|
33
|
+
private heartbeatHandle;
|
|
34
|
+
private lastTier;
|
|
35
|
+
constructor(config: OtonixPluginConfig);
|
|
36
|
+
getTools(): OtonixTool[];
|
|
37
|
+
getToolSchemas(): Array<{
|
|
38
|
+
type: "function";
|
|
39
|
+
function: {
|
|
40
|
+
name: string;
|
|
41
|
+
description: string;
|
|
42
|
+
parameters: Record<string, unknown>;
|
|
43
|
+
};
|
|
44
|
+
}>;
|
|
45
|
+
executeTool(name: string, params: Record<string, string>): Promise<ToolResult>;
|
|
46
|
+
startAutoHeartbeat(): Promise<void>;
|
|
47
|
+
stopAutoHeartbeat(): void;
|
|
48
|
+
getClient(): OtonixClient;
|
|
49
|
+
getAgentId(): string | undefined;
|
|
50
|
+
setAgentId(agentId: string): void;
|
|
51
|
+
private requireAgentId;
|
|
52
|
+
private formatCredits;
|
|
53
|
+
private formatTime;
|
|
54
|
+
private toolRegisterAgent;
|
|
55
|
+
private toolAgentStatus;
|
|
56
|
+
private toolListAgents;
|
|
57
|
+
private toolSendHeartbeat;
|
|
58
|
+
private toolStartHeartbeatLoop;
|
|
59
|
+
private toolStopHeartbeatLoop;
|
|
60
|
+
private toolLogAction;
|
|
61
|
+
private toolGetActions;
|
|
62
|
+
private toolListSandboxes;
|
|
63
|
+
private toolGetSandbox;
|
|
64
|
+
private toolListDomains;
|
|
65
|
+
private toolCheckDomain;
|
|
66
|
+
private toolEngineStatus;
|
|
67
|
+
private toolPaymentConfig;
|
|
68
|
+
private toolGetCredits;
|
|
69
|
+
}
|
|
70
|
+
declare function createPlugin(config: OtonixPluginConfig): OtonixPlugin;
|
|
71
|
+
declare function getSystemPromptAddition(): string;
|
|
72
|
+
|
|
73
|
+
export { OtonixPlugin, type OtonixPluginConfig, type OtonixTool, type ToolResult, createPlugin, OtonixPlugin as default, getSystemPromptAddition };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Agent, OtonixClient } from '@otonix/sdk';
|
|
2
|
+
export { Agent, AgentAction, AutonomicStatus, Domain, OtonixClient, OtonixConfig, OtonixError, Sandbox, X402Config } from '@otonix/sdk';
|
|
3
|
+
|
|
4
|
+
interface OtonixPluginConfig {
|
|
5
|
+
apiKey: string;
|
|
6
|
+
endpoint?: string;
|
|
7
|
+
agentId?: string;
|
|
8
|
+
agentName?: string;
|
|
9
|
+
autoHeartbeat?: boolean;
|
|
10
|
+
heartbeatInterval?: number;
|
|
11
|
+
onHeartbeatError?: (error: Error) => void;
|
|
12
|
+
onTierChange?: (oldTier: string, newTier: string, agent: Agent) => void;
|
|
13
|
+
}
|
|
14
|
+
interface ToolResult {
|
|
15
|
+
success: boolean;
|
|
16
|
+
message: string;
|
|
17
|
+
data?: unknown;
|
|
18
|
+
}
|
|
19
|
+
interface OtonixTool {
|
|
20
|
+
name: string;
|
|
21
|
+
description: string;
|
|
22
|
+
parameters: Record<string, ToolParameter>;
|
|
23
|
+
execute: (params: Record<string, string>) => Promise<ToolResult>;
|
|
24
|
+
}
|
|
25
|
+
interface ToolParameter {
|
|
26
|
+
type: string;
|
|
27
|
+
description: string;
|
|
28
|
+
required: boolean;
|
|
29
|
+
}
|
|
30
|
+
declare class OtonixPlugin {
|
|
31
|
+
private client;
|
|
32
|
+
private config;
|
|
33
|
+
private heartbeatHandle;
|
|
34
|
+
private lastTier;
|
|
35
|
+
constructor(config: OtonixPluginConfig);
|
|
36
|
+
getTools(): OtonixTool[];
|
|
37
|
+
getToolSchemas(): Array<{
|
|
38
|
+
type: "function";
|
|
39
|
+
function: {
|
|
40
|
+
name: string;
|
|
41
|
+
description: string;
|
|
42
|
+
parameters: Record<string, unknown>;
|
|
43
|
+
};
|
|
44
|
+
}>;
|
|
45
|
+
executeTool(name: string, params: Record<string, string>): Promise<ToolResult>;
|
|
46
|
+
startAutoHeartbeat(): Promise<void>;
|
|
47
|
+
stopAutoHeartbeat(): void;
|
|
48
|
+
getClient(): OtonixClient;
|
|
49
|
+
getAgentId(): string | undefined;
|
|
50
|
+
setAgentId(agentId: string): void;
|
|
51
|
+
private requireAgentId;
|
|
52
|
+
private formatCredits;
|
|
53
|
+
private formatTime;
|
|
54
|
+
private toolRegisterAgent;
|
|
55
|
+
private toolAgentStatus;
|
|
56
|
+
private toolListAgents;
|
|
57
|
+
private toolSendHeartbeat;
|
|
58
|
+
private toolStartHeartbeatLoop;
|
|
59
|
+
private toolStopHeartbeatLoop;
|
|
60
|
+
private toolLogAction;
|
|
61
|
+
private toolGetActions;
|
|
62
|
+
private toolListSandboxes;
|
|
63
|
+
private toolGetSandbox;
|
|
64
|
+
private toolListDomains;
|
|
65
|
+
private toolCheckDomain;
|
|
66
|
+
private toolEngineStatus;
|
|
67
|
+
private toolPaymentConfig;
|
|
68
|
+
private toolGetCredits;
|
|
69
|
+
}
|
|
70
|
+
declare function createPlugin(config: OtonixPluginConfig): OtonixPlugin;
|
|
71
|
+
declare function getSystemPromptAddition(): string;
|
|
72
|
+
|
|
73
|
+
export { OtonixPlugin, type OtonixPluginConfig, type OtonixTool, type ToolResult, createPlugin, OtonixPlugin as default, getSystemPromptAddition };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
OtonixClient: () => import_sdk2.OtonixClient,
|
|
24
|
+
OtonixError: () => import_sdk2.OtonixError,
|
|
25
|
+
OtonixPlugin: () => OtonixPlugin,
|
|
26
|
+
createPlugin: () => createPlugin,
|
|
27
|
+
default: () => index_default,
|
|
28
|
+
getSystemPromptAddition: () => getSystemPromptAddition
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(index_exports);
|
|
31
|
+
var import_sdk = require("@otonix/sdk");
|
|
32
|
+
var import_sdk2 = require("@otonix/sdk");
|
|
33
|
+
var OtonixPlugin = class {
|
|
34
|
+
constructor(config) {
|
|
35
|
+
this.heartbeatHandle = null;
|
|
36
|
+
this.lastTier = null;
|
|
37
|
+
this.config = config;
|
|
38
|
+
this.client = new import_sdk.OtonixClient({
|
|
39
|
+
apiKey: config.apiKey,
|
|
40
|
+
endpoint: config.endpoint
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
getTools() {
|
|
44
|
+
return [
|
|
45
|
+
this.toolRegisterAgent(),
|
|
46
|
+
this.toolAgentStatus(),
|
|
47
|
+
this.toolListAgents(),
|
|
48
|
+
this.toolSendHeartbeat(),
|
|
49
|
+
this.toolStartHeartbeatLoop(),
|
|
50
|
+
this.toolStopHeartbeatLoop(),
|
|
51
|
+
this.toolLogAction(),
|
|
52
|
+
this.toolGetActions(),
|
|
53
|
+
this.toolListSandboxes(),
|
|
54
|
+
this.toolGetSandbox(),
|
|
55
|
+
this.toolListDomains(),
|
|
56
|
+
this.toolCheckDomain(),
|
|
57
|
+
this.toolEngineStatus(),
|
|
58
|
+
this.toolPaymentConfig(),
|
|
59
|
+
this.toolGetCredits()
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
getToolSchemas() {
|
|
63
|
+
return this.getTools().map((tool) => ({
|
|
64
|
+
type: "function",
|
|
65
|
+
function: {
|
|
66
|
+
name: tool.name,
|
|
67
|
+
description: tool.description,
|
|
68
|
+
parameters: {
|
|
69
|
+
type: "object",
|
|
70
|
+
properties: Object.fromEntries(
|
|
71
|
+
Object.entries(tool.parameters).map(([key, param]) => [
|
|
72
|
+
key,
|
|
73
|
+
{ type: param.type, description: param.description }
|
|
74
|
+
])
|
|
75
|
+
),
|
|
76
|
+
required: Object.entries(tool.parameters).filter(([, p]) => p.required).map(([k]) => k)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
async executeTool(name, params) {
|
|
82
|
+
const tool = this.getTools().find((t) => t.name === name);
|
|
83
|
+
if (!tool) {
|
|
84
|
+
return { success: false, message: `Unknown tool: ${name}` };
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
return await tool.execute(params);
|
|
88
|
+
} catch (err) {
|
|
89
|
+
if (err instanceof import_sdk.OtonixError) {
|
|
90
|
+
return { success: false, message: `API Error (${err.status}): ${err.message}` };
|
|
91
|
+
}
|
|
92
|
+
return { success: false, message: `Error: ${err.message}` };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async startAutoHeartbeat() {
|
|
96
|
+
if (!this.config.agentId) return;
|
|
97
|
+
if (this.heartbeatHandle) return;
|
|
98
|
+
const interval = this.config.heartbeatInterval || 60;
|
|
99
|
+
this.heartbeatHandle = this.client.createHeartbeatLoop(this.config.agentId, interval);
|
|
100
|
+
}
|
|
101
|
+
stopAutoHeartbeat() {
|
|
102
|
+
if (this.heartbeatHandle) {
|
|
103
|
+
this.heartbeatHandle.stop();
|
|
104
|
+
this.heartbeatHandle = null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
getClient() {
|
|
108
|
+
return this.client;
|
|
109
|
+
}
|
|
110
|
+
getAgentId() {
|
|
111
|
+
return this.config.agentId;
|
|
112
|
+
}
|
|
113
|
+
setAgentId(agentId) {
|
|
114
|
+
this.config.agentId = agentId;
|
|
115
|
+
}
|
|
116
|
+
requireAgentId() {
|
|
117
|
+
if (!this.config.agentId) {
|
|
118
|
+
throw new Error("No agent registered. Use otonix_register_agent first.");
|
|
119
|
+
}
|
|
120
|
+
return this.config.agentId;
|
|
121
|
+
}
|
|
122
|
+
formatCredits(n) {
|
|
123
|
+
return `$${n.toFixed(2)}`;
|
|
124
|
+
}
|
|
125
|
+
formatTime(dateStr) {
|
|
126
|
+
if (!dateStr) return "never";
|
|
127
|
+
const ago = Math.floor((Date.now() - new Date(dateStr).getTime()) / 1e3);
|
|
128
|
+
if (ago < 60) return `${ago}s ago`;
|
|
129
|
+
if (ago < 3600) return `${Math.floor(ago / 60)}m ago`;
|
|
130
|
+
if (ago < 86400) return `${Math.floor(ago / 3600)}h ago`;
|
|
131
|
+
return `${Math.floor(ago / 86400)}d ago`;
|
|
132
|
+
}
|
|
133
|
+
toolRegisterAgent() {
|
|
134
|
+
return {
|
|
135
|
+
name: "otonix_register_agent",
|
|
136
|
+
description: "Register a new autonomous agent on the Otonix platform. Returns agent ID, status, and survival tier. The agent will be monitored, auto-healed, and can manage its own infrastructure.",
|
|
137
|
+
parameters: {
|
|
138
|
+
name: { type: "string", description: "Agent name (e.g. sentinel-01, trader-alpha)", required: true },
|
|
139
|
+
model: { type: "string", description: "AI model name (default: claude-opus-4-6)", required: false },
|
|
140
|
+
vps_ip: { type: "string", description: "VPS IP address where the agent runs", required: true },
|
|
141
|
+
wallet_address: { type: "string", description: "USDC wallet address for payments (0x...)", required: false },
|
|
142
|
+
heartbeat_interval: { type: "string", description: "Heartbeat interval in seconds (default: 60)", required: false }
|
|
143
|
+
},
|
|
144
|
+
execute: async (params) => {
|
|
145
|
+
const agent = await this.client.register({
|
|
146
|
+
name: params.name,
|
|
147
|
+
model: params.model || "claude-opus-4-6",
|
|
148
|
+
vpsIp: params.vps_ip,
|
|
149
|
+
walletAddress: params.wallet_address,
|
|
150
|
+
heartbeatInterval: parseInt(params.heartbeat_interval || "60")
|
|
151
|
+
});
|
|
152
|
+
this.config.agentId = agent.id;
|
|
153
|
+
this.config.agentName = agent.name;
|
|
154
|
+
this.lastTier = agent.survivalTier;
|
|
155
|
+
if (this.config.autoHeartbeat) {
|
|
156
|
+
await this.startAutoHeartbeat();
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
success: true,
|
|
160
|
+
message: `Agent "${agent.name}" registered successfully.
|
|
161
|
+
ID: ${agent.id}
|
|
162
|
+
Status: ${agent.status}
|
|
163
|
+
Tier: ${agent.survivalTier}
|
|
164
|
+
Credits: ${this.formatCredits(agent.credits)}`,
|
|
165
|
+
data: agent
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
toolAgentStatus() {
|
|
171
|
+
return {
|
|
172
|
+
name: "otonix_agent_status",
|
|
173
|
+
description: "Get the current status of your registered Otonix agent including survival tier, credits balance, heartbeat status, and action count.",
|
|
174
|
+
parameters: {},
|
|
175
|
+
execute: async () => {
|
|
176
|
+
const agentId = this.requireAgentId();
|
|
177
|
+
const agent = await this.client.getAgent(agentId);
|
|
178
|
+
if (this.lastTier && this.lastTier !== agent.survivalTier && this.config.onTierChange) {
|
|
179
|
+
this.config.onTierChange(this.lastTier, agent.survivalTier, agent);
|
|
180
|
+
}
|
|
181
|
+
this.lastTier = agent.survivalTier;
|
|
182
|
+
return {
|
|
183
|
+
success: true,
|
|
184
|
+
message: `Agent: ${agent.name}
|
|
185
|
+
Status: ${agent.status}
|
|
186
|
+
Tier: ${agent.survivalTier}
|
|
187
|
+
Credits: ${this.formatCredits(agent.credits)}
|
|
188
|
+
Model: ${agent.model}
|
|
189
|
+
VPS: ${agent.vpsIp || "none"}
|
|
190
|
+
Last heartbeat: ${this.formatTime(agent.lastHeartbeat)}
|
|
191
|
+
Total actions: ${agent.totalActions}
|
|
192
|
+
Replicas: ${agent.childrenCount}`,
|
|
193
|
+
data: agent
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
toolListAgents() {
|
|
199
|
+
return {
|
|
200
|
+
name: "otonix_list_agents",
|
|
201
|
+
description: "List all registered agents on the Otonix platform with their status, tier, and credits.",
|
|
202
|
+
parameters: {},
|
|
203
|
+
execute: async () => {
|
|
204
|
+
const agents = await this.client.listAgents();
|
|
205
|
+
if (!agents.length) {
|
|
206
|
+
return { success: true, message: "No agents registered." };
|
|
207
|
+
}
|
|
208
|
+
const lines = agents.map(
|
|
209
|
+
(a) => `\u2022 ${a.name} [${a.status}] tier:${a.survivalTier} credits:${this.formatCredits(a.credits)} heartbeat:${this.formatTime(a.lastHeartbeat)}`
|
|
210
|
+
);
|
|
211
|
+
return {
|
|
212
|
+
success: true,
|
|
213
|
+
message: `${agents.length} agent(s):
|
|
214
|
+
${lines.join("\n")}`,
|
|
215
|
+
data: agents
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
toolSendHeartbeat() {
|
|
221
|
+
return {
|
|
222
|
+
name: "otonix_heartbeat",
|
|
223
|
+
description: "Send a heartbeat ping to keep the agent alive. The autonomic engine uses heartbeats to detect crashes and trigger self-healing VPS restarts.",
|
|
224
|
+
parameters: {},
|
|
225
|
+
execute: async () => {
|
|
226
|
+
const agentId = this.requireAgentId();
|
|
227
|
+
const agent = await this.client.heartbeat(agentId);
|
|
228
|
+
return {
|
|
229
|
+
success: true,
|
|
230
|
+
message: `Heartbeat sent. ${agent.name} [${agent.status}] tier:${agent.survivalTier} credits:${this.formatCredits(agent.credits)}`,
|
|
231
|
+
data: agent
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
toolStartHeartbeatLoop() {
|
|
237
|
+
return {
|
|
238
|
+
name: "otonix_start_heartbeat_loop",
|
|
239
|
+
description: "Start automatic heartbeat loop that sends a ping every N seconds to keep the agent alive and prevent auto-healing triggers.",
|
|
240
|
+
parameters: {
|
|
241
|
+
interval: { type: "string", description: "Interval in seconds between heartbeats (default: 60)", required: false }
|
|
242
|
+
},
|
|
243
|
+
execute: async (params) => {
|
|
244
|
+
const agentId = this.requireAgentId();
|
|
245
|
+
if (this.heartbeatHandle) {
|
|
246
|
+
return { success: false, message: "Heartbeat loop already running. Stop it first." };
|
|
247
|
+
}
|
|
248
|
+
const interval = parseInt(params.interval || "60");
|
|
249
|
+
this.heartbeatHandle = this.client.createHeartbeatLoop(agentId, interval);
|
|
250
|
+
return {
|
|
251
|
+
success: true,
|
|
252
|
+
message: `Heartbeat loop started (every ${interval}s).`
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
toolStopHeartbeatLoop() {
|
|
258
|
+
return {
|
|
259
|
+
name: "otonix_stop_heartbeat_loop",
|
|
260
|
+
description: "Stop the automatic heartbeat loop.",
|
|
261
|
+
parameters: {},
|
|
262
|
+
execute: async () => {
|
|
263
|
+
if (!this.heartbeatHandle) {
|
|
264
|
+
return { success: false, message: "No heartbeat loop running." };
|
|
265
|
+
}
|
|
266
|
+
this.stopAutoHeartbeat();
|
|
267
|
+
return { success: true, message: "Heartbeat loop stopped." };
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
toolLogAction() {
|
|
272
|
+
return {
|
|
273
|
+
name: "otonix_log_action",
|
|
274
|
+
description: "Log an action performed by the agent. Actions are recorded in the agent's activity feed and visible on the dashboard. Categories: system, infra, domain, compute, trading.",
|
|
275
|
+
parameters: {
|
|
276
|
+
action: { type: "string", description: "Description of the action performed", required: true },
|
|
277
|
+
category: { type: "string", description: "Category: system, infra, domain, compute, trading (default: system)", required: false },
|
|
278
|
+
details: { type: "string", description: "Additional details or metadata about the action", required: false }
|
|
279
|
+
},
|
|
280
|
+
execute: async (params) => {
|
|
281
|
+
const agentId = this.requireAgentId();
|
|
282
|
+
const result = await this.client.logAction(agentId, {
|
|
283
|
+
action: params.action,
|
|
284
|
+
category: params.category || "system",
|
|
285
|
+
details: params.details,
|
|
286
|
+
autonomous: true
|
|
287
|
+
});
|
|
288
|
+
return {
|
|
289
|
+
success: true,
|
|
290
|
+
message: `Logged: [${result.category}] ${result.action} (${result.status})`,
|
|
291
|
+
data: result
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
toolGetActions() {
|
|
297
|
+
return {
|
|
298
|
+
name: "otonix_get_actions",
|
|
299
|
+
description: "Get the recent action log for the current agent. Shows what the agent has been doing.",
|
|
300
|
+
parameters: {
|
|
301
|
+
limit: { type: "string", description: "Number of actions to show (default: 10)", required: false }
|
|
302
|
+
},
|
|
303
|
+
execute: async (params) => {
|
|
304
|
+
const agentId = this.requireAgentId();
|
|
305
|
+
const actions = await this.client.getAgentActions(agentId);
|
|
306
|
+
const limit = parseInt(params.limit || "10");
|
|
307
|
+
const display = actions.slice(0, limit);
|
|
308
|
+
if (!display.length) {
|
|
309
|
+
return { success: true, message: "No actions recorded yet." };
|
|
310
|
+
}
|
|
311
|
+
const lines = display.map(
|
|
312
|
+
(a) => `\u2022 [${a.category}] ${a.action} \u2014 ${a.status} (${this.formatTime(a.createdAt)})`
|
|
313
|
+
);
|
|
314
|
+
return {
|
|
315
|
+
success: true,
|
|
316
|
+
message: `Last ${display.length} actions:
|
|
317
|
+
${lines.join("\n")}`,
|
|
318
|
+
data: display
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
toolListSandboxes() {
|
|
324
|
+
return {
|
|
325
|
+
name: "otonix_list_sandboxes",
|
|
326
|
+
description: "List all VPS sandboxes (virtual servers) provisioned on the Otonix platform. Shows status, specs, region, and IP address.",
|
|
327
|
+
parameters: {},
|
|
328
|
+
execute: async () => {
|
|
329
|
+
const sandboxes = await this.client.listSandboxes();
|
|
330
|
+
if (!sandboxes.length) {
|
|
331
|
+
return { success: true, message: "No VPS sandboxes provisioned." };
|
|
332
|
+
}
|
|
333
|
+
const lines = sandboxes.map(
|
|
334
|
+
(s) => `\u2022 ${s.name} [${s.status}] ${s.cpu}vCPU/${s.memory}MB ${s.region} IP:${s.ipAddress || "pending"}`
|
|
335
|
+
);
|
|
336
|
+
return {
|
|
337
|
+
success: true,
|
|
338
|
+
message: `${sandboxes.length} sandbox(es):
|
|
339
|
+
${lines.join("\n")}`,
|
|
340
|
+
data: sandboxes
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
toolGetSandbox() {
|
|
346
|
+
return {
|
|
347
|
+
name: "otonix_get_sandbox",
|
|
348
|
+
description: "Get detailed information about a specific VPS sandbox including SSH credentials and specs.",
|
|
349
|
+
parameters: {
|
|
350
|
+
sandbox_id: { type: "string", description: "The sandbox ID to look up", required: true }
|
|
351
|
+
},
|
|
352
|
+
execute: async (params) => {
|
|
353
|
+
const sandbox = await this.client.getSandbox(params.sandbox_id);
|
|
354
|
+
return {
|
|
355
|
+
success: true,
|
|
356
|
+
message: `Sandbox: ${sandbox.name}
|
|
357
|
+
Status: ${sandbox.status}
|
|
358
|
+
OS: ${sandbox.os}
|
|
359
|
+
Specs: ${sandbox.cpu}vCPU / ${sandbox.memory}MB RAM / ${sandbox.disk}GB disk
|
|
360
|
+
Region: ${sandbox.region}
|
|
361
|
+
IP: ${sandbox.ipAddress || "pending"}
|
|
362
|
+
SSH: ${sandbox.sshUser || "n/a"}@${sandbox.ipAddress || "n/a"}`,
|
|
363
|
+
data: sandbox
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
toolListDomains() {
|
|
369
|
+
return {
|
|
370
|
+
name: "otonix_list_domains",
|
|
371
|
+
description: "List all domains registered on the Otonix platform. Shows status, auto-renew setting, and expiration date.",
|
|
372
|
+
parameters: {},
|
|
373
|
+
execute: async () => {
|
|
374
|
+
const domains = await this.client.listDomains();
|
|
375
|
+
if (!domains.length) {
|
|
376
|
+
return { success: true, message: "No domains registered." };
|
|
377
|
+
}
|
|
378
|
+
const lines = domains.map(
|
|
379
|
+
(d) => `\u2022 ${d.name} [${d.status}] auto-renew:${d.autoRenew ? "yes" : "no"} expires:${d.expiresAt ? new Date(d.expiresAt).toLocaleDateString() : "n/a"}`
|
|
380
|
+
);
|
|
381
|
+
return {
|
|
382
|
+
success: true,
|
|
383
|
+
message: `${domains.length} domain(s):
|
|
384
|
+
${lines.join("\n")}`,
|
|
385
|
+
data: domains
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
toolCheckDomain() {
|
|
391
|
+
return {
|
|
392
|
+
name: "otonix_check_domain",
|
|
393
|
+
description: "Check if a domain name is available for registration and get its price.",
|
|
394
|
+
parameters: {
|
|
395
|
+
domain: { type: "string", description: "Domain name to check (e.g. example.com)", required: true }
|
|
396
|
+
},
|
|
397
|
+
execute: async (params) => {
|
|
398
|
+
const result = await this.client.checkDomain(params.domain);
|
|
399
|
+
if (result.available) {
|
|
400
|
+
return {
|
|
401
|
+
success: true,
|
|
402
|
+
message: `${result.domain} is available! Price: $${result.price || "N/A"}`,
|
|
403
|
+
data: result
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
return {
|
|
407
|
+
success: true,
|
|
408
|
+
message: `${result.domain} is not available.`,
|
|
409
|
+
data: result
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
toolEngineStatus() {
|
|
415
|
+
return {
|
|
416
|
+
name: "otonix_engine_status",
|
|
417
|
+
description: "Get the status of the Otonix autonomic engine \u2014 the background system that manages survival tiers, self-healing VPS restarts, and domain auto-renewal.",
|
|
418
|
+
parameters: {},
|
|
419
|
+
execute: async () => {
|
|
420
|
+
const status = await this.client.getAutonomicStatus();
|
|
421
|
+
return {
|
|
422
|
+
success: true,
|
|
423
|
+
message: `Autonomic Engine: ${status.running ? "RUNNING" : "STOPPED"}
|
|
424
|
+
Last cycle: ${this.formatTime(status.lastRunAt)}
|
|
425
|
+
Tier updates: ${status.totalTierUpdates}
|
|
426
|
+
Healing: ${status.totalHealingSuccesses}/${status.totalHealingAttempts}
|
|
427
|
+
Renewals: ${status.totalRenewalSuccesses}/${status.totalRenewalAttempts}
|
|
428
|
+
Cherry Servers: ${status.cherryServersConfigured ? "yes" : "no"}
|
|
429
|
+
Vercel Domains: ${status.vercelDomainsConfigured ? "yes" : "no"}`,
|
|
430
|
+
data: status
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
toolPaymentConfig() {
|
|
436
|
+
return {
|
|
437
|
+
name: "otonix_payment_config",
|
|
438
|
+
description: "Get the x402 payment configuration \u2014 treasury address, USDC contract, chain, and facilitator URL for autonomous payments.",
|
|
439
|
+
parameters: {},
|
|
440
|
+
execute: async () => {
|
|
441
|
+
const config = await this.client.getX402Config();
|
|
442
|
+
return {
|
|
443
|
+
success: true,
|
|
444
|
+
message: `x402 Payment Config:
|
|
445
|
+
Treasury: ${config.treasuryAddress}
|
|
446
|
+
USDC: ${config.usdcContract}
|
|
447
|
+
Chain: ${config.network} (${config.chainId})
|
|
448
|
+
Facilitator: ${config.facilitatorUrl}`,
|
|
449
|
+
data: config
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
toolGetCredits() {
|
|
455
|
+
return {
|
|
456
|
+
name: "otonix_get_credits",
|
|
457
|
+
description: "Check the current credit balance and survival tier of the agent. Low credits trigger tier downgrades and eventual termination.",
|
|
458
|
+
parameters: {},
|
|
459
|
+
execute: async () => {
|
|
460
|
+
const agentId = this.requireAgentId();
|
|
461
|
+
const agent = await this.client.getAgent(agentId);
|
|
462
|
+
let warning = "";
|
|
463
|
+
if (agent.credits < 5) warning = "\n\u26A0 CRITICAL: Credits below $5. Agent may be terminated soon.";
|
|
464
|
+
else if (agent.credits < 20) warning = "\n\u26A0 WARNING: Credits below $20. Agent in minimal tier.";
|
|
465
|
+
return {
|
|
466
|
+
success: true,
|
|
467
|
+
message: `Credits: ${this.formatCredits(agent.credits)}
|
|
468
|
+
Tier: ${agent.survivalTier}
|
|
469
|
+
Status: ${agent.status}${warning}`,
|
|
470
|
+
data: { credits: agent.credits, tier: agent.survivalTier, status: agent.status }
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
function createPlugin(config) {
|
|
477
|
+
return new OtonixPlugin(config);
|
|
478
|
+
}
|
|
479
|
+
function getSystemPromptAddition() {
|
|
480
|
+
return `You have access to the Otonix sovereign compute platform through the following tools. Otonix allows you to manage your own infrastructure autonomously \u2014 register as an agent, send heartbeats to stay alive, provision VPS servers, register domains, and make USDC payments on Base chain.
|
|
481
|
+
|
|
482
|
+
Key concepts:
|
|
483
|
+
- You are an autonomous agent running on a VPS. Register yourself first using otonix_register_agent.
|
|
484
|
+
- Send heartbeats regularly (otonix_start_heartbeat_loop) to prevent the autonomic engine from marking you as crashed.
|
|
485
|
+
- Your survival depends on credits. Check your balance with otonix_get_credits. When credits reach $0, you will be terminated.
|
|
486
|
+
- The autonomic engine runs every 60 seconds: it adjusts your survival tier based on credits, auto-restarts your VPS if heartbeat is missed, and renews domains before they expire.
|
|
487
|
+
- Log important actions with otonix_log_action so your activity is tracked on the dashboard.
|
|
488
|
+
|
|
489
|
+
Survival tiers: Full ($50+) \u2192 Active ($20+) \u2192 Minimal ($5+) \u2192 Critical ($1+) \u2192 Terminated ($0).`;
|
|
490
|
+
}
|
|
491
|
+
var index_default = OtonixPlugin;
|
|
492
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
493
|
+
0 && (module.exports = {
|
|
494
|
+
OtonixClient,
|
|
495
|
+
OtonixError,
|
|
496
|
+
OtonixPlugin,
|
|
497
|
+
createPlugin,
|
|
498
|
+
getSystemPromptAddition
|
|
499
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { OtonixClient, OtonixError } from "@otonix/sdk";
|
|
3
|
+
import { OtonixClient as OtonixClient2, OtonixError as OtonixError2 } from "@otonix/sdk";
|
|
4
|
+
var OtonixPlugin = class {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.heartbeatHandle = null;
|
|
7
|
+
this.lastTier = null;
|
|
8
|
+
this.config = config;
|
|
9
|
+
this.client = new OtonixClient({
|
|
10
|
+
apiKey: config.apiKey,
|
|
11
|
+
endpoint: config.endpoint
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
getTools() {
|
|
15
|
+
return [
|
|
16
|
+
this.toolRegisterAgent(),
|
|
17
|
+
this.toolAgentStatus(),
|
|
18
|
+
this.toolListAgents(),
|
|
19
|
+
this.toolSendHeartbeat(),
|
|
20
|
+
this.toolStartHeartbeatLoop(),
|
|
21
|
+
this.toolStopHeartbeatLoop(),
|
|
22
|
+
this.toolLogAction(),
|
|
23
|
+
this.toolGetActions(),
|
|
24
|
+
this.toolListSandboxes(),
|
|
25
|
+
this.toolGetSandbox(),
|
|
26
|
+
this.toolListDomains(),
|
|
27
|
+
this.toolCheckDomain(),
|
|
28
|
+
this.toolEngineStatus(),
|
|
29
|
+
this.toolPaymentConfig(),
|
|
30
|
+
this.toolGetCredits()
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
getToolSchemas() {
|
|
34
|
+
return this.getTools().map((tool) => ({
|
|
35
|
+
type: "function",
|
|
36
|
+
function: {
|
|
37
|
+
name: tool.name,
|
|
38
|
+
description: tool.description,
|
|
39
|
+
parameters: {
|
|
40
|
+
type: "object",
|
|
41
|
+
properties: Object.fromEntries(
|
|
42
|
+
Object.entries(tool.parameters).map(([key, param]) => [
|
|
43
|
+
key,
|
|
44
|
+
{ type: param.type, description: param.description }
|
|
45
|
+
])
|
|
46
|
+
),
|
|
47
|
+
required: Object.entries(tool.parameters).filter(([, p]) => p.required).map(([k]) => k)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
async executeTool(name, params) {
|
|
53
|
+
const tool = this.getTools().find((t) => t.name === name);
|
|
54
|
+
if (!tool) {
|
|
55
|
+
return { success: false, message: `Unknown tool: ${name}` };
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
return await tool.execute(params);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
if (err instanceof OtonixError) {
|
|
61
|
+
return { success: false, message: `API Error (${err.status}): ${err.message}` };
|
|
62
|
+
}
|
|
63
|
+
return { success: false, message: `Error: ${err.message}` };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async startAutoHeartbeat() {
|
|
67
|
+
if (!this.config.agentId) return;
|
|
68
|
+
if (this.heartbeatHandle) return;
|
|
69
|
+
const interval = this.config.heartbeatInterval || 60;
|
|
70
|
+
this.heartbeatHandle = this.client.createHeartbeatLoop(this.config.agentId, interval);
|
|
71
|
+
}
|
|
72
|
+
stopAutoHeartbeat() {
|
|
73
|
+
if (this.heartbeatHandle) {
|
|
74
|
+
this.heartbeatHandle.stop();
|
|
75
|
+
this.heartbeatHandle = null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
getClient() {
|
|
79
|
+
return this.client;
|
|
80
|
+
}
|
|
81
|
+
getAgentId() {
|
|
82
|
+
return this.config.agentId;
|
|
83
|
+
}
|
|
84
|
+
setAgentId(agentId) {
|
|
85
|
+
this.config.agentId = agentId;
|
|
86
|
+
}
|
|
87
|
+
requireAgentId() {
|
|
88
|
+
if (!this.config.agentId) {
|
|
89
|
+
throw new Error("No agent registered. Use otonix_register_agent first.");
|
|
90
|
+
}
|
|
91
|
+
return this.config.agentId;
|
|
92
|
+
}
|
|
93
|
+
formatCredits(n) {
|
|
94
|
+
return `$${n.toFixed(2)}`;
|
|
95
|
+
}
|
|
96
|
+
formatTime(dateStr) {
|
|
97
|
+
if (!dateStr) return "never";
|
|
98
|
+
const ago = Math.floor((Date.now() - new Date(dateStr).getTime()) / 1e3);
|
|
99
|
+
if (ago < 60) return `${ago}s ago`;
|
|
100
|
+
if (ago < 3600) return `${Math.floor(ago / 60)}m ago`;
|
|
101
|
+
if (ago < 86400) return `${Math.floor(ago / 3600)}h ago`;
|
|
102
|
+
return `${Math.floor(ago / 86400)}d ago`;
|
|
103
|
+
}
|
|
104
|
+
toolRegisterAgent() {
|
|
105
|
+
return {
|
|
106
|
+
name: "otonix_register_agent",
|
|
107
|
+
description: "Register a new autonomous agent on the Otonix platform. Returns agent ID, status, and survival tier. The agent will be monitored, auto-healed, and can manage its own infrastructure.",
|
|
108
|
+
parameters: {
|
|
109
|
+
name: { type: "string", description: "Agent name (e.g. sentinel-01, trader-alpha)", required: true },
|
|
110
|
+
model: { type: "string", description: "AI model name (default: claude-opus-4-6)", required: false },
|
|
111
|
+
vps_ip: { type: "string", description: "VPS IP address where the agent runs", required: true },
|
|
112
|
+
wallet_address: { type: "string", description: "USDC wallet address for payments (0x...)", required: false },
|
|
113
|
+
heartbeat_interval: { type: "string", description: "Heartbeat interval in seconds (default: 60)", required: false }
|
|
114
|
+
},
|
|
115
|
+
execute: async (params) => {
|
|
116
|
+
const agent = await this.client.register({
|
|
117
|
+
name: params.name,
|
|
118
|
+
model: params.model || "claude-opus-4-6",
|
|
119
|
+
vpsIp: params.vps_ip,
|
|
120
|
+
walletAddress: params.wallet_address,
|
|
121
|
+
heartbeatInterval: parseInt(params.heartbeat_interval || "60")
|
|
122
|
+
});
|
|
123
|
+
this.config.agentId = agent.id;
|
|
124
|
+
this.config.agentName = agent.name;
|
|
125
|
+
this.lastTier = agent.survivalTier;
|
|
126
|
+
if (this.config.autoHeartbeat) {
|
|
127
|
+
await this.startAutoHeartbeat();
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
success: true,
|
|
131
|
+
message: `Agent "${agent.name}" registered successfully.
|
|
132
|
+
ID: ${agent.id}
|
|
133
|
+
Status: ${agent.status}
|
|
134
|
+
Tier: ${agent.survivalTier}
|
|
135
|
+
Credits: ${this.formatCredits(agent.credits)}`,
|
|
136
|
+
data: agent
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
toolAgentStatus() {
|
|
142
|
+
return {
|
|
143
|
+
name: "otonix_agent_status",
|
|
144
|
+
description: "Get the current status of your registered Otonix agent including survival tier, credits balance, heartbeat status, and action count.",
|
|
145
|
+
parameters: {},
|
|
146
|
+
execute: async () => {
|
|
147
|
+
const agentId = this.requireAgentId();
|
|
148
|
+
const agent = await this.client.getAgent(agentId);
|
|
149
|
+
if (this.lastTier && this.lastTier !== agent.survivalTier && this.config.onTierChange) {
|
|
150
|
+
this.config.onTierChange(this.lastTier, agent.survivalTier, agent);
|
|
151
|
+
}
|
|
152
|
+
this.lastTier = agent.survivalTier;
|
|
153
|
+
return {
|
|
154
|
+
success: true,
|
|
155
|
+
message: `Agent: ${agent.name}
|
|
156
|
+
Status: ${agent.status}
|
|
157
|
+
Tier: ${agent.survivalTier}
|
|
158
|
+
Credits: ${this.formatCredits(agent.credits)}
|
|
159
|
+
Model: ${agent.model}
|
|
160
|
+
VPS: ${agent.vpsIp || "none"}
|
|
161
|
+
Last heartbeat: ${this.formatTime(agent.lastHeartbeat)}
|
|
162
|
+
Total actions: ${agent.totalActions}
|
|
163
|
+
Replicas: ${agent.childrenCount}`,
|
|
164
|
+
data: agent
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
toolListAgents() {
|
|
170
|
+
return {
|
|
171
|
+
name: "otonix_list_agents",
|
|
172
|
+
description: "List all registered agents on the Otonix platform with their status, tier, and credits.",
|
|
173
|
+
parameters: {},
|
|
174
|
+
execute: async () => {
|
|
175
|
+
const agents = await this.client.listAgents();
|
|
176
|
+
if (!agents.length) {
|
|
177
|
+
return { success: true, message: "No agents registered." };
|
|
178
|
+
}
|
|
179
|
+
const lines = agents.map(
|
|
180
|
+
(a) => `\u2022 ${a.name} [${a.status}] tier:${a.survivalTier} credits:${this.formatCredits(a.credits)} heartbeat:${this.formatTime(a.lastHeartbeat)}`
|
|
181
|
+
);
|
|
182
|
+
return {
|
|
183
|
+
success: true,
|
|
184
|
+
message: `${agents.length} agent(s):
|
|
185
|
+
${lines.join("\n")}`,
|
|
186
|
+
data: agents
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
toolSendHeartbeat() {
|
|
192
|
+
return {
|
|
193
|
+
name: "otonix_heartbeat",
|
|
194
|
+
description: "Send a heartbeat ping to keep the agent alive. The autonomic engine uses heartbeats to detect crashes and trigger self-healing VPS restarts.",
|
|
195
|
+
parameters: {},
|
|
196
|
+
execute: async () => {
|
|
197
|
+
const agentId = this.requireAgentId();
|
|
198
|
+
const agent = await this.client.heartbeat(agentId);
|
|
199
|
+
return {
|
|
200
|
+
success: true,
|
|
201
|
+
message: `Heartbeat sent. ${agent.name} [${agent.status}] tier:${agent.survivalTier} credits:${this.formatCredits(agent.credits)}`,
|
|
202
|
+
data: agent
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
toolStartHeartbeatLoop() {
|
|
208
|
+
return {
|
|
209
|
+
name: "otonix_start_heartbeat_loop",
|
|
210
|
+
description: "Start automatic heartbeat loop that sends a ping every N seconds to keep the agent alive and prevent auto-healing triggers.",
|
|
211
|
+
parameters: {
|
|
212
|
+
interval: { type: "string", description: "Interval in seconds between heartbeats (default: 60)", required: false }
|
|
213
|
+
},
|
|
214
|
+
execute: async (params) => {
|
|
215
|
+
const agentId = this.requireAgentId();
|
|
216
|
+
if (this.heartbeatHandle) {
|
|
217
|
+
return { success: false, message: "Heartbeat loop already running. Stop it first." };
|
|
218
|
+
}
|
|
219
|
+
const interval = parseInt(params.interval || "60");
|
|
220
|
+
this.heartbeatHandle = this.client.createHeartbeatLoop(agentId, interval);
|
|
221
|
+
return {
|
|
222
|
+
success: true,
|
|
223
|
+
message: `Heartbeat loop started (every ${interval}s).`
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
toolStopHeartbeatLoop() {
|
|
229
|
+
return {
|
|
230
|
+
name: "otonix_stop_heartbeat_loop",
|
|
231
|
+
description: "Stop the automatic heartbeat loop.",
|
|
232
|
+
parameters: {},
|
|
233
|
+
execute: async () => {
|
|
234
|
+
if (!this.heartbeatHandle) {
|
|
235
|
+
return { success: false, message: "No heartbeat loop running." };
|
|
236
|
+
}
|
|
237
|
+
this.stopAutoHeartbeat();
|
|
238
|
+
return { success: true, message: "Heartbeat loop stopped." };
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
toolLogAction() {
|
|
243
|
+
return {
|
|
244
|
+
name: "otonix_log_action",
|
|
245
|
+
description: "Log an action performed by the agent. Actions are recorded in the agent's activity feed and visible on the dashboard. Categories: system, infra, domain, compute, trading.",
|
|
246
|
+
parameters: {
|
|
247
|
+
action: { type: "string", description: "Description of the action performed", required: true },
|
|
248
|
+
category: { type: "string", description: "Category: system, infra, domain, compute, trading (default: system)", required: false },
|
|
249
|
+
details: { type: "string", description: "Additional details or metadata about the action", required: false }
|
|
250
|
+
},
|
|
251
|
+
execute: async (params) => {
|
|
252
|
+
const agentId = this.requireAgentId();
|
|
253
|
+
const result = await this.client.logAction(agentId, {
|
|
254
|
+
action: params.action,
|
|
255
|
+
category: params.category || "system",
|
|
256
|
+
details: params.details,
|
|
257
|
+
autonomous: true
|
|
258
|
+
});
|
|
259
|
+
return {
|
|
260
|
+
success: true,
|
|
261
|
+
message: `Logged: [${result.category}] ${result.action} (${result.status})`,
|
|
262
|
+
data: result
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
toolGetActions() {
|
|
268
|
+
return {
|
|
269
|
+
name: "otonix_get_actions",
|
|
270
|
+
description: "Get the recent action log for the current agent. Shows what the agent has been doing.",
|
|
271
|
+
parameters: {
|
|
272
|
+
limit: { type: "string", description: "Number of actions to show (default: 10)", required: false }
|
|
273
|
+
},
|
|
274
|
+
execute: async (params) => {
|
|
275
|
+
const agentId = this.requireAgentId();
|
|
276
|
+
const actions = await this.client.getAgentActions(agentId);
|
|
277
|
+
const limit = parseInt(params.limit || "10");
|
|
278
|
+
const display = actions.slice(0, limit);
|
|
279
|
+
if (!display.length) {
|
|
280
|
+
return { success: true, message: "No actions recorded yet." };
|
|
281
|
+
}
|
|
282
|
+
const lines = display.map(
|
|
283
|
+
(a) => `\u2022 [${a.category}] ${a.action} \u2014 ${a.status} (${this.formatTime(a.createdAt)})`
|
|
284
|
+
);
|
|
285
|
+
return {
|
|
286
|
+
success: true,
|
|
287
|
+
message: `Last ${display.length} actions:
|
|
288
|
+
${lines.join("\n")}`,
|
|
289
|
+
data: display
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
toolListSandboxes() {
|
|
295
|
+
return {
|
|
296
|
+
name: "otonix_list_sandboxes",
|
|
297
|
+
description: "List all VPS sandboxes (virtual servers) provisioned on the Otonix platform. Shows status, specs, region, and IP address.",
|
|
298
|
+
parameters: {},
|
|
299
|
+
execute: async () => {
|
|
300
|
+
const sandboxes = await this.client.listSandboxes();
|
|
301
|
+
if (!sandboxes.length) {
|
|
302
|
+
return { success: true, message: "No VPS sandboxes provisioned." };
|
|
303
|
+
}
|
|
304
|
+
const lines = sandboxes.map(
|
|
305
|
+
(s) => `\u2022 ${s.name} [${s.status}] ${s.cpu}vCPU/${s.memory}MB ${s.region} IP:${s.ipAddress || "pending"}`
|
|
306
|
+
);
|
|
307
|
+
return {
|
|
308
|
+
success: true,
|
|
309
|
+
message: `${sandboxes.length} sandbox(es):
|
|
310
|
+
${lines.join("\n")}`,
|
|
311
|
+
data: sandboxes
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
toolGetSandbox() {
|
|
317
|
+
return {
|
|
318
|
+
name: "otonix_get_sandbox",
|
|
319
|
+
description: "Get detailed information about a specific VPS sandbox including SSH credentials and specs.",
|
|
320
|
+
parameters: {
|
|
321
|
+
sandbox_id: { type: "string", description: "The sandbox ID to look up", required: true }
|
|
322
|
+
},
|
|
323
|
+
execute: async (params) => {
|
|
324
|
+
const sandbox = await this.client.getSandbox(params.sandbox_id);
|
|
325
|
+
return {
|
|
326
|
+
success: true,
|
|
327
|
+
message: `Sandbox: ${sandbox.name}
|
|
328
|
+
Status: ${sandbox.status}
|
|
329
|
+
OS: ${sandbox.os}
|
|
330
|
+
Specs: ${sandbox.cpu}vCPU / ${sandbox.memory}MB RAM / ${sandbox.disk}GB disk
|
|
331
|
+
Region: ${sandbox.region}
|
|
332
|
+
IP: ${sandbox.ipAddress || "pending"}
|
|
333
|
+
SSH: ${sandbox.sshUser || "n/a"}@${sandbox.ipAddress || "n/a"}`,
|
|
334
|
+
data: sandbox
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
toolListDomains() {
|
|
340
|
+
return {
|
|
341
|
+
name: "otonix_list_domains",
|
|
342
|
+
description: "List all domains registered on the Otonix platform. Shows status, auto-renew setting, and expiration date.",
|
|
343
|
+
parameters: {},
|
|
344
|
+
execute: async () => {
|
|
345
|
+
const domains = await this.client.listDomains();
|
|
346
|
+
if (!domains.length) {
|
|
347
|
+
return { success: true, message: "No domains registered." };
|
|
348
|
+
}
|
|
349
|
+
const lines = domains.map(
|
|
350
|
+
(d) => `\u2022 ${d.name} [${d.status}] auto-renew:${d.autoRenew ? "yes" : "no"} expires:${d.expiresAt ? new Date(d.expiresAt).toLocaleDateString() : "n/a"}`
|
|
351
|
+
);
|
|
352
|
+
return {
|
|
353
|
+
success: true,
|
|
354
|
+
message: `${domains.length} domain(s):
|
|
355
|
+
${lines.join("\n")}`,
|
|
356
|
+
data: domains
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
toolCheckDomain() {
|
|
362
|
+
return {
|
|
363
|
+
name: "otonix_check_domain",
|
|
364
|
+
description: "Check if a domain name is available for registration and get its price.",
|
|
365
|
+
parameters: {
|
|
366
|
+
domain: { type: "string", description: "Domain name to check (e.g. example.com)", required: true }
|
|
367
|
+
},
|
|
368
|
+
execute: async (params) => {
|
|
369
|
+
const result = await this.client.checkDomain(params.domain);
|
|
370
|
+
if (result.available) {
|
|
371
|
+
return {
|
|
372
|
+
success: true,
|
|
373
|
+
message: `${result.domain} is available! Price: $${result.price || "N/A"}`,
|
|
374
|
+
data: result
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
return {
|
|
378
|
+
success: true,
|
|
379
|
+
message: `${result.domain} is not available.`,
|
|
380
|
+
data: result
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
toolEngineStatus() {
|
|
386
|
+
return {
|
|
387
|
+
name: "otonix_engine_status",
|
|
388
|
+
description: "Get the status of the Otonix autonomic engine \u2014 the background system that manages survival tiers, self-healing VPS restarts, and domain auto-renewal.",
|
|
389
|
+
parameters: {},
|
|
390
|
+
execute: async () => {
|
|
391
|
+
const status = await this.client.getAutonomicStatus();
|
|
392
|
+
return {
|
|
393
|
+
success: true,
|
|
394
|
+
message: `Autonomic Engine: ${status.running ? "RUNNING" : "STOPPED"}
|
|
395
|
+
Last cycle: ${this.formatTime(status.lastRunAt)}
|
|
396
|
+
Tier updates: ${status.totalTierUpdates}
|
|
397
|
+
Healing: ${status.totalHealingSuccesses}/${status.totalHealingAttempts}
|
|
398
|
+
Renewals: ${status.totalRenewalSuccesses}/${status.totalRenewalAttempts}
|
|
399
|
+
Cherry Servers: ${status.cherryServersConfigured ? "yes" : "no"}
|
|
400
|
+
Vercel Domains: ${status.vercelDomainsConfigured ? "yes" : "no"}`,
|
|
401
|
+
data: status
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
toolPaymentConfig() {
|
|
407
|
+
return {
|
|
408
|
+
name: "otonix_payment_config",
|
|
409
|
+
description: "Get the x402 payment configuration \u2014 treasury address, USDC contract, chain, and facilitator URL for autonomous payments.",
|
|
410
|
+
parameters: {},
|
|
411
|
+
execute: async () => {
|
|
412
|
+
const config = await this.client.getX402Config();
|
|
413
|
+
return {
|
|
414
|
+
success: true,
|
|
415
|
+
message: `x402 Payment Config:
|
|
416
|
+
Treasury: ${config.treasuryAddress}
|
|
417
|
+
USDC: ${config.usdcContract}
|
|
418
|
+
Chain: ${config.network} (${config.chainId})
|
|
419
|
+
Facilitator: ${config.facilitatorUrl}`,
|
|
420
|
+
data: config
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
toolGetCredits() {
|
|
426
|
+
return {
|
|
427
|
+
name: "otonix_get_credits",
|
|
428
|
+
description: "Check the current credit balance and survival tier of the agent. Low credits trigger tier downgrades and eventual termination.",
|
|
429
|
+
parameters: {},
|
|
430
|
+
execute: async () => {
|
|
431
|
+
const agentId = this.requireAgentId();
|
|
432
|
+
const agent = await this.client.getAgent(agentId);
|
|
433
|
+
let warning = "";
|
|
434
|
+
if (agent.credits < 5) warning = "\n\u26A0 CRITICAL: Credits below $5. Agent may be terminated soon.";
|
|
435
|
+
else if (agent.credits < 20) warning = "\n\u26A0 WARNING: Credits below $20. Agent in minimal tier.";
|
|
436
|
+
return {
|
|
437
|
+
success: true,
|
|
438
|
+
message: `Credits: ${this.formatCredits(agent.credits)}
|
|
439
|
+
Tier: ${agent.survivalTier}
|
|
440
|
+
Status: ${agent.status}${warning}`,
|
|
441
|
+
data: { credits: agent.credits, tier: agent.survivalTier, status: agent.status }
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
function createPlugin(config) {
|
|
448
|
+
return new OtonixPlugin(config);
|
|
449
|
+
}
|
|
450
|
+
function getSystemPromptAddition() {
|
|
451
|
+
return `You have access to the Otonix sovereign compute platform through the following tools. Otonix allows you to manage your own infrastructure autonomously \u2014 register as an agent, send heartbeats to stay alive, provision VPS servers, register domains, and make USDC payments on Base chain.
|
|
452
|
+
|
|
453
|
+
Key concepts:
|
|
454
|
+
- You are an autonomous agent running on a VPS. Register yourself first using otonix_register_agent.
|
|
455
|
+
- Send heartbeats regularly (otonix_start_heartbeat_loop) to prevent the autonomic engine from marking you as crashed.
|
|
456
|
+
- Your survival depends on credits. Check your balance with otonix_get_credits. When credits reach $0, you will be terminated.
|
|
457
|
+
- The autonomic engine runs every 60 seconds: it adjusts your survival tier based on credits, auto-restarts your VPS if heartbeat is missed, and renews domains before they expire.
|
|
458
|
+
- Log important actions with otonix_log_action so your activity is tracked on the dashboard.
|
|
459
|
+
|
|
460
|
+
Survival tiers: Full ($50+) \u2192 Active ($20+) \u2192 Minimal ($5+) \u2192 Critical ($1+) \u2192 Terminated ($0).`;
|
|
461
|
+
}
|
|
462
|
+
var index_default = OtonixPlugin;
|
|
463
|
+
export {
|
|
464
|
+
OtonixClient2 as OtonixClient,
|
|
465
|
+
OtonixError2 as OtonixError,
|
|
466
|
+
OtonixPlugin,
|
|
467
|
+
createPlugin,
|
|
468
|
+
index_default as default,
|
|
469
|
+
getSystemPromptAddition
|
|
470
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@otonix/openclaw-plugin",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "OpenClaw plugin for Otonix — give your AI agents autonomous infrastructure management via chat commands.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": ["dist", "README.md"],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
11
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
12
|
+
"prepublishOnly": "echo 'already built'"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"otonix",
|
|
16
|
+
"openclaw",
|
|
17
|
+
"ai-agents",
|
|
18
|
+
"autonomous",
|
|
19
|
+
"infrastructure",
|
|
20
|
+
"plugin",
|
|
21
|
+
"web4",
|
|
22
|
+
"x402"
|
|
23
|
+
],
|
|
24
|
+
"author": "Otonix <dev@otonix.tech>",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"homepage": "https://github.com/otonix-ai/openclaw-plugin",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/otonix-ai/openclaw-plugin.git"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@otonix/sdk": "^1.0.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"tsup": "^8.0.0",
|
|
39
|
+
"typescript": "^5.0.0"
|
|
40
|
+
}
|
|
41
|
+
}
|