@atlanai/sdk 0.2.3 → 0.2.4
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/dist/client.d.ts +16 -2
- package/dist/client.js +118 -9
- package/dist/errors.d.ts +9 -0
- package/dist/errors.js +23 -1
- package/dist/evals.d.ts +130 -7
- package/dist/evals.js +724 -8
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -1
- package/dist/resources.d.ts +10 -0
- package/dist/resources.js +54 -4
- package/dist/tracing/version.d.ts +1 -1
- package/dist/tracing/version.js +1 -1
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -42,10 +42,24 @@ export declare class ServiceNamespace {
|
|
|
42
42
|
readonly operations: readonly Omit<Operation, "service">[];
|
|
43
43
|
/** Contract method names for this service, used to resolve a forwarded call. */
|
|
44
44
|
readonly operationMethods: ReadonlySet<string>;
|
|
45
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Whether the configured credential is an API key rather than a user token.
|
|
47
|
+
* Only the credential's shape was read, never its value.
|
|
48
|
+
*/
|
|
49
|
+
readonly apiKeyCredential: boolean;
|
|
50
|
+
constructor(name: string, module: GeneratedModule, configuration: GeneratedConfiguration, serviceOperations: readonly Omit<Operation, "service">[], apiKeyCredential?: boolean);
|
|
46
51
|
}
|
|
47
52
|
/** Build a namespace that also answers its operations by method name. */
|
|
48
|
-
export declare function createService(name: string, module: GeneratedModule, configuration: GeneratedConfiguration, serviceOperations: readonly Omit<Operation, "service">[]): Service;
|
|
53
|
+
export declare function createService(name: string, module: GeneratedModule, configuration: GeneratedConfiguration, serviceOperations: readonly Omit<Operation, "service">[], apiKeyCredential?: boolean): Service;
|
|
54
|
+
/**
|
|
55
|
+
* Whether a credential is a signed JWT, which is the user-token shape.
|
|
56
|
+
*
|
|
57
|
+
* Only the structure is read, and the value is never logged or compared to a
|
|
58
|
+
* literal: three base64url segments whose first decodes to a JSON object. The
|
|
59
|
+
* gateway draws the same line itself - its 401 vocabulary splits
|
|
60
|
+
* `invalid_api_key`/`unknown_key` from the whole `token_*` family.
|
|
61
|
+
*/
|
|
62
|
+
export declare function looksLikeAJwt(token: string): boolean;
|
|
49
63
|
export interface AtlanClient extends ResourceRoots {
|
|
50
64
|
}
|
|
51
65
|
export declare class AtlanClient {
|
package/dist/client.js
CHANGED
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.AtlanClient = exports.ServiceNamespace = exports.WORKSPACE_HEADER = void 0;
|
|
37
37
|
exports.createService = createService;
|
|
38
|
+
exports.looksLikeAJwt = looksLikeAJwt;
|
|
38
39
|
const agentRaw = __importStar(require("./raw/agent/index"));
|
|
39
40
|
const apiRaw = __importStar(require("./raw/api/index"));
|
|
40
41
|
const evalRaw = __importStar(require("./raw/eval/index"));
|
|
@@ -57,8 +58,14 @@ class ServiceNamespace {
|
|
|
57
58
|
operations;
|
|
58
59
|
/** Contract method names for this service, used to resolve a forwarded call. */
|
|
59
60
|
operationMethods;
|
|
60
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Whether the configured credential is an API key rather than a user token.
|
|
63
|
+
* Only the credential's shape was read, never its value.
|
|
64
|
+
*/
|
|
65
|
+
apiKeyCredential;
|
|
66
|
+
constructor(name, module, configuration, serviceOperations, apiKeyCredential = false) {
|
|
61
67
|
this.name = name;
|
|
68
|
+
this.apiKeyCredential = apiKeyCredential;
|
|
62
69
|
this.configuration = configuration;
|
|
63
70
|
this.operations = serviceOperations;
|
|
64
71
|
const operationMethods = new Set(serviceOperations.map((operation) => methodName(operation.operation_id)));
|
|
@@ -69,15 +76,15 @@ class ServiceNamespace {
|
|
|
69
76
|
continue;
|
|
70
77
|
const name = exportName.replace(/Api$/, "").replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase();
|
|
71
78
|
const raw = new value(configuration);
|
|
72
|
-
apis[name] = wrapGeneratedAPI(raw, operationMethods);
|
|
79
|
+
apis[name] = wrapGeneratedAPI(raw, operationMethods, apiKeyCredential);
|
|
73
80
|
}
|
|
74
81
|
this.apis = Object.freeze(apis);
|
|
75
82
|
}
|
|
76
83
|
}
|
|
77
84
|
exports.ServiceNamespace = ServiceNamespace;
|
|
78
85
|
/** Build a namespace that also answers its operations by method name. */
|
|
79
|
-
function createService(name, module, configuration, serviceOperations) {
|
|
80
|
-
const namespace = new ServiceNamespace(name, module, configuration, serviceOperations);
|
|
86
|
+
function createService(name, module, configuration, serviceOperations, apiKeyCredential = false) {
|
|
87
|
+
const namespace = new ServiceNamespace(name, module, configuration, serviceOperations, apiKeyCredential);
|
|
81
88
|
return forwardOperations(namespace, namespace.operationMethods);
|
|
82
89
|
}
|
|
83
90
|
/**
|
|
@@ -138,7 +145,69 @@ function methodName(operationId) {
|
|
|
138
145
|
const [service, operation] = operationId.split(".", 2);
|
|
139
146
|
return service + operation.charAt(0).toUpperCase() + operation.slice(1);
|
|
140
147
|
}
|
|
141
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Recover a success body the generated client would have thrown away.
|
|
150
|
+
*
|
|
151
|
+
* A handful of operations document their 200 as `application/json` with no
|
|
152
|
+
* schema. The generator reads that as "no response type" and renders the
|
|
153
|
+
* method as `Promise<void>`: it awaits the `…Raw` sibling and returns nothing,
|
|
154
|
+
* never calling `value()` at all. `GET /skill/v1/skills/{skill_id}` is one -
|
|
155
|
+
* the gateway sends the whole skill and the caller receives `undefined`, which
|
|
156
|
+
* makes a skill impossible to read back.
|
|
157
|
+
*
|
|
158
|
+
* Hand-fixing the contract would not hold, since `contracts/` is synced from
|
|
159
|
+
* the gateway. So the generated method is still the one called, with its own
|
|
160
|
+
* parameter defaults intact, over a receiver that keeps hold of the
|
|
161
|
+
* `ApiResponse` it discards. Only when the call resolves to `undefined` is
|
|
162
|
+
* that response read, and its body is still unconsumed precisely because the
|
|
163
|
+
* generated method ignored it. One request either way, and nothing changes for
|
|
164
|
+
* an operation whose body the generator already keeps.
|
|
165
|
+
*/
|
|
166
|
+
async function callKeepingBody(target, method, property, args) {
|
|
167
|
+
const rawName = `${property}Raw`;
|
|
168
|
+
if (typeof target[rawName] !== "function") {
|
|
169
|
+
return await Reflect.apply(method, target, args);
|
|
170
|
+
}
|
|
171
|
+
let captured;
|
|
172
|
+
const receiver = new Proxy(target, {
|
|
173
|
+
get(proxied, name, self) {
|
|
174
|
+
const member = Reflect.get(proxied, name, self);
|
|
175
|
+
if (name !== rawName || typeof member !== "function")
|
|
176
|
+
return member;
|
|
177
|
+
return async (...rawArgs) => {
|
|
178
|
+
captured = (await Reflect.apply(member, proxied, rawArgs));
|
|
179
|
+
return captured;
|
|
180
|
+
};
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
const result = await Reflect.apply(method, receiver, args);
|
|
184
|
+
if (result !== undefined || captured === undefined)
|
|
185
|
+
return result;
|
|
186
|
+
return await recoverValue(captured);
|
|
187
|
+
}
|
|
188
|
+
async function recoverValue(response) {
|
|
189
|
+
let value;
|
|
190
|
+
try {
|
|
191
|
+
value = await response.value?.();
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
// The generated method already read the body; there is nothing to recover.
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
if (value !== undefined || !response.raw)
|
|
198
|
+
return value;
|
|
199
|
+
const contentType = response.raw.headers.get("content-type") ?? "";
|
|
200
|
+
if (!contentType.toLowerCase().includes("json"))
|
|
201
|
+
return value;
|
|
202
|
+
try {
|
|
203
|
+
return await response.raw.json();
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// An empty or unparseable body is the `void` the generator promised.
|
|
207
|
+
return value;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function wrapGeneratedAPI(api, operationMethods, apiKeyCredential) {
|
|
142
211
|
return new Proxy(api, {
|
|
143
212
|
get(target, property, receiver) {
|
|
144
213
|
const value = Reflect.get(target, property, receiver);
|
|
@@ -147,22 +216,58 @@ function wrapGeneratedAPI(api, operationMethods) {
|
|
|
147
216
|
}
|
|
148
217
|
return async (...args) => {
|
|
149
218
|
try {
|
|
150
|
-
return await
|
|
219
|
+
return await callKeepingBody(target, value, property, args);
|
|
151
220
|
}
|
|
152
221
|
catch (error) {
|
|
153
222
|
const response = error?.response;
|
|
154
223
|
if (response instanceof Response) {
|
|
155
|
-
throw await errors_1.AtlanAPIError.fromResponse(response);
|
|
224
|
+
throw annotateCredential(await errors_1.AtlanAPIError.fromResponse(response), apiKeyCredential);
|
|
156
225
|
}
|
|
157
226
|
const cause = error?.cause;
|
|
158
227
|
if (cause instanceof errors_1.AtlanAPIError)
|
|
159
|
-
throw cause;
|
|
228
|
+
throw annotateCredential(cause, apiKeyCredential);
|
|
160
229
|
throw error;
|
|
161
230
|
}
|
|
162
231
|
};
|
|
163
232
|
},
|
|
164
233
|
});
|
|
165
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Say which kind of credential a 403 was refused for.
|
|
237
|
+
*
|
|
238
|
+
* A bare "403 forbidden" sends people hunting for a missing role when the
|
|
239
|
+
* credential kind is the whole story: the same POST an API key is refused is
|
|
240
|
+
* accepted from a user token.
|
|
241
|
+
*/
|
|
242
|
+
function annotateCredential(error, apiKeyCredential) {
|
|
243
|
+
if (error.status !== 403 || !apiKeyCredential)
|
|
244
|
+
return error;
|
|
245
|
+
return error.withHint("the configured credential is an API key, not a user token; the gateway grants " +
|
|
246
|
+
"an API key a narrower set of permissions - creating an agent or a skill, for " +
|
|
247
|
+
"one, is refused for an API key and accepted for a user token from " +
|
|
248
|
+
"`atlanai auth login` (read it with `atlanai auth token`)");
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Whether a credential is a signed JWT, which is the user-token shape.
|
|
252
|
+
*
|
|
253
|
+
* Only the structure is read, and the value is never logged or compared to a
|
|
254
|
+
* literal: three base64url segments whose first decodes to a JSON object. The
|
|
255
|
+
* gateway draws the same line itself - its 401 vocabulary splits
|
|
256
|
+
* `invalid_api_key`/`unknown_key` from the whole `token_*` family.
|
|
257
|
+
*/
|
|
258
|
+
function looksLikeAJwt(token) {
|
|
259
|
+
const segments = token.split(".");
|
|
260
|
+
if (segments.length !== 3 || segments.some((segment) => segment === ""))
|
|
261
|
+
return false;
|
|
262
|
+
try {
|
|
263
|
+
const header = segments[0].replace(/-/g, "+").replace(/_/g, "/");
|
|
264
|
+
const decoded = JSON.parse(atob(header));
|
|
265
|
+
return typeof decoded === "object" && decoded !== null && !Array.isArray(decoded);
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
166
271
|
class AtlanClient {
|
|
167
272
|
/** Per-service generated clients, for an operation the map has not surfaced. */
|
|
168
273
|
raw;
|
|
@@ -181,6 +286,10 @@ class AtlanClient {
|
|
|
181
286
|
const fetchApi = withTimeout(options.fetch ?? globalThis.fetch, timeoutMs);
|
|
182
287
|
const accessToken = safeTokenProvider(options.bearerToken, options.tokenProvider);
|
|
183
288
|
const workspace = validateWorkspace(options.workspace);
|
|
289
|
+
// Read once, from the shape alone. A tokenProvider is left unclassified
|
|
290
|
+
// rather than called here: resolving it early could refresh a credential
|
|
291
|
+
// nobody asked for yet.
|
|
292
|
+
const apiKeyCredential = options.bearerToken !== undefined && !looksLikeAJwt(options.bearerToken);
|
|
184
293
|
const modules = {
|
|
185
294
|
registry: registryRaw,
|
|
186
295
|
skill: skillRaw,
|
|
@@ -202,7 +311,7 @@ class AtlanClient {
|
|
|
202
311
|
accessToken,
|
|
203
312
|
...(workspace === undefined ? {} : { headers: { [exports.WORKSPACE_HEADER]: workspace } }),
|
|
204
313
|
});
|
|
205
|
-
namespaces[service.name] = createService(service.name, module, configuration, service.operations);
|
|
314
|
+
namespaces[service.name] = createService(service.name, module, configuration, service.operations, apiKeyCredential);
|
|
206
315
|
}
|
|
207
316
|
this.raw = Object.freeze(namespaces);
|
|
208
317
|
// Resources, not services. A service is a base path; a resource is what a
|
package/dist/errors.d.ts
CHANGED
|
@@ -4,13 +4,22 @@ export declare class AtlanAPIError extends Error {
|
|
|
4
4
|
readonly title: string;
|
|
5
5
|
readonly detail: string;
|
|
6
6
|
readonly traceId?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Set by the SDK when it, not the gateway, knows why the call failed - a
|
|
9
|
+
* 403 refused for the kind of credential configured, for instance. Never
|
|
10
|
+
* server-supplied, so unlike `detail` it is safe to put in the message.
|
|
11
|
+
*/
|
|
12
|
+
readonly hint: string;
|
|
7
13
|
constructor(options: {
|
|
8
14
|
status: number;
|
|
9
15
|
code?: string;
|
|
10
16
|
title?: string;
|
|
11
17
|
detail?: string;
|
|
12
18
|
traceId?: string;
|
|
19
|
+
hint?: string;
|
|
13
20
|
});
|
|
21
|
+
/** The same failure, carrying a client-side explanation in its message. */
|
|
22
|
+
withHint(hint: string): AtlanAPIError;
|
|
14
23
|
static fromResponse(response: Response): Promise<AtlanAPIError>;
|
|
15
24
|
static fromConnectionError(timedOut?: boolean): AtlanAPIError;
|
|
16
25
|
}
|
package/dist/errors.js
CHANGED
|
@@ -7,11 +7,21 @@ class AtlanAPIError extends Error {
|
|
|
7
7
|
title;
|
|
8
8
|
detail;
|
|
9
9
|
traceId;
|
|
10
|
+
/**
|
|
11
|
+
* Set by the SDK when it, not the gateway, knows why the call failed - a
|
|
12
|
+
* 403 refused for the kind of credential configured, for instance. Never
|
|
13
|
+
* server-supplied, so unlike `detail` it is safe to put in the message.
|
|
14
|
+
*/
|
|
15
|
+
hint;
|
|
10
16
|
constructor(options) {
|
|
11
17
|
const suffix = options.code ? ` (${options.code})` : "";
|
|
18
|
+
const hint = options.hint ? `; ${options.hint}` : "";
|
|
19
|
+
// `detail` stays out: it is server text and may echo what was sent.
|
|
20
|
+
// `traceId` is an opaque correlation id and is what support asks for.
|
|
21
|
+
const trace = options.traceId ? ` [trace_id=${options.traceId}]` : "";
|
|
12
22
|
const message = options.status === 0
|
|
13
23
|
? `${options.title ?? "Could not reach the Atlan Gateway"}${options.detail ? `; ${options.detail}` : ""}`
|
|
14
|
-
: `Atlan API request failed with status ${options.status}${suffix}`;
|
|
24
|
+
: `Atlan API request failed with status ${options.status}${suffix}${trace}${hint}`;
|
|
15
25
|
super(message);
|
|
16
26
|
this.name = "AtlanAPIError";
|
|
17
27
|
this.status = options.status;
|
|
@@ -19,6 +29,18 @@ class AtlanAPIError extends Error {
|
|
|
19
29
|
this.title = options.title ?? "";
|
|
20
30
|
this.detail = options.detail ?? "";
|
|
21
31
|
this.traceId = options.traceId;
|
|
32
|
+
this.hint = options.hint ?? "";
|
|
33
|
+
}
|
|
34
|
+
/** The same failure, carrying a client-side explanation in its message. */
|
|
35
|
+
withHint(hint) {
|
|
36
|
+
return new AtlanAPIError({
|
|
37
|
+
status: this.status,
|
|
38
|
+
code: this.code,
|
|
39
|
+
title: this.title,
|
|
40
|
+
detail: this.detail,
|
|
41
|
+
traceId: this.traceId,
|
|
42
|
+
hint,
|
|
43
|
+
});
|
|
22
44
|
}
|
|
23
45
|
static async fromResponse(response) {
|
|
24
46
|
let problem = {};
|
package/dist/evals.d.ts
CHANGED
|
@@ -28,6 +28,47 @@ export interface ContextManifest {
|
|
|
28
28
|
export declare function createContextManifest(input: readonly ContextItem[]): Promise<ContextManifest>;
|
|
29
29
|
/** Resolve one dataset by artifact ID or exact name, never fuzzy matching. */
|
|
30
30
|
export declare function resolveDataset(client: AtlanClient, idOrExactName: string, workspaceId?: string): Promise<unknown>;
|
|
31
|
+
/**
|
|
32
|
+
* The Registry handle for the case called `key` inside `datasetId`.
|
|
33
|
+
*
|
|
34
|
+
* Deterministic, so pushing the same suite twice lands on the same row, and
|
|
35
|
+
* dataset-scoped, so the same suite can also be pushed into a new dataset.
|
|
36
|
+
*/
|
|
37
|
+
export declare function recordName(datasetId: string, key: string): Promise<string>;
|
|
38
|
+
/** What one case in a pushed suite ended up as. */
|
|
39
|
+
export interface RecordPush {
|
|
40
|
+
readonly key: string;
|
|
41
|
+
readonly name: string;
|
|
42
|
+
readonly id: string;
|
|
43
|
+
readonly action: "created" | "updated" | "unchanged";
|
|
44
|
+
readonly record: unknown;
|
|
45
|
+
}
|
|
46
|
+
/** A pushed suite: the dataset it landed in and what each case did. */
|
|
47
|
+
export interface DatasetPush {
|
|
48
|
+
readonly dataset: unknown;
|
|
49
|
+
readonly id: string;
|
|
50
|
+
readonly created: boolean;
|
|
51
|
+
readonly records: readonly RecordPush[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Create or update each case, so the same suite can be pushed repeatedly.
|
|
55
|
+
*
|
|
56
|
+
* Each record's `name` is the developer's key for the case: it becomes the
|
|
57
|
+
* row's `displayName` and keys the Registry handle. A case already in the
|
|
58
|
+
* dataset is patched when its content moved and left alone when it did not.
|
|
59
|
+
*/
|
|
60
|
+
export declare function pushRecords(client: AtlanClient, datasetId: string, records: Iterable<Record<string, unknown>>, workspaceId?: string): Promise<RecordPush[]>;
|
|
61
|
+
/**
|
|
62
|
+
* Push a suite under `name`, creating the dataset the first time only.
|
|
63
|
+
*
|
|
64
|
+
* Idempotent: run it again after correcting an expected value and the
|
|
65
|
+
* correction lands on the same rows, in the same dataset, without a 409.
|
|
66
|
+
*/
|
|
67
|
+
export declare function pushDataset(client: AtlanClient, name: string, records: Iterable<Record<string, unknown>>, options?: {
|
|
68
|
+
workspaceId?: string;
|
|
69
|
+
displayName?: string;
|
|
70
|
+
description?: string;
|
|
71
|
+
}): Promise<DatasetPush>;
|
|
31
72
|
export interface StartExperimentOptions {
|
|
32
73
|
contextManifest?: ContextManifest;
|
|
33
74
|
}
|
|
@@ -35,17 +76,59 @@ export declare class EvalRun {
|
|
|
35
76
|
readonly experiment: unknown;
|
|
36
77
|
readonly dataset: unknown;
|
|
37
78
|
readonly contextManifest?: ContextManifest | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* The session id stamped on every span this run emits.
|
|
81
|
+
*
|
|
82
|
+
* It is the only join key the gateway promotes off an eval span that can
|
|
83
|
+
* reach the run's subject: `recordExperimentSession` registers this value
|
|
84
|
+
* against the experiment's subject.
|
|
85
|
+
*/
|
|
38
86
|
constructor(experiment: unknown, dataset: unknown, contextManifest?: ContextManifest | undefined);
|
|
39
87
|
get id(): string;
|
|
40
88
|
get experimentId(): string;
|
|
41
|
-
/**
|
|
89
|
+
/** Stable across retries because the experiment is the resumable unit. */
|
|
90
|
+
get sessionId(): string;
|
|
91
|
+
/**
|
|
92
|
+
* Options for `propagateAttributes` from `@atlanai/sdk/tracing`.
|
|
93
|
+
*
|
|
94
|
+
* Carries the experiment join and the subject join. A nested
|
|
95
|
+
* `propagateAttributes({ sessionId })` still wins for the spans inside it.
|
|
96
|
+
*/
|
|
42
97
|
get traceOptions(): {
|
|
43
98
|
experimentId: string;
|
|
99
|
+
sessionId: string;
|
|
44
100
|
metadata?: Record<string, unknown>;
|
|
45
101
|
};
|
|
46
102
|
}
|
|
47
103
|
/** Create a running experiment over a dataset ID or exact dataset name. */
|
|
48
104
|
export declare function startExperiment(client: AtlanClient, dataset: string, body: Readonly<Record<string, unknown>>, options?: StartExperimentOptions): Promise<EvalRun>;
|
|
105
|
+
export interface ExperimentTracesOptions {
|
|
106
|
+
limit?: number;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Every trace an experiment recorded, newest first.
|
|
110
|
+
*
|
|
111
|
+
* **The experiment is the scope eval traces are filed under.** A subject's own
|
|
112
|
+
* Traces tab (`GET /agent/v1/agents/{id}/traces`) resolves on the trace's
|
|
113
|
+
* *creator identity*, so it lists a run only when the run's spans were exported
|
|
114
|
+
* with that agent's own credential. An eval exported with your user key or a
|
|
115
|
+
* service-account key is filed under that identity instead, and the agent's
|
|
116
|
+
* Traces tab reads empty even though every trace exists. That is not the traces
|
|
117
|
+
* going missing; it is a different scope. Read them here, and call
|
|
118
|
+
* `recordExperimentSession` so the run is also reachable from the subject's
|
|
119
|
+
* Sessions tab.
|
|
120
|
+
*
|
|
121
|
+
* To fill the agent's own Traces tab, export the spans as the agent: pass
|
|
122
|
+
* `logger: initLogger({ apiKey: <the agent's credential> })` while the
|
|
123
|
+
* management `client` keeps your own, since the agent's identity is not
|
|
124
|
+
* entitled to create experiments.
|
|
125
|
+
*/
|
|
126
|
+
export declare function experimentTraces(client: AtlanClient, experimentId: string, options?: ExperimentTracesOptions): Promise<unknown[]>;
|
|
127
|
+
export interface RecordExperimentSessionOptions {
|
|
128
|
+
sessionStatus?: string;
|
|
129
|
+
title?: string;
|
|
130
|
+
}
|
|
131
|
+
export declare function recordExperimentSession(client: AtlanClient, run: EvalRun, options?: RecordExperimentSessionOptions): Promise<unknown | undefined>;
|
|
49
132
|
export interface EvalCase<Input, Expected = unknown, Metadata = Record<string, unknown>> {
|
|
50
133
|
input: Input;
|
|
51
134
|
expected?: Expected;
|
|
@@ -147,6 +230,13 @@ export interface EvalResultWithSummary<Input, Output, Expected, Metadata> {
|
|
|
147
230
|
dataset: unknown;
|
|
148
231
|
summary: Record<string, unknown>;
|
|
149
232
|
results: EvalCaseResult<Input, Output, Expected, Metadata>[];
|
|
233
|
+
/** The session id stamped on every span of the run. */
|
|
234
|
+
sessionId: string;
|
|
235
|
+
/**
|
|
236
|
+
* The `session` record that binds the run to the experiment's subject.
|
|
237
|
+
* `undefined` when the experiment named no subject to bind it to.
|
|
238
|
+
*/
|
|
239
|
+
session?: unknown;
|
|
150
240
|
}
|
|
151
241
|
/** Structural trace surface keeps the management bundle decoupled at build time. */
|
|
152
242
|
export interface EvalTraceSpan {
|
|
@@ -169,13 +259,46 @@ export interface EvalTraceLogger {
|
|
|
169
259
|
readonly client: EvalTraceClient;
|
|
170
260
|
flush(): Promise<void>;
|
|
171
261
|
}
|
|
262
|
+
export declare function Eval<Input, Output, Expected = unknown, Metadata extends Record<string, unknown> = Record<string, unknown>>(name: string, evaluator: Evaluator<Input, Output, Expected, Metadata>, options?: EvalOptions): Promise<EvalResultWithSummary<Input, Output, Expected, Metadata>>;
|
|
263
|
+
/** One gate result. `ok` is undefined when only a human can answer it. */
|
|
264
|
+
export interface VerificationCheck {
|
|
265
|
+
readonly gate: number;
|
|
266
|
+
readonly name: string;
|
|
267
|
+
readonly ok: boolean | undefined;
|
|
268
|
+
readonly detail: string;
|
|
269
|
+
}
|
|
270
|
+
/** The structured report `verifyExperiment` returns. */
|
|
271
|
+
export interface ExperimentVerification {
|
|
272
|
+
readonly experimentId: string;
|
|
273
|
+
readonly experiment: unknown;
|
|
274
|
+
readonly checks: readonly VerificationCheck[];
|
|
275
|
+
readonly results: readonly unknown[];
|
|
276
|
+
readonly traceIds: readonly string[];
|
|
277
|
+
readonly verifiedTraceIds: readonly string[];
|
|
278
|
+
/** Checks that failed. */
|
|
279
|
+
readonly failures: readonly VerificationCheck[];
|
|
280
|
+
/** Checks a human has to decide. They do not make `ok` false. */
|
|
281
|
+
readonly manual: readonly VerificationCheck[];
|
|
282
|
+
readonly ok: boolean;
|
|
283
|
+
/** Turn a failed gate into an exception, for use in CI. */
|
|
284
|
+
raiseForStatus(): void;
|
|
285
|
+
toString(): string;
|
|
286
|
+
}
|
|
287
|
+
export interface VerifyExperimentOptions {
|
|
288
|
+
/** Fail the gate unless exactly this many result rows exist. */
|
|
289
|
+
readonly expectedCaseCount?: number;
|
|
290
|
+
/** How many case traces to read spans for. `null` reads every one. */
|
|
291
|
+
readonly maxTraces?: number | null;
|
|
292
|
+
}
|
|
172
293
|
/**
|
|
173
|
-
* Run
|
|
294
|
+
* Run the documented seven-point evidence gate over a finished experiment.
|
|
295
|
+
*
|
|
296
|
+
* Reads the experiment, its result rows, its trace list and the spans of up to
|
|
297
|
+
* `maxTraces` case traces, and reports whether the evidence chain actually
|
|
298
|
+
* holds. It only reads; nothing is written.
|
|
174
299
|
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
* carry the root trace ID, traces flush before summary, and the experiment is
|
|
178
|
-
* explicitly finalized.
|
|
300
|
+
* Gate 7, the content and masking policy, cannot be decided from the data and
|
|
301
|
+
* is reported as a manual check rather than silently passed.
|
|
179
302
|
*/
|
|
180
|
-
export declare function
|
|
303
|
+
export declare function verifyExperiment(client: unknown, experimentId: string, options?: VerifyExperimentOptions): Promise<ExperimentVerification>;
|
|
181
304
|
export {};
|