@erdoai/server 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.js +241 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# @erdoai/server
|
|
2
|
+
|
|
3
|
+
Server-side TypeScript client for invoking Erdo AI agents.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @erdoai/server
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Basic Invocation
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { ErdoClient } from '@erdoai/server';
|
|
17
|
+
|
|
18
|
+
const client = new ErdoClient({
|
|
19
|
+
endpoint: 'https://api.erdo.ai',
|
|
20
|
+
authToken: process.env.ERDO_API_KEY,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Get final result
|
|
24
|
+
const result = await client.invoke('data-analyst', {
|
|
25
|
+
messages: [{ role: 'user', content: 'What were our top products last month?' }],
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
console.log(result.messages);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Streaming
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
for await (const event of client.invokeStream('data-analyst', {
|
|
35
|
+
messages: [{ role: 'user', content: 'Analyze our sales data' }],
|
|
36
|
+
})) {
|
|
37
|
+
switch (event.type) {
|
|
38
|
+
case 'content':
|
|
39
|
+
console.log('New content:', event.payload);
|
|
40
|
+
break;
|
|
41
|
+
case 'status':
|
|
42
|
+
console.log('Status:', event.payload);
|
|
43
|
+
break;
|
|
44
|
+
case 'error':
|
|
45
|
+
console.error('Error:', event.payload);
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Environment Variables
|
|
52
|
+
|
|
53
|
+
The client can be configured via environment variables:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
ERDO_ENDPOINT=https://api.erdo.ai
|
|
57
|
+
ERDO_AUTH_TOKEN=your-api-key
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// Uses environment variables automatically
|
|
62
|
+
const client = new ErdoClient();
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## API Reference
|
|
66
|
+
|
|
67
|
+
### `ErdoClient`
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
class ErdoClient {
|
|
71
|
+
constructor(options?: {
|
|
72
|
+
endpoint?: string; // API endpoint (default: env or https://api.erdo.ai)
|
|
73
|
+
authToken?: string; // API key (default: env ERDO_AUTH_TOKEN)
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
invoke(botKey: string, params: InvokeParams): Promise<InvokeResult>;
|
|
77
|
+
invokeStream(botKey: string, params: InvokeParams): AsyncGenerator<SSEEvent>;
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### `InvokeParams`
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
interface InvokeParams {
|
|
85
|
+
messages?: Message[]; // Messages to send to the agent
|
|
86
|
+
parameters?: Record<string, any>; // Parameters to pass to the agent
|
|
87
|
+
datasets?: string[]; // Dataset slugs to include
|
|
88
|
+
mode?: InvocationMode; // Invocation mode
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### `SSEEvent`
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
interface SSEEvent {
|
|
96
|
+
type: 'content' | 'status' | 'error' | 'done';
|
|
97
|
+
payload: any;
|
|
98
|
+
metadata?: Record<string, any>;
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { ErdoClientConfig, InvokeParams, InvokeResult, SSEEvent } from '@erdoai/types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Erdo Client for invoking agents
|
|
5
|
+
*
|
|
6
|
+
* Ported from: erdo-python-sdk/erdo/invoke/client.py and invoke.py
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
declare class ErdoClient {
|
|
10
|
+
private readonly endpoint;
|
|
11
|
+
private readonly authToken;
|
|
12
|
+
constructor(config?: Partial<ErdoClientConfig>);
|
|
13
|
+
/**
|
|
14
|
+
* Invoke an agent and wait for the complete result
|
|
15
|
+
*/
|
|
16
|
+
invoke(botKey: string, params?: InvokeParams): Promise<InvokeResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Invoke an agent and stream SSE events
|
|
19
|
+
*/
|
|
20
|
+
invokeStream(botKey: string, params?: InvokeParams): AsyncGenerator<SSEEvent, void, unknown>;
|
|
21
|
+
/**
|
|
22
|
+
* Collect all events from an invocation
|
|
23
|
+
*/
|
|
24
|
+
private collectEvents;
|
|
25
|
+
/**
|
|
26
|
+
* Make the HTTP request to invoke an agent
|
|
27
|
+
*/
|
|
28
|
+
private makeRequest;
|
|
29
|
+
/**
|
|
30
|
+
* Extract structured result from SSE events
|
|
31
|
+
*
|
|
32
|
+
* Ported from: erdo-python-sdk/erdo/invoke/invoke.py - _extract_result_data()
|
|
33
|
+
*/
|
|
34
|
+
private extractResult;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Invoke an agent with a clean API
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* import { invoke } from '@erdoai/server';
|
|
42
|
+
*
|
|
43
|
+
* const result = await invoke('org.my-agent', {
|
|
44
|
+
* messages: [{ role: 'user', content: 'Analyze Q4 sales' }],
|
|
45
|
+
* mode: 'replay',
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
declare function invoke(botKey: string, params?: InvokeParams): Promise<InvokeResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Invoke an agent and stream events
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* import { invokeStream } from '@erdoai/server';
|
|
56
|
+
*
|
|
57
|
+
* for await (const event of invokeStream('org.my-agent', params)) {
|
|
58
|
+
* console.log(event.type, event.payload);
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
declare function invokeStream(botKey: string, params?: InvokeParams): AsyncGenerator<SSEEvent, void, unknown>;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Configuration management for Erdo TypeScript SDK
|
|
66
|
+
*
|
|
67
|
+
* Ported from: erdo-python-sdk/erdo/config/config.py
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get configuration from environment variables
|
|
72
|
+
*/
|
|
73
|
+
declare function getConfigFromEnv(): ErdoClientConfig;
|
|
74
|
+
/**
|
|
75
|
+
* Merge user config with environment config
|
|
76
|
+
*/
|
|
77
|
+
declare function resolveConfig(userConfig?: Partial<ErdoClientConfig>): Required<ErdoClientConfig>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* SSE Client for Server-Sent Events streaming
|
|
81
|
+
*
|
|
82
|
+
* Ported from: erdo-python-sdk/erdo/invoke/client.py
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Parse SSE events from a ReadableStream
|
|
87
|
+
*/
|
|
88
|
+
declare function parseSSEStream(response: Response): AsyncGenerator<SSEEvent, void, unknown>;
|
|
89
|
+
/**
|
|
90
|
+
* Collect all events from an SSE stream
|
|
91
|
+
*/
|
|
92
|
+
declare function collectSSEEvents(response: Response): Promise<SSEEvent[]>;
|
|
93
|
+
|
|
94
|
+
export { ErdoClient, collectSSEEvents, getConfigFromEnv, invoke, invokeStream, parseSSEStream, resolveConfig };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// src/config.ts
|
|
2
|
+
var DEFAULT_ENDPOINT = "https://api.erdo.ai";
|
|
3
|
+
function getConfigFromEnv() {
|
|
4
|
+
const env = typeof process !== "undefined" ? process.env : {};
|
|
5
|
+
return {
|
|
6
|
+
endpoint: env.ERDO_ENDPOINT || env.NEXT_PUBLIC_ERDO_ENDPOINT || DEFAULT_ENDPOINT,
|
|
7
|
+
authToken: env.ERDO_AUTH_TOKEN || env.NEXT_PUBLIC_ERDO_API_KEY
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function resolveConfig(userConfig) {
|
|
11
|
+
const envConfig = getConfigFromEnv();
|
|
12
|
+
const endpoint = userConfig?.endpoint || envConfig.endpoint || DEFAULT_ENDPOINT;
|
|
13
|
+
const authToken = userConfig?.authToken || envConfig.authToken;
|
|
14
|
+
if (!authToken) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
"No auth token configured. Set ERDO_AUTH_TOKEN environment variable or pass authToken to ErdoClient."
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
endpoint,
|
|
21
|
+
authToken
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// src/streaming/sse-client.ts
|
|
26
|
+
async function* parseSSEStream(response) {
|
|
27
|
+
if (!response.body) {
|
|
28
|
+
throw new Error("Response body is null");
|
|
29
|
+
}
|
|
30
|
+
const reader = response.body.getReader();
|
|
31
|
+
const decoder = new TextDecoder();
|
|
32
|
+
let buffer = "";
|
|
33
|
+
try {
|
|
34
|
+
while (true) {
|
|
35
|
+
const { done, value } = await reader.read();
|
|
36
|
+
if (done) {
|
|
37
|
+
if (buffer.trim()) {
|
|
38
|
+
const event = parseSSELine(buffer);
|
|
39
|
+
if (event) {
|
|
40
|
+
yield event;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
buffer += decoder.decode(value, { stream: true });
|
|
46
|
+
const lines = buffer.split("\n");
|
|
47
|
+
buffer = lines.pop() || "";
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
const event = parseSSELine(line);
|
|
50
|
+
if (event) {
|
|
51
|
+
yield event;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
} finally {
|
|
56
|
+
reader.releaseLock();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function parseSSELine(line) {
|
|
60
|
+
const trimmedLine = line.trim();
|
|
61
|
+
if (!trimmedLine) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
if (trimmedLine.startsWith("data: ")) {
|
|
65
|
+
const data = trimmedLine.slice(6);
|
|
66
|
+
if (!data.trim()) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
return JSON.parse(data);
|
|
71
|
+
} catch {
|
|
72
|
+
return { raw: data };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
async function collectSSEEvents(response) {
|
|
78
|
+
const events = [];
|
|
79
|
+
for await (const event of parseSSEStream(response)) {
|
|
80
|
+
events.push(event);
|
|
81
|
+
}
|
|
82
|
+
return events;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/client.ts
|
|
86
|
+
var ErdoClient = class {
|
|
87
|
+
endpoint;
|
|
88
|
+
authToken;
|
|
89
|
+
constructor(config) {
|
|
90
|
+
const resolved = resolveConfig(config);
|
|
91
|
+
this.endpoint = resolved.endpoint;
|
|
92
|
+
this.authToken = resolved.authToken;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Invoke an agent and wait for the complete result
|
|
96
|
+
*/
|
|
97
|
+
async invoke(botKey, params = {}) {
|
|
98
|
+
const events = await this.collectEvents(botKey, params);
|
|
99
|
+
return this.extractResult(botKey, events);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Invoke an agent and stream SSE events
|
|
103
|
+
*/
|
|
104
|
+
async *invokeStream(botKey, params = {}) {
|
|
105
|
+
const response = await this.makeRequest(botKey, params);
|
|
106
|
+
yield* parseSSEStream(response);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Collect all events from an invocation
|
|
110
|
+
*/
|
|
111
|
+
async collectEvents(botKey, params) {
|
|
112
|
+
const response = await this.makeRequest(botKey, params);
|
|
113
|
+
return collectSSEEvents(response);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Make the HTTP request to invoke an agent
|
|
117
|
+
*/
|
|
118
|
+
async makeRequest(botKey, params) {
|
|
119
|
+
const url = `${this.endpoint}/bots/${botKey}/invoke`;
|
|
120
|
+
const invokeParams = {};
|
|
121
|
+
if (params.messages) {
|
|
122
|
+
invokeParams.messages = params.messages;
|
|
123
|
+
}
|
|
124
|
+
if (params.parameters) {
|
|
125
|
+
invokeParams.parameters = params.parameters;
|
|
126
|
+
}
|
|
127
|
+
if (params.datasets) {
|
|
128
|
+
invokeParams.dataset_slugs = params.datasets;
|
|
129
|
+
}
|
|
130
|
+
if (params.mode) {
|
|
131
|
+
invokeParams.mode = params.mode;
|
|
132
|
+
}
|
|
133
|
+
if (params.manualMocks) {
|
|
134
|
+
invokeParams.manual_mocks = params.manualMocks;
|
|
135
|
+
}
|
|
136
|
+
const response = await fetch(url, {
|
|
137
|
+
method: "POST",
|
|
138
|
+
headers: {
|
|
139
|
+
Authorization: `Bearer ${this.authToken}`,
|
|
140
|
+
"Content-Type": "application/json",
|
|
141
|
+
Accept: "text/event-stream"
|
|
142
|
+
},
|
|
143
|
+
body: JSON.stringify(invokeParams)
|
|
144
|
+
});
|
|
145
|
+
if (!response.ok) {
|
|
146
|
+
const errorText = await response.text();
|
|
147
|
+
throw new Error(`API request failed with status ${response.status}: ${errorText}`);
|
|
148
|
+
}
|
|
149
|
+
return response;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Extract structured result from SSE events
|
|
153
|
+
*
|
|
154
|
+
* Ported from: erdo-python-sdk/erdo/invoke/invoke.py - _extract_result_data()
|
|
155
|
+
*/
|
|
156
|
+
extractResult(botKey, events) {
|
|
157
|
+
const messages = [];
|
|
158
|
+
const steps = [];
|
|
159
|
+
const stepsSeenKeys = /* @__PURE__ */ new Set();
|
|
160
|
+
let finalResult;
|
|
161
|
+
let invocationId;
|
|
162
|
+
for (const event of events) {
|
|
163
|
+
if (!event) continue;
|
|
164
|
+
const payload = event.payload;
|
|
165
|
+
const metadata = event.metadata;
|
|
166
|
+
if (payload && typeof payload === "object") {
|
|
167
|
+
if ("invocation_id" in payload && !invocationId) {
|
|
168
|
+
invocationId = payload.invocation_id;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (payload && typeof payload === "object" && "action_type" in payload && "key" in payload) {
|
|
172
|
+
const stepKey = payload.key;
|
|
173
|
+
if (!stepsSeenKeys.has(stepKey)) {
|
|
174
|
+
stepsSeenKeys.add(stepKey);
|
|
175
|
+
steps.push({
|
|
176
|
+
key: stepKey,
|
|
177
|
+
action: payload.action_type,
|
|
178
|
+
status: "completed"
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (payload && typeof payload === "object" && "output" in payload && metadata?.user_visibility === "visible") {
|
|
183
|
+
const output = payload.output;
|
|
184
|
+
if (output && typeof output === "object" && "content" in output) {
|
|
185
|
+
const contentArray = output.content;
|
|
186
|
+
if (Array.isArray(contentArray)) {
|
|
187
|
+
for (const item of contentArray) {
|
|
188
|
+
if (item.content_type === "text") {
|
|
189
|
+
const role = metadata?.role || "assistant";
|
|
190
|
+
messages.push({
|
|
191
|
+
role,
|
|
192
|
+
content: item.content || ""
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (payload && typeof payload === "object" && "status" in payload && "output" in payload) {
|
|
200
|
+
finalResult = {
|
|
201
|
+
status: payload.status,
|
|
202
|
+
parameters: payload.parameters,
|
|
203
|
+
output: payload.output,
|
|
204
|
+
message: payload.message,
|
|
205
|
+
error: payload.error
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
success: true,
|
|
211
|
+
botId: botKey,
|
|
212
|
+
invocationId,
|
|
213
|
+
result: finalResult,
|
|
214
|
+
messages,
|
|
215
|
+
events,
|
|
216
|
+
steps
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
var defaultClient = null;
|
|
221
|
+
function getDefaultClient() {
|
|
222
|
+
if (!defaultClient) {
|
|
223
|
+
defaultClient = new ErdoClient();
|
|
224
|
+
}
|
|
225
|
+
return defaultClient;
|
|
226
|
+
}
|
|
227
|
+
async function invoke(botKey, params = {}) {
|
|
228
|
+
return getDefaultClient().invoke(botKey, params);
|
|
229
|
+
}
|
|
230
|
+
async function* invokeStream(botKey, params = {}) {
|
|
231
|
+
yield* getDefaultClient().invokeStream(botKey, params);
|
|
232
|
+
}
|
|
233
|
+
export {
|
|
234
|
+
ErdoClient,
|
|
235
|
+
collectSSEEvents,
|
|
236
|
+
getConfigFromEnv,
|
|
237
|
+
invoke,
|
|
238
|
+
invokeStream,
|
|
239
|
+
parseSSEStream,
|
|
240
|
+
resolveConfig
|
|
241
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@erdoai/server",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "Erdo server SDK for invoking agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public",
|
|
20
|
+
"registry": "https://registry.npmjs.org/"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup",
|
|
24
|
+
"dev": "tsup --watch",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"test:watch": "vitest"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"erdo",
|
|
31
|
+
"ai",
|
|
32
|
+
"agent",
|
|
33
|
+
"sdk"
|
|
34
|
+
],
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/erdoai/erdo-ts-sdk.git",
|
|
39
|
+
"directory": "packages/server"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@erdoai/types": "workspace:^"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^24.10.1",
|
|
46
|
+
"tsup": "^8.5.1",
|
|
47
|
+
"typescript": "^5.9.3",
|
|
48
|
+
"vitest": "^4.0.15"
|
|
49
|
+
}
|
|
50
|
+
}
|