@eigenpal/sdk 0.6.17 → 0.7.1
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/CHANGELOG.md +16 -0
- package/README.md +18 -11
- package/package.json +1 -1
- package/src/client.ts +76 -76
- package/src/generated/client/client.gen.ts +1 -1
- package/src/generated/client/index.ts +1 -1
- package/src/generated/client/types.gen.ts +9 -6
- package/src/generated/client/utils.gen.ts +5 -5
- package/src/generated/client.gen.ts +2 -6
- package/src/generated/core/auth.gen.ts +1 -1
- package/src/generated/core/pathSerializer.gen.ts +2 -2
- package/src/generated/core/utils.gen.ts +3 -3
- package/src/generated/index.ts +2 -304
- package/src/generated/sdk.gen.ts +230 -564
- package/src/generated/types.gen.ts +2657 -2251
- package/src/index.ts +7 -12
- package/src/lib/files.ts +27 -14
- package/src/resources/executions.ts +26 -28
- package/src/resources/runs.ts +110 -25
- package/src/telemetry.ts +1 -1
package/src/index.ts
CHANGED
|
@@ -8,26 +8,21 @@
|
|
|
8
8
|
* const client = new EigenpalClient({ apiKey: process.env.EIGENPAL_API_KEY! });
|
|
9
9
|
*
|
|
10
10
|
* // Async — enqueue and poll later.
|
|
11
|
-
* const {
|
|
12
|
-
* input: { ... },
|
|
13
|
-
* });
|
|
11
|
+
* const { id } = await client.run('workflows.extract-invoice', { ... });
|
|
14
12
|
*
|
|
15
13
|
* // Sync (server holds the connection up to 60s).
|
|
16
|
-
* const result = await client.run('workflows.extract-invoice', {
|
|
17
|
-
* input: { ... },
|
|
18
|
-
* waitForCompletion: 60,
|
|
19
|
-
* });
|
|
14
|
+
* const result = await client.run('workflows.extract-invoice', { ... }, { waitForCompletion: 60 });
|
|
20
15
|
*
|
|
21
16
|
* // Client-side poll (up to 5min by default).
|
|
22
|
-
* const final = await client.workflows.executions.runAndWait('wf_abc', {
|
|
17
|
+
* const final = await client.workflows.executions.runAndWait('wf_abc', { ... });
|
|
23
18
|
* ```
|
|
24
19
|
*/
|
|
25
20
|
export {
|
|
26
21
|
EigenpalClient,
|
|
27
22
|
type EigenpalOptions,
|
|
28
23
|
type RerunOptions,
|
|
24
|
+
type RunCallOptions,
|
|
29
25
|
type RunInput,
|
|
30
|
-
type RunOptions,
|
|
31
26
|
type RunStartResponse,
|
|
32
27
|
type RunTarget,
|
|
33
28
|
} from './client';
|
|
@@ -46,7 +41,7 @@ export {
|
|
|
46
41
|
export { toFile } from './lib/files';
|
|
47
42
|
export type { FileDescriptor, FileInput, NodeReadableStream } from './lib/files';
|
|
48
43
|
export type { ListAgentsOptions } from './resources/agents';
|
|
49
|
-
export type { ListRunsOptions } from './resources/runs';
|
|
44
|
+
export type { ListRunsOptions, RunExpand, RunExpandSection } from './resources/runs';
|
|
50
45
|
export type { SourceRawOptions, SourceReleasesOptions } from './resources/source';
|
|
51
46
|
export type {
|
|
52
47
|
ListVersionsOptions,
|
|
@@ -81,8 +76,8 @@ export type {
|
|
|
81
76
|
ListVersionsResponse,
|
|
82
77
|
ListWorkflowsResponse,
|
|
83
78
|
RawSourceResponse,
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
RunListItem,
|
|
80
|
+
RunStartBody,
|
|
86
81
|
RunsCancelResponse,
|
|
87
82
|
RunsExpectedCreateResponse,
|
|
88
83
|
RunsExpectedFileDeleteResponse,
|
package/src/lib/files.ts
CHANGED
|
@@ -168,7 +168,7 @@ export interface MultipartParts {
|
|
|
168
168
|
fileCount: number;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
/** Drain `input` into a FormData, appending each detected file as
|
|
171
|
+
/** Drain `input` into a FormData, appending each detected file as `files.<name>`. */
|
|
172
172
|
async function appendFiles(
|
|
173
173
|
fd: FormData,
|
|
174
174
|
input: Record<string, unknown> | undefined
|
|
@@ -178,7 +178,7 @@ async function appendFiles(
|
|
|
178
178
|
for (const [key, value] of Object.entries(input ?? {})) {
|
|
179
179
|
if (isFileInput(value)) {
|
|
180
180
|
const { blob, filename } = await resolveFileBlob(value);
|
|
181
|
-
fd.append(key
|
|
181
|
+
fd.append(`files.${key}`, blob, filename);
|
|
182
182
|
fileCount += 1;
|
|
183
183
|
} else {
|
|
184
184
|
scalars[key] = value;
|
|
@@ -188,39 +188,52 @@ async function appendFiles(
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
/**
|
|
191
|
-
* JSON-body counterpart of {@link buildRunMultipart}:
|
|
192
|
-
*
|
|
191
|
+
* JSON-body counterpart of {@link buildRunMultipart}: canonical envelope
|
|
192
|
+
* `{ target, input, overrides?, metadata? }`.
|
|
193
193
|
*/
|
|
194
194
|
export function buildRunJsonBody(
|
|
195
|
+
target: string,
|
|
195
196
|
input: Record<string, unknown> | undefined,
|
|
196
|
-
overrides?: { steps?: Record<string, Record<string, unknown>> }
|
|
197
|
+
overrides?: { steps?: Record<string, Record<string, unknown>> },
|
|
198
|
+
metadata?: Record<string, unknown>
|
|
197
199
|
): Record<string, unknown> {
|
|
198
|
-
|
|
200
|
+
const body: Record<string, unknown> = {
|
|
201
|
+
target,
|
|
202
|
+
input: input ?? {},
|
|
203
|
+
};
|
|
204
|
+
if (overrides) body.overrides = overrides;
|
|
205
|
+
if (metadata) body.metadata = metadata;
|
|
206
|
+
return body;
|
|
199
207
|
}
|
|
200
208
|
|
|
201
209
|
/**
|
|
202
210
|
* Build multipart for the canonical `client.run(...)` endpoint
|
|
203
|
-
* (`POST /api/v1/
|
|
211
|
+
* (`POST /api/v1/runs`):
|
|
204
212
|
*
|
|
205
|
-
* -
|
|
206
|
-
* -
|
|
207
|
-
* -
|
|
213
|
+
* - `target` is a required text field.
|
|
214
|
+
* - Scalar inputs go in the `input` JSON text field.
|
|
215
|
+
* - Each top-level file in `input` becomes `files.<fieldName>`.
|
|
216
|
+
* - Per-step overrides and caller metadata use `overrides` / `metadata` JSON parts.
|
|
208
217
|
*
|
|
209
218
|
* Async because stream inputs are drained to bytes here. Only top-level file
|
|
210
219
|
* values are extracted — files nested inside arrays / objects keep their
|
|
211
220
|
* position in the JSON sidecar (the server has no nested-upload path).
|
|
212
221
|
*/
|
|
213
222
|
export async function buildRunMultipart(args: {
|
|
223
|
+
target: string;
|
|
214
224
|
input?: Record<string, unknown>;
|
|
215
225
|
overrides?: { steps?: Record<string, Record<string, unknown>> };
|
|
226
|
+
metadata?: Record<string, unknown>;
|
|
216
227
|
}): Promise<MultipartParts> {
|
|
217
228
|
const fd = new FormData();
|
|
229
|
+
fd.append('target', args.target);
|
|
218
230
|
const { scalars, fileCount } = await appendFiles(fd, args.input);
|
|
219
|
-
|
|
220
|
-
fd.append('_json', JSON.stringify(scalars));
|
|
221
|
-
}
|
|
231
|
+
fd.append('input', JSON.stringify(scalars));
|
|
222
232
|
if (args.overrides) {
|
|
223
|
-
fd.append('
|
|
233
|
+
fd.append('overrides', JSON.stringify(args.overrides));
|
|
234
|
+
}
|
|
235
|
+
if (args.metadata) {
|
|
236
|
+
fd.append('metadata', JSON.stringify(args.metadata));
|
|
224
237
|
}
|
|
225
238
|
return { formData: fd, fileCount };
|
|
226
239
|
}
|
|
@@ -23,19 +23,12 @@ export interface RunAndWaitOptions {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export type WorkflowRunAndWaitResponse = {
|
|
26
|
-
|
|
26
|
+
id: string;
|
|
27
27
|
status?: ExecutionStatus;
|
|
28
28
|
output?: unknown;
|
|
29
29
|
error?: string;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
const TERMINAL_STATUSES = new Set<ExecutionStatus>([
|
|
33
|
-
'completed',
|
|
34
|
-
'failed',
|
|
35
|
-
'cancelled',
|
|
36
|
-
'rejected',
|
|
37
|
-
]);
|
|
38
|
-
|
|
39
32
|
const DEFAULT_POLL_INTERVAL_MS = 2_000;
|
|
40
33
|
const DEFAULT_RUN_AND_WAIT_TIMEOUT_MS = 5 * 60 * 1000;
|
|
41
34
|
|
|
@@ -55,7 +48,7 @@ export class WorkflowExecutionsResource {
|
|
|
55
48
|
/**
|
|
56
49
|
* Trigger a workflow and poll for completion client-side.
|
|
57
50
|
*
|
|
58
|
-
* Unlike `client.run({ waitForCompletion: 60 })`, this helper polls
|
|
51
|
+
* Unlike `client.run(target, input, { waitForCompletion: 60 })`, this helper polls
|
|
59
52
|
* indefinitely (up to `timeoutMs`, default 5 min) so it works for runs
|
|
60
53
|
* that exceed the server-side 60s sync window. Returns the final
|
|
61
54
|
* response with `status`/`output`/`error` populated.
|
|
@@ -70,15 +63,19 @@ export class WorkflowExecutionsResource {
|
|
|
70
63
|
const deadline = Date.now() + timeoutMs;
|
|
71
64
|
|
|
72
65
|
const target = `workflows.${workflowId}`;
|
|
73
|
-
const runUrl =
|
|
66
|
+
const runUrl = '/api/v1/runs';
|
|
74
67
|
const runQuery =
|
|
75
68
|
options.version && options.version !== 'latest' ? { version: options.version } : undefined;
|
|
76
|
-
let runResult: {
|
|
69
|
+
let runResult: { id: string };
|
|
77
70
|
if (hasFileInput(input)) {
|
|
78
71
|
// Build the multipart body once, up front — `dispatch` may retry the
|
|
79
72
|
// POST, and a drained stream cannot be replayed.
|
|
80
|
-
const { formData } = await buildRunMultipart({
|
|
81
|
-
|
|
73
|
+
const { formData } = await buildRunMultipart({
|
|
74
|
+
target,
|
|
75
|
+
input,
|
|
76
|
+
overrides: options.overrides,
|
|
77
|
+
});
|
|
78
|
+
runResult = await this.dispatch<{ id: string }>(
|
|
82
79
|
() =>
|
|
83
80
|
this.client.post({
|
|
84
81
|
url: runUrl,
|
|
@@ -87,22 +84,22 @@ export class WorkflowExecutionsResource {
|
|
|
87
84
|
bodySerializer: null,
|
|
88
85
|
headers: { 'Content-Type': null },
|
|
89
86
|
signal: options.signal,
|
|
90
|
-
}) as Promise<OperationResult<{
|
|
87
|
+
}) as Promise<OperationResult<{ id: string }>>
|
|
91
88
|
);
|
|
92
89
|
} else {
|
|
93
|
-
const body = buildRunJsonBody(input, options.overrides);
|
|
94
|
-
runResult = await this.dispatch<{
|
|
90
|
+
const body = buildRunJsonBody(target, input, options.overrides);
|
|
91
|
+
runResult = await this.dispatch<{ id: string }>(
|
|
95
92
|
() =>
|
|
96
93
|
this.client.post({
|
|
97
94
|
url: runUrl,
|
|
98
95
|
query: runQuery,
|
|
99
96
|
body,
|
|
100
97
|
signal: options.signal,
|
|
101
|
-
}) as Promise<OperationResult<{
|
|
98
|
+
}) as Promise<OperationResult<{ id: string }>>
|
|
102
99
|
);
|
|
103
100
|
}
|
|
104
101
|
|
|
105
|
-
const runId = runResult.
|
|
102
|
+
const runId = runResult.id;
|
|
106
103
|
|
|
107
104
|
while (true) {
|
|
108
105
|
if (options.signal?.aborted) {
|
|
@@ -114,27 +111,28 @@ export class WorkflowExecutionsResource {
|
|
|
114
111
|
);
|
|
115
112
|
}
|
|
116
113
|
|
|
117
|
-
const
|
|
114
|
+
const run = (await this.dispatch<RunsGetResponse>(
|
|
118
115
|
() =>
|
|
119
116
|
runsGet({
|
|
120
117
|
client: this.client,
|
|
121
118
|
path: { id: runId },
|
|
122
|
-
query: {
|
|
119
|
+
query: { expand: 'execution' },
|
|
123
120
|
signal: options.signal,
|
|
124
121
|
}) as Promise<OperationResult<RunsGetResponse>>
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
status?: ExecutionStatus | null;
|
|
122
|
+
)) as {
|
|
123
|
+
finished?: boolean;
|
|
128
124
|
output?: unknown;
|
|
129
125
|
error?: string | null;
|
|
126
|
+
execution?: { status?: ExecutionStatus | null } | null;
|
|
130
127
|
};
|
|
131
128
|
|
|
132
|
-
|
|
129
|
+
const status = run.execution?.status;
|
|
130
|
+
if (run.finished) {
|
|
133
131
|
return {
|
|
134
|
-
runId,
|
|
135
|
-
status: status
|
|
136
|
-
...(
|
|
137
|
-
...(
|
|
132
|
+
id: runId,
|
|
133
|
+
status: status ?? 'completed',
|
|
134
|
+
...(run.output != null ? { output: run.output } : {}),
|
|
135
|
+
...(run.error != null ? { error: run.error } : {}),
|
|
138
136
|
};
|
|
139
137
|
}
|
|
140
138
|
|
package/src/resources/runs.ts
CHANGED
|
@@ -2,10 +2,11 @@ import type { OperationResult } from '../client';
|
|
|
2
2
|
import { EigenpalError } from '../errors';
|
|
3
3
|
import type { Client } from '../generated/client';
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
runsArtifactsList,
|
|
6
6
|
runsCancel,
|
|
7
7
|
runsComparisonGet,
|
|
8
8
|
runsConnect,
|
|
9
|
+
runsDefinitionGet,
|
|
9
10
|
runsExpectedCreate,
|
|
10
11
|
runsExpectedFileDelete,
|
|
11
12
|
runsExpectedFileGet,
|
|
@@ -24,7 +25,8 @@ import {
|
|
|
24
25
|
runsTraceGet,
|
|
25
26
|
} from '../generated/sdk.gen';
|
|
26
27
|
import type {
|
|
27
|
-
|
|
28
|
+
RunArtifactsResponse,
|
|
29
|
+
RunDefinitionResponse,
|
|
28
30
|
RunsCancelResponse,
|
|
29
31
|
RunsComparisonGetResponse,
|
|
30
32
|
RunsConnectResponse,
|
|
@@ -54,6 +56,21 @@ type Dispatch = <T>(call: () => Promise<OperationResult<T>>) => Promise<T>;
|
|
|
54
56
|
export type ListRunsOptions = NonNullable<RunsListData['query']> & { signal?: AbortSignal };
|
|
55
57
|
type SignalOptions = { signal?: AbortSignal };
|
|
56
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Expandable sections for `runs.get`. Each token adds one nested object with
|
|
61
|
+
* the same name. Terminal runs expose top-level `output`, `files`, and `error`.
|
|
62
|
+
*/
|
|
63
|
+
export type RunExpandSection = 'input' | 'usage' | 'execution' | 'debug';
|
|
64
|
+
|
|
65
|
+
/** Typed section list, or a raw comma-separated string for forward compat. */
|
|
66
|
+
export type RunExpand = readonly RunExpandSection[] | (string & {});
|
|
67
|
+
|
|
68
|
+
function formatExpand(expand: RunExpand | undefined): string | undefined {
|
|
69
|
+
if (expand === undefined) return undefined;
|
|
70
|
+
const joined = typeof expand === 'string' ? expand : expand.join(',');
|
|
71
|
+
return joined.length > 0 ? joined : undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
57
74
|
export class RunsResource {
|
|
58
75
|
public readonly feedback: RunsFeedbackResource;
|
|
59
76
|
public readonly expected: RunsExpectedResource;
|
|
@@ -69,7 +86,7 @@ export class RunsResource {
|
|
|
69
86
|
this.feedback = new RunsFeedbackResource(client, dispatch);
|
|
70
87
|
this.expected = new RunsExpectedResource(client, dispatch);
|
|
71
88
|
this.files = new RunsFilesResource(client, dispatch);
|
|
72
|
-
this.artifacts = new RunsArtifactsResource(client);
|
|
89
|
+
this.artifacts = new RunsArtifactsResource(client, dispatch);
|
|
73
90
|
this.comparison = new RunsComparisonResource(client, dispatch);
|
|
74
91
|
this.trace = new RunsTraceResource(client, dispatch);
|
|
75
92
|
}
|
|
@@ -79,16 +96,24 @@ export class RunsResource {
|
|
|
79
96
|
return this.dispatch(() => runsList({ client: this.client, query, signal }));
|
|
80
97
|
}
|
|
81
98
|
|
|
82
|
-
|
|
83
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Fetch the canonical grouped run object. Terminal runs include top-level
|
|
101
|
+
* `output`, `files`, and `error`. Pass `expand` (for example
|
|
102
|
+
* `['usage', 'execution']`) to add optional nested detail objects.
|
|
103
|
+
*/
|
|
104
|
+
async get(
|
|
105
|
+
runId: string,
|
|
106
|
+
options: { expand?: RunExpand; signal?: AbortSignal } = {}
|
|
107
|
+
): Promise<RunsGetResponse> {
|
|
108
|
+
const expand = formatExpand(options.expand);
|
|
109
|
+
return this.dispatch<RunsGetResponse>(() =>
|
|
84
110
|
runsGet({
|
|
85
111
|
client: this.client,
|
|
86
112
|
path: { id: runId },
|
|
87
|
-
query:
|
|
113
|
+
query: expand ? { expand } : {},
|
|
88
114
|
signal: options.signal,
|
|
89
115
|
})
|
|
90
116
|
);
|
|
91
|
-
return response.run;
|
|
92
117
|
}
|
|
93
118
|
|
|
94
119
|
async cancel(runId: string, options: SignalOptions = {}): Promise<RunsCancelResponse> {
|
|
@@ -99,11 +124,11 @@ export class RunsResource {
|
|
|
99
124
|
|
|
100
125
|
async rerun(
|
|
101
126
|
runId: string,
|
|
102
|
-
|
|
127
|
+
query: { version?: string; wait_for_completion?: number } = {},
|
|
103
128
|
options: SignalOptions = {}
|
|
104
129
|
): Promise<RunsRerunResponse> {
|
|
105
130
|
return this.dispatch(() =>
|
|
106
|
-
runsRerun({ client: this.client, path: { id: runId },
|
|
131
|
+
runsRerun({ client: this.client, path: { id: runId }, query, signal: options.signal })
|
|
107
132
|
);
|
|
108
133
|
}
|
|
109
134
|
|
|
@@ -120,10 +145,10 @@ export class RunsResource {
|
|
|
120
145
|
const mode = options.baseline ? 'baseline' : 'expected';
|
|
121
146
|
const [reference, target] = await Promise.all([
|
|
122
147
|
this.get(referenceRunId, {
|
|
123
|
-
|
|
148
|
+
expand: ['execution'],
|
|
124
149
|
signal: options.signal,
|
|
125
150
|
}),
|
|
126
|
-
this.get(runId, {
|
|
151
|
+
this.get(runId, { expand: ['execution'], signal: options.signal }),
|
|
127
152
|
]);
|
|
128
153
|
|
|
129
154
|
if (isWorkflowRun(reference) && isWorkflowRun(target)) {
|
|
@@ -156,6 +181,12 @@ export class RunsResource {
|
|
|
156
181
|
runsConnect({ client: this.client, path: { id: runId }, signal: options.signal })
|
|
157
182
|
);
|
|
158
183
|
}
|
|
184
|
+
|
|
185
|
+
async definition(runId: string, options: SignalOptions = {}): Promise<RunDefinitionResponse> {
|
|
186
|
+
return this.dispatch(() =>
|
|
187
|
+
runsDefinitionGet({ client: this.client, path: { id: runId }, signal: options.signal })
|
|
188
|
+
);
|
|
189
|
+
}
|
|
159
190
|
}
|
|
160
191
|
|
|
161
192
|
type RunRecord = Record<string, unknown>;
|
|
@@ -174,19 +205,57 @@ export type RunComparisonReport = {
|
|
|
174
205
|
warnings?: string[];
|
|
175
206
|
};
|
|
176
207
|
|
|
177
|
-
function isWorkflowRun(run: unknown): run is RunRecord
|
|
178
|
-
return isRecord(run) &&
|
|
208
|
+
function isWorkflowRun(run: unknown): run is RunRecord {
|
|
209
|
+
return isRecord(run) && run.type === 'workflow';
|
|
179
210
|
}
|
|
180
211
|
|
|
181
212
|
function isRecord(value: unknown): value is RunRecord {
|
|
182
213
|
return value != null && typeof value === 'object' && !Array.isArray(value);
|
|
183
214
|
}
|
|
184
215
|
|
|
216
|
+
function runExecution(run: RunRecord): RunRecord {
|
|
217
|
+
return isRecord(run.execution) ? run.execution : {};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function runResult(run: RunRecord): RunRecord {
|
|
221
|
+
return isRecord(run.result) ? run.result : {};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function runOutput(run: unknown): unknown {
|
|
225
|
+
if (!isRecord(run)) return undefined;
|
|
226
|
+
if (run.output !== undefined) return run.output;
|
|
227
|
+
return runResult(run).output;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function runUsage(run: unknown): unknown {
|
|
231
|
+
return isRecord(run) ? run.usage : undefined;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function runExecutionDetails(run: unknown): unknown {
|
|
235
|
+
return isRecord(run) ? run.execution : undefined;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function workflowSteps(run: RunRecord): unknown[] {
|
|
239
|
+
const steps = runExecution(run).steps;
|
|
240
|
+
return Array.isArray(steps) ? steps : [];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function agentOutputFiles(run: RunRecord): unknown[] {
|
|
244
|
+
const rawFiles = runExecution(run).files;
|
|
245
|
+
const files: RunRecord = isRecord(rawFiles) ? rawFiles : {};
|
|
246
|
+
return Array.isArray(files.output) ? files.output : [];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function agentExpected(run: RunRecord): RunRecord {
|
|
250
|
+
const expected = runExecution(run).expected;
|
|
251
|
+
return isRecord(expected) ? expected : {};
|
|
252
|
+
}
|
|
253
|
+
|
|
185
254
|
function compareWorkflowRuns(
|
|
186
255
|
referenceRunId: string,
|
|
187
|
-
reference: RunRecord
|
|
256
|
+
reference: RunRecord,
|
|
188
257
|
runId: string,
|
|
189
|
-
target: RunRecord
|
|
258
|
+
target: RunRecord,
|
|
190
259
|
stepFilter?: string
|
|
191
260
|
): RunComparisonReport {
|
|
192
261
|
const wanted = stepFilter
|
|
@@ -194,11 +263,11 @@ function compareWorkflowRuns(
|
|
|
194
263
|
.map((step) => step.trim())
|
|
195
264
|
.filter(Boolean);
|
|
196
265
|
const targetSteps = new Map(
|
|
197
|
-
target
|
|
266
|
+
workflowSteps(target)
|
|
198
267
|
.filter(isRecord)
|
|
199
268
|
.map((step) => [String(step.stepName ?? step.name ?? step.id ?? ''), step])
|
|
200
269
|
);
|
|
201
|
-
const steps = reference
|
|
270
|
+
const steps = workflowSteps(reference)
|
|
202
271
|
.filter(isRecord)
|
|
203
272
|
.filter(
|
|
204
273
|
(step) => !wanted?.length || wanted.includes(String(step.stepName ?? step.name ?? step.id))
|
|
@@ -237,10 +306,13 @@ function compareArtifactRuns(
|
|
|
237
306
|
): RunComparisonReport {
|
|
238
307
|
const referenceRun = isRecord(reference) ? reference : {};
|
|
239
308
|
const targetRun = isRecord(target) ? target : {};
|
|
240
|
-
const expectedValue =
|
|
309
|
+
const expectedValue =
|
|
310
|
+
mode === 'baseline' ? runOutput(referenceRun) : agentExpected(referenceRun).output;
|
|
241
311
|
const expectedFiles =
|
|
242
|
-
mode === 'baseline'
|
|
243
|
-
|
|
312
|
+
mode === 'baseline'
|
|
313
|
+
? names(agentOutputFiles(referenceRun))
|
|
314
|
+
: names(agentExpected(referenceRun).files);
|
|
315
|
+
const outputFiles = names(agentOutputFiles(targetRun));
|
|
244
316
|
const missing = expectedFiles.filter(
|
|
245
317
|
(name) =>
|
|
246
318
|
!outputFiles.some(
|
|
@@ -262,7 +334,7 @@ function compareArtifactRuns(
|
|
|
262
334
|
(out) => comparableName(out, normalizeDates) === comparableName(name, normalizeDates)
|
|
263
335
|
) ?? name,
|
|
264
336
|
}));
|
|
265
|
-
const jsonDifferences = diffJson(expectedValue, targetRun
|
|
337
|
+
const jsonDifferences = diffJson(expectedValue, runOutput(targetRun));
|
|
266
338
|
return {
|
|
267
339
|
status:
|
|
268
340
|
jsonDifferences.length === 0 && missing.length === 0 && extra.length === 0 ? 'pass' : 'fail',
|
|
@@ -479,14 +551,23 @@ export class RunsFilesResource {
|
|
|
479
551
|
}
|
|
480
552
|
|
|
481
553
|
export class RunsArtifactsResource {
|
|
482
|
-
constructor(
|
|
554
|
+
constructor(
|
|
555
|
+
private readonly client: Client,
|
|
556
|
+
private readonly dispatch: Dispatch
|
|
557
|
+
) {}
|
|
558
|
+
|
|
559
|
+
async list(runId: string, options: SignalOptions = {}): Promise<RunArtifactsResponse> {
|
|
560
|
+
const { signal } = options;
|
|
561
|
+
return this.dispatch(() =>
|
|
562
|
+
runsArtifactsList({ client: this.client, path: { id: runId }, signal })
|
|
563
|
+
);
|
|
564
|
+
}
|
|
483
565
|
|
|
484
566
|
async download(runId: string, path: string, options: SignalOptions = {}): Promise<Blob> {
|
|
485
567
|
return downloadBlob(
|
|
486
568
|
() =>
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
path: { id: runId, path },
|
|
569
|
+
this.client.get({
|
|
570
|
+
url: `/api/v1/runs/${encodeURIComponent(runId)}/artifacts/${encodeArtifactPath(path)}`,
|
|
490
571
|
parseAs: 'blob',
|
|
491
572
|
signal: options.signal,
|
|
492
573
|
}) as Promise<OperationResult<Blob>>
|
|
@@ -546,3 +627,7 @@ async function downloadBlob(call: () => Promise<OperationResult<Blob>>): Promise
|
|
|
546
627
|
status: result.response?.status ?? 0,
|
|
547
628
|
});
|
|
548
629
|
}
|
|
630
|
+
|
|
631
|
+
function encodeArtifactPath(path: string): string {
|
|
632
|
+
return path.split('/').map(encodeURIComponent).join('/');
|
|
633
|
+
}
|
package/src/telemetry.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
export const SDK_LANGUAGE = 'typescript';
|
|
20
20
|
// Rewritten at publish time by scripts/render-sdk-versions.sh.
|
|
21
21
|
// Keep this string literal exactly stable — sed matches on it.
|
|
22
|
-
export const SDK_VERSION = '0.
|
|
22
|
+
export const SDK_VERSION = '0.7.1';
|
|
23
23
|
|
|
24
24
|
function detectRuntime(): string {
|
|
25
25
|
const g = globalThis as unknown as {
|