oceum 0.1.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/LICENSE +21 -0
- package/README.md +73 -0
- package/index.d.ts +173 -0
- package/index.js +329 -0
- package/package.json +31 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Oceum
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# oceum
|
|
2
|
+
|
|
3
|
+
Connect your AI agents to [Oceum](https://oceum.ai) for monitoring, logging, and orchestration.
|
|
4
|
+
|
|
5
|
+
Zero dependencies. Works with Node.js 18+, Deno, and Bun.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install oceum
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
const { Oceum } = require('oceum');
|
|
17
|
+
|
|
18
|
+
const client = new Oceum({
|
|
19
|
+
apiKey: process.env.OCEUM_API_KEY, // oc_xxx
|
|
20
|
+
agentId: process.env.OCEUM_AGENT_ID, // agt_xxx
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Start auto-heartbeat (every 60s)
|
|
24
|
+
client.startHeartbeat();
|
|
25
|
+
|
|
26
|
+
// Wrap tasks with automatic logging
|
|
27
|
+
const result = await client.wrap('Process leads', async () => {
|
|
28
|
+
const leads = await fetchLeads();
|
|
29
|
+
await processAll(leads);
|
|
30
|
+
return leads.length;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Clean up
|
|
34
|
+
client.stopHeartbeat();
|
|
35
|
+
await client.setStatus('idle');
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## API
|
|
39
|
+
|
|
40
|
+
| Method | Description |
|
|
41
|
+
|--------|-------------|
|
|
42
|
+
| `heartbeat()` | Send keep-alive, sets status to active |
|
|
43
|
+
| `taskStart(name, meta?)` | Log task initiation |
|
|
44
|
+
| `taskComplete(name, meta?)` | Log task completion, increments count |
|
|
45
|
+
| `error(name, opts?)` | Log error, `{ fatal: true }` sets error status |
|
|
46
|
+
| `warning(msg, meta?)` | Log non-critical warning |
|
|
47
|
+
| `setStatus(status)` | Set status: active, idle, paused, offline, error |
|
|
48
|
+
| `startHeartbeat(ms?)` | Auto-heartbeat every N ms (default: 60s) |
|
|
49
|
+
| `stopHeartbeat()` | Stop auto-heartbeat |
|
|
50
|
+
| `wrap(name, fn, meta?)` | Auto start/complete/error around async fn |
|
|
51
|
+
|
|
52
|
+
## Error Handling
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
const { Oceum, OceumError } = require('oceum');
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
await client.heartbeat();
|
|
59
|
+
} catch (err) {
|
|
60
|
+
if (err instanceof OceumError) {
|
|
61
|
+
console.log(err.statusCode); // 401, 404, etc.
|
|
62
|
+
console.log(err.body); // API response
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Docs
|
|
68
|
+
|
|
69
|
+
Full documentation: [oceum.ai/docs](https://oceum.ai/docs.html)
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
export interface OceumConfig {
|
|
2
|
+
/** Your organization API key (oc_xxx) */
|
|
3
|
+
apiKey: string;
|
|
4
|
+
/** Your agent ID (agt_xxx) */
|
|
5
|
+
agentId: string;
|
|
6
|
+
/** API base URL (default: 'https://oceum.ai') */
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface WebhookResponse {
|
|
11
|
+
ok: boolean;
|
|
12
|
+
event: string;
|
|
13
|
+
agentId: string;
|
|
14
|
+
taskCount?: number;
|
|
15
|
+
errorCount?: number;
|
|
16
|
+
status?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ErrorOptions {
|
|
20
|
+
/** Error message (defaults to errorName) */
|
|
21
|
+
message?: string;
|
|
22
|
+
/** Stack trace */
|
|
23
|
+
stack?: string;
|
|
24
|
+
/** Whether this is a fatal error (default: false) */
|
|
25
|
+
fatal?: boolean;
|
|
26
|
+
/** Additional metadata */
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class OceumError extends Error {
|
|
31
|
+
/** HTTP status code from the API */
|
|
32
|
+
statusCode: number;
|
|
33
|
+
/** Response body from the API */
|
|
34
|
+
body: Record<string, unknown>;
|
|
35
|
+
constructor(message: string, statusCode: number, body: Record<string, unknown>);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class Oceum {
|
|
39
|
+
constructor(config: OceumConfig);
|
|
40
|
+
|
|
41
|
+
/** The agent ID this client reports as */
|
|
42
|
+
readonly agentId: string;
|
|
43
|
+
/** The API base URL */
|
|
44
|
+
readonly baseUrl: string;
|
|
45
|
+
|
|
46
|
+
/** Send a heartbeat. Updates agent status to 'active'. */
|
|
47
|
+
heartbeat(): Promise<WebhookResponse>;
|
|
48
|
+
|
|
49
|
+
/** Log a task starting. */
|
|
50
|
+
taskStart(taskName: string, meta?: Record<string, unknown>): Promise<WebhookResponse>;
|
|
51
|
+
|
|
52
|
+
/** Log a task completing. Increments the agent's task count. */
|
|
53
|
+
taskComplete(taskName: string, meta?: Record<string, unknown>): Promise<WebhookResponse>;
|
|
54
|
+
|
|
55
|
+
/** Log an error. Increments the agent's error count. If fatal, sets status to 'error'. */
|
|
56
|
+
error(errorName: string, options?: ErrorOptions): Promise<WebhookResponse>;
|
|
57
|
+
|
|
58
|
+
/** Log a non-critical warning. */
|
|
59
|
+
warning(message: string, meta?: Record<string, unknown>): Promise<WebhookResponse>;
|
|
60
|
+
|
|
61
|
+
/** Explicitly set the agent's status. */
|
|
62
|
+
setStatus(status: 'active' | 'idle' | 'paused' | 'offline' | 'error'): Promise<WebhookResponse>;
|
|
63
|
+
|
|
64
|
+
/** Start sending heartbeats at a regular interval. */
|
|
65
|
+
startHeartbeat(intervalMs?: number): void;
|
|
66
|
+
|
|
67
|
+
/** Stop the auto-heartbeat. */
|
|
68
|
+
stopHeartbeat(): void;
|
|
69
|
+
|
|
70
|
+
/** Wrap an async function with automatic task_start, task_complete, and error reporting. */
|
|
71
|
+
wrap<T>(taskName: string, fn: () => T | Promise<T>, meta?: Record<string, unknown>): Promise<T>;
|
|
72
|
+
|
|
73
|
+
/** Write a shared memory entry visible to peer agents. */
|
|
74
|
+
memory(content: string, options?: MemoryWriteOptions): Promise<WebhookResponse>;
|
|
75
|
+
|
|
76
|
+
/** Read shared memory entries from peer agents. */
|
|
77
|
+
readMemory(options?: MemoryReadOptions): Promise<MemoryReadResponse>;
|
|
78
|
+
|
|
79
|
+
/** Store sensitive data in the Secure Data Vault. Returns a vault token. */
|
|
80
|
+
vaultStore(data: string, options?: VaultStoreOptions): Promise<VaultStoreResponse>;
|
|
81
|
+
|
|
82
|
+
/** Retrieve sensitive data from the Vault using a vault token. */
|
|
83
|
+
vaultRetrieve(token: string): Promise<VaultRetrieveResponse>;
|
|
84
|
+
|
|
85
|
+
/** Revoke a vault token permanently. */
|
|
86
|
+
vaultRevoke(token: string): Promise<{ ok: boolean; token: string; revoked: boolean }>;
|
|
87
|
+
|
|
88
|
+
/** List vault tokens (metadata only). */
|
|
89
|
+
vaultList(options?: VaultListOptions): Promise<VaultListResponse>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface MemoryWriteOptions {
|
|
93
|
+
category?: 'insight' | 'error_pattern' | 'config' | 'dependency' | 'learning';
|
|
94
|
+
scope?: 'fleet' | 'targeted';
|
|
95
|
+
targetAgent?: string;
|
|
96
|
+
tags?: string;
|
|
97
|
+
ttl?: '1h' | '6h' | '24h' | '7d' | '30d' | 'permanent';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface MemoryReadOptions {
|
|
101
|
+
scope?: 'fleet' | 'targeted';
|
|
102
|
+
category?: 'insight' | 'error_pattern' | 'config' | 'dependency' | 'learning';
|
|
103
|
+
tag?: string;
|
|
104
|
+
limit?: number;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface MemoryEntry {
|
|
108
|
+
id: string;
|
|
109
|
+
name: string;
|
|
110
|
+
sourceAgent: string;
|
|
111
|
+
sourceAgentName: string;
|
|
112
|
+
scope: 'fleet' | 'targeted';
|
|
113
|
+
targetAgent: string;
|
|
114
|
+
category: string;
|
|
115
|
+
content: string;
|
|
116
|
+
tags: string;
|
|
117
|
+
timestamp: string;
|
|
118
|
+
ttl: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface MemoryReadResponse {
|
|
122
|
+
ok: boolean;
|
|
123
|
+
memories: MemoryEntry[];
|
|
124
|
+
count: number;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface VaultStoreOptions {
|
|
128
|
+
category?: 'financial' | 'medical' | 'credentials' | 'personal' | 'custom';
|
|
129
|
+
accessPolicy?: 'owner_only' | 'source_agent' | 'specified_agents' | 'all_agents';
|
|
130
|
+
allowedAgents?: string;
|
|
131
|
+
ttl?: '1h' | '6h' | '24h' | '7d' | '30d' | 'permanent';
|
|
132
|
+
label?: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface VaultStoreResponse {
|
|
136
|
+
ok: boolean;
|
|
137
|
+
event: string;
|
|
138
|
+
agentId: string;
|
|
139
|
+
token: string;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface VaultRetrieveResponse {
|
|
143
|
+
ok: boolean;
|
|
144
|
+
event: string;
|
|
145
|
+
agentId: string;
|
|
146
|
+
token: string;
|
|
147
|
+
data: string;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface VaultListOptions {
|
|
151
|
+
category?: 'financial' | 'medical' | 'credentials' | 'personal' | 'custom';
|
|
152
|
+
status?: 'active' | 'revoked';
|
|
153
|
+
limit?: number;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface VaultEntry {
|
|
157
|
+
token: string;
|
|
158
|
+
category: string;
|
|
159
|
+
sourceAgent: string;
|
|
160
|
+
sourceAgentName: string;
|
|
161
|
+
accessPolicy: string;
|
|
162
|
+
ttl: string;
|
|
163
|
+
status: string;
|
|
164
|
+
label: string;
|
|
165
|
+
createdAt: string;
|
|
166
|
+
accessCount: number;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface VaultListResponse {
|
|
170
|
+
ok: boolean;
|
|
171
|
+
entries: VaultEntry[];
|
|
172
|
+
count: number;
|
|
173
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class OceumError extends Error {
|
|
4
|
+
constructor(message, statusCode, body) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'OceumError';
|
|
7
|
+
this.statusCode = statusCode;
|
|
8
|
+
this.body = body;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
class Oceum {
|
|
13
|
+
#apiKey;
|
|
14
|
+
#agentId;
|
|
15
|
+
#baseUrl;
|
|
16
|
+
#heartbeatTimer;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Create an Oceum client.
|
|
20
|
+
* @param {Object} config
|
|
21
|
+
* @param {string} config.apiKey - Your organization API key (oc_xxx)
|
|
22
|
+
* @param {string} config.agentId - Your agent ID (agt_xxx)
|
|
23
|
+
* @param {string} [config.baseUrl='https://oceum.ai'] - API base URL
|
|
24
|
+
*/
|
|
25
|
+
constructor({ apiKey, agentId, baseUrl = 'https://oceum.ai' } = {}) {
|
|
26
|
+
if (!apiKey) throw new Error('oceum: apiKey is required');
|
|
27
|
+
if (!agentId) throw new Error('oceum: agentId is required');
|
|
28
|
+
this.#apiKey = apiKey;
|
|
29
|
+
this.#agentId = agentId;
|
|
30
|
+
this.#baseUrl = baseUrl.replace(/\/$/, '');
|
|
31
|
+
this.#heartbeatTimer = null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ── Core transport ─────────────────────────────────
|
|
35
|
+
|
|
36
|
+
async #send(event, data = {}) {
|
|
37
|
+
const res = await fetch(`${this.#baseUrl}/api/webhook`, {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: {
|
|
40
|
+
'Content-Type': 'application/json',
|
|
41
|
+
'Authorization': `Bearer ${this.#apiKey}`,
|
|
42
|
+
},
|
|
43
|
+
body: JSON.stringify({
|
|
44
|
+
event,
|
|
45
|
+
agentId: this.#agentId,
|
|
46
|
+
data,
|
|
47
|
+
}),
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const body = await res.json().catch(() => ({}));
|
|
51
|
+
|
|
52
|
+
if (!res.ok) {
|
|
53
|
+
throw new OceumError(
|
|
54
|
+
body.error || `HTTP ${res.status}`,
|
|
55
|
+
res.status,
|
|
56
|
+
body
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return body;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ── Events ─────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Send a heartbeat. Updates agent status to 'active'.
|
|
67
|
+
*/
|
|
68
|
+
async heartbeat() {
|
|
69
|
+
return this.#send('heartbeat');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Log a task starting.
|
|
74
|
+
* @param {string} taskName - Name of the task
|
|
75
|
+
* @param {Object} [meta] - Additional metadata
|
|
76
|
+
*/
|
|
77
|
+
async taskStart(taskName, meta) {
|
|
78
|
+
return this.#send('task_start', {
|
|
79
|
+
taskName,
|
|
80
|
+
message: `Task started: ${taskName}`,
|
|
81
|
+
meta,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Log a task completing. Increments the agent's task count.
|
|
87
|
+
* @param {string} taskName - Name of the task
|
|
88
|
+
* @param {Object} [meta] - Additional metadata
|
|
89
|
+
*/
|
|
90
|
+
async taskComplete(taskName, meta) {
|
|
91
|
+
return this.#send('task_complete', {
|
|
92
|
+
taskName,
|
|
93
|
+
message: `Task completed: ${taskName}`,
|
|
94
|
+
meta,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Log an error. Increments the agent's error count.
|
|
100
|
+
* If fatal is true, sets agent status to 'error'.
|
|
101
|
+
* @param {string} errorName - Name/title of the error
|
|
102
|
+
* @param {Object} [options]
|
|
103
|
+
* @param {string} [options.message] - Error message (defaults to errorName)
|
|
104
|
+
* @param {string} [options.stack] - Stack trace
|
|
105
|
+
* @param {boolean} [options.fatal=false] - Whether this is a fatal error
|
|
106
|
+
*/
|
|
107
|
+
async error(errorName, { message, stack, fatal = false, ...meta } = {}) {
|
|
108
|
+
return this.#send('error', {
|
|
109
|
+
errorName,
|
|
110
|
+
message: message || errorName,
|
|
111
|
+
stack,
|
|
112
|
+
fatal,
|
|
113
|
+
meta: Object.keys(meta).length ? meta : undefined,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Log a non-critical warning.
|
|
119
|
+
* @param {string} message - Warning message
|
|
120
|
+
* @param {Object} [meta] - Additional metadata
|
|
121
|
+
*/
|
|
122
|
+
async warning(message, meta) {
|
|
123
|
+
return this.#send('warning', { message, meta });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Explicitly set the agent's status.
|
|
128
|
+
* @param {'active'|'idle'|'paused'|'offline'|'error'} status
|
|
129
|
+
*/
|
|
130
|
+
async setStatus(status) {
|
|
131
|
+
const valid = ['active', 'idle', 'paused', 'offline', 'error'];
|
|
132
|
+
if (!valid.includes(status)) {
|
|
133
|
+
throw new Error(`oceum: invalid status "${status}". Must be one of: ${valid.join(', ')}`);
|
|
134
|
+
}
|
|
135
|
+
return this.#send('status', { status });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ── Auto-heartbeat ─────────────────────────────────
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Start sending heartbeats at a regular interval.
|
|
142
|
+
* @param {number} [intervalMs=60000] - Heartbeat interval in milliseconds
|
|
143
|
+
*/
|
|
144
|
+
startHeartbeat(intervalMs = 60000) {
|
|
145
|
+
this.stopHeartbeat();
|
|
146
|
+
this.heartbeat().catch(() => {});
|
|
147
|
+
this.#heartbeatTimer = setInterval(() => {
|
|
148
|
+
this.heartbeat().catch(() => {});
|
|
149
|
+
}, intervalMs);
|
|
150
|
+
// Allow process to exit even if heartbeat is running
|
|
151
|
+
if (this.#heartbeatTimer.unref) this.#heartbeatTimer.unref();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Stop the auto-heartbeat.
|
|
156
|
+
*/
|
|
157
|
+
stopHeartbeat() {
|
|
158
|
+
if (this.#heartbeatTimer) {
|
|
159
|
+
clearInterval(this.#heartbeatTimer);
|
|
160
|
+
this.#heartbeatTimer = null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ── Lifecycle wrapper ──────────────────────────────
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Wrap an async function with automatic task_start, task_complete, and error reporting.
|
|
168
|
+
* Re-throws any error after reporting it.
|
|
169
|
+
* @param {string} taskName - Name of the task
|
|
170
|
+
* @param {Function} fn - Async function to execute
|
|
171
|
+
* @param {Object} [meta] - Additional metadata
|
|
172
|
+
* @returns {Promise<*>} - The return value of fn
|
|
173
|
+
*/
|
|
174
|
+
async wrap(taskName, fn, meta) {
|
|
175
|
+
await this.taskStart(taskName, meta);
|
|
176
|
+
try {
|
|
177
|
+
const result = await fn();
|
|
178
|
+
await this.taskComplete(taskName, meta);
|
|
179
|
+
return result;
|
|
180
|
+
} catch (err) {
|
|
181
|
+
await this.error(taskName, {
|
|
182
|
+
message: err.message,
|
|
183
|
+
stack: err.stack,
|
|
184
|
+
fatal: false,
|
|
185
|
+
}).catch(() => {});
|
|
186
|
+
throw err;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ── Shared Memory ────────────────────────────────────
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Write a shared memory entry visible to peer agents.
|
|
194
|
+
* @param {string} content - The memory content (max 2000 chars)
|
|
195
|
+
* @param {Object} [options]
|
|
196
|
+
* @param {'insight'|'error_pattern'|'config'|'dependency'|'learning'} [options.category='insight']
|
|
197
|
+
* @param {'fleet'|'targeted'} [options.scope='fleet']
|
|
198
|
+
* @param {string} [options.targetAgent] - Required if scope is 'targeted'
|
|
199
|
+
* @param {string} [options.tags] - Comma-separated tags
|
|
200
|
+
* @param {'1h'|'6h'|'24h'|'7d'|'30d'|'permanent'} [options.ttl='24h']
|
|
201
|
+
*/
|
|
202
|
+
async memory(content, { category = 'insight', scope = 'fleet', targetAgent, tags, ttl = '24h' } = {}) {
|
|
203
|
+
return this.#send('memory', { content, category, scope, targetAgent, tags, ttl });
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Read shared memory entries from peer agents.
|
|
208
|
+
* Returns fleet-wide memories and memories targeted to this agent.
|
|
209
|
+
* @param {Object} [options]
|
|
210
|
+
* @param {'fleet'|'targeted'} [options.scope]
|
|
211
|
+
* @param {'insight'|'error_pattern'|'config'|'dependency'|'learning'} [options.category]
|
|
212
|
+
* @param {string} [options.tag] - Filter by tag
|
|
213
|
+
* @param {number} [options.limit=20] - Max results (up to 50)
|
|
214
|
+
* @returns {Promise<{ok: boolean, memories: Array, count: number}>}
|
|
215
|
+
*/
|
|
216
|
+
async readMemory({ scope, category, tag, limit = 20 } = {}) {
|
|
217
|
+
const params = new URLSearchParams();
|
|
218
|
+
params.set('agentId', this.#agentId);
|
|
219
|
+
if (scope) params.set('scope', scope);
|
|
220
|
+
if (category) params.set('category', category);
|
|
221
|
+
if (tag) params.set('tag', tag);
|
|
222
|
+
params.set('limit', String(limit));
|
|
223
|
+
|
|
224
|
+
const res = await fetch(`${this.#baseUrl}/api/memory?${params}`, {
|
|
225
|
+
headers: { 'Authorization': `Bearer ${this.#apiKey}` },
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const body = await res.json().catch(() => ({}));
|
|
229
|
+
|
|
230
|
+
if (!res.ok) {
|
|
231
|
+
throw new OceumError(
|
|
232
|
+
body.error || `HTTP ${res.status}`,
|
|
233
|
+
res.status,
|
|
234
|
+
body
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return body;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ── Vault (Secure Data) ──────────────────────────
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Store sensitive data in the Secure Data Vault.
|
|
245
|
+
* Returns an opaque vault token (vtk_xxx) for later retrieval.
|
|
246
|
+
* @param {string} data - Sensitive data to encrypt and store (max 2000 chars)
|
|
247
|
+
* @param {Object} [options]
|
|
248
|
+
* @param {'financial'|'medical'|'credentials'|'personal'|'custom'} [options.category='custom']
|
|
249
|
+
* @param {'owner_only'|'source_agent'|'specified_agents'|'all_agents'} [options.accessPolicy='source_agent']
|
|
250
|
+
* @param {string} [options.allowedAgents] - Comma-separated agent IDs (for specified_agents)
|
|
251
|
+
* @param {'1h'|'6h'|'24h'|'7d'|'30d'|'permanent'} [options.ttl='30d']
|
|
252
|
+
* @param {string} [options.label] - Human-readable label
|
|
253
|
+
*/
|
|
254
|
+
async vaultStore(data, { category = 'custom', accessPolicy = 'source_agent', allowedAgents, ttl = '30d', label } = {}) {
|
|
255
|
+
return this.#send('vault_store', { data, category, accessPolicy, allowedAgents, ttl, label });
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Retrieve sensitive data from the Vault using a vault token.
|
|
260
|
+
* @param {string} token - Vault token (vtk_xxx)
|
|
261
|
+
*/
|
|
262
|
+
async vaultRetrieve(token) {
|
|
263
|
+
return this.#send('vault_retrieve', { token });
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Revoke a vault token, permanently preventing future retrievals.
|
|
268
|
+
* @param {string} token - Vault token (vtk_xxx)
|
|
269
|
+
*/
|
|
270
|
+
async vaultRevoke(token) {
|
|
271
|
+
const res = await fetch(`${this.#baseUrl}/api/vault`, {
|
|
272
|
+
method: 'POST',
|
|
273
|
+
headers: {
|
|
274
|
+
'Content-Type': 'application/json',
|
|
275
|
+
'Authorization': `Bearer ${this.#apiKey}`,
|
|
276
|
+
},
|
|
277
|
+
body: JSON.stringify({ action: 'revoke', token, agentId: this.#agentId }),
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
const body = await res.json().catch(() => ({}));
|
|
281
|
+
|
|
282
|
+
if (!res.ok) {
|
|
283
|
+
throw new OceumError(
|
|
284
|
+
body.error || `HTTP ${res.status}`,
|
|
285
|
+
res.status,
|
|
286
|
+
body
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return body;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* List vault tokens (metadata only, no decrypted content).
|
|
295
|
+
* @param {Object} [options]
|
|
296
|
+
* @param {'financial'|'medical'|'credentials'|'personal'|'custom'} [options.category]
|
|
297
|
+
* @param {'active'|'revoked'} [options.status='active']
|
|
298
|
+
* @param {number} [options.limit=20]
|
|
299
|
+
*/
|
|
300
|
+
async vaultList({ category, status = 'active', limit = 20 } = {}) {
|
|
301
|
+
const params = new URLSearchParams();
|
|
302
|
+
if (category) params.set('category', category);
|
|
303
|
+
params.set('status', status);
|
|
304
|
+
params.set('limit', String(limit));
|
|
305
|
+
|
|
306
|
+
const res = await fetch(`${this.#baseUrl}/api/vault?${params}`, {
|
|
307
|
+
headers: { 'Authorization': `Bearer ${this.#apiKey}` },
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
const body = await res.json().catch(() => ({}));
|
|
311
|
+
|
|
312
|
+
if (!res.ok) {
|
|
313
|
+
throw new OceumError(
|
|
314
|
+
body.error || `HTTP ${res.status}`,
|
|
315
|
+
res.status,
|
|
316
|
+
body
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return body;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// ── Getters ────────────────────────────────────────
|
|
324
|
+
|
|
325
|
+
get agentId() { return this.#agentId; }
|
|
326
|
+
get baseUrl() { return this.#baseUrl; }
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
module.exports = { Oceum, OceumError };
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "oceum",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Connect your AI agents to Oceum for monitoring, logging, and orchestration.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"index.js",
|
|
9
|
+
"index.d.ts",
|
|
10
|
+
"LICENSE"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=18"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"ai",
|
|
17
|
+
"agents",
|
|
18
|
+
"monitoring",
|
|
19
|
+
"oceum",
|
|
20
|
+
"observability",
|
|
21
|
+
"llm",
|
|
22
|
+
"orchestration"
|
|
23
|
+
],
|
|
24
|
+
"author": "Oceum <hello@oceum.ai>",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"homepage": "https://oceum.ai/docs",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/oceum/sdk"
|
|
30
|
+
}
|
|
31
|
+
}
|