roe-typescript 0.1.0

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.
Files changed (45) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +189 -0
  3. package/dist/api/agents.d.ts +87 -0
  4. package/dist/api/agents.js +263 -0
  5. package/dist/auth.d.ts +6 -0
  6. package/dist/auth.js +11 -0
  7. package/dist/client.d.ts +13 -0
  8. package/dist/client.js +18 -0
  9. package/dist/config.d.ts +17 -0
  10. package/dist/config.js +43 -0
  11. package/dist/exceptions.d.ts +25 -0
  12. package/dist/exceptions.js +73 -0
  13. package/dist/index.d.ts +10 -0
  14. package/dist/index.js +9 -0
  15. package/dist/integration_test.js +686 -0
  16. package/dist/models/agent.d.ts +78 -0
  17. package/dist/models/agent.js +40 -0
  18. package/dist/models/file.d.ts +30 -0
  19. package/dist/models/file.js +85 -0
  20. package/dist/models/job.d.ts +37 -0
  21. package/dist/models/job.js +133 -0
  22. package/dist/models/responses.d.ts +71 -0
  23. package/dist/models/responses.js +36 -0
  24. package/dist/models/user.d.ts +6 -0
  25. package/dist/models/user.js +1 -0
  26. package/dist/src/api/agents.js +269 -0
  27. package/dist/src/auth.js +15 -0
  28. package/dist/src/client.js +22 -0
  29. package/dist/src/config.js +47 -0
  30. package/dist/src/exceptions.js +86 -0
  31. package/dist/src/models/agent.js +45 -0
  32. package/dist/src/models/file.js +92 -0
  33. package/dist/src/models/job.js +138 -0
  34. package/dist/src/models/responses.js +42 -0
  35. package/dist/src/models/user.js +2 -0
  36. package/dist/src/utils/fileDetection.js +46 -0
  37. package/dist/src/utils/httpClient.js +236 -0
  38. package/dist/src/utils/pagination.js +18 -0
  39. package/dist/utils/fileDetection.d.ts +11 -0
  40. package/dist/utils/fileDetection.js +38 -0
  41. package/dist/utils/httpClient.d.ts +30 -0
  42. package/dist/utils/httpClient.js +229 -0
  43. package/dist/utils/pagination.d.ts +3 -0
  44. package/dist/utils/pagination.js +14 -0
  45. package/package.json +36 -0
