@relevanceai/sdk 3.0.0-alpha.0 → 3.0.0-alpha.2
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 +320 -0
- package/package.json +4 -2
- package/script/agent-task.d.ts +61 -0
- package/script/agent-task.js +116 -0
- package/script/agent.d.ts +17 -0
- package/script/agent.js +56 -0
- package/script/client.d.ts +36 -0
- package/script/client.js +74 -0
- package/script/events.d.ts +40 -0
- package/script/events.js +48 -0
- package/script/key.d.ts +86 -0
- package/script/key.js +125 -0
- package/script/message.d.ts +18 -0
- package/script/message.js +22 -0
- package/script/mod.d.ts +7 -0
- package/script/mod.js +14 -0
- package/script/package.json +3 -0
- package/script/region.d.ts +5 -0
- package/script/region.js +10 -0
- package/script/task.d.ts +25 -0
- package/script/task.js +100 -0
- package/script/utils.d.ts +8 -0
- package/script/utils.js +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Relevance AI
|
|
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,320 @@
|
|
|
1
|
+
# Relevance AI JavaScript SDK
|
|
2
|
+
|
|
3
|
+
Build full-stack AI applications using our JavaScript SDK. This multi-environment
|
|
4
|
+
SDK enables you to integrate, extend, or build end-to-end solutions on top of
|
|
5
|
+
our powerful AI Workforce platform.
|
|
6
|
+
|
|
7
|
+
> **Note:** The SDK is in active development and not all features are available
|
|
8
|
+
> yet. Please refer to our roadmap for updates.
|
|
9
|
+
|
|
10
|
+
## Quickstart
|
|
11
|
+
|
|
12
|
+
```js
|
|
13
|
+
import { createClient, AU_REGION } from "@relevanceai/sdk";
|
|
14
|
+
|
|
15
|
+
// Create a client with your credentials
|
|
16
|
+
const client = createClient({
|
|
17
|
+
apiKey: "sk-abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKL",
|
|
18
|
+
region: AU_REGION,
|
|
19
|
+
project: "12345678-90ab-cdef-1234-567890abcdef",
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Create a task for an agent
|
|
23
|
+
const task = client.createTask({
|
|
24
|
+
agent: "fedcba09-8765-4321-fedc-ba0987654321",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Send a message to the agent
|
|
28
|
+
task.sendMessage(
|
|
29
|
+
"What is the weather like in Sydney, Australia this weekend?"
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
// Listen for responses
|
|
33
|
+
task.addEventListener("message", ({ detail }) => {
|
|
34
|
+
const { message } = detail;
|
|
35
|
+
console.log(message.text);
|
|
36
|
+
|
|
37
|
+
task.sendMessage("Thanks!");
|
|
38
|
+
|
|
39
|
+
// Important: Stop listening when done to prevent memory leaks
|
|
40
|
+
task.stopListening();
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Getting Started
|
|
45
|
+
|
|
46
|
+
The JavaScript SDK is a stateless, event-driven toolkit that provides the
|
|
47
|
+
flexibility to build any application you need. It sits on top of our API and
|
|
48
|
+
offers a streamlined developer experience, making it easier for your apps to
|
|
49
|
+
integrate with agents, tools, and workforces.
|
|
50
|
+
|
|
51
|
+
This multi-environment library allows you to build wherever modern JavaScript
|
|
52
|
+
runs:
|
|
53
|
+
|
|
54
|
+
- Node.js
|
|
55
|
+
- Deno
|
|
56
|
+
- Bun
|
|
57
|
+
- Cloudflare Workers
|
|
58
|
+
- Browser
|
|
59
|
+
|
|
60
|
+
### Installation
|
|
61
|
+
|
|
62
|
+
Install the SDK for your environment:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Node.js / Cloudflare Workers / Browser (with bundler)
|
|
66
|
+
npm install @relevanceai/sdk@latest
|
|
67
|
+
|
|
68
|
+
# Deno
|
|
69
|
+
deno add jsr:@relevanceai/sdk
|
|
70
|
+
|
|
71
|
+
# Bun
|
|
72
|
+
bun add @relevanceai/sdk@latest
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Browser (CDN)
|
|
76
|
+
|
|
77
|
+
If you are developing a frontend application and not using a bundler like
|
|
78
|
+
[Vite](https://vite.dev) or [Webpack](https://webpack.js.org), you can use the
|
|
79
|
+
CDN version directly:
|
|
80
|
+
|
|
81
|
+
```html
|
|
82
|
+
<script type="importmap">
|
|
83
|
+
{
|
|
84
|
+
"imports": {
|
|
85
|
+
"@relevanceai/sdk": "https://esm.run/@relevanceai/sdk"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
</script>
|
|
89
|
+
<script type="module">
|
|
90
|
+
import { createClient } from "@relevanceai/sdk";
|
|
91
|
+
// ...
|
|
92
|
+
</script>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Usage
|
|
96
|
+
|
|
97
|
+
### Keys
|
|
98
|
+
|
|
99
|
+
To communicate with Relevance AI, you will need a key. Keys authenticate your
|
|
100
|
+
requests and grant access to your project.
|
|
101
|
+
|
|
102
|
+
There are two types of keys: _API_ and _Embed_.
|
|
103
|
+
|
|
104
|
+
#### API Key
|
|
105
|
+
|
|
106
|
+
API keys grant access to the entire project, including agents, tools, and
|
|
107
|
+
workforces. This key is best used for server-side applications or protected web
|
|
108
|
+
apps where third parties do not have access.
|
|
109
|
+
|
|
110
|
+
Using the default client `createClient({ apiKey, region, project })` will create
|
|
111
|
+
an API Key for convenience. Alternatively, you can create a `Key` instance and
|
|
112
|
+
pass it to the client.
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
import { createClient, Key, AU_REGION } from "@relevanceai/sdk";
|
|
116
|
+
|
|
117
|
+
const apiKey = "sk-...";
|
|
118
|
+
const region = AU_REGION;
|
|
119
|
+
const project = "1234...";
|
|
120
|
+
|
|
121
|
+
const key = new Key({ apiKey, region, project });
|
|
122
|
+
const client = createClient(key);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### Embed Key
|
|
126
|
+
|
|
127
|
+
If you are developing a web app that allows third-party access, such as for your
|
|
128
|
+
customers, it's best to share resources from the Relevance AI platform. This
|
|
129
|
+
makes them available for public use and requires an embed key scoped only to
|
|
130
|
+
that resource.
|
|
131
|
+
|
|
132
|
+
To get an embed key, specify which public resource you wish to scope it to. For
|
|
133
|
+
example, to create an embed key for a publicly available agent in your project:
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
import { createClient, Key, AU_REGION } from "@relevanceai/sdk";
|
|
137
|
+
|
|
138
|
+
const region = AU_REGION;
|
|
139
|
+
const project = "1234...";
|
|
140
|
+
const agent = "abcd..."; // a *public* agent
|
|
141
|
+
|
|
142
|
+
const embedKey = await Key.generateEmbedKey({ region, project, agent });
|
|
143
|
+
const client = createClient(embedKey);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Clients
|
|
147
|
+
|
|
148
|
+
A client is the main entry point for the SDK. It configures communication with
|
|
149
|
+
Relevance AI and manages authentication.
|
|
150
|
+
|
|
151
|
+
You can create multiple clients, which is useful for multi-project setups.
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
import { Client, Key, AU_REGION } from "@relevanceai/sdk";
|
|
155
|
+
|
|
156
|
+
const apiKey = "sk-...";
|
|
157
|
+
const region = AU_REGION;
|
|
158
|
+
const projectOne = "1234...";
|
|
159
|
+
const projectTwo = "abcd...";
|
|
160
|
+
|
|
161
|
+
const oneKey = new Key({ apiKey, region, project: projectOne });
|
|
162
|
+
const twoKey = new Key({ apiKey, region, project: projectTwo });
|
|
163
|
+
|
|
164
|
+
const oneClient = new Client(oneKey);
|
|
165
|
+
const twoClient = new Client(twoKey);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### Default client
|
|
169
|
+
|
|
170
|
+
Typically, you will only need a single client. In this case, use the default
|
|
171
|
+
client factory as shown in the quickstart:
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
import { createClient, Client } from "@relevanceai/sdk";
|
|
175
|
+
|
|
176
|
+
const client = createClient({ apiKey, region, project });
|
|
177
|
+
|
|
178
|
+
// elsewhere in your app
|
|
179
|
+
Client.default();
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Attempting to create more than one default client will throw an error. Referencing
|
|
183
|
+
the default client before creating one will also throw an error.
|
|
184
|
+
|
|
185
|
+
### Tasks
|
|
186
|
+
|
|
187
|
+
Whenever you run anything in Relevance AI, these are known as tasks. Tasks have
|
|
188
|
+
a subject: an agent, tool, or workforce. You can send messages to these subjects,
|
|
189
|
+
receive replies, and follow updates and errors.
|
|
190
|
+
|
|
191
|
+
> **Important:** Always call `task.stopListening()` when you're done with a task
|
|
192
|
+
> to prevent memory leaks and clean up resources properly.
|
|
193
|
+
|
|
194
|
+
#### Creating Tasks
|
|
195
|
+
|
|
196
|
+
The easiest way to create a new task is to use the client's convenient method
|
|
197
|
+
`createTask` and provide the subject ID.
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
const agentId = "1234...";
|
|
201
|
+
const task = client.createTask({ agent: agentId });
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### Sending a Message
|
|
205
|
+
|
|
206
|
+
Once you have a task instance, you can send messages to the subject using the
|
|
207
|
+
`sendMessage()` method.
|
|
208
|
+
|
|
209
|
+
```js
|
|
210
|
+
task.sendMessage("How many letter r's are there in the word 'strawberry'?");
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Note that this call is not `async`. It sends the message and does not `await`
|
|
214
|
+
a reply. This is intentional, as tasks are event-driven.
|
|
215
|
+
|
|
216
|
+
### Events
|
|
217
|
+
|
|
218
|
+
Tasks are event-driven and an application must listen to predefined events to
|
|
219
|
+
manage the status and messages of a task.
|
|
220
|
+
|
|
221
|
+
Use `.addEventListener()` to listen for task events.
|
|
222
|
+
|
|
223
|
+
```js
|
|
224
|
+
task.sendMessage("What came first; the chicken or the egg?");
|
|
225
|
+
|
|
226
|
+
task.addEventListener("message", ({ detail }) => {
|
|
227
|
+
const { message } = detail;
|
|
228
|
+
console.log("> %s", message.text);
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Tasks dispatch `CustomEvent`. Event properties will be set in the `detail`
|
|
233
|
+
field of the event. You can see the types of events for more information about
|
|
234
|
+
the properties associated with different events.
|
|
235
|
+
|
|
236
|
+
Remember to call `task.stopListening()` once you no longer need to listen to
|
|
237
|
+
the task.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
The following events are available for agent subjects.
|
|
242
|
+
|
|
243
|
+
#### `start`
|
|
244
|
+
|
|
245
|
+
When a _new_ task starts.
|
|
246
|
+
|
|
247
|
+
**Details**
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
interface StartEventDetails {
|
|
251
|
+
id: string;
|
|
252
|
+
status: TaskStatus;
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
#### `status`
|
|
257
|
+
|
|
258
|
+
Whenever the task's _status_ changes.
|
|
259
|
+
|
|
260
|
+
> **Note:** this event does **not** fire for starting status. Use the `start`
|
|
261
|
+
> event if you need the initial status.
|
|
262
|
+
|
|
263
|
+
**Details**
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
interface StatusEventDetails {
|
|
267
|
+
status: TaskStatus;
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
##### `update`
|
|
272
|
+
|
|
273
|
+
A task has updated. This update will always be a tool for now but may expand in
|
|
274
|
+
the future.
|
|
275
|
+
|
|
276
|
+
**Details**
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
interface UpdateEventDetails {
|
|
280
|
+
update: TaskMessage<"tool">;
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
#### `message`
|
|
285
|
+
|
|
286
|
+
A task has received a message.
|
|
287
|
+
|
|
288
|
+
> **Note:** you will receive messages from _both_ subjects and users.
|
|
289
|
+
|
|
290
|
+
**Details**
|
|
291
|
+
|
|
292
|
+
```ts
|
|
293
|
+
interface MessageEventDetails {
|
|
294
|
+
message: TaskMessage<"agent" | "user">;
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
#### `error`
|
|
299
|
+
|
|
300
|
+
Whenever the task has failed.
|
|
301
|
+
|
|
302
|
+
**Details**
|
|
303
|
+
|
|
304
|
+
```ts
|
|
305
|
+
interface ErrorEventDetails {
|
|
306
|
+
error: TaskMessage<"error">;
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Example**
|
|
311
|
+
|
|
312
|
+
```js
|
|
313
|
+
task.addEventListener("error", ({ detail }) => {
|
|
314
|
+
const { error } = detail;
|
|
315
|
+
console.error("Task failed:", error.text);
|
|
316
|
+
|
|
317
|
+
// clean up
|
|
318
|
+
task.stopListening();
|
|
319
|
+
});
|
|
320
|
+
```
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@relevanceai/sdk",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.2",
|
|
4
4
|
"license": "MIT",
|
|
5
|
+
"main": "./script/mod.js",
|
|
5
6
|
"module": "./esm/mod.js",
|
|
6
7
|
"exports": {
|
|
7
8
|
".": {
|
|
8
|
-
"import": "./esm/mod.js"
|
|
9
|
+
"import": "./esm/mod.js",
|
|
10
|
+
"require": "./script/mod.js"
|
|
9
11
|
}
|
|
10
12
|
},
|
|
11
13
|
"scripts": {},
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Agent } from "./agent.js";
|
|
2
|
+
import { TaskMessage } from "./message.js";
|
|
3
|
+
import { Task, type TaskStatus } from "./task.js";
|
|
4
|
+
type AgentTaskEvents = {
|
|
5
|
+
start: {
|
|
6
|
+
status: TaskStatus;
|
|
7
|
+
};
|
|
8
|
+
status: {
|
|
9
|
+
status: TaskStatus;
|
|
10
|
+
};
|
|
11
|
+
message: {
|
|
12
|
+
message: TaskMessage<"agent-message" | "user-message">;
|
|
13
|
+
};
|
|
14
|
+
update: {
|
|
15
|
+
message: TaskMessage<"tool-run">;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export type AgentTaskState = "idle" | "starting-up" | "running" | "pending-approval" | "waiting-for-capacity" | "cancelled" | "timed-out" | "escalated" | "unrecoverable" | "paused" | "completed" | "errored-pending-approval" | "queued-for-approval" | "queued-for-rerun";
|
|
19
|
+
/**
|
|
20
|
+
* AgentTask represents a conversation task with an AI agent. It extends the
|
|
21
|
+
* base Task class with agent-specific functionality for sending messages and
|
|
22
|
+
* retrieving conversation history.
|
|
23
|
+
*
|
|
24
|
+
* @see {@link Task} for the base task functionality.
|
|
25
|
+
* @see {@link Agent} for the agent this task is associated with.
|
|
26
|
+
*
|
|
27
|
+
* @class AgentTask
|
|
28
|
+
* @extends Task<Agent, AgentTaskEvents>
|
|
29
|
+
*/
|
|
30
|
+
export declare class AgentTask extends Task<Agent, AgentTaskEvents> {
|
|
31
|
+
/**
|
|
32
|
+
* Sends a message to the agent. This method triggers the agent with the
|
|
33
|
+
* message and updates the task ID if this is the first message.
|
|
34
|
+
*
|
|
35
|
+
* Note: This method is asynchronous but doesn't return a promise. Use event
|
|
36
|
+
* listeners to track the response.
|
|
37
|
+
*
|
|
38
|
+
* @param {string} message
|
|
39
|
+
*/
|
|
40
|
+
sendMessage(message: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* Fetches the current status of the task from the API.
|
|
43
|
+
*
|
|
44
|
+
* @returns {Promise<TaskStatus>} The current task status.
|
|
45
|
+
* @throws {Error} if the agent or task ID is missing.
|
|
46
|
+
*/
|
|
47
|
+
fetchStatus(): Promise<TaskStatus>;
|
|
48
|
+
/**
|
|
49
|
+
* Fetches messages from the conversation.
|
|
50
|
+
*
|
|
51
|
+
* @param {Object} [options] Optional fetch options.
|
|
52
|
+
* @param {Date} [options.from] Fetch messages after this timestamp.
|
|
53
|
+
*
|
|
54
|
+
* @returns {Promise<TaskMessage[]>} Array of messages in ascending order.
|
|
55
|
+
* @throws {Error} if the agent or task ID is missing.
|
|
56
|
+
*/
|
|
57
|
+
fetchMessages({ from }?: {
|
|
58
|
+
from?: Date;
|
|
59
|
+
}): Promise<TaskMessage[]>;
|
|
60
|
+
}
|
|
61
|
+
export {};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AgentTask = void 0;
|
|
4
|
+
const message_js_1 = require("./message.js");
|
|
5
|
+
const task_js_1 = require("./task.js");
|
|
6
|
+
/**
|
|
7
|
+
* Converts an AgentTaskState to a simplified TaskStatus.
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*
|
|
11
|
+
* @param {AgentTaskState} state The agent task state to convert.
|
|
12
|
+
* @returns {TaskStatus} The simplified task status.
|
|
13
|
+
*/
|
|
14
|
+
function stateToStatus(state) {
|
|
15
|
+
switch (state) {
|
|
16
|
+
case "paused":
|
|
17
|
+
case "idle":
|
|
18
|
+
return "idle";
|
|
19
|
+
case "starting-up":
|
|
20
|
+
case "waiting-for-capacity":
|
|
21
|
+
case "queued-for-approval":
|
|
22
|
+
case "queued-for-rerun":
|
|
23
|
+
return "queued";
|
|
24
|
+
case "running":
|
|
25
|
+
return "running";
|
|
26
|
+
case "pending-approval":
|
|
27
|
+
case "escalated":
|
|
28
|
+
return "action";
|
|
29
|
+
case "timed-out":
|
|
30
|
+
return "error";
|
|
31
|
+
case "cancelled":
|
|
32
|
+
case "completed":
|
|
33
|
+
return "complete";
|
|
34
|
+
case "unrecoverable":
|
|
35
|
+
case "errored-pending-approval":
|
|
36
|
+
return "error";
|
|
37
|
+
default:
|
|
38
|
+
throw new Error(`unhandled task state: ${state}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* AgentTask represents a conversation task with an AI agent. It extends the
|
|
43
|
+
* base Task class with agent-specific functionality for sending messages and
|
|
44
|
+
* retrieving conversation history.
|
|
45
|
+
*
|
|
46
|
+
* @see {@link Task} for the base task functionality.
|
|
47
|
+
* @see {@link Agent} for the agent this task is associated with.
|
|
48
|
+
*
|
|
49
|
+
* @class AgentTask
|
|
50
|
+
* @extends Task<Agent, AgentTaskEvents>
|
|
51
|
+
*/
|
|
52
|
+
class AgentTask extends task_js_1.Task {
|
|
53
|
+
/**
|
|
54
|
+
* Sends a message to the agent. This method triggers the agent with the
|
|
55
|
+
* message and updates the task ID if this is the first message.
|
|
56
|
+
*
|
|
57
|
+
* Note: This method is asynchronous but doesn't return a promise. Use event
|
|
58
|
+
* listeners to track the response.
|
|
59
|
+
*
|
|
60
|
+
* @param {string} message
|
|
61
|
+
*/
|
|
62
|
+
sendMessage(message) {
|
|
63
|
+
this.subject.trigger(message, this.id || undefined).then(({ id, state }) => {
|
|
64
|
+
// started
|
|
65
|
+
if (!this.id) {
|
|
66
|
+
this.setId(id, stateToStatus(state));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Fetches the current status of the task from the API.
|
|
72
|
+
*
|
|
73
|
+
* @returns {Promise<TaskStatus>} The current task status.
|
|
74
|
+
* @throws {Error} if the agent or task ID is missing.
|
|
75
|
+
*/
|
|
76
|
+
async fetchStatus() {
|
|
77
|
+
if (!this.subject.id) {
|
|
78
|
+
throw new Error("expecting agent id");
|
|
79
|
+
}
|
|
80
|
+
if (!this.id) {
|
|
81
|
+
return "not-started";
|
|
82
|
+
}
|
|
83
|
+
const url = `/agents/${this.subject.id}/tasks/${this.id}/metadata`;
|
|
84
|
+
const res = await this.client.fetch(url);
|
|
85
|
+
return stateToStatus(res.metadata.conversation.state);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Fetches messages from the conversation.
|
|
89
|
+
*
|
|
90
|
+
* @param {Object} [options] Optional fetch options.
|
|
91
|
+
* @param {Date} [options.from] Fetch messages after this timestamp.
|
|
92
|
+
*
|
|
93
|
+
* @returns {Promise<TaskMessage[]>} Array of messages in ascending order.
|
|
94
|
+
* @throws {Error} if the agent or task ID is missing.
|
|
95
|
+
*/
|
|
96
|
+
async fetchMessages({ from = new Date(0) } = {}) {
|
|
97
|
+
if (!this.subject.id) {
|
|
98
|
+
throw new Error("expecting agent id");
|
|
99
|
+
}
|
|
100
|
+
if (!this.id) {
|
|
101
|
+
throw new Error("expecting task id");
|
|
102
|
+
}
|
|
103
|
+
const url = `/agents/${this.subject.id}/tasks/${this.id}/view`;
|
|
104
|
+
const res = await this.client.fetch(url, {
|
|
105
|
+
method: "POST",
|
|
106
|
+
body: JSON.stringify({
|
|
107
|
+
cursor: {
|
|
108
|
+
after: from.toISOString(),
|
|
109
|
+
},
|
|
110
|
+
}),
|
|
111
|
+
});
|
|
112
|
+
// message should be in ascending order
|
|
113
|
+
return res.results.reverse().map((data) => new message_js_1.TaskMessage(data));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
exports.AgentTask = AgentTask;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AgentTaskState } from "./agent-task.js";
|
|
2
|
+
import { Client } from "./client.js";
|
|
3
|
+
export declare class Agent {
|
|
4
|
+
#private;
|
|
5
|
+
private readonly client;
|
|
6
|
+
static fetch(agentId: string, cli?: Client): Promise<Agent>;
|
|
7
|
+
private constructor();
|
|
8
|
+
get id(): string;
|
|
9
|
+
get name(): string | undefined;
|
|
10
|
+
get description(): string | undefined;
|
|
11
|
+
get avatar(): string | undefined;
|
|
12
|
+
isPublic(): boolean;
|
|
13
|
+
trigger(message: string, taskId?: string): Promise<{
|
|
14
|
+
id: string;
|
|
15
|
+
state: AgentTaskState;
|
|
16
|
+
}>;
|
|
17
|
+
}
|
package/script/agent.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Agent = void 0;
|
|
4
|
+
const client_js_1 = require("./client.js");
|
|
5
|
+
const utils_js_1 = require("./utils.js");
|
|
6
|
+
const taskPrefixDelimiter = "_-_";
|
|
7
|
+
class Agent {
|
|
8
|
+
#config;
|
|
9
|
+
client;
|
|
10
|
+
static async fetch(agentId, cli = client_js_1.Client.default()) {
|
|
11
|
+
const config = await cli.fetch(`/agents/${agentId}/get`);
|
|
12
|
+
return new Agent(config.agent, cli);
|
|
13
|
+
}
|
|
14
|
+
constructor(config, client) {
|
|
15
|
+
this.#config = config;
|
|
16
|
+
this.client = client;
|
|
17
|
+
}
|
|
18
|
+
get id() {
|
|
19
|
+
return this.#config.agent_id;
|
|
20
|
+
}
|
|
21
|
+
get name() {
|
|
22
|
+
return this.#config.name;
|
|
23
|
+
}
|
|
24
|
+
get description() {
|
|
25
|
+
return this.#config.description;
|
|
26
|
+
}
|
|
27
|
+
get avatar() {
|
|
28
|
+
return this.#config.emoji;
|
|
29
|
+
}
|
|
30
|
+
isPublic() {
|
|
31
|
+
return this.#config.public;
|
|
32
|
+
}
|
|
33
|
+
async trigger(message, taskId) {
|
|
34
|
+
// embed keys require a task prefixing for new tasks
|
|
35
|
+
if (!taskId && this.client.isEmbedKey()) {
|
|
36
|
+
taskId = [this.client.key.taskPrefix, await (0, utils_js_1.randomUUID)()].join(taskPrefixDelimiter);
|
|
37
|
+
}
|
|
38
|
+
const res = await this.client.fetch("/agents/trigger", {
|
|
39
|
+
method: "POST",
|
|
40
|
+
body: JSON.stringify({
|
|
41
|
+
agent_id: this.#config.agent_id,
|
|
42
|
+
conversation_id: taskId,
|
|
43
|
+
message: {
|
|
44
|
+
role: "user",
|
|
45
|
+
content: message,
|
|
46
|
+
attachments: [], // @todo
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
id: res.conversation_id,
|
|
52
|
+
state: res.state,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.Agent = Agent;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Agent } from "./agent.js";
|
|
2
|
+
import { type Region } from "./region.js";
|
|
3
|
+
import { AgentTask } from "./agent-task.js";
|
|
4
|
+
import { Key } from "./key.js";
|
|
5
|
+
type CreateClientOptions = {
|
|
6
|
+
apiKey: string;
|
|
7
|
+
region: Region;
|
|
8
|
+
project: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Creates and returns the _default_ client instance.
|
|
12
|
+
*
|
|
13
|
+
* @throws {Error} if a default client already exists.
|
|
14
|
+
* @see {Client.default}
|
|
15
|
+
*/
|
|
16
|
+
export declare function createClient(keyOrOptions: Key | CreateClientOptions): Client;
|
|
17
|
+
export declare class Client {
|
|
18
|
+
/**
|
|
19
|
+
* Returns the _default_ client instance.
|
|
20
|
+
*
|
|
21
|
+
* @throws {Error} if there is no default client.
|
|
22
|
+
* @see {createClient}
|
|
23
|
+
*/
|
|
24
|
+
static default(): Client;
|
|
25
|
+
readonly key: Key;
|
|
26
|
+
private readonly baseURL;
|
|
27
|
+
constructor(key: Key);
|
|
28
|
+
get region(): Region;
|
|
29
|
+
get project(): string;
|
|
30
|
+
isEmbedKey(): boolean;
|
|
31
|
+
createTask({ agent }: {
|
|
32
|
+
agent: string | Agent;
|
|
33
|
+
}): Promise<AgentTask>;
|
|
34
|
+
fetch<T>(input: `/agents/trigger` | `/agents/${string}/get` | `/agents/${string}/tasks/${string}/metadata` | `/agents/${string}/tasks/${string}/view`, init?: RequestInit): Promise<T>;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
package/script/client.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Client = void 0;
|
|
4
|
+
exports.createClient = createClient;
|
|
5
|
+
const agent_js_1 = require("./agent.js");
|
|
6
|
+
const region_js_1 = require("./region.js");
|
|
7
|
+
const agent_task_js_1 = require("./agent-task.js");
|
|
8
|
+
const utils_js_1 = require("./utils.js");
|
|
9
|
+
const key_js_1 = require("./key.js");
|
|
10
|
+
let defaultClient;
|
|
11
|
+
/**
|
|
12
|
+
* Creates and returns the _default_ client instance.
|
|
13
|
+
*
|
|
14
|
+
* @throws {Error} if a default client already exists.
|
|
15
|
+
* @see {Client.default}
|
|
16
|
+
*/
|
|
17
|
+
function createClient(keyOrOptions) {
|
|
18
|
+
if (defaultClient) {
|
|
19
|
+
throw new Error("default client already exists");
|
|
20
|
+
}
|
|
21
|
+
const key = keyOrOptions instanceof key_js_1.Key ? keyOrOptions : new key_js_1.Key({
|
|
22
|
+
key: keyOrOptions.apiKey,
|
|
23
|
+
region: keyOrOptions.region,
|
|
24
|
+
project: keyOrOptions.project,
|
|
25
|
+
});
|
|
26
|
+
defaultClient = new Client(key);
|
|
27
|
+
return defaultClient;
|
|
28
|
+
}
|
|
29
|
+
class Client {
|
|
30
|
+
/**
|
|
31
|
+
* Returns the _default_ client instance.
|
|
32
|
+
*
|
|
33
|
+
* @throws {Error} if there is no default client.
|
|
34
|
+
* @see {createClient}
|
|
35
|
+
*/
|
|
36
|
+
static default() {
|
|
37
|
+
if (!defaultClient) {
|
|
38
|
+
throw new Error("no default client");
|
|
39
|
+
}
|
|
40
|
+
return defaultClient;
|
|
41
|
+
}
|
|
42
|
+
key;
|
|
43
|
+
baseURL;
|
|
44
|
+
constructor(key) {
|
|
45
|
+
this.key = key;
|
|
46
|
+
this.baseURL = (0, region_js_1.regionBaseURL)(this.key.region);
|
|
47
|
+
}
|
|
48
|
+
get region() {
|
|
49
|
+
return this.key.region;
|
|
50
|
+
}
|
|
51
|
+
get project() {
|
|
52
|
+
return this.key.project;
|
|
53
|
+
}
|
|
54
|
+
isEmbedKey() {
|
|
55
|
+
return this.key.isEmbed();
|
|
56
|
+
}
|
|
57
|
+
async createTask({ agent }) {
|
|
58
|
+
if (agent) {
|
|
59
|
+
return new agent_task_js_1.AgentTask(typeof agent === "string" ? await agent_js_1.Agent.fetch(agent) : agent, undefined, this);
|
|
60
|
+
}
|
|
61
|
+
throw new Error("task not implemented");
|
|
62
|
+
}
|
|
63
|
+
async fetch(input, init) {
|
|
64
|
+
const url = new URL((0, utils_js_1.cleanPath)(input), this.baseURL);
|
|
65
|
+
const headers = new Headers(this.key.fetchHeaders());
|
|
66
|
+
const response = await fetch(url, Object.assign({ headers }, init));
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
console.error(url, init, headers);
|
|
69
|
+
throw new Error(response.statusText);
|
|
70
|
+
}
|
|
71
|
+
return response.json();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.Client = Client;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { TaskMessage } from "./message.js";
|
|
2
|
+
import type { TaskStatus } from "./task.js";
|
|
3
|
+
export declare class TaskStartEvent extends CustomEvent<{
|
|
4
|
+
id: string;
|
|
5
|
+
status: TaskStatus;
|
|
6
|
+
}> {
|
|
7
|
+
readonly type = "start";
|
|
8
|
+
constructor(id: string, status: TaskStatus);
|
|
9
|
+
}
|
|
10
|
+
export declare class TaskStatusEvent extends CustomEvent<{
|
|
11
|
+
status: TaskStatus;
|
|
12
|
+
}> {
|
|
13
|
+
readonly type = "status";
|
|
14
|
+
constructor(status: TaskStatus);
|
|
15
|
+
}
|
|
16
|
+
export declare class TaskMessageEvent extends CustomEvent<{
|
|
17
|
+
message: TaskMessage;
|
|
18
|
+
}> {
|
|
19
|
+
readonly type = "message";
|
|
20
|
+
constructor(message: TaskMessage);
|
|
21
|
+
isUserMessage(): boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare class TaskUpdateEvent extends CustomEvent<{
|
|
24
|
+
message: TaskMessage;
|
|
25
|
+
}> {
|
|
26
|
+
readonly type = "update";
|
|
27
|
+
constructor(message: TaskMessage);
|
|
28
|
+
}
|
|
29
|
+
export declare class TaskActionEvent extends CustomEvent<{
|
|
30
|
+
message: TaskMessage;
|
|
31
|
+
}> {
|
|
32
|
+
readonly type = "action";
|
|
33
|
+
constructor(message: TaskMessage);
|
|
34
|
+
}
|
|
35
|
+
export declare class TaskErrorEvent extends CustomEvent<{
|
|
36
|
+
message: TaskMessage;
|
|
37
|
+
}> {
|
|
38
|
+
readonly type = "error";
|
|
39
|
+
constructor(message: TaskMessage);
|
|
40
|
+
}
|
package/script/events.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TaskErrorEvent = exports.TaskActionEvent = exports.TaskUpdateEvent = exports.TaskMessageEvent = exports.TaskStatusEvent = exports.TaskStartEvent = void 0;
|
|
4
|
+
class TaskStartEvent extends CustomEvent {
|
|
5
|
+
type = "start";
|
|
6
|
+
constructor(id, status) {
|
|
7
|
+
super("start", { detail: { id, status } });
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.TaskStartEvent = TaskStartEvent;
|
|
11
|
+
class TaskStatusEvent extends CustomEvent {
|
|
12
|
+
type = "status";
|
|
13
|
+
constructor(status) {
|
|
14
|
+
super("status", { detail: { status } });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.TaskStatusEvent = TaskStatusEvent;
|
|
18
|
+
class TaskMessageEvent extends CustomEvent {
|
|
19
|
+
type = "message";
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super("message", { detail: { message } });
|
|
22
|
+
}
|
|
23
|
+
isUserMessage() {
|
|
24
|
+
return this.detail.message.type === "user-message";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.TaskMessageEvent = TaskMessageEvent;
|
|
28
|
+
class TaskUpdateEvent extends CustomEvent {
|
|
29
|
+
type = "update";
|
|
30
|
+
constructor(message) {
|
|
31
|
+
super("update", { detail: { message } });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.TaskUpdateEvent = TaskUpdateEvent;
|
|
35
|
+
class TaskActionEvent extends CustomEvent {
|
|
36
|
+
type = "action";
|
|
37
|
+
constructor(message) {
|
|
38
|
+
super("action", { detail: { message } });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.TaskActionEvent = TaskActionEvent;
|
|
42
|
+
class TaskErrorEvent extends CustomEvent {
|
|
43
|
+
type = "error";
|
|
44
|
+
constructor(message) {
|
|
45
|
+
super("error", { detail: { message } });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.TaskErrorEvent = TaskErrorEvent;
|
package/script/key.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { Region } from "./mod.js";
|
|
2
|
+
type CreateKeyOptions = {
|
|
3
|
+
key: string;
|
|
4
|
+
region: Region;
|
|
5
|
+
project: string;
|
|
6
|
+
agentId?: string;
|
|
7
|
+
taskPrefix?: string;
|
|
8
|
+
};
|
|
9
|
+
type GenerateEmbedKeyOptions = Omit<CreateKeyOptions, "key" | "taskPrefix">;
|
|
10
|
+
/**
|
|
11
|
+
* Key is used to authenticate requests for the {@link Client}. A Key can be
|
|
12
|
+
* either a _full_ key or an _embed_ key.
|
|
13
|
+
*
|
|
14
|
+
* A full key has access to SDK features. An embed key is scoped to a specific
|
|
15
|
+
* agent and is only used to create and interact with tasks for that agent.
|
|
16
|
+
*
|
|
17
|
+
* @see {@link Key.generateEmbedKey} to generate an embed key for a specific agent.
|
|
18
|
+
*
|
|
19
|
+
* @class Key
|
|
20
|
+
*/
|
|
21
|
+
export declare class Key {
|
|
22
|
+
#private;
|
|
23
|
+
/**
|
|
24
|
+
* Generates an embed key for the specified agent. The embed key can then be
|
|
25
|
+
* used to create a {@link Client} instance that can create and interact with
|
|
26
|
+
* tasks for that agent.
|
|
27
|
+
*
|
|
28
|
+
* @throws {Error} if the request to generate an embed key fails.
|
|
29
|
+
*
|
|
30
|
+
* @param {GenerateEmbedKeyOptions} options The generation options.
|
|
31
|
+
*
|
|
32
|
+
* @returns {Promise<Key>}
|
|
33
|
+
*/
|
|
34
|
+
static generateEmbedKey({ region, project, agentId, }: GenerateEmbedKeyOptions): Promise<Key>;
|
|
35
|
+
/**
|
|
36
|
+
* The region the key is scoped to.
|
|
37
|
+
*
|
|
38
|
+
* @property {string} region
|
|
39
|
+
*/
|
|
40
|
+
readonly region: Region;
|
|
41
|
+
/**
|
|
42
|
+
* The project the key is scoped to.
|
|
43
|
+
*
|
|
44
|
+
* @property {string} project
|
|
45
|
+
*/
|
|
46
|
+
readonly project: string;
|
|
47
|
+
/**
|
|
48
|
+
* The agent ID the embed key is scoped to. This is `undefined` for full
|
|
49
|
+
* keys.
|
|
50
|
+
*
|
|
51
|
+
* @property {string | undefined} agentId
|
|
52
|
+
*/
|
|
53
|
+
readonly agentId: string | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* The task prefix used to namespace tasks created with the embed key. This
|
|
56
|
+
* is `undefined` for full keys.
|
|
57
|
+
*
|
|
58
|
+
* @property {string | undefined} taskPrefix
|
|
59
|
+
*/
|
|
60
|
+
readonly taskPrefix: string | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Creates a new {@link Key} instance with the provided options.
|
|
63
|
+
*
|
|
64
|
+
* @param {CreateKeyOptions} options
|
|
65
|
+
*/
|
|
66
|
+
constructor({ key, region, project, agentId, taskPrefix }: CreateKeyOptions);
|
|
67
|
+
/**
|
|
68
|
+
* Returns whether the key is an embed key.
|
|
69
|
+
*
|
|
70
|
+
* @returns {boolean}
|
|
71
|
+
*/
|
|
72
|
+
isEmbed(): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Returns the headers required for authenticating requests with this key.
|
|
75
|
+
*
|
|
76
|
+
* @returns {HeadersInit}
|
|
77
|
+
*/
|
|
78
|
+
fetchHeaders(): HeadersInit;
|
|
79
|
+
/**
|
|
80
|
+
* Returns a JSON representation of the key.
|
|
81
|
+
*
|
|
82
|
+
* @returns {CreateKeyOptions}
|
|
83
|
+
*/
|
|
84
|
+
toJSON(): CreateKeyOptions;
|
|
85
|
+
}
|
|
86
|
+
export {};
|
package/script/key.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Key = void 0;
|
|
4
|
+
const region_js_1 = require("./region.js");
|
|
5
|
+
const utils_js_1 = require("./utils.js");
|
|
6
|
+
/**
|
|
7
|
+
* Key is used to authenticate requests for the {@link Client}. A Key can be
|
|
8
|
+
* either a _full_ key or an _embed_ key.
|
|
9
|
+
*
|
|
10
|
+
* A full key has access to SDK features. An embed key is scoped to a specific
|
|
11
|
+
* agent and is only used to create and interact with tasks for that agent.
|
|
12
|
+
*
|
|
13
|
+
* @see {@link Key.generateEmbedKey} to generate an embed key for a specific agent.
|
|
14
|
+
*
|
|
15
|
+
* @class Key
|
|
16
|
+
*/
|
|
17
|
+
class Key {
|
|
18
|
+
/**
|
|
19
|
+
* Generates an embed key for the specified agent. The embed key can then be
|
|
20
|
+
* used to create a {@link Client} instance that can create and interact with
|
|
21
|
+
* tasks for that agent.
|
|
22
|
+
*
|
|
23
|
+
* @throws {Error} if the request to generate an embed key fails.
|
|
24
|
+
*
|
|
25
|
+
* @param {GenerateEmbedKeyOptions} options The generation options.
|
|
26
|
+
*
|
|
27
|
+
* @returns {Promise<Key>}
|
|
28
|
+
*/
|
|
29
|
+
static async generateEmbedKey({ region, project, agentId, }) {
|
|
30
|
+
const embedKeyURL = new URL((0, utils_js_1.cleanPath)("/agents/get_embed_key"), (0, region_js_1.regionBaseURL)(region));
|
|
31
|
+
const response = await fetch(embedKeyURL, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
body: JSON.stringify({ agent_id: agentId, project }),
|
|
34
|
+
});
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
throw new Error("failed to fetch embed key", { cause: response });
|
|
37
|
+
}
|
|
38
|
+
const { embed_key: embedKey, conversation_prefix: taskPrefix } = await response.json();
|
|
39
|
+
return new Key({
|
|
40
|
+
key: embedKey,
|
|
41
|
+
region,
|
|
42
|
+
project,
|
|
43
|
+
agentId,
|
|
44
|
+
taskPrefix,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The region the key is scoped to.
|
|
49
|
+
*
|
|
50
|
+
* @property {string} region
|
|
51
|
+
*/
|
|
52
|
+
region;
|
|
53
|
+
/**
|
|
54
|
+
* The project the key is scoped to.
|
|
55
|
+
*
|
|
56
|
+
* @property {string} project
|
|
57
|
+
*/
|
|
58
|
+
project;
|
|
59
|
+
/**
|
|
60
|
+
* The API key used for authentication.
|
|
61
|
+
*
|
|
62
|
+
* @private
|
|
63
|
+
* @property {string} key
|
|
64
|
+
*/
|
|
65
|
+
#key;
|
|
66
|
+
/**
|
|
67
|
+
* The agent ID the embed key is scoped to. This is `undefined` for full
|
|
68
|
+
* keys.
|
|
69
|
+
*
|
|
70
|
+
* @property {string | undefined} agentId
|
|
71
|
+
*/
|
|
72
|
+
agentId;
|
|
73
|
+
/**
|
|
74
|
+
* The task prefix used to namespace tasks created with the embed key. This
|
|
75
|
+
* is `undefined` for full keys.
|
|
76
|
+
*
|
|
77
|
+
* @property {string | undefined} taskPrefix
|
|
78
|
+
*/
|
|
79
|
+
taskPrefix;
|
|
80
|
+
/**
|
|
81
|
+
* Creates a new {@link Key} instance with the provided options.
|
|
82
|
+
*
|
|
83
|
+
* @param {CreateKeyOptions} options
|
|
84
|
+
*/
|
|
85
|
+
constructor({ key, region, project, agentId, taskPrefix }) {
|
|
86
|
+
this.#key = key;
|
|
87
|
+
this.region = region;
|
|
88
|
+
this.project = project;
|
|
89
|
+
this.agentId = agentId;
|
|
90
|
+
this.taskPrefix = taskPrefix;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Returns whether the key is an embed key.
|
|
94
|
+
*
|
|
95
|
+
* @returns {boolean}
|
|
96
|
+
*/
|
|
97
|
+
isEmbed() {
|
|
98
|
+
return (this.agentId !== undefined && this.taskPrefix !== undefined);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Returns the headers required for authenticating requests with this key.
|
|
102
|
+
*
|
|
103
|
+
* @returns {HeadersInit}
|
|
104
|
+
*/
|
|
105
|
+
fetchHeaders() {
|
|
106
|
+
return {
|
|
107
|
+
Authorization: `${this.project}:${this.#key}`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Returns a JSON representation of the key.
|
|
112
|
+
*
|
|
113
|
+
* @returns {CreateKeyOptions}
|
|
114
|
+
*/
|
|
115
|
+
toJSON() {
|
|
116
|
+
return {
|
|
117
|
+
key: this.#key,
|
|
118
|
+
region: this.region,
|
|
119
|
+
project: this.project,
|
|
120
|
+
agentId: this.agentId,
|
|
121
|
+
taskPrefix: this.taskPrefix,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.Key = Key;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type TaskMessageType = "user-message" | "agent-message" | "tool-run" | "agent-error";
|
|
2
|
+
export type MessageData = {
|
|
3
|
+
item_id: string;
|
|
4
|
+
insert_date_: string;
|
|
5
|
+
content: {
|
|
6
|
+
type: TaskMessageType;
|
|
7
|
+
text: string;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export declare class TaskMessage<T extends TaskMessageType = TaskMessageType> {
|
|
11
|
+
#private;
|
|
12
|
+
constructor(data: MessageData);
|
|
13
|
+
get id(): string;
|
|
14
|
+
get type(): T;
|
|
15
|
+
get createdAt(): Date;
|
|
16
|
+
get text(): string;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TaskMessage = void 0;
|
|
4
|
+
class TaskMessage {
|
|
5
|
+
#data;
|
|
6
|
+
constructor(data) {
|
|
7
|
+
this.#data = data;
|
|
8
|
+
}
|
|
9
|
+
get id() {
|
|
10
|
+
return this.#data.item_id;
|
|
11
|
+
}
|
|
12
|
+
get type() {
|
|
13
|
+
return this.#data.content.type;
|
|
14
|
+
}
|
|
15
|
+
get createdAt() {
|
|
16
|
+
return new Date(this.#data.insert_date_);
|
|
17
|
+
}
|
|
18
|
+
get text() {
|
|
19
|
+
return this.#data.content.text;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.TaskMessage = TaskMessage;
|
package/script/mod.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Agent } from "./agent.js";
|
|
2
|
+
export { Client, createClient } from "./client.js";
|
|
3
|
+
export { Key } from "./key.js";
|
|
4
|
+
export { type Region, REGION_AU, REGION_EU, REGION_US } from "./region.js";
|
|
5
|
+
export type { AgentTask } from "./agent-task.js";
|
|
6
|
+
export type { TaskMessage } from "./message.js";
|
|
7
|
+
export type { Task, TaskStatus } from "./task.js";
|
package/script/mod.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.REGION_US = exports.REGION_EU = exports.REGION_AU = exports.Key = exports.createClient = exports.Client = exports.Agent = void 0;
|
|
4
|
+
var agent_js_1 = require("./agent.js");
|
|
5
|
+
Object.defineProperty(exports, "Agent", { enumerable: true, get: function () { return agent_js_1.Agent; } });
|
|
6
|
+
var client_js_1 = require("./client.js");
|
|
7
|
+
Object.defineProperty(exports, "Client", { enumerable: true, get: function () { return client_js_1.Client; } });
|
|
8
|
+
Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return client_js_1.createClient; } });
|
|
9
|
+
var key_js_1 = require("./key.js");
|
|
10
|
+
Object.defineProperty(exports, "Key", { enumerable: true, get: function () { return key_js_1.Key; } });
|
|
11
|
+
var region_js_1 = require("./region.js");
|
|
12
|
+
Object.defineProperty(exports, "REGION_AU", { enumerable: true, get: function () { return region_js_1.REGION_AU; } });
|
|
13
|
+
Object.defineProperty(exports, "REGION_EU", { enumerable: true, get: function () { return region_js_1.REGION_EU; } });
|
|
14
|
+
Object.defineProperty(exports, "REGION_US", { enumerable: true, get: function () { return region_js_1.REGION_US; } });
|
package/script/region.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.REGION_AU = exports.REGION_EU = exports.REGION_US = void 0;
|
|
4
|
+
exports.regionBaseURL = regionBaseURL;
|
|
5
|
+
exports.REGION_US = "bcbe5a";
|
|
6
|
+
exports.REGION_EU = "d7b62b";
|
|
7
|
+
exports.REGION_AU = "f1db6c";
|
|
8
|
+
function regionBaseURL(region) {
|
|
9
|
+
return `https://api-${region}.stack.tryrelevance.com`;
|
|
10
|
+
}
|
package/script/task.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Client } from "./client.js";
|
|
2
|
+
import type { TaskMessage } from "./message.js";
|
|
3
|
+
export type TaskStatus = "not-started" | "idle" | "queued" | "running" | "action" | "complete" | "error";
|
|
4
|
+
export declare abstract class Task<S, E extends Record<string, unknown>> extends EventTarget {
|
|
5
|
+
#private;
|
|
6
|
+
readonly subject: S;
|
|
7
|
+
protected readonly client: Client;
|
|
8
|
+
private listenController;
|
|
9
|
+
abstract fetchMessages(fetchOptions?: {
|
|
10
|
+
from?: Date;
|
|
11
|
+
}): Promise<TaskMessage[]>;
|
|
12
|
+
abstract fetchStatus(): Promise<TaskStatus>;
|
|
13
|
+
constructor(subject: S, id?: string | undefined, client?: Client);
|
|
14
|
+
get id(): string | undefined;
|
|
15
|
+
protected setId(id: string, status?: TaskStatus): void;
|
|
16
|
+
listen(): void;
|
|
17
|
+
isListening(): boolean;
|
|
18
|
+
stopListening(): void;
|
|
19
|
+
addEventListener<K extends keyof E>(type: Extract<K, string>, listener: ((event: CustomEvent<E[K]>) => void) | {
|
|
20
|
+
handleEvent: (event: CustomEvent<E[K]>) => void;
|
|
21
|
+
} | null, options?: boolean | AddEventListenerOptions): void;
|
|
22
|
+
removeEventListener<K extends keyof E>(type: Extract<K, string>, listener: ((event: CustomEvent<E[K]>) => void) | {
|
|
23
|
+
handleEvent: (event: CustomEvent<E[K]>) => void;
|
|
24
|
+
} | null, options?: boolean | AddEventListenerOptions): void;
|
|
25
|
+
}
|
package/script/task.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Task = void 0;
|
|
4
|
+
const client_js_1 = require("./client.js");
|
|
5
|
+
const events_js_1 = require("./events.js");
|
|
6
|
+
const utils_js_1 = require("./utils.js");
|
|
7
|
+
class Task extends EventTarget {
|
|
8
|
+
subject;
|
|
9
|
+
client;
|
|
10
|
+
#id;
|
|
11
|
+
listenController;
|
|
12
|
+
constructor(subject, id = undefined, client = client_js_1.Client.default()) {
|
|
13
|
+
super();
|
|
14
|
+
this.subject = subject;
|
|
15
|
+
this.client = client;
|
|
16
|
+
this.#id = id;
|
|
17
|
+
}
|
|
18
|
+
get id() {
|
|
19
|
+
return this.#id;
|
|
20
|
+
}
|
|
21
|
+
setId(id, status = "not-started") {
|
|
22
|
+
if (this.#id) {
|
|
23
|
+
throw new Error("task id is already set");
|
|
24
|
+
}
|
|
25
|
+
// @ts-ignore: allow assignment to readonly in this special case
|
|
26
|
+
this.#id = id;
|
|
27
|
+
this.dispatchEvent(new events_js_1.TaskStartEvent(id, status));
|
|
28
|
+
}
|
|
29
|
+
listen() {
|
|
30
|
+
if (this.isListening()) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
this.listenController = new AbortController();
|
|
34
|
+
const signal = this.listenController.signal;
|
|
35
|
+
let currentStatus = null;
|
|
36
|
+
const messagesCursor = new Date(0);
|
|
37
|
+
void (0, utils_js_1.runInterval)(async () => {
|
|
38
|
+
// no task, yet
|
|
39
|
+
if (!this.id) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const [status, messages] = await Promise.all([
|
|
43
|
+
this.fetchStatus(),
|
|
44
|
+
this.fetchMessages({
|
|
45
|
+
from: messagesCursor,
|
|
46
|
+
}),
|
|
47
|
+
]);
|
|
48
|
+
if (!this.isListening()) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (status !== currentStatus) {
|
|
52
|
+
currentStatus = status;
|
|
53
|
+
this.dispatchEvent(new events_js_1.TaskStatusEvent(status));
|
|
54
|
+
}
|
|
55
|
+
if (messages.length) {
|
|
56
|
+
for (const message of messages) {
|
|
57
|
+
switch (message.type) {
|
|
58
|
+
case "agent-error":
|
|
59
|
+
this.dispatchEvent(new events_js_1.TaskErrorEvent(message));
|
|
60
|
+
break;
|
|
61
|
+
case "tool-run":
|
|
62
|
+
this.dispatchEvent(new events_js_1.TaskUpdateEvent(message));
|
|
63
|
+
break;
|
|
64
|
+
case "agent-message":
|
|
65
|
+
case "user-message":
|
|
66
|
+
this.dispatchEvent(new events_js_1.TaskMessageEvent(message));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
messagesCursor.setTime(
|
|
70
|
+
// +1 the api treats after inclusively
|
|
71
|
+
messages.at(-1).createdAt.getTime() + 1);
|
|
72
|
+
}
|
|
73
|
+
}, 15_000, { signal });
|
|
74
|
+
}
|
|
75
|
+
isListening() {
|
|
76
|
+
return this.listenController !== undefined;
|
|
77
|
+
}
|
|
78
|
+
stopListening() {
|
|
79
|
+
this.listenController?.abort();
|
|
80
|
+
this.listenController = undefined;
|
|
81
|
+
}
|
|
82
|
+
addEventListener(type, listener, options) {
|
|
83
|
+
this.listen();
|
|
84
|
+
const signal = AbortSignal.any([
|
|
85
|
+
...(options && typeof options === "object" && options.signal
|
|
86
|
+
? [options.signal]
|
|
87
|
+
: []),
|
|
88
|
+
this.listenController.signal,
|
|
89
|
+
]);
|
|
90
|
+
const capture = typeof options === "boolean"
|
|
91
|
+
? options
|
|
92
|
+
: Boolean(options?.capture);
|
|
93
|
+
const addOptions = Object.assign({}, options, { signal, capture });
|
|
94
|
+
super.addEventListener(type, listener, addOptions);
|
|
95
|
+
}
|
|
96
|
+
removeEventListener(type, listener, options) {
|
|
97
|
+
super.removeEventListener(type, listener, options);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
exports.Task = Task;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function abortPromise(signal: AbortSignal, reject?: boolean): Promise<void>;
|
|
2
|
+
export declare function delay(timeout: number): Promise<void>;
|
|
3
|
+
export declare function runInterval(runner: () => Promise<void> | void, interval: number, { signal, }?: {
|
|
4
|
+
signal?: AbortSignal;
|
|
5
|
+
immediate?: boolean;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
export declare function cleanPath(path: string, version?: string): string;
|
|
8
|
+
export declare function randomUUID(): Promise<any>;
|
package/script/utils.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.abortPromise = abortPromise;
|
|
37
|
+
exports.delay = delay;
|
|
38
|
+
exports.runInterval = runInterval;
|
|
39
|
+
exports.cleanPath = cleanPath;
|
|
40
|
+
exports.randomUUID = randomUUID;
|
|
41
|
+
function abortPromise(signal, reject) {
|
|
42
|
+
return new Promise((res, rej) => signal.addEventListener("abort", () => reject ? rej() : res()));
|
|
43
|
+
}
|
|
44
|
+
function delay(timeout) {
|
|
45
|
+
return new Promise((done) => setTimeout(done, timeout));
|
|
46
|
+
}
|
|
47
|
+
async function runInterval(runner, interval, { signal, } = {}) {
|
|
48
|
+
while (true) {
|
|
49
|
+
if (signal?.aborted) {
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
await runner();
|
|
53
|
+
await Promise.race([
|
|
54
|
+
delay(interval),
|
|
55
|
+
signal ? abortPromise(signal) : new Promise(() => { }),
|
|
56
|
+
]);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function cleanPath(path, version = "latest") {
|
|
60
|
+
return `/${version}/${path.trim().replace(/^\/+/, "")}`;
|
|
61
|
+
}
|
|
62
|
+
async function randomUUID() {
|
|
63
|
+
if (typeof crypto !== "undefined") {
|
|
64
|
+
return crypto.randomUUID();
|
|
65
|
+
}
|
|
66
|
+
// @ts-ignore allow this import for node builds
|
|
67
|
+
const cryptoModule = await Promise.resolve().then(() => __importStar(require("node:crypto")));
|
|
68
|
+
return cryptoModule.randomUUID();
|
|
69
|
+
}
|