@relevanceai/sdk 3.0.0-alpha.3 → 3.0.0-alpha.5
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 +195 -100
- package/esm/agent.d.ts +41 -8
- package/esm/agent.js +150 -13
- package/esm/client.d.ts +6 -1
- package/esm/client.js +38 -4
- package/esm/event.d.ts +6 -25
- package/esm/event.js +4 -19
- package/esm/key.d.ts +1 -1
- package/esm/message/agent-error.d.ts +7 -2
- package/esm/message/agent-error.js +8 -2
- package/esm/message/agent.d.ts +2 -2
- package/esm/message/agent.js +2 -2
- package/esm/message/task.d.ts +25 -4
- package/esm/message/task.js +26 -2
- package/esm/message/tool.d.ts +16 -6
- package/esm/message/tool.js +32 -6
- package/esm/message/user.d.ts +2 -2
- package/esm/message/user.js +2 -2
- package/esm/message/workforce-agent-handover.d.ts +23 -0
- package/esm/message/workforce-agent-handover.js +3 -0
- package/esm/message/workforce-agent.d.ts +23 -0
- package/esm/message/workforce-agent.js +3 -0
- package/esm/mod.d.ts +1 -6
- package/esm/mod.js +1 -1
- package/esm/task/agent-strategy.d.ts +26 -0
- package/esm/task/agent-strategy.js +63 -0
- package/esm/task/task.d.ts +59 -0
- package/esm/task/task.js +166 -0
- package/esm/task/workforce-strategy.d.ts +17 -0
- package/esm/task/workforce-strategy.js +68 -0
- package/esm/utils.d.ts +1 -0
- package/esm/utils.js +4 -0
- package/esm/workforce.d.ts +22 -0
- package/esm/workforce.js +50 -0
- package/package.json +1 -1
- package/script/agent.d.ts +41 -8
- package/script/agent.js +151 -13
- package/script/client.d.ts +6 -1
- package/script/client.js +37 -3
- package/script/event.d.ts +6 -25
- package/script/event.js +6 -23
- package/script/key.d.ts +1 -1
- package/script/message/agent-error.d.ts +7 -2
- package/script/message/agent-error.js +7 -1
- package/script/message/agent.d.ts +2 -2
- package/script/message/agent.js +1 -1
- package/script/message/task.d.ts +25 -4
- package/script/message/task.js +28 -4
- package/script/message/tool.d.ts +16 -6
- package/script/message/tool.js +31 -5
- package/script/message/user.d.ts +2 -2
- package/script/message/user.js +1 -1
- package/script/message/workforce-agent-handover.d.ts +23 -0
- package/script/message/workforce-agent-handover.js +7 -0
- package/script/message/workforce-agent.d.ts +23 -0
- package/script/message/workforce-agent.js +7 -0
- package/script/mod.d.ts +1 -6
- package/script/mod.js +3 -3
- package/script/task/agent-strategy.d.ts +26 -0
- package/script/task/agent-strategy.js +67 -0
- package/script/task/task.d.ts +59 -0
- package/script/task/task.js +170 -0
- package/script/task/workforce-strategy.d.ts +17 -0
- package/script/task/workforce-strategy.js +72 -0
- package/script/utils.d.ts +1 -0
- package/script/utils.js +5 -0
- package/script/workforce.d.ts +22 -0
- package/script/workforce.js +54 -0
- package/esm/task.d.ts +0 -57
- package/esm/task.js +0 -259
- package/script/task.d.ts +0 -57
- package/script/task.js +0 -263
package/esm/task.d.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { Agent } from "./agent.js";
|
|
2
|
-
import { Client } from "./client.js";
|
|
3
|
-
import { Emitter } from "./emitter.js";
|
|
4
|
-
import { AgentMessage } from "./message/agent.js";
|
|
5
|
-
import type { AnyTaskMessage } from "./message/task.js";
|
|
6
|
-
import { ToolMessage } from "./message/tool.js";
|
|
7
|
-
import { UserMessage } from "./message/user.js";
|
|
8
|
-
export type TaskState = "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";
|
|
9
|
-
export type TaskStatus = "not-started" | "idle" | "queued" | "running" | "action" | "complete" | "error";
|
|
10
|
-
type TaskMetadata = {
|
|
11
|
-
knowledge_set: string;
|
|
12
|
-
insert_date: string;
|
|
13
|
-
update_date: string;
|
|
14
|
-
conversation: {
|
|
15
|
-
created_by_user_id: string;
|
|
16
|
-
state: TaskState;
|
|
17
|
-
title: string;
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
type TaskEventMap = {
|
|
21
|
-
start: {
|
|
22
|
-
status: TaskStatus;
|
|
23
|
-
};
|
|
24
|
-
status: {
|
|
25
|
-
status: TaskStatus;
|
|
26
|
-
};
|
|
27
|
-
message: {
|
|
28
|
-
message: AgentMessage | UserMessage;
|
|
29
|
-
};
|
|
30
|
-
update: {
|
|
31
|
-
message: ToolMessage;
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
export declare const resetSubscribeBackoff: unique symbol;
|
|
35
|
-
export declare class Task extends Emitter<TaskEventMap> {
|
|
36
|
-
#private;
|
|
37
|
-
static get(id: string, agentOrAgentId: Agent | string, client?: Client): Promise<Task>;
|
|
38
|
-
readonly agent: Agent;
|
|
39
|
-
protected readonly client: Client;
|
|
40
|
-
protected constructor(metadata: TaskMetadata, agent: Agent, client?: Client);
|
|
41
|
-
get id(): string;
|
|
42
|
-
get title(): string;
|
|
43
|
-
get status(): TaskStatus;
|
|
44
|
-
isRunning(): boolean;
|
|
45
|
-
getMessages({ from }?: {
|
|
46
|
-
from?: Date;
|
|
47
|
-
}): Promise<AnyTaskMessage[]>;
|
|
48
|
-
protected refresh(): Promise<void>;
|
|
49
|
-
[resetSubscribeBackoff](): void;
|
|
50
|
-
subscribe(): void;
|
|
51
|
-
protected isSubscribed(): boolean;
|
|
52
|
-
unsubscribe(): void;
|
|
53
|
-
addEventListener<K extends keyof TaskEventMap>(type: Extract<K, string>, listener: ((event: CustomEvent<TaskEventMap[K]>) => void) | {
|
|
54
|
-
handleEvent: (event: CustomEvent<TaskEventMap[K]>) => void;
|
|
55
|
-
} | null, options?: boolean | AddEventListenerOptions): void;
|
|
56
|
-
}
|
|
57
|
-
export {};
|
package/esm/task.js
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import { Agent } from "./agent.js";
|
|
2
|
-
import { Client } from "./client.js";
|
|
3
|
-
import { Emitter } from "./emitter.js";
|
|
4
|
-
import { TaskErrorEvent, TaskMessageEvent, TaskStatusEvent, TaskUpdateEvent, } from "./event.js";
|
|
5
|
-
import { AgentErrorMessage, } from "./message/agent-error.js";
|
|
6
|
-
import { AgentMessage } from "./message/agent.js";
|
|
7
|
-
import { ToolMessage } from "./message/tool.js";
|
|
8
|
-
import { UserMessage } from "./message/user.js";
|
|
9
|
-
import { abortPromise, delay } from "./utils.js";
|
|
10
|
-
/**
|
|
11
|
-
* Converts an AgentTaskState to a simplified TaskStatus.
|
|
12
|
-
*
|
|
13
|
-
* @internal
|
|
14
|
-
*
|
|
15
|
-
* @param {AgentTaskState} state The agent task state to convert.
|
|
16
|
-
* @returns {TaskStatus} The simplified task status.
|
|
17
|
-
*/
|
|
18
|
-
function stateToStatus(state) {
|
|
19
|
-
switch (state) {
|
|
20
|
-
case "paused":
|
|
21
|
-
case "idle":
|
|
22
|
-
return "idle";
|
|
23
|
-
case "starting-up":
|
|
24
|
-
case "waiting-for-capacity":
|
|
25
|
-
case "queued-for-approval":
|
|
26
|
-
case "queued-for-rerun":
|
|
27
|
-
return "queued";
|
|
28
|
-
case "running":
|
|
29
|
-
return "running";
|
|
30
|
-
case "pending-approval":
|
|
31
|
-
case "escalated":
|
|
32
|
-
return "action";
|
|
33
|
-
case "timed-out":
|
|
34
|
-
return "error";
|
|
35
|
-
case "cancelled":
|
|
36
|
-
case "completed":
|
|
37
|
-
return "complete";
|
|
38
|
-
case "unrecoverable":
|
|
39
|
-
case "errored-pending-approval":
|
|
40
|
-
return "error";
|
|
41
|
-
default:
|
|
42
|
-
throw new Error(`unhandled task state: ${state}`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
export const resetSubscribeBackoff = Symbol("resetSubscribeBackoff");
|
|
46
|
-
export class Task extends Emitter {
|
|
47
|
-
static async get(id, agentOrAgentId, client = Client.default()) {
|
|
48
|
-
const agent = typeof agentOrAgentId === "string"
|
|
49
|
-
? await Agent.get(agentOrAgentId, client)
|
|
50
|
-
: agentOrAgentId;
|
|
51
|
-
const metadata = await Task.#fetchMetadata(id, agent.id, client);
|
|
52
|
-
return new Task(metadata, agent, client);
|
|
53
|
-
}
|
|
54
|
-
static #fetchMetadata(id, agentId, client) {
|
|
55
|
-
return client.fetch(`/agents/${agentId}/tasks/${id}/metadata`).then(({ metadata }) => metadata);
|
|
56
|
-
}
|
|
57
|
-
#controller;
|
|
58
|
-
#backoffMs = 1000;
|
|
59
|
-
#lastUpdatedAt;
|
|
60
|
-
#delayController;
|
|
61
|
-
#metadata;
|
|
62
|
-
agent;
|
|
63
|
-
client;
|
|
64
|
-
constructor(metadata, agent, client = Client.default()) {
|
|
65
|
-
super();
|
|
66
|
-
this.#metadata = metadata;
|
|
67
|
-
this.agent = agent;
|
|
68
|
-
this.client = client;
|
|
69
|
-
}
|
|
70
|
-
get id() {
|
|
71
|
-
return this.#metadata.knowledge_set;
|
|
72
|
-
}
|
|
73
|
-
get title() {
|
|
74
|
-
return this.#metadata.conversation.title ?? "";
|
|
75
|
-
}
|
|
76
|
-
get status() {
|
|
77
|
-
return stateToStatus(this.#metadata.conversation.state);
|
|
78
|
-
}
|
|
79
|
-
isRunning() {
|
|
80
|
-
switch (this.status) {
|
|
81
|
-
case "queued":
|
|
82
|
-
case "running":
|
|
83
|
-
return true;
|
|
84
|
-
default:
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
async getMessages({ from = new Date(0) } = {}) {
|
|
89
|
-
const url = `/agents/${this.agent.id}/tasks/${this.id}/view`;
|
|
90
|
-
const res = await this.client.fetch(url, {
|
|
91
|
-
method: "POST",
|
|
92
|
-
body: JSON.stringify({
|
|
93
|
-
page_size: 1_000, // @todo: pagination
|
|
94
|
-
cursor: {
|
|
95
|
-
after: from.toISOString(),
|
|
96
|
-
},
|
|
97
|
-
}),
|
|
98
|
-
});
|
|
99
|
-
// message should be in ascending order
|
|
100
|
-
return res.results.reverse().map((data) => {
|
|
101
|
-
switch (data.content.type) {
|
|
102
|
-
case "agent-error":
|
|
103
|
-
return new AgentErrorMessage(data);
|
|
104
|
-
case "agent-message":
|
|
105
|
-
return new AgentMessage(data);
|
|
106
|
-
case "tool-run":
|
|
107
|
-
return new ToolMessage(data);
|
|
108
|
-
case "user-message":
|
|
109
|
-
return new UserMessage(data);
|
|
110
|
-
default:
|
|
111
|
-
throw new Error("unknown message response");
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
async refresh() {
|
|
116
|
-
this.#metadata = await Task.#fetchMetadata(this.id, this.agent.id, this.client);
|
|
117
|
-
}
|
|
118
|
-
[resetSubscribeBackoff]() {
|
|
119
|
-
this.#backoffMs = 1000;
|
|
120
|
-
this.#delayController?.abort();
|
|
121
|
-
}
|
|
122
|
-
subscribe() {
|
|
123
|
-
if (this.isSubscribed()) {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
this.#controller = new AbortController();
|
|
127
|
-
const signal = this.#controller.signal;
|
|
128
|
-
let currentStatus = this.status;
|
|
129
|
-
const messagesCursor = new Date(0);
|
|
130
|
-
const emitted = new Set();
|
|
131
|
-
let lastMessage = null;
|
|
132
|
-
const pendingTools = new Map();
|
|
133
|
-
// Initialize backoff and tracking
|
|
134
|
-
this.#backoffMs = 1000;
|
|
135
|
-
this.#lastUpdatedAt = this.#metadata.update_date;
|
|
136
|
-
void (async () => {
|
|
137
|
-
while (this.isSubscribed() && !signal.aborted) {
|
|
138
|
-
try {
|
|
139
|
-
const [, result] = await Promise.allSettled([
|
|
140
|
-
this.refresh(),
|
|
141
|
-
this.getMessages({ from: messagesCursor }),
|
|
142
|
-
]);
|
|
143
|
-
if (!this.isSubscribed() || signal.aborted) {
|
|
144
|
-
break;
|
|
145
|
-
}
|
|
146
|
-
const messages = result.status === "fulfilled" ? result.value : [];
|
|
147
|
-
// Track if any changes occurred
|
|
148
|
-
let hasChanges = false;
|
|
149
|
-
// Check for status changes
|
|
150
|
-
if (this.status !== currentStatus) {
|
|
151
|
-
currentStatus = this.status;
|
|
152
|
-
this.dispatchEvent(new TaskStatusEvent(this.status));
|
|
153
|
-
hasChanges = true;
|
|
154
|
-
}
|
|
155
|
-
// Check for metadata update_date changes
|
|
156
|
-
if (this.#metadata.update_date !== this.#lastUpdatedAt) {
|
|
157
|
-
this.#lastUpdatedAt = this.#metadata.update_date;
|
|
158
|
-
hasChanges = true;
|
|
159
|
-
}
|
|
160
|
-
// Process messages
|
|
161
|
-
if (messages.length) {
|
|
162
|
-
hasChanges = true;
|
|
163
|
-
for (const message of messages) {
|
|
164
|
-
if (emitted.has(message.id)) {
|
|
165
|
-
switch (message.type) {
|
|
166
|
-
case "agent-error":
|
|
167
|
-
case "agent-message":
|
|
168
|
-
case "user-message":
|
|
169
|
-
// don't re-fire
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
emitted.add(message.id);
|
|
174
|
-
switch (message.type) {
|
|
175
|
-
case "agent-error":
|
|
176
|
-
this.dispatchEvent(new TaskErrorEvent(message));
|
|
177
|
-
break;
|
|
178
|
-
case "tool-run": {
|
|
179
|
-
const { status } = message;
|
|
180
|
-
if (pendingTools.get(message.id)?.status == status) {
|
|
181
|
-
// no change to the tool status
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
if (["pending", "running"].includes(status)) {
|
|
185
|
-
pendingTools.set(message.id, message);
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
pendingTools.delete(message.id);
|
|
189
|
-
}
|
|
190
|
-
this.dispatchEvent(new TaskUpdateEvent(message));
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
case "agent-message":
|
|
194
|
-
case "user-message":
|
|
195
|
-
this.dispatchEvent(new TaskMessageEvent(message));
|
|
196
|
-
}
|
|
197
|
-
lastMessage = message;
|
|
198
|
-
}
|
|
199
|
-
// +1 the api treats after inclusively
|
|
200
|
-
let nextCursor = messages.at(-1).createdAt.getTime() + 1;
|
|
201
|
-
// set the cursor as the earliest pending tool
|
|
202
|
-
for (const pending of pendingTools.values()) {
|
|
203
|
-
if (nextCursor > pending.createdAt.getTime()) {
|
|
204
|
-
nextCursor = pending.createdAt.getTime();
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
messagesCursor.setTime(nextCursor);
|
|
208
|
-
}
|
|
209
|
-
// Apply backoff logic
|
|
210
|
-
if (hasChanges) {
|
|
211
|
-
// Reset backoff on any changes
|
|
212
|
-
this.#backoffMs = 1000;
|
|
213
|
-
}
|
|
214
|
-
else if (!this.isRunning() && lastMessage?.isAgent()) {
|
|
215
|
-
// Apply exponential backoff when idle with last message from agent
|
|
216
|
-
this.#backoffMs = Math.min(this.#backoffMs * 2, 60000);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
finally {
|
|
220
|
-
// Wait for the backoff period or abort signal
|
|
221
|
-
if (!signal.aborted) {
|
|
222
|
-
// Create a new controller for this delay that can be aborted independently
|
|
223
|
-
this.#delayController = new AbortController();
|
|
224
|
-
await Promise.race([
|
|
225
|
-
delay(this.#backoffMs),
|
|
226
|
-
abortPromise(AbortSignal.any([
|
|
227
|
-
signal,
|
|
228
|
-
this.#delayController.signal,
|
|
229
|
-
])),
|
|
230
|
-
]);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
})();
|
|
235
|
-
}
|
|
236
|
-
isSubscribed() {
|
|
237
|
-
return this.#controller !== undefined;
|
|
238
|
-
}
|
|
239
|
-
unsubscribe() {
|
|
240
|
-
this.#delayController?.abort();
|
|
241
|
-
this.#controller?.abort();
|
|
242
|
-
this.#delayController = undefined;
|
|
243
|
-
this.#controller = undefined;
|
|
244
|
-
}
|
|
245
|
-
addEventListener(type, listener, options) {
|
|
246
|
-
this.subscribe();
|
|
247
|
-
const signal = AbortSignal.any([
|
|
248
|
-
...(options && typeof options === "object" && options.signal
|
|
249
|
-
? [options.signal]
|
|
250
|
-
: []),
|
|
251
|
-
this.#controller.signal,
|
|
252
|
-
]);
|
|
253
|
-
const capture = typeof options === "boolean"
|
|
254
|
-
? options
|
|
255
|
-
: Boolean(options?.capture);
|
|
256
|
-
const addOptions = Object.assign({}, options, { signal, capture });
|
|
257
|
-
super.addEventListener(type, listener, addOptions);
|
|
258
|
-
}
|
|
259
|
-
}
|
package/script/task.d.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { Agent } from "./agent.js";
|
|
2
|
-
import { Client } from "./client.js";
|
|
3
|
-
import { Emitter } from "./emitter.js";
|
|
4
|
-
import { AgentMessage } from "./message/agent.js";
|
|
5
|
-
import type { AnyTaskMessage } from "./message/task.js";
|
|
6
|
-
import { ToolMessage } from "./message/tool.js";
|
|
7
|
-
import { UserMessage } from "./message/user.js";
|
|
8
|
-
export type TaskState = "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";
|
|
9
|
-
export type TaskStatus = "not-started" | "idle" | "queued" | "running" | "action" | "complete" | "error";
|
|
10
|
-
type TaskMetadata = {
|
|
11
|
-
knowledge_set: string;
|
|
12
|
-
insert_date: string;
|
|
13
|
-
update_date: string;
|
|
14
|
-
conversation: {
|
|
15
|
-
created_by_user_id: string;
|
|
16
|
-
state: TaskState;
|
|
17
|
-
title: string;
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
type TaskEventMap = {
|
|
21
|
-
start: {
|
|
22
|
-
status: TaskStatus;
|
|
23
|
-
};
|
|
24
|
-
status: {
|
|
25
|
-
status: TaskStatus;
|
|
26
|
-
};
|
|
27
|
-
message: {
|
|
28
|
-
message: AgentMessage | UserMessage;
|
|
29
|
-
};
|
|
30
|
-
update: {
|
|
31
|
-
message: ToolMessage;
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
export declare const resetSubscribeBackoff: unique symbol;
|
|
35
|
-
export declare class Task extends Emitter<TaskEventMap> {
|
|
36
|
-
#private;
|
|
37
|
-
static get(id: string, agentOrAgentId: Agent | string, client?: Client): Promise<Task>;
|
|
38
|
-
readonly agent: Agent;
|
|
39
|
-
protected readonly client: Client;
|
|
40
|
-
protected constructor(metadata: TaskMetadata, agent: Agent, client?: Client);
|
|
41
|
-
get id(): string;
|
|
42
|
-
get title(): string;
|
|
43
|
-
get status(): TaskStatus;
|
|
44
|
-
isRunning(): boolean;
|
|
45
|
-
getMessages({ from }?: {
|
|
46
|
-
from?: Date;
|
|
47
|
-
}): Promise<AnyTaskMessage[]>;
|
|
48
|
-
protected refresh(): Promise<void>;
|
|
49
|
-
[resetSubscribeBackoff](): void;
|
|
50
|
-
subscribe(): void;
|
|
51
|
-
protected isSubscribed(): boolean;
|
|
52
|
-
unsubscribe(): void;
|
|
53
|
-
addEventListener<K extends keyof TaskEventMap>(type: Extract<K, string>, listener: ((event: CustomEvent<TaskEventMap[K]>) => void) | {
|
|
54
|
-
handleEvent: (event: CustomEvent<TaskEventMap[K]>) => void;
|
|
55
|
-
} | null, options?: boolean | AddEventListenerOptions): void;
|
|
56
|
-
}
|
|
57
|
-
export {};
|
package/script/task.js
DELETED
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Task = exports.resetSubscribeBackoff = void 0;
|
|
4
|
-
const agent_js_1 = require("./agent.js");
|
|
5
|
-
const client_js_1 = require("./client.js");
|
|
6
|
-
const emitter_js_1 = require("./emitter.js");
|
|
7
|
-
const event_js_1 = require("./event.js");
|
|
8
|
-
const agent_error_js_1 = require("./message/agent-error.js");
|
|
9
|
-
const agent_js_2 = require("./message/agent.js");
|
|
10
|
-
const tool_js_1 = require("./message/tool.js");
|
|
11
|
-
const user_js_1 = require("./message/user.js");
|
|
12
|
-
const utils_js_1 = require("./utils.js");
|
|
13
|
-
/**
|
|
14
|
-
* Converts an AgentTaskState to a simplified TaskStatus.
|
|
15
|
-
*
|
|
16
|
-
* @internal
|
|
17
|
-
*
|
|
18
|
-
* @param {AgentTaskState} state The agent task state to convert.
|
|
19
|
-
* @returns {TaskStatus} The simplified task status.
|
|
20
|
-
*/
|
|
21
|
-
function stateToStatus(state) {
|
|
22
|
-
switch (state) {
|
|
23
|
-
case "paused":
|
|
24
|
-
case "idle":
|
|
25
|
-
return "idle";
|
|
26
|
-
case "starting-up":
|
|
27
|
-
case "waiting-for-capacity":
|
|
28
|
-
case "queued-for-approval":
|
|
29
|
-
case "queued-for-rerun":
|
|
30
|
-
return "queued";
|
|
31
|
-
case "running":
|
|
32
|
-
return "running";
|
|
33
|
-
case "pending-approval":
|
|
34
|
-
case "escalated":
|
|
35
|
-
return "action";
|
|
36
|
-
case "timed-out":
|
|
37
|
-
return "error";
|
|
38
|
-
case "cancelled":
|
|
39
|
-
case "completed":
|
|
40
|
-
return "complete";
|
|
41
|
-
case "unrecoverable":
|
|
42
|
-
case "errored-pending-approval":
|
|
43
|
-
return "error";
|
|
44
|
-
default:
|
|
45
|
-
throw new Error(`unhandled task state: ${state}`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
exports.resetSubscribeBackoff = Symbol("resetSubscribeBackoff");
|
|
49
|
-
class Task extends emitter_js_1.Emitter {
|
|
50
|
-
static async get(id, agentOrAgentId, client = client_js_1.Client.default()) {
|
|
51
|
-
const agent = typeof agentOrAgentId === "string"
|
|
52
|
-
? await agent_js_1.Agent.get(agentOrAgentId, client)
|
|
53
|
-
: agentOrAgentId;
|
|
54
|
-
const metadata = await Task.#fetchMetadata(id, agent.id, client);
|
|
55
|
-
return new Task(metadata, agent, client);
|
|
56
|
-
}
|
|
57
|
-
static #fetchMetadata(id, agentId, client) {
|
|
58
|
-
return client.fetch(`/agents/${agentId}/tasks/${id}/metadata`).then(({ metadata }) => metadata);
|
|
59
|
-
}
|
|
60
|
-
#controller;
|
|
61
|
-
#backoffMs = 1000;
|
|
62
|
-
#lastUpdatedAt;
|
|
63
|
-
#delayController;
|
|
64
|
-
#metadata;
|
|
65
|
-
agent;
|
|
66
|
-
client;
|
|
67
|
-
constructor(metadata, agent, client = client_js_1.Client.default()) {
|
|
68
|
-
super();
|
|
69
|
-
this.#metadata = metadata;
|
|
70
|
-
this.agent = agent;
|
|
71
|
-
this.client = client;
|
|
72
|
-
}
|
|
73
|
-
get id() {
|
|
74
|
-
return this.#metadata.knowledge_set;
|
|
75
|
-
}
|
|
76
|
-
get title() {
|
|
77
|
-
return this.#metadata.conversation.title ?? "";
|
|
78
|
-
}
|
|
79
|
-
get status() {
|
|
80
|
-
return stateToStatus(this.#metadata.conversation.state);
|
|
81
|
-
}
|
|
82
|
-
isRunning() {
|
|
83
|
-
switch (this.status) {
|
|
84
|
-
case "queued":
|
|
85
|
-
case "running":
|
|
86
|
-
return true;
|
|
87
|
-
default:
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
async getMessages({ from = new Date(0) } = {}) {
|
|
92
|
-
const url = `/agents/${this.agent.id}/tasks/${this.id}/view`;
|
|
93
|
-
const res = await this.client.fetch(url, {
|
|
94
|
-
method: "POST",
|
|
95
|
-
body: JSON.stringify({
|
|
96
|
-
page_size: 1_000, // @todo: pagination
|
|
97
|
-
cursor: {
|
|
98
|
-
after: from.toISOString(),
|
|
99
|
-
},
|
|
100
|
-
}),
|
|
101
|
-
});
|
|
102
|
-
// message should be in ascending order
|
|
103
|
-
return res.results.reverse().map((data) => {
|
|
104
|
-
switch (data.content.type) {
|
|
105
|
-
case "agent-error":
|
|
106
|
-
return new agent_error_js_1.AgentErrorMessage(data);
|
|
107
|
-
case "agent-message":
|
|
108
|
-
return new agent_js_2.AgentMessage(data);
|
|
109
|
-
case "tool-run":
|
|
110
|
-
return new tool_js_1.ToolMessage(data);
|
|
111
|
-
case "user-message":
|
|
112
|
-
return new user_js_1.UserMessage(data);
|
|
113
|
-
default:
|
|
114
|
-
throw new Error("unknown message response");
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
async refresh() {
|
|
119
|
-
this.#metadata = await Task.#fetchMetadata(this.id, this.agent.id, this.client);
|
|
120
|
-
}
|
|
121
|
-
[exports.resetSubscribeBackoff]() {
|
|
122
|
-
this.#backoffMs = 1000;
|
|
123
|
-
this.#delayController?.abort();
|
|
124
|
-
}
|
|
125
|
-
subscribe() {
|
|
126
|
-
if (this.isSubscribed()) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
this.#controller = new AbortController();
|
|
130
|
-
const signal = this.#controller.signal;
|
|
131
|
-
let currentStatus = this.status;
|
|
132
|
-
const messagesCursor = new Date(0);
|
|
133
|
-
const emitted = new Set();
|
|
134
|
-
let lastMessage = null;
|
|
135
|
-
const pendingTools = new Map();
|
|
136
|
-
// Initialize backoff and tracking
|
|
137
|
-
this.#backoffMs = 1000;
|
|
138
|
-
this.#lastUpdatedAt = this.#metadata.update_date;
|
|
139
|
-
void (async () => {
|
|
140
|
-
while (this.isSubscribed() && !signal.aborted) {
|
|
141
|
-
try {
|
|
142
|
-
const [, result] = await Promise.allSettled([
|
|
143
|
-
this.refresh(),
|
|
144
|
-
this.getMessages({ from: messagesCursor }),
|
|
145
|
-
]);
|
|
146
|
-
if (!this.isSubscribed() || signal.aborted) {
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
const messages = result.status === "fulfilled" ? result.value : [];
|
|
150
|
-
// Track if any changes occurred
|
|
151
|
-
let hasChanges = false;
|
|
152
|
-
// Check for status changes
|
|
153
|
-
if (this.status !== currentStatus) {
|
|
154
|
-
currentStatus = this.status;
|
|
155
|
-
this.dispatchEvent(new event_js_1.TaskStatusEvent(this.status));
|
|
156
|
-
hasChanges = true;
|
|
157
|
-
}
|
|
158
|
-
// Check for metadata update_date changes
|
|
159
|
-
if (this.#metadata.update_date !== this.#lastUpdatedAt) {
|
|
160
|
-
this.#lastUpdatedAt = this.#metadata.update_date;
|
|
161
|
-
hasChanges = true;
|
|
162
|
-
}
|
|
163
|
-
// Process messages
|
|
164
|
-
if (messages.length) {
|
|
165
|
-
hasChanges = true;
|
|
166
|
-
for (const message of messages) {
|
|
167
|
-
if (emitted.has(message.id)) {
|
|
168
|
-
switch (message.type) {
|
|
169
|
-
case "agent-error":
|
|
170
|
-
case "agent-message":
|
|
171
|
-
case "user-message":
|
|
172
|
-
// don't re-fire
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
emitted.add(message.id);
|
|
177
|
-
switch (message.type) {
|
|
178
|
-
case "agent-error":
|
|
179
|
-
this.dispatchEvent(new event_js_1.TaskErrorEvent(message));
|
|
180
|
-
break;
|
|
181
|
-
case "tool-run": {
|
|
182
|
-
const { status } = message;
|
|
183
|
-
if (pendingTools.get(message.id)?.status == status) {
|
|
184
|
-
// no change to the tool status
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
if (["pending", "running"].includes(status)) {
|
|
188
|
-
pendingTools.set(message.id, message);
|
|
189
|
-
}
|
|
190
|
-
else {
|
|
191
|
-
pendingTools.delete(message.id);
|
|
192
|
-
}
|
|
193
|
-
this.dispatchEvent(new event_js_1.TaskUpdateEvent(message));
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
196
|
-
case "agent-message":
|
|
197
|
-
case "user-message":
|
|
198
|
-
this.dispatchEvent(new event_js_1.TaskMessageEvent(message));
|
|
199
|
-
}
|
|
200
|
-
lastMessage = message;
|
|
201
|
-
}
|
|
202
|
-
// +1 the api treats after inclusively
|
|
203
|
-
let nextCursor = messages.at(-1).createdAt.getTime() + 1;
|
|
204
|
-
// set the cursor as the earliest pending tool
|
|
205
|
-
for (const pending of pendingTools.values()) {
|
|
206
|
-
if (nextCursor > pending.createdAt.getTime()) {
|
|
207
|
-
nextCursor = pending.createdAt.getTime();
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
messagesCursor.setTime(nextCursor);
|
|
211
|
-
}
|
|
212
|
-
// Apply backoff logic
|
|
213
|
-
if (hasChanges) {
|
|
214
|
-
// Reset backoff on any changes
|
|
215
|
-
this.#backoffMs = 1000;
|
|
216
|
-
}
|
|
217
|
-
else if (!this.isRunning() && lastMessage?.isAgent()) {
|
|
218
|
-
// Apply exponential backoff when idle with last message from agent
|
|
219
|
-
this.#backoffMs = Math.min(this.#backoffMs * 2, 60000);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
finally {
|
|
223
|
-
// Wait for the backoff period or abort signal
|
|
224
|
-
if (!signal.aborted) {
|
|
225
|
-
// Create a new controller for this delay that can be aborted independently
|
|
226
|
-
this.#delayController = new AbortController();
|
|
227
|
-
await Promise.race([
|
|
228
|
-
(0, utils_js_1.delay)(this.#backoffMs),
|
|
229
|
-
(0, utils_js_1.abortPromise)(AbortSignal.any([
|
|
230
|
-
signal,
|
|
231
|
-
this.#delayController.signal,
|
|
232
|
-
])),
|
|
233
|
-
]);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
})();
|
|
238
|
-
}
|
|
239
|
-
isSubscribed() {
|
|
240
|
-
return this.#controller !== undefined;
|
|
241
|
-
}
|
|
242
|
-
unsubscribe() {
|
|
243
|
-
this.#delayController?.abort();
|
|
244
|
-
this.#controller?.abort();
|
|
245
|
-
this.#delayController = undefined;
|
|
246
|
-
this.#controller = undefined;
|
|
247
|
-
}
|
|
248
|
-
addEventListener(type, listener, options) {
|
|
249
|
-
this.subscribe();
|
|
250
|
-
const signal = AbortSignal.any([
|
|
251
|
-
...(options && typeof options === "object" && options.signal
|
|
252
|
-
? [options.signal]
|
|
253
|
-
: []),
|
|
254
|
-
this.#controller.signal,
|
|
255
|
-
]);
|
|
256
|
-
const capture = typeof options === "boolean"
|
|
257
|
-
? options
|
|
258
|
-
: Boolean(options?.capture);
|
|
259
|
-
const addOptions = Object.assign({}, options, { signal, capture });
|
|
260
|
-
super.addEventListener(type, listener, addOptions);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
exports.Task = Task;
|