@relevanceai/sdk 3.0.0-rc.1 → 3.0.0-rc.3

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/esm/agent.js CHANGED
@@ -2,6 +2,7 @@ import { Client } from "./client.js";
2
2
  import { randomUUID } from "./utils.js";
3
3
  import { AgentStrategy, } from "./task/agent-strategy.js";
4
4
  import { resetBackoffDuration, Task } from "./task/task.js";
5
+ import { TASK_PREFIX_DELIM } from "./const.js";
5
6
  /**
6
7
  * Converts an AgentTaskState to a simplified TaskStatus.
7
8
  *
@@ -87,7 +88,6 @@ function taskSortOptionsToParam(sort) {
87
88
  }
88
89
  throw new Error("invalid sort option");
89
90
  }
90
- const taskPrefixDelimiter = "_-_";
91
91
  export class Agent {
92
92
  static async get(id, client = Client.default()) {
93
93
  const config = await Agent.#fetchConfig(id, client);
@@ -187,7 +187,7 @@ export class Agent {
187
187
  let taskId;
188
188
  // embed keys require a task prefixing for new tasks
189
189
  if (!task && this.client.isEmbedKey()) {
190
- taskId = [this.client.key.taskPrefix, await randomUUID()].join(taskPrefixDelimiter);
190
+ taskId = [this.client.key.taskPrefix, await randomUUID()].join(TASK_PREFIX_DELIM);
191
191
  }
192
192
  else if (task) {
193
193
  taskId = task.id;
package/esm/client.d.ts CHANGED
@@ -30,7 +30,7 @@ export declare class Client {
30
30
  get region(): Region;
31
31
  get project(): string;
32
32
  isEmbedKey(): boolean;
33
- fetch<T>(input: "/agents/trigger" | `/agents/${string}/get` | `/agents/${string}/tasks/${string}/metadata` | `/agents/${string}/tasks/${string}/view` | "/agents/conversations/list" | "/services/get_temporary_file_upload_url" | `/workforce/items/${string}` | `/workforce/tasks/${string}/metadata` | `/workforce/items/${string}/tasks/${string}/messages` | "/workforce/trigger" | "/agents/list", init?: RequestInit): Promise<T>;
33
+ fetch<T>(input: "/agents/trigger" | `/agents/${string}/get` | `/agents/${string}/tasks/${string}/metadata` | `/agents/${string}/tasks/${string}/view` | "/agents/conversations/list" | "/services/get_temporary_file_upload_url" | `/workforce/items/${string}` | `/workforce/tasks/${string}/metadata` | `/workforce/items/${string}/tasks/${string}/messages` | "/workforce/trigger" | "/workforce/tasks/list" | "/agents/list", init?: RequestInit): Promise<T>;
34
34
  url(path: string): URL;
35
35
  uploadTempFile(file: File): Promise<Attachment>;
36
36
  }
package/esm/const.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare const TASK_PREFIX_DELIM = "_-_";
package/esm/const.js ADDED
@@ -0,0 +1 @@
1
+ export const TASK_PREFIX_DELIM = "_-_";
package/esm/key.d.ts CHANGED
@@ -4,9 +4,13 @@ type CreateKeyOptions = {
4
4
  region: Region;
5
5
  project: string;
6
6
  agentId?: string;
7
+ workforceId?: string;
7
8
  taskPrefix?: string;
8
9
  };
9
- type GenerateEmbedKeyOptions = Omit<CreateKeyOptions, "key" | "taskPrefix">;
10
+ type GenerateEmbedKeyOptions = {
11
+ region: Region;
12
+ project: string;
13
+ };
10
14
  /**
11
15
  * Key is used to authenticate requests for the {@link Client}. A Key can be
12
16
  * either a _full_ key or an _embed_ key.
@@ -31,7 +35,13 @@ export declare class Key {
31
35
  *
32
36
  * @returns {Promise<Key>}
33
37
  */
34
- static generateEmbedKey({ region, project, agentId, }: GenerateEmbedKeyOptions): Promise<Key>;
38
+ static generateEmbedKey(options: GenerateEmbedKeyOptions & ({
39
+ workforceId: string;
40
+ } | {
41
+ agentId: string;
42
+ })): Promise<Key>;
43
+ private static generateAgentEmbedKey;
44
+ private static generateWorkforceEmbedKey;
35
45
  /**
36
46
  * The region the key is scoped to.
37
47
  *
@@ -46,11 +56,18 @@ export declare class Key {
46
56
  readonly project: string;
47
57
  /**
48
58
  * The agent ID the embed key is scoped to. This is `undefined` for full
49
- * keys.
59
+ * keys and workforce embed keys.
50
60
  *
51
61
  * @property {string | undefined} agentId
52
62
  */
53
63
  readonly agentId: string | undefined;
64
+ /**
65
+ * The workforce ID the embed key is scoped to. This is `undefined` for full
66
+ * keys
67
+ *
68
+ * @property {string | undefined} workforceId
69
+ */
70
+ readonly workforceId: string | undefined;
54
71
  /**
55
72
  * The task prefix used to namespace tasks created with the embed key. This
56
73
  * is `undefined` for full keys.
@@ -63,7 +80,7 @@ export declare class Key {
63
80
  *
64
81
  * @param {CreateKeyOptions} options
65
82
  */
