@erdoai/server 0.1.8 → 0.1.9
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 +4 -2
- package/dist/index.d.ts +63 -5
- package/dist/index.js +3 -3
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ npm install @erdoai/server
|
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
|
-
### Basic Invocation
|
|
13
|
+
### Basic Invocation (Server-Only)
|
|
14
14
|
|
|
15
15
|
```typescript
|
|
16
16
|
import { ErdoClient } from '@erdoai/server';
|
|
@@ -28,7 +28,9 @@ const result = await client.invoke('data-analyst', {
|
|
|
28
28
|
console.log(result.messages);
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
> **Note**: `invoke()` and `invokeStream()` are for server-side processing only. They use `/bots/{key}/invoke` which returns raw SSE events. For React UI rendering with `@erdoai/ui` components, use thread-based messaging (`sendMessage()` or the `useThread` hook).
|
|
32
|
+
|
|
33
|
+
### Streaming (Server-Only)
|
|
32
34
|
|
|
33
35
|
```typescript
|
|
34
36
|
for await (const event of client.invokeStream('data-analyst', {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ErdoClientConfig, CreateTokenParams, TokenResponse, CreateThreadParams, Thread, ListThreadsResponse, SendMessageParams, SSEEvent, InvokeParams, InvokeResult } from '@erdoai/types';
|
|
1
|
+
import { ErdoClientConfig, CreateTokenParams, TokenResponse, CreateThreadParams, Thread, ListThreadsResponse, ListThreadMessagesResponse, SendMessageParams, SSEEvent, InvokeParams, InvokeResult } from '@erdoai/types';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Erdo Client for invoking agents
|
|
@@ -78,6 +78,21 @@ declare class ErdoClient {
|
|
|
78
78
|
* ```
|
|
79
79
|
*/
|
|
80
80
|
getThread(threadId: string): Promise<Thread>;
|
|
81
|
+
/**
|
|
82
|
+
* Get messages for a thread (chat history)
|
|
83
|
+
*
|
|
84
|
+
* Requires token authentication.
|
|
85
|
+
* Access is granted via RBAC external_user or explicit thread scope.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* const { messages } = await client.getThreadMessages(threadId);
|
|
90
|
+
* for (const msg of messages) {
|
|
91
|
+
* console.log(msg.role, msg.contents.length, 'content items');
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
getThreadMessages(threadId: string): Promise<ListThreadMessagesResponse>;
|
|
81
96
|
/**
|
|
82
97
|
* Send a message to a thread and stream the bot response
|
|
83
98
|
*
|
|
@@ -106,11 +121,48 @@ declare class ErdoClient {
|
|
|
106
121
|
*/
|
|
107
122
|
sendMessageAndWait(threadId: string, params: SendMessageParams): Promise<SSEEvent[]>;
|
|
108
123
|
/**
|
|
109
|
-
* Invoke an agent and wait for the complete result
|
|
124
|
+
* Invoke an agent and wait for the complete result.
|
|
125
|
+
*
|
|
126
|
+
* **Server-only**: This method uses the `/bots/{key}/invoke` endpoint which returns
|
|
127
|
+
* raw SSE events without message wrapping. Use this for server-side processing where
|
|
128
|
+
* you don't need React UI components.
|
|
129
|
+
*
|
|
130
|
+
* **For React UI rendering**, use thread-based messaging instead:
|
|
131
|
+
* - `useThread` hook (client-side with token auth)
|
|
132
|
+
* - `sendMessage()` / `sendMessageAndWait()` (server-side proxy)
|
|
133
|
+
*
|
|
134
|
+
* The thread endpoint wraps events with message metadata required by `handleSSEEvent`
|
|
135
|
+
* and the `Content` component for proper rendering.
|
|
136
|
+
*
|
|
137
|
+
* @example Server-side processing (no React)
|
|
138
|
+
* ```typescript
|
|
139
|
+
* const result = await client.invoke('data-analyst', {
|
|
140
|
+
* messages: [{ role: 'user', content: 'Analyze Q4 sales' }],
|
|
141
|
+
* });
|
|
142
|
+
* // Process result.messages, result.events, etc.
|
|
143
|
+
* ```
|
|
110
144
|
*/
|
|
111
145
|
invoke(botKey: string, params?: InvokeParams): Promise<InvokeResult>;
|
|
112
146
|
/**
|
|
113
|
-
* Invoke an agent and stream SSE events
|
|
147
|
+
* Invoke an agent and stream SSE events.
|
|
148
|
+
*
|
|
149
|
+
* **Server-only**: This method uses the `/bots/{key}/invoke` endpoint which returns
|
|
150
|
+
* raw SSE events without message wrapping. Use this for server-side processing or
|
|
151
|
+
* proxying to custom clients.
|
|
152
|
+
*
|
|
153
|
+
* **For React UI rendering**, use thread-based messaging instead:
|
|
154
|
+
* - `useThread` hook (client-side with token auth)
|
|
155
|
+
* - `sendMessage()` (server-side proxy to client)
|
|
156
|
+
*
|
|
157
|
+
* The thread endpoint wraps events with message metadata required by `handleSSEEvent`
|
|
158
|
+
* and the `Content` component for proper rendering.
|
|
159
|
+
*
|
|
160
|
+
* @example Server-side streaming (no React)
|
|
161
|
+
* ```typescript
|
|
162
|
+
* for await (const event of client.invokeStream('data-analyst', params)) {
|
|
163
|
+
* console.log(event.type, event.payload);
|
|
164
|
+
* }
|
|
165
|
+
* ```
|
|
114
166
|
*/
|
|
115
167
|
invokeStream(botKey: string, params?: InvokeParams): AsyncGenerator<SSEEvent, void, unknown>;
|
|
116
168
|
/**
|
|
@@ -129,7 +181,10 @@ declare class ErdoClient {
|
|
|
129
181
|
private extractResult;
|
|
130
182
|
}
|
|
131
183
|
/**
|
|
132
|
-
* Invoke an agent with a clean API
|
|
184
|
+
* Invoke an agent with a clean API.
|
|
185
|
+
*
|
|
186
|
+
* **Server-only**: Uses `/bots/{key}/invoke` which returns raw SSE events.
|
|
187
|
+
* For React UI rendering, use thread-based messaging (`useThread` hook or `sendMessage()`).
|
|
133
188
|
*
|
|
134
189
|
* @example
|
|
135
190
|
* ```typescript
|
|
@@ -143,7 +198,10 @@ declare class ErdoClient {
|
|
|
143
198
|
*/
|
|
144
199
|
declare function invoke(botKey: string, params?: InvokeParams): Promise<InvokeResult>;
|
|
145
200
|
/**
|
|
146
|
-
* Invoke an agent and stream events
|
|
201
|
+
* Invoke an agent and stream events.
|
|
202
|
+
*
|
|
203
|
+
* **Server-only**: Uses `/bots/{key}/invoke` which returns raw SSE events.
|
|
204
|
+
* For React UI rendering, use thread-based messaging (`useThread` hook or `sendMessage()`).
|
|
147
205
|
*
|
|
148
206
|
* @example
|
|
149
207
|
* ```typescript
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
2
|
-
`);
|
|
3
|
-
`+d;}}}}finally{e.releaseLock();}}function E(
|
|
1
|
+
var w="https://api.erdo.ai";function m(){let a=typeof process<"u"?process.env:{};return {endpoint:a.ERDO_ENDPOINT||w,authToken:a.ERDO_AUTH_TOKEN}}function g(a){let e=m(),t=a?.endpoint||e.endpoint||w,o=a?.authToken||e.authToken,n=a?.token;return {endpoint:t,authToken:o,token:n}}async function*l(a){if(!a.body)throw new Error("Response body is null");let e=a.body.getReader(),t=new TextDecoder,o="",n,s;try{for(;;){let{done:i,value:c}=await e.read();if(i){if(s!==void 0){let r=E(n,s);r&&(yield r);}break}o+=t.decode(c,{stream:!0});let u=o.split(`
|
|
2
|
+
`);o=u.pop()||"";for(let r of u){let h=r.trim();if(!h){if(s!==void 0){let d=E(n,s);d&&(yield d),n=void 0,s=void 0;}continue}if(h.startsWith("event:"))n=h.slice(6).trim();else if(h.startsWith("data:")){let d=h.slice(5).trim();s===void 0?s=d:s+=`
|
|
3
|
+
`+d;}}}}finally{e.releaseLock();}}function E(a,e){if(!e)return null;try{let t=JSON.parse(e);return a&&(t.type=a),t}catch{return {type:a,raw:e}}}async function f(a){let e=[];for await(let t of l(a))e.push(t);return e}var p=class{endpoint;authToken;token;constructor(e){let t=g(e);if(this.endpoint=t.endpoint,this.authToken=t.authToken,this.token=t.token,!this.authToken&&!this.token)throw new Error("Either authToken or token is required")}async createToken(e){if(!this.authToken)throw new Error("createToken requires authToken (API key) authentication");let t;if(e.botKeys&&e.botKeys.length>0){let c=`${this.endpoint}/resolve-bot-keys`,u=await fetch(c,{method:"POST",headers:{Authorization:`Bearer ${this.authToken}`,"Content-Type":"application/json"},body:JSON.stringify({keys:e.botKeys})});if(!u.ok){let d=await u.text();throw new Error(`Failed to resolve bot keys: ${u.status}: ${d}`)}let r=await u.json();t=Object.values(r.bots);let h=e.botKeys.filter(d=>!r.bots[d]);if(h.length>0)throw new Error(`Bot keys not found or access denied: ${h.join(", ")}`)}let o=`${this.endpoint}/tokens`,n={};t&&(n.bot_ids=t),e.datasetIds&&(n.dataset_ids=e.datasetIds),e.threadIds&&(n.thread_ids=e.threadIds),e.externalUserId&&(n.external_user_id=e.externalUserId),e.expiresInSeconds&&(n.expires_in_seconds=e.expiresInSeconds);let s=await fetch(o,{method:"POST",headers:{Authorization:`Bearer ${this.authToken}`,"Content-Type":"application/json"},body:JSON.stringify(n)});if(!s.ok){let c=await s.text();throw new Error(`Failed to create token: ${s.status}: ${c}`)}let i=await s.json();return {tokenId:i.token_id,token:i.token,expiresAt:i.expires_at}}async createThread(e={}){if(!this.token)throw new Error("createThread requires token authentication");let t=`${this.endpoint}/threads`,o={};e.name&&(o.name=e.name),e.datasetIds&&(o.dataset_ids=e.datasetIds);let n=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"},body:JSON.stringify(o)});if(!n.ok){let i=await n.text();throw new Error(`Failed to create thread: ${n.status}: ${i}`)}let s=await n.json();return {id:s.id,name:s.name,createdAt:s.created_at,updatedAt:s.updated_at}}async listThreads(){if(!this.token)throw new Error("listThreads requires token authentication");let e=`${this.endpoint}/threads-user`,t=await fetch(e,{method:"GET",headers:{Authorization:`Bearer ${this.token}`}});if(!t.ok){let n=await t.text();throw new Error(`Failed to list threads: ${t.status}: ${n}`)}return {threads:(await t.json()).threads.map(n=>({id:n.id,name:n.name,createdAt:n.created_at,updatedAt:n.updated_at}))}}async getThread(e){if(!this.token)throw new Error("getThread requires token authentication");let t=`${this.endpoint}/threads/${e}`,o=await fetch(t,{method:"GET",headers:{Authorization:`Bearer ${this.token}`}});if(!o.ok){let s=await o.text();throw new Error(`Failed to get thread: ${o.status}: ${s}`)}let n=await o.json();return {id:n.id,name:n.name,createdAt:n.created_at,updatedAt:n.updated_at}}async getThreadMessages(e){if(!this.token)throw new Error("getThreadMessages requires token authentication");let t=`${this.endpoint}/threads/${e}/messages`,o=await fetch(t,{method:"GET",headers:{Authorization:`Bearer ${this.token}`}});if(!o.ok){let s=await o.text();throw new Error(`Failed to get thread messages: ${o.status}: ${s}`)}return {messages:(await o.json()).messages.map(s=>({id:s.id,thread_id:s.thread_id,role:s.role,created_at:s.created_at,updated_at:s.updated_at,contents:s.contents.map(i=>({id:i.id,content_type:i.content_type,ui_content_type:i.ui_content_type,content:i.content,user_visibility:i.user_visibility,bot_visibility:i.bot_visibility,created_at:i.created_at}))}))}}async*sendMessage(e,t){if(!this.token)throw new Error("sendMessage requires token authentication");let o=`${this.endpoint}/threads/${e}/message`,n={content:t.content};t.botKey&&(n.bot_key=t.botKey);let s=await fetch(o,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json",Accept:"text/event-stream"},body:JSON.stringify(n)});if(!s.ok){let i=await s.text();throw new Error(`Failed to send message: ${s.status}: ${i}`)}yield*l(s);}async sendMessageAndWait(e,t){if(!this.token)throw new Error("sendMessageAndWait requires token authentication");let o=`${this.endpoint}/threads/${e}/message`,n={content:t.content};t.botKey&&(n.bot_key=t.botKey);let s=await fetch(o,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json",Accept:"text/event-stream"},body:JSON.stringify(n)});if(!s.ok){let i=await s.text();throw new Error(`Failed to send message: ${s.status}: ${i}`)}return f(s)}async invoke(e,t={}){let o=await this.collectEvents(e,t);return this.extractResult(e,o)}async*invokeStream(e,t={}){let o=await this.makeRequest(e,t);yield*l(o);}async collectEvents(e,t){let o=await this.makeRequest(e,t);return f(o)}async makeRequest(e,t){let o=`${this.endpoint}/bots/${e}/invoke`,n={};t.messages&&(n.messages=t.messages),t.parameters&&(n.parameters=t.parameters),t.datasets&&(n.dataset_slugs=t.datasets),t.mode&&(n.mode=t.mode),t.manualMocks&&(n.manual_mocks=t.manualMocks);let s=this.token||this.authToken,i=await fetch(o,{method:"POST",headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json",Accept:"text/event-stream"},body:JSON.stringify(n)});if(!i.ok){let c=await i.text();throw new Error(`API request failed with status ${i.status}: ${c}`)}return i}extractResult(e,t){let o=[],n=[],s=new Set,i,c;for(let u of t){if(!u)continue;let r=u.payload,h=u.metadata;if(r&&typeof r=="object"&&"invocation_id"in r&&!c&&(c=r.invocation_id),r&&typeof r=="object"&&"action_type"in r&&"key"in r){let d=r.key;s.has(d)||(s.add(d),n.push({key:d,action:r.action_type,status:"completed"}));}if(r&&typeof r=="object"&&"output"in r&&h?.user_visibility==="visible"){let d=r.output;if(d&&typeof d=="object"&&"content"in d){let y=d.content;if(Array.isArray(y)){for(let v of y)if(v.content_type==="text"){let S=h?.role||"assistant";o.push({role:S,content:v.content||""});}}}}r&&typeof r=="object"&&"status"in r&&"output"in r&&(i={status:r.status,parameters:r.parameters,output:r.output,message:r.message,error:r.error});}return {success:true,botKey:e,invocationId:c,result:i,messages:o,events:t,steps:n}}},k=null;function T(){return k||(k=new p),k}async function _(a,e={}){return T().invoke(a,e)}async function*b(a,e={}){yield*T().invokeStream(a,e);}export{p as ErdoClient,f as collectSSEEvents,m as getConfigFromEnv,_ as invoke,b as invokeStream,l as parseSSEStream,g as resolveConfig};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@erdoai/server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Erdo server SDK for invoking agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
23
|
"build": "tsup",
|
|
24
|
+
"build:check": "tsup --outDir dist-check",
|
|
24
25
|
"dev": "tsup --watch",
|
|
25
26
|
"typecheck": "tsc --noEmit",
|
|
26
27
|
"test": "vitest run",
|
|
@@ -39,7 +40,7 @@
|
|
|
39
40
|
"directory": "packages/server"
|
|
40
41
|
},
|
|
41
42
|
"dependencies": {
|
|
42
|
-
"@erdoai/types": "^0.1.
|
|
43
|
+
"@erdoai/types": "^0.1.8"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"@types/node": "^24.10.1",
|