@@ -0,0 +1,78 @@
1
+ import { UserInfo } from "./user";
2
+ import { AgentsAPI } from "../api/agents";
3
+ import { Job } from "./job";
4
+ export type AgentInputDefinition = {
5
+ key: string;
6
+ data_type: string;
7
+ description: string;
8
+ example?: string;
9
+ accepts_multiple_files?: boolean | null;
10
+ };
11
+ export type BaseAgent = {
12
+ id: string;
13
+ name: string;
14
+ creator?: UserInfo | null;
15
+ created_at: string;
16
+ disable_cache: boolean;
17
+ cache_failed_jobs: boolean;
18
+ organization_id: string;
19
+ engine_class_id: string;
20
+ current_version_id?: string | null;
21
+ job_count?: number;
22
+ most_recent_job?: string | null;
23
+ engine_name?: string;
24
+ };
25
+ export declare class BaseAgentWithApi implements BaseAgent {
26
+ id: string;
27
+ name: string;
28
+ creator?: UserInfo | null;
29
+ created_at: string;
30
+ disable_cache: boolean;
31
+ cache_failed_jobs: boolean;
32
+ organization_id: string;
33
+ engine_class_id: string;
34
+ current_version_id?: string | null;
35
+ job_count?: number;
36
+ most_recent_job?: string | null;
37
+ engine_name?: string;
38
+ private _agentsApi?;
39
+ constructor(data: BaseAgent);
40
+ setAgentsApi(api: AgentsAPI): void;
41
+ run(inputs: Record<string, unknown>): Promise<Job>;
42
+ listVersions(): Promise<AgentVersionWithApi[]>;
43
+ getCurrentVersion(): Promise<AgentVersionWithApi> | null;
44
+ }
45
+ export type AgentVersion = {
46
+ id: string;
47
+ name: string;
48
+ version_name: string;
49
+ creator?: UserInfo | null;
50
+ created_at: string;
51
+ description?: string | null;
52
+ engine_class_id: string;
53
+ engine_name: string;
54
+ input_definitions: AgentInputDefinition[];
55
+ engine_config: Record<string, unknown>;
56
+ organization_id: string;
57
+ readonly: boolean;
58
+ base_agent: BaseAgent;
59
+ };
60
+ export declare class AgentVersionWithApi implements AgentVersion {
61
+ id: string;
62
+ name: string;
63
+ version_name: string;
64
+ creator?: UserInfo | null;
65
+ created_at: string;
66
+ description?: string | null;
67
+ engine_class_id: string;
68
+ engine_name: string;
69
+ input_definitions: AgentInputDefinition[];
70
+ engine_config: Record<string, unknown>;
71
+ organization_id: string;
72
+ readonly: boolean;
73
+ base_agent: BaseAgent;
74
+ private _agentsApi?;
75
+ constructor(data: AgentVersion);
76
+ setAgentsApi(api: AgentsAPI): void;
77
+ run(inputs: Record<string, unknown>): Promise<Job>;
78
+ }
@@ -0,0 +1,40 @@
1
+ export class BaseAgentWithApi {
2
+ constructor(data) {
3
+ Object.assign(this, data);
4
+ }
5
+ setAgentsApi(api) {
6
+ this._agentsApi = api;
7
+ }
8
+ run(inputs) {
9
+ if (!this._agentsApi)
10
+ throw new Error("Agents API not set");
11
+ return this._agentsApi.run({ agentId: this.id, inputs });
12
+ }
13
+ listVersions() {
14
+ if (!this._agentsApi)
15
+ throw new Error("Agents API not set");
16
+ return this._agentsApi.versions.list(this.id);
17
+ }
18
+ getCurrentVersion() {
19
+ if (!this._agentsApi)
20
+ throw new Error("Agents API not set");
21
+ if (!this.current_version_id)
22
+ return null;
23
+ return this._agentsApi.versions.retrieve(this.id, this.current_version_id);
24
+ }
25
+ }
26
+ export class AgentVersionWithApi {
27
+ constructor(data) {
28
+ Object.assign(this, data);
29
+ }
30
+ setAgentsApi(api) {
31
+ this._agentsApi = api;
32
+ }
33
+ run(inputs) {
34
+ if (!this._agentsApi)
35
+ throw new Error("Agents API not set");
36
+ if (!this.base_agent?.id)
37
+ throw new Error("AgentVersion missing base_agent id");
38
+ return this._agentsApi.runVersion({ agentId: this.base_agent.id, versionId: this.id, inputs });
39
+ }
40
+ }
@@ -0,0 +1,30 @@
1
+ export type FileUploadInit = {
2
+ path?: string;
3
+ file?: NodeJS.ReadableStream;
4
+ filename?: string;
5
+ mimeType?: string;
6
+ };
7
+ export declare class FileUpload {
8
+ readonly path?: string;
9
+ readonly file?: NodeJS.ReadableStream;
10
+ readonly filename?: string;
11
+ readonly mimeType?: string;
12
+ private _openedStream;
13
+ constructor(init: FileUploadInit);
14
+ get effectiveFilename(): string;
15
+ get effectiveMimeType(): string;
16
+ /**
17
+ * Opens the file for reading. If a path was provided, creates a new ReadStream.
18
+ * Track opened streams so they can be closed later.
19
+ */
20
+ open(): NodeJS.ReadableStream;
21
+ /**
22
+ * Closes any opened file stream to prevent resource leaks.
23
+ * Should be called after the file upload is complete.
24
+ */
25
+ close(): void;
26
+ /**
27
+ * Returns the file size in bytes, if available.
28
+ */
29
+ getSize(): number | undefined;
30
+ }
@@ -0,0 +1,85 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import mime from "mime-types";
4
+ import { BadRequestError } from "../exceptions";
5
+ /** Maximum file size: 2GB (aligned with main-roe backend) */
6
+ const MAX_FILE_SIZE = 2 * 1024 * 1024 * 1024;
7
+ export class FileUpload {
8
+ constructor(init) {
9
+ this._openedStream = null;
10
+ this.path = init.path;
11
+ this.file = init.file;
12
+ this.filename = init.filename;
13
+ this.mimeType = init.mimeType;
14
+ if (!this.path && !this.file) {
15
+ throw new Error("Either path or file must be provided");
16
+ }
17
+ if (this.path && this.file) {
18
+ throw new Error("Only one of path or file should be provided");
19
+ }
20
+ // Validate file size if path is provided
21
+ if (this.path) {
22
+ try {
23
+ const stat = fs.statSync(this.path);
24
+ if (stat.size > MAX_FILE_SIZE) {
25
+ throw new BadRequestError(`File exceeds maximum size of 2GB: ${this.path} (${(stat.size / (1024 * 1024 * 1024)).toFixed(2)}GB)`, 400);
26
+ }
27
+ }
28
+ catch (err) {
29
+ if (err instanceof BadRequestError)
30
+ throw err;
31
+ throw new Error(`Cannot access file: ${this.path}`);
32
+ }
33
+ }
34
+ }
35
+ get effectiveFilename() {
36
+ if (this.filename)
37
+ return this.filename;
38
+ if (this.path)
39
+ return path.basename(this.path);
40
+ return "upload";
41
+ }
42
+ get effectiveMimeType() {
43
+ if (this.mimeType)
44
+ return this.mimeType;
45
+ const guess = mime.lookup(this.effectiveFilename);
46
+ return (guess || "application/octet-stream");
47
+ }
48
+ /**
49
+ * Opens the file for reading. If a path was provided, creates a new ReadStream.
50
+ * Track opened streams so they can be closed later.
51
+ */
52
+ open() {
53
+ if (this.file)
54
+ return this.file;
55
+ if (this.path) {
56
+ this._openedStream = fs.createReadStream(this.path);
57
+ return this._openedStream;
58
+ }
59
+ throw new Error("No file source available");
60
+ }
61
+ /**
62
+ * Closes any opened file stream to prevent resource leaks.
63
+ * Should be called after the file upload is complete.
64
+ */
65
+ close() {
66
+ if (this._openedStream) {
67
+ this._openedStream.destroy();
68
+ this._openedStream = null;
69
+ }
70
+ }
71
+ /**
72
+ * Returns the file size in bytes, if available.
73
+ */
74
+ getSize() {
75
+ if (this.path) {
76
+ try {
77
+ return fs.statSync(this.path).size;
78
+ }
79
+ catch {
80
+ return undefined;
81
+ }
82
+ }
83
+ return undefined;
84
+ }
85
+ }
@@ -0,0 +1,37 @@
1
+ import { AgentsAPI } from "../api/agents";
2
+ import { AgentJobResult, AgentJobStatus } from "./responses";
3
+ export declare class Job {
4
+ private readonly agentsApi;
5
+ private readonly jobId;
6
+ private readonly timeoutSeconds;
7
+ constructor(opts: {
8
+ agentsApi: AgentsAPI;
9
+ jobId: string;
10
+ timeoutSeconds?: number;
11
+ });
12
+ get id(): string;
13
+ wait(params?: {
14
+ intervalSeconds?: number;
15
+ timeoutSeconds?: number;
16
+ }): Promise<AgentJobResult>;
17
+ retrieveStatus(): Promise<AgentJobStatus>;
18
+ retrieveResult(): Promise<AgentJobResult>;
19
+ }
20
+ export declare class JobBatch {
21
+ private readonly agentsApi;
22
+ private readonly jobIds;
23
+ private readonly timeoutSeconds;
24
+ private completed;
25
+ private statusCache;
26
+ constructor(opts: {
27
+ agentsApi: AgentsAPI;
28
+ jobIds: string[];
29
+ timeoutSeconds?: number;
30
+ });
31
+ get jobs(): Job[];
32
+ wait(params?: {
33
+ intervalSeconds?: number;
34
+ timeoutSeconds?: number;
35
+ }): Promise<AgentJobResult[]>;
36
+ retrieveStatus(): Promise<Record<string, number>>;
37
+ }
@@ -0,0 +1,133 @@
1
+ import { JobStatus } from "./responses";
2
+ export class Job {
3
+ constructor(opts) {
4
+ this.agentsApi = opts.agentsApi;
5
+ this.jobId = opts.jobId;
6
+ this.timeoutSeconds = opts.timeoutSeconds ?? 7200;
7
+ if (this.timeoutSeconds <= 0) {
8
+ throw new Error(`timeoutSeconds must be positive, got ${this.timeoutSeconds}`);
9
+ }
10
+ }
11
+ get id() {
12
+ return this.jobId;
13
+ }
14
+ async wait(params) {
15
+ const intervalSeconds = params?.intervalSeconds ?? 5;
16
+ const timeoutSeconds = params?.timeoutSeconds ?? this.timeoutSeconds;
17
+ if (timeoutSeconds <= 0)
18
+ throw new Error(`timeoutSeconds must be positive, got ${timeoutSeconds}`);
19
+ const start = Date.now();
20
+ while (true) {
21
+ const status = await this.retrieveStatus();
22
+ const code = status.status;
23
+ if (code === JobStatus.SUCCESS || code === JobStatus.CACHED) {
24
+ return this.retrieveResult();
25
+ }
26
+ if (code === JobStatus.FAILURE || code === JobStatus.CANCELLED) {
27
+ throw new Error(`Job ${this.jobId} failed with status ${code}${status.error_message ? `: ${status.error_message}` : ""}`);
28
+ }
29
+ if (Date.now() - start > timeoutSeconds * 1000) {
30
+ throw new Error(`Job ${this.jobId} did not complete within ${timeoutSeconds} seconds`);
31
+ }
32
+ await new Promise((r) => setTimeout(r, intervalSeconds * 1000));
33
+ }
34
+ }
35
+ retrieveStatus() {
36
+ return this.agentsApi.jobs.retrieveStatus(this.jobId);
37
+ }
38
+ retrieveResult() {
39
+ return this.agentsApi.jobs.retrieveResult(this.jobId);
40
+ }
41
+ }
42
+ export class JobBatch {
43
+ constructor(opts) {
44
+ this.completed = {};
45
+ this.statusCache = {};
46
+ this.agentsApi = opts.agentsApi;
47
+ this.jobIds = opts.jobIds;
48
+ this.timeoutSeconds = opts.timeoutSeconds ?? 7200;
49
+ if (this.timeoutSeconds <= 0) {
50
+ throw new Error(`timeoutSeconds must be positive, got ${this.timeoutSeconds}`);
51
+ }
52
+ }
53
+ get jobs() {
54
+ return this.jobIds.map((id) => new Job({ agentsApi: this.agentsApi, jobId: id, timeoutSeconds: this.timeoutSeconds }));
55
+ }
56
+ async wait(params) {
57
+ const intervalSeconds = params?.intervalSeconds ?? 5;
58
+ const timeoutSeconds = params?.timeoutSeconds ?? this.timeoutSeconds;
59
+ if (timeoutSeconds <= 0)
60
+ throw new Error(`timeoutSeconds must be positive, got ${timeoutSeconds}`);
61
+ const start = Date.now();
62
+ while (Object.keys(this.completed).length < this.jobIds.length) {
63
+ const pending = this.jobIds.filter((id) => !this.completed[id]);
64
+ if (!pending.length)
65
+ break;
66
+ const statusBatch = await this.agentsApi.jobs.retrieveStatusMany(pending);
67
+ const failures = statusBatch.filter((s) => s.status === JobStatus.FAILURE || s.status === JobStatus.CANCELLED);
68
+ if (failures.length) {
69
+ const detail = failures.map((f) => `${f.id}:${f.status ?? "unknown"}`).join(', ');
70
+ throw new Error(`Jobs failed or cancelled: ${detail}`);
71
+ }
72
+ const completedIds = [];
73
+ for (const status of statusBatch) {
74
+ const code = status.status;
75
+ if (code === JobStatus.SUCCESS || code === JobStatus.CACHED) {
76
+ completedIds.push(status.id);
77
+ }
78
+ if (code !== undefined && code !== null) {
79
+ this.statusCache[status.id] = code;
80
+ }
81
+ }
82
+ if (completedIds.length) {
83
+ const resultBatch = await this.agentsApi.jobs.retrieveResultMany(completedIds);
84
+ for (const res of resultBatch) {
85
+ if (!res.agent_id || !res.agent_version_id) {
86
+ const id = res.id ?? 'unknown';
87
+ throw new Error(`Job ${id} missing agent identifiers`);
88
+ }
89
+ // Use corrected_outputs as fallback if result is null/undefined
90
+ const outputs = res.result ?? res.corrected_outputs;
91
+ if (outputs == null) {
92
+ // Both result and corrected_outputs are null - this may indicate an error or incomplete job
93
+ throw new Error(`Job ${res.id} returned null or undefined result`);
94
+ }
95
+ if (!Array.isArray(outputs)) {
96
+ // Result exists but is not an array - unexpected format
97
+ throw new Error(`Job ${res.id} returned unexpected result format: ${typeof outputs}`);
98
+ }
99
+ this.completed[res.id] = {
100
+ agent_id: res.agent_id,
101
+ agent_version_id: res.agent_version_id,
102
+ inputs: res.inputs ?? [],
103
+ input_tokens: res.input_tokens,
104
+ output_tokens: res.output_tokens,
105
+ outputs,
106
+ };
107
+ }
108
+ }
109
+ if (Object.keys(this.completed).length < this.jobIds.length) {
110
+ if (Date.now() - start > timeoutSeconds * 1000) {
111
+ const remaining = this.jobIds.filter((id) => !this.completed[id]);
112
+ throw new Error(`Jobs ${remaining.join(", ")} did not complete within ${timeoutSeconds} seconds`);
113
+ }
114
+ await new Promise((r) => setTimeout(r, intervalSeconds * 1000));
115
+ }
116
+ }
117
+ return this.jobIds.map((id) => this.completed[id]);
118
+ }
119
+ async retrieveStatus() {
120
+ const statusMap = { ...this.statusCache };
121
+ const toQuery = this.jobIds.filter((id) => statusMap[id] === undefined);
122
+ if (toQuery.length) {
123
+ const statuses = await this.agentsApi.jobs.retrieveStatusMany(toQuery);
124
+ for (const s of statuses) {
125
+ if (s.status !== undefined && s.status !== null) {
126
+ statusMap[s.id] = s.status;
127
+ this.statusCache[s.id] = s.status;
128
+ }
129
+ }
130
+ }
131
+ return statusMap;
132
+ }
133
+ }
@@ -0,0 +1,71 @@
1
+ export declare enum JobStatus {
2
+ PENDING = 0,
3
+ STARTED = 1,
4
+ RETRY = 2,
5
+ SUCCESS = 3,
6
+ FAILURE = 4,
7
+ CANCELLED = 5,
8
+ CACHED = 6
9
+ }
10
+ export type ErrorResponse = {
11
+ detail: string;
12
+ status_code: number;
13
+ };
14
+ export type AgentDatum = {
15
+ key: string;
16
+ description: string;
17
+ data_type: string;
18
+ value: string;
19
+ cost?: number | null;
20
+ };
21
+ export type PaginatedResponse<T> = {
22
+ count: number;
23
+ next: string | null;
24
+ previous: string | null;
25
+ results: T[];
26
+ };
27
+ export type AgentJobStatus = {
28
+ status: number;
29
+ timestamp: number;
30
+ error_message?: string | null;
31
+ };
32
+ export type Reference = {
33
+ url: string;
34
+ resource_id: string;
35
+ };
36
+ export declare function referenceFromUrl(url: string): Reference;
37
+ export declare function extractReferencesFromOutputs(outputs: AgentDatum[]): Reference[];
38
+ export declare function getJobReferences(result: Pick<AgentJobResult, "outputs">): Reference[];
39
+ export type AgentJobResult = {
40
+ agent_id: string;
41
+ agent_version_id: string;
42
+ inputs: unknown[];
43
+ input_tokens?: number | null;
44
+ output_tokens?: number | null;
45
+ outputs: AgentDatum[];
46
+ };
47
+ export type AgentJobStatusBatch = {
48
+ id: string;
49
+ status?: number | null;
50
+ created_at?: unknown;
51
+ last_updated_at?: unknown;
52
+ };
53
+ export type AgentJobResultBatch = {
54
+ id: string;
55
+ status?: number | null;
56
+ result?: AgentDatum[] | unknown | null;
57
+ corrected_outputs?: AgentDatum[] | null;
58
+ agent_id?: string | null;
59
+ agent_version_id?: string | null;
60
+ cost?: number | null;
61
+ inputs?: unknown[] | null;
62
+ input_tokens?: number | null;
63
+ output_tokens?: number | null;
64
+ };
65
+ export type JobDataDeleteResponse = {
66
+ status: string;
67
+ deleted_count: number;
68
+ failed_count: number;
69
+ outputs_sanitized: boolean;
70
+ errors?: string[] | null;
71
+ };
@@ -0,0 +1,36 @@
1
+ import { v4 as uuidv4 } from "uuid";
2
+ export var JobStatus;
3
+ (function (JobStatus) {
4
+ JobStatus[JobStatus["PENDING"] = 0] = "PENDING";
5
+ JobStatus[JobStatus["STARTED"] = 1] = "STARTED";
6
+ JobStatus[JobStatus["RETRY"] = 2] = "RETRY";
7
+ JobStatus[JobStatus["SUCCESS"] = 3] = "SUCCESS";
8
+ JobStatus[JobStatus["FAILURE"] = 4] = "FAILURE";
9
+ JobStatus[JobStatus["CANCELLED"] = 5] = "CANCELLED";
10
+ JobStatus[JobStatus["CACHED"] = 6] = "CACHED";
11
+ })(JobStatus || (JobStatus = {}));
12
+ export function referenceFromUrl(url) {
13
+ const resource_id = url.split("/references/").at(-1)?.replace(/\/+$/, "") ?? uuidv4();
14
+ return { url, resource_id };
15
+ }
16
+ export function extractReferencesFromOutputs(outputs) {
17
+ const references = [];
18
+ for (const output of outputs) {
19
+ try {
20
+ const parsed = JSON.parse(output.value);
21
+ const refs = Array.isArray(parsed?.references) ? parsed.references : [];
22
+ for (const ref of refs) {
23
+ if (typeof ref === "string" && ref.includes("/references/")) {
24
+ references.push(referenceFromUrl(ref));
25
+ }
26
+ }
27
+ }
28
+ catch {
29
+ // ignore unparsable outputs
30
+ }
31
+ }
32
+ return references;
33
+ }
34
+ export function getJobReferences(result) {
35
+ return extractReferencesFromOutputs(result.outputs ?? []);
36
+ }
@@ -0,0 +1,6 @@
1
+ export type UserInfo = {
2
+ id: number;
3
+ email: string;
4
+ first_name?: string;
5
+ last_name?: string;
6
+ };
@@ -0,0 +1 @@
1
+ export {};