66
- constructor({ key, region, project, agentId, taskPrefix }: CreateKeyOptions);
83
+ constructor({ key, region, project, agentId, workforceId, taskPrefix }: CreateKeyOptions);
67
84
  /**
68
85
  * Returns whether the key is an embed key.
69
86
  *
package/esm/key.js CHANGED
@@ -23,14 +23,23 @@ export class Key {
23
23
  *
24
24
  * @returns {Promise<Key>}
25
25
  */
26
- static async generateEmbedKey({ region, project, agentId, }) {
26
+ static async generateEmbedKey(options) {
27
+ if ("workforceId" in options) {
28
+ return await Key.generateWorkforceEmbedKey(options);
29
+ }
30
+ if ("agentId" in options) {
31
+ return await Key.generateAgentEmbedKey(options);
32
+ }
33
+ throw new Error("invalid embed key options");
34
+ }
35
+ static async generateAgentEmbedKey({ region, project, agentId }) {
27
36
  const embedKeyURL = new URL(cleanPath("/agents/get_embed_key"), regionBaseURL(region));
28
37
  const response = await fetch(embedKeyURL, {
29
38
  method: "POST",
30
39
  body: JSON.stringify({ agent_id: agentId, project }),
31
40
  });
32
41
  if (!response.ok) {
33
- throw new Error("failed to fetch embed key", { cause: response });
42
+ throw new Error("failed to fetch agent embed key", { cause: response });
34
43
  }
35
44
  const { embed_key: embedKey, conversation_prefix: taskPrefix } = await response.json();
36
45
  return new Key({
@@ -41,6 +50,26 @@ export class Key {
41
50
  taskPrefix,
42
51
  });
43
52
  }
53
+ static async generateWorkforceEmbedKey({ region, project, workforceId }) {
54
+ const embedKeyURL = new URL(cleanPath("/workforce/get_embed_key"), regionBaseURL(region));
55
+ const response = await fetch(embedKeyURL, {
56
+ method: "POST",
57
+ body: JSON.stringify({ workforce_id: workforceId, project }),
58
+ });
59
+ if (!response.ok) {
60
+ throw new Error("failed to fetch workforce embed key", {
61
+ cause: response,
62
+ });
63
+ }
64
+ const { embed_key: embedKey, conversation_prefix: taskPrefix } = await response.json();
65
+ return new Key({
66
+ key: embedKey,
67
+ region,
68
+ project,
69
+ workforceId,
70
+ taskPrefix,
71
+ });
72
+ }
44
73
  /**
45
74
  * The region the key is scoped to.
46
75
  *
@@ -62,11 +91,18 @@ export class Key {
62
91
  #key;
63
92
  /**
64
93
  * The agent ID the embed key is scoped to. This is `undefined` for full
65
- * keys.
94
+ * keys and workforce embed keys.
66
95
  *
67
96
  * @property {string | undefined} agentId
68
97
  */
69
98
  agentId;
99
+ /**
100
+ * The workforce ID the embed key is scoped to. This is `undefined` for full
101
+ * keys
102
+ *
103
+ * @property {string | undefined} workforceId
104
+ */
105
+ workforceId;
70
106
  /**
71
107
  * The task prefix used to namespace tasks created with the embed key. This
72
108
  * is `undefined` for full keys.
@@ -79,12 +115,13 @@ export class Key {
79
115
  *
80
116
  * @param {CreateKeyOptions} options
81
117
  */
82
- constructor({ key, region, project, agentId, taskPrefix }) {
118
+ constructor({ key, region, project, agentId, workforceId, taskPrefix }) {
83
119
  this.#key = key;
84
120
  this.region = region;
85
121
  this.project = project;
86
122
  this.agentId = agentId;
87
123
  this.taskPrefix = taskPrefix;
124
+ this.workforceId = workforceId;
88
125
  }
89
126
  /**
90
127
  * Returns whether the key is an embed key.
@@ -92,7 +129,8 @@ export class Key {
92
129
  * @returns {boolean}
93
130
  */
94
131
  isEmbed() {
95
- return (this.agentId !== undefined && this.taskPrefix !== undefined);
132
+ return ((this.agentId !== undefined || this.workforceId !== undefined) &&
133
+ this.taskPrefix !== undefined);
96
134
  }
97
135
  /**
98
136
  * Returns the headers required for authenticating requests with this key.
@@ -114,8 +152,12 @@ export class Key {
114
152
  key: this.#key,
115
153
  region: this.region,
116
154
  project: this.project,
117
- agentId: this.agentId,
118
- taskPrefix: this.taskPrefix,
155
+ ...(this.agentId
156
+ ? { agentId: this.agentId, taskPrefix: this.taskPrefix }
157
+ : {}),
158
+ ...(this.workforceId
159
+ ? { workforceId: this.workforceId, taskPrefix: this.taskPrefix }
160
+ : {}),
119
161
  };
120
162
  }
121
163
  }
@@ -1,9 +1,14 @@
1
- import { GenericMessage } from "./task.js";
1
+ import type { Agent } from "../agent.js";
2
+ import { GenericMessage, type TaskMessageData } from "./task.js";
2
3
  export interface AgentMessageContent {
3
4
  type: "agent-message";
4
5
  text: string;
6
+ thought_about_tool_calls?: boolean;
5
7
  }
6
8
  export declare class AgentMessage extends GenericMessage<AgentMessageContent> {
9
+ readonly agent?: Agent;
10
+ constructor(message: TaskMessageData<AgentMessageContent>, agent?: Agent);
7
11
  get text(): string;
8
12
  get agentId(): string;
13
+ isThought(): boolean;
9
14
  }
@@ -1,9 +1,17 @@
1
1
  import { GenericMessage } from "./task.js";
2
2
  export class AgentMessage extends GenericMessage {
3
+ agent;
4
+ constructor(message, agent) {
5
+ super(message);
6
+ this.agent = agent;
7
+ }
3
8
  get text() {
4
9
  return this.message.content.text;
5
10
  }
6
11
  get agentId() {
7
- return "";
12
+ return this.agent?.id ?? "";
13
+ }
14
+ isThought() {
15
+ return this.message.content.thought_about_tool_calls ?? false;
8
16
  }
9
17
  }
package/esm/mod.d.ts CHANGED
@@ -4,3 +4,4 @@ export { Key } from "./key.js";
4
4
  export { type Region, REGION_AU, REGION_EU, REGION_US } from "./region.js";
5
5
  export { Workforce } from "./workforce.js";
6
6
  export type { Task } from "./task/task.js";
7
+ export type { AnyTaskMessage } from "./message/task.js";
@@ -50,7 +50,7 @@ export class AgentStrategy {
50
50
  case "agent-error":
51
51
  return new AgentErrorMessage(data);
52
52
  case "agent-message":
53
- return new AgentMessage(data);
53
+ return new AgentMessage(data, this.agent);
54
54
  case "tool-run":
55
55
  return new ToolMessage(data);
56
56
  case "user-message":
@@ -2,16 +2,22 @@ import type { AnyTaskMessage } from "../message/task.js";
2
2
  import { Client } from "../client.js";
3
3
  import { Task, type TaskMetadata, type TaskStatus, type TaskStrategy } from "./task.js";
4
4
  import type { Workforce } from "../workforce.js";
5
+ export type WorkforceTaskState = "running" | "completed" | "execution-limit-reached" | "pending-approval" | "errored-pending-approval" | "escalated";
6
+ /**
7
+ * Converts a WorkforceTaskState to a simplified TaskStatus.
8
+ *
9
+ * @param {WorkforceTaskState} state The workforce task state to convert.
10
+ * @returns {TaskStatus} The simplified task status.
11
+ */
12
+ export declare function stateToStatus(state: WorkforceTaskState): TaskStatus;
5
13
  export declare class WorkforceStrategy implements TaskStrategy<Workforce> {
6
14
  static get(id: string, workforce: Workforce, client?: Client): Promise<Task<Workforce>>;
7
- static convertStatus(): TaskStatus;
15
+ static convertStatus(state: WorkforceTaskState): TaskStatus;
8
16
  private readonly id;
9
17
  private readonly workforce;
10
18
  private readonly client;
11
- private constructor();
19
+ constructor(id: string, workforce: Workforce, client: Client);
12
20
  get subject(): Workforce;
13
- getMessages({ after: _after }: {
14
- after?: Date;
15
- }): Promise<AnyTaskMessage[]>;
21
+ getMessages(): Promise<AnyTaskMessage[]>;
16
22
  getMetadata(): Promise<TaskMetadata>;
17
23
  }
@@ -6,14 +6,37 @@ import { ToolMessage } from "../message/tool.js";
6
6
  import { UserMessage } from "../message/user.js";
7
7
  import { WorkforceAgentMessage, } from "../message/workforce-agent.js";
8
8
  import { WorkforceAgentHandoverMessage, } from "../message/workforce-agent-handover.js";
9
+ /**
10
+ * Converts a WorkforceTaskState to a simplified TaskStatus.
11
+ *
12
+ * @param {WorkforceTaskState} state The workforce task state to convert.
13
+ * @returns {TaskStatus} The simplified task status.
14
+ */
15
+ export function stateToStatus(state) {
16
+ switch (state) {
17
+ case "running":
18
+ return "running";
19
+ case "completed":
20
+ return "completed";
21
+ case "execution-limit-reached":
22
+ return "error";
23
+ case "pending-approval":
24
+ case "escalated":
25
+ return "action";
26
+ case "errored-pending-approval":
27
+ return "error";
28
+ default:
29
+ throw new Error(`unhandled workforce task state: ${state}`);
30
+ }
31
+ }
9
32
  export class WorkforceStrategy {
10
33
  static async get(id, workforce, client = Client.default()) {
11
34
  const subject = new this(id, workforce, client);
12
35
  const metadata = await subject.getMetadata();
13
36
  return new Task(metadata, subject);
14
37
  }
15
- static convertStatus() {
16
- return "not-implemented";
38
+ static convertStatus(state) {
39
+ return stateToStatus(state);
17
40
  }
18
41
  id;
19
42
  workforce;
@@ -26,7 +49,7 @@ export class WorkforceStrategy {
26
49
  get subject() {
27
50
  return this.workforce;
28
51
  }
29
- async getMessages({ after: _after }) {
52
+ async getMessages() {
30
53
  const { results } = await this.client.fetch(`/workforce/items/${this.workforce.id}/tasks/${this.id}/messages`, {
31
54
  method: "POST",
32
55
  body: JSON.stringify({
@@ -60,7 +83,7 @@ export class WorkforceStrategy {
60
83
  region: this.client.region,
61
84
  project: this.client.project,
62
85
  name: metadata.title,
63
- status: WorkforceStrategy.convertStatus(), // @todo: not implemented
86
+ status: WorkforceStrategy.convertStatus(metadata.requested_state),
64
87
  createdAt: new Date(metadata.insert_date),
65
88
  updatedAt: new Date(metadata.update_date),
66
89
  };
@@ -1,12 +1,17 @@
1
1
  import { Client } from "./client.js";
2
2
  import type { Region } from "./region.js";
3
- import { type Task } from "./task/task.js";
3
+ import { Task } from "./task/task.js";
4
4
  type WorkforceConfig = {
5
5
  id: string;
6
6
  workforce_metadata: {
7
7
  name: string;
8
8
  };
9
9
  };
10
+ type GetTaskOptions = {
11
+ pageSize?: number;
12
+ cursor?: string;
13
+ search?: string;
14
+ };
10
15
  export declare class Workforce {
11
16
  #private;
12
17
  static get(id: string, client?: Client): Promise<Workforce>;
@@ -17,6 +22,7 @@ export declare class Workforce {
17
22
  get project(): string;
18
23
  get name(): string;
19
24
  getTask(id: string): Promise<Task<Workforce>>;
25
+ getTasks({ pageSize, cursor, search, }?: GetTaskOptions): Promise<Task<Workforce>[]>;
20
26
  sendMessage(message: string, task?: Task<Workforce>): Promise<Task<Workforce>>;
21
27
  }
22
28
  export {};
package/esm/workforce.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { Client } from "./client.js";
2
- import { resetBackoffDuration } from "./task/task.js";
3
- import { WorkforceStrategy } from "./task/workforce-strategy.js";
2
+ import { TASK_PREFIX_DELIM } from "./const.js";
3
+ import { resetBackoffDuration, Task } from "./task/task.js";
4
+ import { WorkforceStrategy, } from "./task/workforce-strategy.js";
5
+ import { randomUUID } from "./utils.js";
4
6
  export class Workforce {
5
7
  static async get(id, client = Client.default()) {
6
8
  const config = await client.fetch(`/workforce/items/${id}`);
@@ -27,12 +29,45 @@ export class Workforce {
27
29
  async getTask(id) {
28
30
  return await WorkforceStrategy.get(id, this, this.client);
29
31
  }
32
+ async getTasks({ pageSize = 100, cursor, search, } = {}) {
33
+ const body = {
34
+ workforce_id: this.id,
35
+ page_size: pageSize,
36
+ };
37
+ if (search?.trim()) {
38
+ body.query = search.trim();
39
+ }
40
+ if (cursor?.trim()) {
41
+ body.cursor = cursor.trim();
42
+ }
43
+ const { results } = await this.client.fetch("/workforce/tasks/list", {
44
+ method: "POST",
45
+ body: JSON.stringify(body),
46
+ });
47
+ return results.map((t) => new Task({
48
+ id: t.workforce_task_id,
49
+ region: this.client.region,
50
+ project: this.client.project,
51
+ name: t.title,
52
+ status: WorkforceStrategy.convertStatus(t.state),
53
+ createdAt: new Date(t.insert_date),
54
+ updatedAt: new Date(t.update_date),
55
+ }, new WorkforceStrategy(t.workforce_task_id, this, this.client)));
56
+ }
30
57
  async sendMessage(message, task) {
31
- const { workforce_task_id: taskId } = await this.client.fetch("/workforce/trigger", {
58
+ let taskId;
59
+ // embed keys require a task prefixing for new tasks
60
+ if (!task && this.client.isEmbedKey()) {
61
+ taskId = [this.client.key.taskPrefix, await randomUUID()].join(TASK_PREFIX_DELIM);
62
+ }
63
+ else if (task) {
64
+ taskId = task.id;
65
+ }
66
+ const { workforce_task_id: taskIdResponse } = await this.client.fetch("/workforce/trigger", {
32
67
  method: "POST",
33
68
  body: JSON.stringify({
34
69
  workforce_id: this.id,
35
- workforce_task_id: task?.id,
70
+ workforce_task_id: taskId,
36
71
  trigger: {
37
72
  message: {
38
73
  role: "user",
@@ -45,6 +80,6 @@ export class Workforce {
45
80
  if (task) {
46
81
  task[resetBackoffDuration]();
47
82
  }
48
- return task ?? this.getTask(taskId);
83
+ return task ?? this.getTask(taskIdResponse);
49
84
  }
50
85
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@relevanceai/sdk",
3
- "version": "3.0.0-rc.1",
3
+ "version": "3.0.0-rc.3",
4
4
  "license": "MIT",
5
5
  "main": "./script/mod.js",
6
6
  "module": "./esm/mod.js",
package/script/agent.js CHANGED
@@ -6,6 +6,7 @@ const client_js_1 = require("./client.js");
6
6
  const utils_js_1 = require("./utils.js");
7
7
  const agent_strategy_js_1 = require("./task/agent-strategy.js");
8
8
  const task_js_1 = require("./task/task.js");
9
+ const const_js_1 = require("./const.js");
9
10
  /**
10
11
  * Converts an AgentTaskState to a simplified TaskStatus.
11
12
  *
@@ -91,7 +92,6 @@ function taskSortOptionsToParam(sort) {
91
92
  }
92
93
  throw new Error("invalid sort option");
93
94
  }
94
- const taskPrefixDelimiter = "_-_";
95
95
  class Agent {
96
96
  static async get(id, client = client_js_1.Client.default()) {
97
97
  const config = await Agent.#fetchConfig(id, client);
@@ -191,7 +191,7 @@ class Agent {
191
191
  let taskId;
192
192
  // embed keys require a task prefixing for new tasks
193
193
  if (!task && this.client.isEmbedKey()) {
194
- taskId = [this.client.key.taskPrefix, await (0, utils_js_1.randomUUID)()].join(taskPrefixDelimiter);
194
+ taskId = [this.client.key.taskPrefix, await (0, utils_js_1.randomUUID)()].join(const_js_1.TASK_PREFIX_DELIM);
195
195
  }
196
196
  else if (task) {
197
197
  taskId = task.id;
@@ -30,7 +30,7 @@ export declare class Client {
30
30
  get region(): Region;
31
31
  get project(): string;
32
32
  isEmbedKey(): boolean;
33
- fetch<T>(input: "/agents/trigger" | `/agents/${string}/get` | `/agents/${string}/tasks/${string}/metadata` | `/agents/${string}/tasks/${string}/view` | "/agents/conversations/list" | "/services/get_temporary_file_upload_url" | `/workforce/items/${string}` | `/workforce/tasks/${string}/metadata` | `/workforce/items/${string}/tasks/${string}/messages` | "/workforce/trigger" | "/agents/list", init?: RequestInit): Promise<T>;
33
+ fetch<T>(input: "/agents/trigger" | `/agents/${string}/get` | `/agents/${string}/tasks/${string}/metadata` | `/agents/${string}/tasks/${string}/view` | "/agents/conversations/list" | "/services/get_temporary_file_upload_url" | `/workforce/items/${string}` | `/workforce/tasks/${string}/metadata` | `/workforce/items/${string}/tasks/${string}/messages` | "/workforce/trigger" | "/workforce/tasks/list" | "/agents/list", init?: RequestInit): Promise<T>;
34
34
  url(path: string): URL;
35
35
  uploadTempFile(file: File): Promise<Attachment>;
36
36
  }
@@ -0,0 +1 @@
1
+ export declare const TASK_PREFIX_DELIM = "_-_";
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TASK_PREFIX_DELIM = void 0;
4
+ exports.TASK_PREFIX_DELIM = "_-_";
package/script/key.d.ts CHANGED
@@ -4,9 +4,13 @@ type CreateKeyOptions = {
4
4
  region: Region;
5
5
  project: string;
6
6
  agentId?: string;
7
+ workforceId?: string;
7
8
  taskPrefix?: string;
8
9
  };
9
- type GenerateEmbedKeyOptions = Omit<CreateKeyOptions, "key" | "taskPrefix">;
10
+ type GenerateEmbedKeyOptions = {
11
+ region: Region;
12
+ project: string;
13
+ };
10
14
  /**
11
15
  * Key is used to authenticate requests for the {@link Client}. A Key can be
12
16
  * either a _full_ key or an _embed_ key.
@@ -31,7 +35,13 @@ export declare class Key {
31
35
  *
32
36
  * @returns {Promise<Key>}
33
37
  */
34
- static generateEmbedKey({ region, project, agentId, }: GenerateEmbedKeyOptions): Promise<Key>;
38
+ static generateEmbedKey(options: GenerateEmbedKeyOptions & ({
39
+ workforceId: string;
40
+ } | {
41
+ agentId: string;
42
+ })): Promise<Key>;
43
+ private static generateAgentEmbedKey;
44
+ private static generateWorkforceEmbedKey;
35
45
  /**
36
46
  * The region the key is scoped to.
37
47
  *
@@ -46,11 +56,18 @@ export declare class Key {
46
56
  readonly project: string;
47
57
  /**
48
58
  * The agent ID the embed key is scoped to. This is `undefined` for full
49
- * keys.
59
+ * keys and workforce embed keys.
50
60
  *
51
61
  * @property {string | undefined} agentId
52
62
  */
53
63
  readonly agentId: string | undefined;
64
+ /**
65
+ * The workforce ID the embed key is scoped to. This is `undefined` for full
66
+ * keys
67
+ *
68
+ * @property {string | undefined} workforceId
69
+ */
70
+ readonly workforceId: string | undefined;
54
71
  /**
55
72
  * The task prefix used to namespace tasks created with the embed key. This
56
73
  * is `undefined` for full keys.
@@ -63,7 +80,7 @@ export declare class Key {
63
80
  *
64
81
  * @param {CreateKeyOptions} options
65
82
  */
66
- constructor({ key, region, project, agentId, taskPrefix }: CreateKeyOptions);
83
+ constructor({ key, region, project, agentId, workforceId, taskPrefix }: CreateKeyOptions);
67
84
  /**
68
85
  * Returns whether the key is an embed key.
69
86
  *
package/script/key.js CHANGED
@@ -26,14 +26,23 @@ class Key {
26
26
  *
27
27
  * @returns {Promise<Key>}
28
28
  */
29
- static async generateEmbedKey({ region, project, agentId, }) {
29
+ static async generateEmbedKey(options) {
30
+ if ("workforceId" in options) {
31
+ return await Key.generateWorkforceEmbedKey(options);
32
+ }
33
+ if ("agentId" in options) {
34
+ return await Key.generateAgentEmbedKey(options);
35
+ }
36
+ throw new Error("invalid embed key options");
37
+ }
38
+ static async generateAgentEmbedKey({ region, project, agentId }) {
30
39
  const embedKeyURL = new URL((0, utils_js_1.cleanPath)("/agents/get_embed_key"), (0, region_js_1.regionBaseURL)(region));
31
40
  const response = await fetch(embedKeyURL, {
32
41
  method: "POST",
33
42
  body: JSON.stringify({ agent_id: agentId, project }),
34
43
  });
35
44
  if (!response.ok) {
36
- throw new Error("failed to fetch embed key", { cause: response });
45
+ throw new Error("failed to fetch agent embed key", { cause: response });
37
46
  }
38
47
  const { embed_key: embedKey, conversation_prefix: taskPrefix } = await response.json();
39
48
  return new Key({
@@ -44,6 +53,26 @@ class Key {
44
53
  taskPrefix,
45
54
  });
46
55
  }
56
+ static async generateWorkforceEmbedKey({ region, project, workforceId }) {
57
+ const embedKeyURL = new URL((0, utils_js_1.cleanPath)("/workforce/get_embed_key"), (0, region_js_1.regionBaseURL)(region));
58
+ const response = await fetch(embedKeyURL, {
59
+ method: "POST",
60
+ body: JSON.stringify({ workforce_id: workforceId, project }),
61
+ });
62
+ if (!response.ok) {
63
+ throw new Error("failed to fetch workforce embed key", {
64
+ cause: response,
65
+ });
66
+ }
67
+ const { embed_key: embedKey, conversation_prefix: taskPrefix } = await response.json();
68
+ return new Key({
69
+ key: embedKey,
70
+ region,
71
+ project,
72
+ workforceId,
73
+ taskPrefix,
74
+ });
75
+ }
47
76
  /**
48
77
  * The region the key is scoped to.
49
78
  *
@@ -65,11 +94,18 @@ class Key {
65
94
  #key;
66
95
  /**
67
96
  * The agent ID the embed key is scoped to. This is `undefined` for full
68
- * keys.
97
+ * keys and workforce embed keys.
69
98
  *
70
99
  * @property {string | undefined} agentId
71
100
  */
72
101
  agentId;
102
+ /**
103
+ * The workforce ID the embed key is scoped to. This is `undefined` for full
104
+ * keys
105
+ *
106
+ * @property {string | undefined} workforceId
107
+ */
108
+ workforceId;
73
109
  /**
74
110
  * The task prefix used to namespace tasks created with the embed key. This
75
111
  * is `undefined` for full keys.
@@ -82,12 +118,13 @@ class Key {
82
118
  *
83
119
  * @param {CreateKeyOptions} options
84
120
  */
85
- constructor({ key, region, project, agentId, taskPrefix }) {
121
+ constructor({ key, region, project, agentId, workforceId, taskPrefix }) {
86
122
  this.#key = key;
87
123
  this.region = region;
88
124
  this.project = project;
89
125
  this.agentId = agentId;
90
126
  this.taskPrefix = taskPrefix;
127
+ this.workforceId = workforceId;
91
128
  }
92
129
  /**
93
130
  * Returns whether the key is an embed key.
@@ -95,7 +132,8 @@ class Key {
95
132
  * @returns {boolean}
96
133
  */
97
134
  isEmbed() {
98
- return (this.agentId !== undefined && this.taskPrefix !== undefined);
135
+ return ((this.agentId !== undefined || this.workforceId !== undefined) &&
136
+ this.taskPrefix !== undefined);
99
137
  }
100
138
  /**
101
139
  * Returns the headers required for authenticating requests with this key.
@@ -117,8 +155,12 @@ class Key {
117
155
  key: this.#key,
118
156
  region: this.region,
119
157
  project: this.project,
120
- agentId: this.agentId,
121
- taskPrefix: this.taskPrefix,
158
+ ...(this.agentId
159
+ ? { agentId: this.agentId, taskPrefix: this.taskPrefix }
160
+ : {}),
161
+ ...(this.workforceId
162
+ ? { workforceId: this.workforceId, taskPrefix: this.taskPrefix }
163
+ : {}),
122
164
  };
123
165
  }
124
166
  }
@@ -1,9 +1,14 @@
1
- import { GenericMessage } from "./task.js";
1
+ import type { Agent } from "../agent.js";
2
+ import { GenericMessage, type TaskMessageData } from "./task.js";
2
3
  export interface AgentMessageContent {
3
4
  type: "agent-message";
4
5
  text: string;
6
+ thought_about_tool_calls?: boolean;
5
7
  }
6
8
  export declare class AgentMessage extends GenericMessage<AgentMessageContent> {
9
+ readonly agent?: Agent;
10
+ constructor(message: TaskMessageData<AgentMessageContent>, agent?: Agent);
7
11
  get text(): string;
8
12
  get agentId(): string;
13
+ isThought(): boolean;
9
14
  }
@@ -3,11 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AgentMessage = void 0;
4
4
  const task_js_1 = require("./task.js");
5
5
  class AgentMessage extends task_js_1.GenericMessage {
6
+ agent;
7
+ constructor(message, agent) {
8
+ super(message);
9
+ this.agent = agent;
10
+ }
6
11
  get text() {
7
12
  return this.message.content.text;
8
13
  }
9
14
  get agentId() {
10
- return "";
15
+ return this.agent?.id ?? "";
16
+ }
17
+ isThought() {
18
+ return this.message.content.thought_about_tool_calls ?? false;
11
19
  }
12
20
  }
13
21
  exports.AgentMessage = AgentMessage;
package/script/mod.d.ts CHANGED
@@ -4,3 +4,4 @@ export { Key } from "./key.js";
4
4
  export { type Region, REGION_AU, REGION_EU, REGION_US } from "./region.js";
5
5
  export { Workforce } from "./workforce.js";
6
6
  export type { Task } from "./task/task.js";
7
+ export type { AnyTaskMessage } from "./message/task.js";
@@ -53,7 +53,7 @@ class AgentStrategy {
53
53
  case "agent-error":
54
54
  return new agent_error_js_1.AgentErrorMessage(data);
55
55
  case "agent-message":
56
- return new agent_js_2.AgentMessage(data);
56
+ return new agent_js_2.AgentMessage(data, this.agent);
57
57
  case "tool-run":
58
58
  return new tool_js_1.ToolMessage(data);
59
59
  case "user-message":
@@ -2,16 +2,22 @@ import type { AnyTaskMessage } from "../message/task.js";
2
2
  import { Client } from "../client.js";
3
3
  import { Task, type TaskMetadata, type TaskStatus, type TaskStrategy } from "./task.js";
4
4
  import type { Workforce } from "../workforce.js";
5
+ export type WorkforceTaskState = "running" | "completed" | "execution-limit-reached" | "pending-approval" | "errored-pending-approval" | "escalated";
6
+ /**
7
+ * Converts a WorkforceTaskState to a simplified TaskStatus.
8
+ *
9
+ * @param {WorkforceTaskState} state The workforce task state to convert.
10
+ * @returns {TaskStatus} The simplified task status.
11
+ */
12
+ export declare function stateToStatus(state: WorkforceTaskState): TaskStatus;
5
13
  export declare class WorkforceStrategy implements TaskStrategy<Workforce> {
6
14
  static get(id: string, workforce: Workforce, client?: Client): Promise<Task<Workforce>>;
7
- static convertStatus(): TaskStatus;
15
+ static convertStatus(state: WorkforceTaskState): TaskStatus;
8
16
  private readonly id;
9
17
  private readonly workforce;
10
18
  private readonly client;
11
- private constructor();
19
+ constructor(id: string, workforce: Workforce, client: Client);
12
20
  get subject(): Workforce;
13
- getMessages({ after: _after }: {
14
- after?: Date;
15
- }): Promise<AnyTaskMessage[]>;
21
+ getMessages(): Promise<AnyTaskMessage[]>;
16
22
  getMetadata(): Promise<TaskMetadata>;
17
23
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WorkforceStrategy = void 0;
4
+ exports.stateToStatus = stateToStatus;
4
5
  const client_js_1 = require("../client.js");
5
6
  const task_js_1 = require("./task.js");
6
7
  const agent_error_js_1 = require("../message/agent-error.js");
@@ -9,14 +10,37 @@ const tool_js_1 = require("../message/tool.js");
9
10
  const user_js_1 = require("../message/user.js");
10
11
  const workforce_agent_js_1 = require("../message/workforce-agent.js");
11
12
  const workforce_agent_handover_js_1 = require("../message/workforce-agent-handover.js");
13
+ /**
14
+ * Converts a WorkforceTaskState to a simplified TaskStatus.
15
+ *
16
+ * @param {WorkforceTaskState} state The workforce task state to convert.
17
+ * @returns {TaskStatus} The simplified task status.
18
+ */
19
+ function stateToStatus(state) {
20
+ switch (state) {
21
+ case "running":
22
+ return "running";
23
+ case "completed":
24
+ return "completed";
25
+ case "execution-limit-reached":
26
+ return "error";
27
+ case "pending-approval":
28
+ case "escalated":
29
+ return "action";
30
+ case "errored-pending-approval":
31
+ return "error";
32
+ default:
33
+ throw new Error(`unhandled workforce task state: ${state}`);
34
+ }
35
+ }
12
36
  class WorkforceStrategy {
13
37
  static async get(id, workforce, client = client_js_1.Client.default()) {
14
38
  const subject = new this(id, workforce, client);
15
39
  const metadata = await subject.getMetadata();
16
40
  return new task_js_1.Task(metadata, subject);
17
41
  }
18
- static convertStatus() {
19
- return "not-implemented";
42
+ static convertStatus(state) {
43
+ return stateToStatus(state);
20
44
  }
21
45
  id;
22
46
  workforce;
@@ -29,7 +53,7 @@ class WorkforceStrategy {
29
53
  get subject() {
30
54
  return this.workforce;
31
55
  }
32
- async getMessages({ after: _after }) {
56
+ async getMessages() {
33
57
  const { results } = await this.client.fetch(`/workforce/items/${this.workforce.id}/tasks/${this.id}/messages`, {
34
58
  method: "POST",
35
59
  body: JSON.stringify({
@@ -63,7 +87,7 @@ class WorkforceStrategy {
63
87
  region: this.client.region,
64
88
  project: this.client.project,
65
89
  name: metadata.title,
66
- status: WorkforceStrategy.convertStatus(), // @todo: not implemented
90
+ status: WorkforceStrategy.convertStatus(metadata.requested_state),
67
91
  createdAt: new Date(metadata.insert_date),
68
92
  updatedAt: new Date(metadata.update_date),
69
93
  };
@@ -1,12 +1,17 @@
1
1
  import { Client } from "./client.js";
2
2
  import type { Region } from "./region.js";
3
- import { type Task } from "./task/task.js";
3
+ import { Task } from "./task/task.js";
4
4
  type WorkforceConfig = {
5
5
  id: string;
6
6
  workforce_metadata: {
7
7
  name: string;
8
8
  };
9
9
  };
10
+ type GetTaskOptions = {
11
+ pageSize?: number;
12
+ cursor?: string;
13
+ search?: string;
14
+ };
10
15
  export declare class Workforce {
11
16
  #private;
12
17
  static get(id: string, client?: Client): Promise<Workforce>;
@@ -17,6 +22,7 @@ export declare class Workforce {
17
22
  get project(): string;
18
23
  get name(): string;
19
24
  getTask(id: string): Promise<Task<Workforce>>;
25
+ getTasks({ pageSize, cursor, search, }?: GetTaskOptions): Promise<Task<Workforce>[]>;
20
26
  sendMessage(message: string, task?: Task<Workforce>): Promise<Task<Workforce>>;
21
27
  }
22
28
  export {};
@@ -2,8 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Workforce = void 0;
4
4
  const client_js_1 = require("./client.js");
5
+ const const_js_1 = require("./const.js");
5
6
  const task_js_1 = require("./task/task.js");
6
7
  const workforce_strategy_js_1 = require("./task/workforce-strategy.js");
8
+ const utils_js_1 = require("./utils.js");
7
9
  class Workforce {
8
10
  static async get(id, client = client_js_1.Client.default()) {
9
11
  const config = await client.fetch(`/workforce/items/${id}`);
@@ -30,12 +32,45 @@ class Workforce {
30
32
  async getTask(id) {
31
33
  return await workforce_strategy_js_1.WorkforceStrategy.get(id, this, this.client);
32
34
  }
35
+ async getTasks({ pageSize = 100, cursor, search, } = {}) {
36
+ const body = {
37
+ workforce_id: this.id,
38
+ page_size: pageSize,
39
+ };
40
+ if (search?.trim()) {
41
+ body.query = search.trim();
42
+ }
43
+ if (cursor?.trim()) {
44
+ body.cursor = cursor.trim();
45
+ }
46
+ const { results } = await this.client.fetch("/workforce/tasks/list", {
47
+ method: "POST",
48
+ body: JSON.stringify(body),
49
+ });
50
+ return results.map((t) => new task_js_1.Task({
51
+ id: t.workforce_task_id,
52
+ region: this.client.region,
53
+ project: this.client.project,
54
+ name: t.title,
55
+ status: workforce_strategy_js_1.WorkforceStrategy.convertStatus(t.state),
56
+ createdAt: new Date(t.insert_date),
57
+ updatedAt: new Date(t.update_date),
58
+ }, new workforce_strategy_js_1.WorkforceStrategy(t.workforce_task_id, this, this.client)));
59
+ }
33
60
  async sendMessage(message, task) {
34
- const { workforce_task_id: taskId } = await this.client.fetch("/workforce/trigger", {
61
+ let taskId;
62
+ // embed keys require a task prefixing for new tasks
63
+ if (!task && this.client.isEmbedKey()) {
64
+ taskId = [this.client.key.taskPrefix, await (0, utils_js_1.randomUUID)()].join(const_js_1.TASK_PREFIX_DELIM);
65
+ }
66
+ else if (task) {
67
+ taskId = task.id;
68
+ }
69
+ const { workforce_task_id: taskIdResponse } = await this.client.fetch("/workforce/trigger", {
35
70
  method: "POST",
36
71
  body: JSON.stringify({
37
72
  workforce_id: this.id,
38
- workforce_task_id: task?.id,
73
+ workforce_task_id: taskId,
39
74
  trigger: {
40
75
  message: {
41
76
  role: "user",
@@ -48,7 +83,7 @@ class Workforce {
48
83
  if (task) {
49
84
  task[task_js_1.resetBackoffDuration]();
50
85
  }
51
- return task ?? this.getTask(taskId);
86
+ return task ?? this.getTask(taskIdResponse);
52
87
  }
53
88
  }
54
89
  exports.Workforce = Workforce;