langwatch 1.4.0 → 1.6.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 (34) hide show
  1. package/dist/{chunk-DINMABRW.js → chunk-B6GGJBDM.js} +75 -37
  2. package/dist/chunk-B6GGJBDM.js.map +1 -0
  3. package/dist/{chunk-TMIZYFEI.mjs → chunk-IBZ4J3HY.mjs} +2 -2
  4. package/dist/chunk-IBZ4J3HY.mjs.map +1 -0
  5. package/dist/{chunk-H7FNDLEM.mjs → chunk-LZS4B33H.mjs} +65 -27
  6. package/dist/chunk-LZS4B33H.mjs.map +1 -0
  7. package/dist/{chunk-G724AXIB.js → chunk-VBI6IJS4.js} +2 -2
  8. package/dist/chunk-VBI6IJS4.js.map +1 -0
  9. package/dist/cli/bundle.js +694 -432
  10. package/dist/{implementation-WfGxOvyq.d.mts → implementation-D3kg-y8n.d.mts} +1 -1
  11. package/dist/{implementation-bVu7gJFf.d.ts → implementation-D4uH_rQl.d.ts} +1 -1
  12. package/dist/index.d.mts +571 -44
  13. package/dist/index.d.ts +571 -44
  14. package/dist/index.js +860 -101
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +832 -73
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/observability-sdk/index.d.mts +3 -3
  19. package/dist/observability-sdk/index.d.ts +3 -3
  20. package/dist/observability-sdk/index.js +2 -2
  21. package/dist/observability-sdk/index.mjs +1 -1
  22. package/dist/observability-sdk/instrumentation/langchain/index.d.mts +1 -1
  23. package/dist/observability-sdk/instrumentation/langchain/index.d.ts +1 -1
  24. package/dist/observability-sdk/setup/node/index.d.mts +25 -0
  25. package/dist/observability-sdk/setup/node/index.d.ts +25 -0
  26. package/dist/observability-sdk/setup/node/index.js +3 -3
  27. package/dist/observability-sdk/setup/node/index.mjs +2 -2
  28. package/dist/{types-NCH43GuW.d.mts → types-BS1JaoZZ.d.mts} +12419 -8114
  29. package/dist/{types-DB6nS7nW.d.ts → types-DBNWsM_D.d.ts} +12419 -8114
  30. package/package.json +4 -4
  31. package/dist/chunk-DINMABRW.js.map +0 -1
  32. package/dist/chunk-G724AXIB.js.map +0 -1
  33. package/dist/chunk-H7FNDLEM.mjs.map +0 -1
  34. package/dist/chunk-TMIZYFEI.mjs.map +0 -1
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { L as Logger, C as ConsoleLogger, N as NoOpLogger } from './index-D7rKIGrO.mjs';
2
- export { F as FilterableBatchSpanProcessor, L as LangWatchExporter, S as SpanProcessingExcludeRule, g as getLangWatchLogger, a as getLangWatchTracer } from './implementation-WfGxOvyq.mjs';
2
+ export { F as FilterableBatchSpanProcessor, L as LangWatchExporter, S as SpanProcessingExcludeRule, g as getLangWatchLogger, a as getLangWatchTracer } from './implementation-D3kg-y8n.mjs';
3
3
  import { z } from 'zod';
4
- import { p as paths, P as PromptResponse, C as CreatePromptBody, U as UpdatePromptBody, T as TagDefinition, a as CreatedTag, o as operations, b as PromptData, F as FetchPolicy, c as Prompt, L as LangWatchSpan, d as components } from './types-NCH43GuW.mjs';
4
+ import { p as paths, P as PromptResponse, C as CreatePromptBody, U as UpdatePromptBody, T as TagDefinition, a as CreatedTag, o as operations, b as PromptData, F as FetchPolicy, c as Prompt, L as LangWatchSpan, d as components } from './types-BS1JaoZZ.mjs';
5
5
  import openApiCreateClient from 'openapi-fetch';
6
6
  export { l as attributes } from './types-VOZv9LYO.mjs';
7
7
  import { CliHandledErrorReason, CliHandledError } from '@langwatch/langy/cards/handled-error';
@@ -976,6 +976,105 @@ type EvaluateOptions$1 = {
976
976
  /** Metadata for the target */
977
977
  metadata?: TargetMetadata;
978
978
  };
979
+ /**
980
+ * Per-candidate metric the judge can be asked to weigh alongside quality
981
+ *
982
+ * Duration is the one the SDK measures itself. Cost is not on offer: the
983
+ * platform works a target's cost out from its traces after the run, so there
984
+ * is nothing to show the judge at the moment a verdict is asked for.
985
+ */
986
+ type ComparisonMetric = "duration";
987
+ /**
988
+ * Outcome of a comparison
989
+ *
990
+ * - `decided`: the judge picked a winner
991
+ * - `tie`: the judge judged the candidates and found none clearly better
992
+ * - `inconclusive`: the judge judged the candidates and established no winner,
993
+ * which under swap-and-reconcile means its two passes disagreed. A finding
994
+ * about the candidates, and not a tie: a tie is a measurement, this is the
995
+ * absence of one
996
+ * - `skipped`: fewer than two targets had an output, so no judge ran
997
+ * - `error`: the judge could not be reached or failed, so nothing was measured
998
+ * about the candidates at all. Never conflated with `inconclusive`, which
999
+ * says something about them
1000
+ */
1001
+ type ComparisonStatus = "decided" | "tie" | "inconclusive" | "skipped" | "error";
1002
+ /**
1003
+ * The result of comparing a row's targets
1004
+ */
1005
+ type ComparisonVerdict = {
1006
+ /** What the comparison concluded */
1007
+ status: ComparisonStatus;
1008
+ /** The winning target's name. Non-null only when `status` is `decided` */
1009
+ winner: string | null;
1010
+ /**
1011
+ * The judge's reasoning, why the row established no winner, or the failure
1012
+ * when `status` is `error`
1013
+ */
1014
+ reasoning: string | null;
1015
+ /** The target names actually judged, in registration order */
1016
+ candidates: string[];
1017
+ };
1018
+ /**
1019
+ * Options for the compare() method
1020
+ *
1021
+ * Every option below is optional because the judge already has a default for
1022
+ * it. An option left unset is absent from the request, so the judge's own
1023
+ * default applies and there is exactly one place where each default is
1024
+ * written down. The defaults are documented here for reference only, and are
1025
+ * deliberately not restated in code.
1026
+ */
1027
+ type ComparisonOptions = {
1028
+ /**
1029
+ * Row index in the dataset. Also seeds the judge's deterministic candidate
1030
+ * shuffle.
1031
+ *
1032
+ * compare() takes the row the way log() does: inside a run() callback it is
1033
+ * inferred from the row being processed, and outside one it is required.
1034
+ */
1035
+ index?: number;
1036
+ /** Name the verdict is recorded under (default: "comparison") */
1037
+ name?: string;
1038
+ /**
1039
+ * Restrict the comparison to these targets, in place of every target that
1040
+ * recorded an output for the row. Naming a target with no output for the
1041
+ * row is an error rather than a narrower comparison.
1042
+ */
1043
+ targets?: string[];
1044
+ /** The task the candidates were answering, for the judge's framing */
1045
+ input?: string;
1046
+ /**
1047
+ * Reference answer to judge the candidates against. Passing one is what
1048
+ * turns on reference-answer judging; leave it out to have the candidates
1049
+ * compared on their own merits.
1050
+ */
1051
+ golden?: string;
1052
+ /**
1053
+ * Judge prompt template, used verbatim. Placeholders: `{input}`,
1054
+ * `{golden}`, `{candidates}`. Leave it out and the judge picks the shipped
1055
+ * default that fits what the row actually carries.
1056
+ */
1057
+ prompt?: string;
1058
+ /** Judge model (server default: the platform's configured judge model) */
1059
+ model?: string;
1060
+ /** Let the judge answer "tie" when no candidate is better (server default: true) */
1061
+ allowTie?: boolean;
1062
+ /** Shuffle candidate order per row to counter position bias (server default: true) */
1063
+ randomizeOrder?: boolean;
1064
+ /**
1065
+ * Judge each row a second time with the candidate order reversed and report
1066
+ * no verdict when the two disagree (server default: true). Doubles the
1067
+ * judge-call cost per row.
1068
+ */
1069
+ swapAndReconcile?: boolean;
1070
+ /**
1071
+ * Per-candidate metrics to put in front of the judge, so it can prefer a
1072
+ * faster candidate when quality is comparable (server default: none)
1073
+ */
1074
+ includeMetrics?: ComparisonMetric[];
1075
+ /** Judge sampling temperature (server default: 0) */
1076
+ temperature?: number;
1077
+ };
979
1078
  /**
980
1079
  * Context passed to the run() callback
981
1080
  */
@@ -1064,8 +1163,7 @@ declare class Experiment {
1064
1163
  private cumulativeEntries;
1065
1164
  private runUrl;
1066
1165
  private targets;
1067
- private currentTraceId;
1068
- private currentIndex;
1166
+ private capturedOutputs;
1069
1167
  private iterationUsedWithTarget;
1070
1168
  private evaluationUsesTargets;
1071
1169
  private constructor();
@@ -1123,6 +1221,10 @@ declare class Experiment {
1123
1221
  * ```
1124
1222
  */
1125
1223
  log(metric: string, options: LogOptions): void;
1224
+ /**
1225
+ * Queue an evaluation result for the next batch
1226
+ */
1227
+ private pushEvaluation;
1126
1228
  /**
1127
1229
  * Run a built-in evaluator
1128
1230
  *
@@ -1150,6 +1252,76 @@ declare class Experiment {
1150
1252
  * ```
1151
1253
  */
1152
1254
  evaluate(evaluatorSlug: string, options: EvaluateOptions$1): Promise<void>;
1255
+ /**
1256
+ * Call an evaluator and return its raw result
1257
+ */
1258
+ private callEvaluator;
1259
+ /**
1260
+ * Compare a row's targets and pick the best one
1261
+ *
1262
+ * Every target that recorded an output for the row is judged together in a
1263
+ * single call, and the winner comes back named with the target name you
1264
+ * registered. Call it once the row's withTarget() calls have all settled,
1265
+ * which under the usual Promise.all is right after the await.
1266
+ *
1267
+ * The verdict grades no single target, so it is recorded against the row.
1268
+ *
1269
+ * The row is named the way log() names it: inside a run() callback it is
1270
+ * inferred from the row being processed, and outside one it is required.
1271
+ *
1272
+ * A row with fewer than two outputs cannot be compared: it is recorded as
1273
+ * skipped, naming the targets that produced nothing, and the run carries on.
1274
+ * A judge that fails or cannot be reached comes back as an `error` verdict
1275
+ * for the same reason, and stays distinct from `inconclusive`, which is the
1276
+ * judge telling you something about your candidates. Naming a target that
1277
+ * produced no output is a different thing again, and throws, because a
1278
+ * two-way verdict read as the three-way one you asked for is worse than a
1279
+ * failure.
1280
+ *
1281
+ * @param options - How the judge should read the row, and which row when
1282
+ * it cannot be inferred
1283
+ * @returns The verdict, including the candidates it actually saw
1284
+ *
1285
+ * @example
1286
+ * ```typescript
1287
+ * await experiment.run(dataset, async ({ item }) => {
1288
+ * await Promise.all([
1289
+ * experiment.withTarget('gpt-5-mini', () => askGpt(item.question)),
1290
+ * experiment.withTarget('claude-sonnet-5', () => askClaude(item.question)),
1291
+ * ]);
1292
+ *
1293
+ * const verdict = await experiment.compare({ input: item.question });
1294
+ * console.log(verdict.winner);
1295
+ * });
1296
+ * ```
1297
+ */
1298
+ compare(options?: ComparisonOptions): Promise<ComparisonVerdict>;
1299
+ /**
1300
+ * The row a comparison is about
1301
+ *
1302
+ * Inferred from the row being processed, the same way withTarget() and
1303
+ * log() infer theirs, so a comparison inside a run() callback never repeats
1304
+ * an index the SDK already has. It reads that row from the iteration's own
1305
+ * context, which is what keeps a run of many rows at once from handing one
1306
+ * row's comparison the row a neighbour happens to be on.
1307
+ *
1308
+ * What it deliberately does not do is fall back to a row: judging row 0
1309
+ * because no row was named would hand back a confident verdict about
1310
+ * candidates the caller never asked about.
1311
+ */
1312
+ private resolveComparisonRow;
1313
+ /**
1314
+ * Record a comparison verdict against the row
1315
+ *
1316
+ * The verdict the caller is handed is the only input, so the row can never
1317
+ * say one thing while the return value says another.
1318
+ *
1319
+ * Deliberately not routed through log(): a comparison grades no single
1320
+ * target, so it must not pick one up from an ambient withTarget() context,
1321
+ * and it is recorded under the judge's own evaluator id so the results page
1322
+ * can tell it apart from a hand-logged metric.
1323
+ */
1324
+ private recordComparison;
1153
1325
  /**
1154
1326
  * Execute code within a target context with automatic tracing
1155
1327
  *
@@ -1186,6 +1358,15 @@ declare class Experiment {
1186
1358
  */
1187
1359
  withTarget<R>(targetName: string, metadata: TargetMetadata | null, callback: TargetCallback<R>): Promise<TargetResult<R>>;
1188
1360
  withTarget<R>(targetName: string, callback: TargetCallback<R>): Promise<TargetResult<R>>;
1361
+ /**
1362
+ * Keep a target's output for the row so compare() can reach it later
1363
+ *
1364
+ * The batch this output also went into is flushed on a timer and cleared, so
1365
+ * a comparison that read its candidates from there would find them missing
1366
+ * whenever the flush landed first. A target that produced nothing is not
1367
+ * captured at all: it has no output to judge.
1368
+ */
1369
+ private captureTargetOutput;
1189
1370
  /**
1190
1371
  * Register a target for multi-target comparison
1191
1372
  */
@@ -1535,6 +1716,17 @@ declare class TargetMetadataConflictError extends ExperimentError {
1535
1716
  readonly newMetadata: Record<string, unknown>;
1536
1717
  constructor(targetName: string, existingMetadata: Record<string, unknown>, newMetadata: Record<string, unknown>);
1537
1718
  }
1719
+ /**
1720
+ * Thrown when a comparison cannot produce a verdict the caller asked for
1721
+ *
1722
+ * A row that is simply too thin to judge is skipped instead, so this is
1723
+ * reserved for a mismatch between what the caller named and what the run
1724
+ * actually recorded.
1725
+ */
1726
+ declare class ComparisonError extends ExperimentError {
1727
+ readonly missingTargets: string[];
1728
+ constructor(message: string, missingTargets?: string[]);
1729
+ }
1538
1730
  /**
1539
1731
  * Thrown when an evaluator call fails
1540
1732
  */
@@ -1768,6 +1960,21 @@ type SuiteResponse = NonNullable<paths["/api/suites"]["get"]["responses"]["200"]
1768
1960
  type CreateSuiteBody = NonNullable<paths["/api/suites"]["post"]["requestBody"]>["content"]["application/json"];
1769
1961
  type UpdateSuiteBody = NonNullable<paths["/api/suites/{id}"]["patch"]["requestBody"]>["content"]["application/json"];
1770
1962
  type SuiteRunResult = paths["/api/suites/{id}/run"]["post"]["responses"]["200"]["content"]["application/json"];
1963
+ /** Options for `POST /api/suites/{id}/run`. */
1964
+ interface SuiteRunOptions {
1965
+ /**
1966
+ * Key that makes the request safe to retry. Generated per call when omitted,
1967
+ * so two retries of the same command schedule two runs unless the caller
1968
+ * pins one.
1969
+ */
1970
+ idempotencyKey?: string;
1971
+ /**
1972
+ * Constant values applied to every scenario in the run, e.g. a fixture id or
1973
+ * a tenant. A value supplied here overrides the scenario's own default for
1974
+ * that name.
1975
+ */
1976
+ parameters?: Record<string, string | number | boolean>;
1977
+ }
1771
1978
  declare class SuitesApiService {
1772
1979
  private readonly apiClient;
1773
1980
  constructor(config?: Pick<InternalConfig, "langwatchApiClient">);
@@ -1777,7 +1984,12 @@ declare class SuitesApiService {
1777
1984
  create(params: CreateSuiteBody): Promise<SuiteResponse>;
1778
1985
  update(id: string, params: UpdateSuiteBody): Promise<SuiteResponse>;
1779
1986
  duplicate(id: string): Promise<SuiteResponse>;
1780
- run(id: string, idempotencyKey?: string): Promise<SuiteRunResult>;
1987
+ run(id: string, options?: SuiteRunOptions): Promise<SuiteRunResult>;
1988
+ /**
1989
+ * @deprecated Pass `{ idempotencyKey }` instead. The options object is what
1990
+ * carries run parameters, and a positional key cannot reach them.
1991
+ */
1992
+ run(id: string, idempotencyKey: string): Promise<SuiteRunResult>;
1781
1993
  delete(id: string): Promise<{
1782
1994
  id: string;
1783
1995
  archived: boolean;
@@ -2154,10 +2366,19 @@ interface VirtualKey {
2154
2366
  display_prefix: string;
2155
2367
  principal_user_id: string | null;
2156
2368
  /**
2157
- * Where an org- or team-owned key's traces and costs land. Not a
2158
- * scope: it grants no access to the key.
2369
+ * Where this key's traces and costs land. Not a scope: it grants no
2370
+ * access to the key. Decided when the key is written and stored on it,
2371
+ * so editing what the key is scoped to never moves it. Null only on a
2372
+ * key created before this was stored, in an organization that had no
2373
+ * governance project to fall back to.
2159
2374
  */
2160
2375
  trace_project_id: string | null;
2376
+ /**
2377
+ * True when the project in `trace_project_id` has been deleted. The key
2378
+ * goes on sending its traces there, so the data stays whole and
2379
+ * reappears if the project is restored, and traffic is never refused.
2380
+ */
2381
+ trace_project_archived: boolean;
2161
2382
  scopes: VirtualKeyScope[];
2162
2383
  routing_policy_id: string | null;
2163
2384
  routing_mode: VirtualKeyRoutingMode;
@@ -2167,6 +2388,13 @@ interface VirtualKey {
2167
2388
  updated_at: string;
2168
2389
  last_used_at: string | null;
2169
2390
  revoked_at: string | null;
2391
+ /**
2392
+ * When the key stops serving, or null for a key that never expires.
2393
+ * Requests presented after this moment are refused with
2394
+ * `virtual_key_expired`. `status` stays "active" past the date, so read
2395
+ * this field rather than the status to tell an expired key apart.
2396
+ */
2397
+ expires_at: string | null;
2170
2398
  }
2171
2399
  /**
2172
2400
  * The cap a key carries on itself, created atomically with the key. Only
@@ -2192,6 +2420,11 @@ interface CreateVirtualKeyInput {
2192
2420
  trace_project_id?: string | null;
2193
2421
  routing_policy_id?: string | null;
2194
2422
  routing_mode?: VirtualKeyRoutingMode;
2423
+ /**
2424
+ * When the key stops serving, as an ISO 8601 instant. Omit it and the key
2425
+ * never expires. A date already in the past is refused.
2426
+ */
2427
+ expires_at?: string;
2195
2428
  /** Optional cap created atomically with the key. */
2196
2429
  budget?: VirtualKeyBudgetInput | null;
2197
2430
  config?: Record<string, unknown>;
@@ -2215,6 +2448,12 @@ interface UpdateVirtualKeyInput {
2215
2448
  trace_project_id?: string | null;
2216
2449
  routing_policy_id?: string | null;
2217
2450
  routing_mode?: VirtualKeyRoutingMode;
2451
+ /**
2452
+ * Undefined leaves the expiration alone; null clears it, so the key never
2453
+ * expires; an ISO 8601 instant moves it. An expired key accepts this edit
2454
+ * like any other, which is how it goes back into service.
2455
+ */
2456
+ expires_at?: string | null;
2218
2457
  /** Undefined leaves the cap alone; a value upserts it; null archives it. */
2219
2458
  budget?: VirtualKeyBudgetInput | null;
2220
2459
  config?: Record<string, unknown>;
@@ -2638,7 +2877,16 @@ interface SpendEvent {
2638
2877
  };
2639
2878
  }
2640
2879
  interface SpendSummaryRow {
2880
+ /**
2881
+ * The FIRST grouping dimension's value. Unchanged from when a rollup could
2882
+ * only be grouped one way, so existing code keeps reading what it did. With
2883
+ * two dimensions, two rows can share a key: read `group` to tell them apart.
2884
+ */
2641
2885
  key: string;
2886
+ /** Every grouping dimension by name, e.g. `{ model: "gpt-5-mini" }`. */
2887
+ group: Record<string, string>;
2888
+ /** Start of the time bucket in the requested zone, null when unbucketed. */
2889
+ bucket_start: string | null;
2642
2890
  /** Priced outcomes (confirmed and failed). */
2643
2891
  event_count: number;
2644
2892
  /** Unpriced settled requests, counted separately: never in cost sums. */
@@ -2662,6 +2910,75 @@ interface SpendSummaryRow {
2662
2910
  * `success` and `error` are the coarse outcome pair over those.
2663
2911
  */
2664
2912
  type SpendEventStatus = "success" | "error" | "admitted" | "confirmed" | "failed" | "settled";
2913
+ /**
2914
+ * The states a ROLLUP can be filtered by. A rollup sums the cost of requests
2915
+ * past admission, so `admitted` is refused there rather than answered with a
2916
+ * zero; list the events to see those. Derived by exclusion so the two stay one
2917
+ * vocabulary.
2918
+ */
2919
+ type SpendSummaryStatus = Exclude<SpendEventStatus, "admitted">;
2920
+ /** A dimension a rollup can be grouped by. */
2921
+ type SpendGroupBy = "virtual_key" | "end_user" | "project" | "model" | "provider" | "principal" | "request_type";
2922
+ /**
2923
+ * The filters BOTH spend reads accept. A reconciliation checksums the rollups
2924
+ * and diffs the events when a checksum disagrees, so the two take the same
2925
+ * vocabulary and a divergence can be walked on exactly the narrowing that
2926
+ * produced it.
2927
+ *
2928
+ * Every field takes one value or many; many means "any of these". Naming two
2929
+ * different fields narrows.
2930
+ */
2931
+ interface SpendFilterOptions {
2932
+ projectId?: string | string[];
2933
+ /** Resolved to the projects the team owns. A team with none matches nothing. */
2934
+ teamId?: string | string[];
2935
+ /** Your own id for a virtual key. One nobody minted matches nothing. */
2936
+ externalId?: string | string[];
2937
+ virtualKeyId?: string | string[];
2938
+ endUserId?: string | string[];
2939
+ principalUserId?: string | string[];
2940
+ model?: string | string[];
2941
+ providerKey?: string | string[];
2942
+ requestType?: string | string[];
2943
+ label?: string | string[];
2944
+ /**
2945
+ * Your own request metadata, e.g. `{ customer_tier: "gold" }`. Several
2946
+ * values for one key widen it; several keys narrow.
2947
+ */
2948
+ metadata?: Record<string, string | string[]>;
2949
+ status?: SpendEventStatus;
2950
+ }
2951
+ /**
2952
+ * What a rollup is grouped by, and over what window.
2953
+ *
2954
+ * Grouping by `model` or `provider`, or into time buckets, is REFUSED with
2955
+ * `gateway_spend_group_by_unstable` over a window recent enough that outcomes
2956
+ * can still arrive: until a request settles, the model and provider recorded
2957
+ * against it are the ones that were asked for, and they are replaced by the
2958
+ * ones that actually served it. A page walk over a group that can move counts
2959
+ * some requests twice and misses others.
2960
+ *
2961
+ * Reconcile closed periods and this never fires. For a live view where an
2962
+ * approximate shape is enough, send `allowUnstable`.
2963
+ */
2964
+ interface SpendSummariesOptions extends Omit<SpendFilterOptions, "status"> {
2965
+ /**
2966
+ * One lifecycle status, minus `admitted`: a rollup sums the cost of requests
2967
+ * past admission, and an admitted request has none yet. List the events for
2968
+ * those.
2969
+ */
2970
+ status?: SpendSummaryStatus;
2971
+ /** One or two dimensions. Two rows can share `key`; read `group`. */
2972
+ groupBy: SpendGroupBy | SpendGroupBy[];
2973
+ from: number;
2974
+ to: number;
2975
+ /** Adds a time column. Counts as movable, so the same refusal applies. */
2976
+ bucket?: "none" | "hour" | "day";
2977
+ /** IANA zone the bucket boundary falls on, e.g. "Europe/Amsterdam". */
2978
+ timezone?: string;
2979
+ /** Serve a movable grouping anyway, accepting an inexact walk. */
2980
+ allowUnstable?: boolean;
2981
+ }
2665
2982
  interface SpendSummariesPage {
2666
2983
  data: SpendSummaryRow[];
2667
2984
  /**
@@ -2764,17 +3081,12 @@ declare class SpendEventsApiService {
2764
3081
  * stops on the first page silently under-counts the window, so read every
2765
3082
  * page or stream them with `iterate()`.
2766
3083
  */
2767
- listPage(options: {
3084
+ listPage(options: SpendFilterOptions & {
2768
3085
  /** Required: the pull is a ranged read by contract. */
2769
3086
  from: number;
2770
3087
  to: number;
2771
3088
  cursor?: string;
2772
3089
  limit?: number;
2773
- virtualKeyId?: string;
2774
- endUserId?: string;
2775
- projectId?: string;
2776
- model?: string;
2777
- status?: SpendEventStatus;
2778
3090
  }): Promise<SpendEventsPage>;
2779
3091
  /**
2780
3092
  * Every spend event in the window, one row at a time, fetching each page
@@ -2785,17 +3097,12 @@ declare class SpendEventsApiService {
2785
3097
  * collect it into an array. Raises rather than looping forever on a cursor
2786
3098
  * chain that never ends.
2787
3099
  */
2788
- iterate(options: {
3100
+ iterate(options: SpendFilterOptions & {
2789
3101
  /** Required: the pull is a ranged read by contract. */
2790
3102
  from: number;
2791
3103
  to: number;
2792
3104
  cursor?: string;
2793
3105
  limit?: number;
2794
- virtualKeyId?: string;
2795
- endUserId?: string;
2796
- projectId?: string;
2797
- model?: string;
2798
- status?: SpendEventStatus;
2799
3106
  }): AsyncGenerator<SpendEvent>;
2800
3107
  /**
2801
3108
  * ONE page of per-key spend rollups for a window, paged by group key
@@ -2806,13 +3113,7 @@ declare class SpendEventsApiService {
2806
3113
  * reconciler that reads only the first page silently under-counts every
2807
3114
  * tenant past the limit.
2808
3115
  */
2809
- summariesPage(options: {
2810
- groupBy: "virtual_key" | "end_user";
2811
- from: number;
2812
- to: number;
2813
- projectId?: string;
2814
- /** Narrow the rollup to one key, exact match. */
2815
- virtualKeyId?: string;
3116
+ summariesPage(options: SpendSummariesOptions & {
2816
3117
  cursor?: string;
2817
3118
  limit?: number;
2818
3119
  }): Promise<SpendSummariesPage>;
@@ -2824,13 +3125,7 @@ declare class SpendEventsApiService {
2824
3125
  * covers, so there is deliberately no eager whole-set read here either: a
2825
3126
  * checksum that quietly covers part of the window is worse than none.
2826
3127
  */
2827
- iterSummaries(options: {
2828
- groupBy: "virtual_key" | "end_user";
2829
- from: number;
2830
- to: number;
2831
- projectId?: string;
2832
- /** Narrow the rollup to one key, exact match. */
2833
- virtualKeyId?: string;
3128
+ iterSummaries(options: SpendSummariesOptions & {
2834
3129
  cursor?: string;
2835
3130
  limit?: number;
2836
3131
  }): AsyncGenerator<SpendSummaryRow>;
@@ -2854,9 +3149,43 @@ declare class SpendEventsApiService {
2854
3149
  }): Promise<EndUserSpend>;
2855
3150
  }
2856
3151
 
3152
+ /** Where an endpoint delivers. */
3153
+ type WebhookDestinationKind = "http" | "sqs";
3154
+ /** The queue an `sqs` endpoint delivers to, as any read surface sees it: the
3155
+ * secret half of a static key pair is never returned. */
3156
+ interface WebhookSqsDestination {
3157
+ queue_url: string;
3158
+ /** Read off the queue URL, never configured beside it. */
3159
+ region: string;
3160
+ /** Whose queue it is. */
3161
+ account_id: string;
3162
+ queue_name: string;
3163
+ credential_mode: "assume_role" | "static" | "ambient";
3164
+ role_arn: string | null;
3165
+ /** Generated at save time, to paste into the role's trust policy. */
3166
+ external_id: string | null;
3167
+ access_key_id: string | null;
3168
+ }
3169
+ /** The queue half of a create or update body. */
3170
+ interface WebhookSqsDestinationInput {
3171
+ queue_url: string;
3172
+ /** The role to assume, with an external id we generate. The recommended
3173
+ * way to grant access: nothing long-lived is stored, and the customer
3174
+ * revokes by editing their own trust policy. */
3175
+ role_arn?: string;
3176
+ external_id?: string;
3177
+ /** A static key pair instead. The secret is stored encrypted and never
3178
+ * returned. */
3179
+ access_key_id?: string;
3180
+ secret_access_key?: string;
3181
+ }
2857
3182
  interface WebhookEndpointSummary {
2858
3183
  id: string;
2859
- url: string;
3184
+ destination_kind: WebhookDestinationKind;
3185
+ /** The receiver URL on an `http` endpoint, null on every other kind. */
3186
+ url: string | null;
3187
+ /** The queue on an `sqs` endpoint, null on every other kind. */
3188
+ sqs: WebhookSqsDestination | null;
2860
3189
  max_batch_size: number;
2861
3190
  max_batch_delay_ms: number;
2862
3191
  max_in_flight: number;
@@ -2874,9 +3203,8 @@ interface WebhookEndpointWithSecret extends WebhookEndpointSummary {
2874
3203
  /** Present only on create and roll-secret responses; never again. */
2875
3204
  secret: string;
2876
3205
  }
2877
- /** The POST body, exactly as the wire takes it. */
2878
- interface CreateWebhookEndpointInput {
2879
- url: string;
3206
+ /** Everything a create body carries that is not the destination. */
3207
+ interface CreateWebhookEndpointBase {
2880
3208
  enabled_events: string[];
2881
3209
  /** Envelopes per delivery. The receiver always gets an array. */
2882
3210
  max_batch_size?: number;
@@ -2885,9 +3213,39 @@ interface CreateWebhookEndpointInput {
2885
3213
  /** Concurrent in-flight deliveries to this endpoint. */
2886
3214
  max_in_flight?: number;
2887
3215
  }
3216
+ /**
3217
+ * The POST body, exactly as the wire takes it.
3218
+ *
3219
+ * A destination is one kind and one address, so the two are a union rather
3220
+ * than independent optional fields: the type refuses `{destination_kind:
3221
+ * "sqs"}` with no queue, and `{url, sqs}` together, which is what the server
3222
+ * refuses too. `destination_kind` is optional only on the http branch, where
3223
+ * absent has always meant http.
3224
+ */
3225
+ type WebhookDestinationInput = {
3226
+ destination_kind?: "http";
3227
+ url: string;
3228
+ sqs?: never;
3229
+ } | {
3230
+ destination_kind: "sqs";
3231
+ sqs: WebhookSqsDestinationInput;
3232
+ url?: never;
3233
+ };
3234
+ type CreateWebhookEndpointInput = CreateWebhookEndpointBase & WebhookDestinationInput;
2888
3235
  /** The PATCH body, exactly as the wire takes it. Omitted fields are left alone. */
2889
3236
  interface UpdateWebhookEndpointInput {
2890
3237
  url?: string;
3238
+ /** Only the queue's own fields; the destination kind cannot change, because
3239
+ * batches already planned against the old transport are in flight. Create
3240
+ * a new endpoint and archive this one once it has drained. A credential
3241
+ * field sent as null is CLEARED; omitted keeps what is stored. */
3242
+ sqs?: Partial<{
3243
+ queue_url: string;
3244
+ role_arn: string | null;
3245
+ external_id: string | null;
3246
+ access_key_id: string | null;
3247
+ secret_access_key: string | null;
3248
+ }>;
2891
3249
  enabled_events?: string[];
2892
3250
  status?: "active" | "disabled";
2893
3251
  max_batch_size?: number;
@@ -3035,10 +3393,11 @@ declare class WebhooksApiService {
3035
3393
  * that missed a delivery reads the window back from here. Walk the whole
3036
3394
  * window with `iterEvents()`.
3037
3395
  */
3038
- eventsPage(options?: {
3396
+ eventsPage(options: {
3039
3397
  type?: string;
3040
- from?: number;
3041
- to?: number;
3398
+ /** Required: the log is a ranged read by contract. Epoch milliseconds. */
3399
+ from: number;
3400
+ to: number;
3042
3401
  cursor?: string;
3043
3402
  limit?: number;
3044
3403
  }): Promise<EmittedEventsPage>;
@@ -3046,10 +3405,11 @@ declare class WebhooksApiService {
3046
3405
  * Every emitted event matching the filter, one at a time, fetching each
3047
3406
  * page only when the consumer reaches it.
3048
3407
  */
3049
- iterEvents(options?: {
3408
+ iterEvents(options: {
3050
3409
  type?: string;
3051
- from?: number;
3052
- to?: number;
3410
+ /** Required: the log is a ranged read by contract. Epoch milliseconds. */
3411
+ from: number;
3412
+ to: number;
3053
3413
  cursor?: string;
3054
3414
  limit?: number;
3055
3415
  }): AsyncGenerator<EmittedEvent>;
@@ -3062,6 +3422,158 @@ declare class WebhooksApiService {
3062
3422
  getEvent(id: string): Promise<EmittedEvent>;
3063
3423
  }
3064
3424
 
3425
+ /**
3426
+ * The vocabulary the management REST families share on the wire.
3427
+ *
3428
+ * A role binding grants a scoped role, and the same three words appear on
3429
+ * roles, role bindings, groups, teams and API keys. Declared once here so the
3430
+ * CLI's flag parsers validate against one list rather than five copies that
3431
+ * can disagree with the platform.
3432
+ */
3433
+ /** The role a binding grants at its scope. `CUSTOM` defers to a custom role. */
3434
+ declare const MANAGEMENT_ROLES: readonly ["ADMIN", "MEMBER", "VIEWER", "CUSTOM"];
3435
+ type ManagementRole = (typeof MANAGEMENT_ROLES)[number];
3436
+
3437
+ interface Team {
3438
+ id: string;
3439
+ name: string;
3440
+ slug: string;
3441
+ organizationId: string;
3442
+ createdAt: string;
3443
+ updatedAt: string;
3444
+ }
3445
+ interface TeamPagination {
3446
+ page: number;
3447
+ limit: number;
3448
+ total: number;
3449
+ }
3450
+ interface ListTeamsResponse {
3451
+ data: Team[];
3452
+ pagination: TeamPagination;
3453
+ }
3454
+ interface ArchivedTeam {
3455
+ id: string;
3456
+ name: string;
3457
+ archivedAt: string | null;
3458
+ }
3459
+ interface TeamMember {
3460
+ userId: string | null;
3461
+ name: string | null;
3462
+ email: string | null;
3463
+ role: ManagementRole;
3464
+ }
3465
+ declare class TeamsApiError extends Error {
3466
+ readonly operation: string;
3467
+ readonly originalError?: unknown | undefined;
3468
+ constructor(message: string, operation: string, originalError?: unknown | undefined);
3469
+ }
3470
+ declare class TeamsApiService {
3471
+ #private;
3472
+ constructor(config?: {
3473
+ endpoint?: string;
3474
+ apiKey?: string;
3475
+ });
3476
+ list(options?: {
3477
+ page?: number;
3478
+ limit?: number;
3479
+ }): Promise<ListTeamsResponse>;
3480
+ get(id: string): Promise<Team>;
3481
+ create(input: {
3482
+ name: string;
3483
+ }): Promise<Team>;
3484
+ update({ id, input, }: {
3485
+ id: string;
3486
+ input: {
3487
+ name?: string;
3488
+ };
3489
+ }): Promise<Team>;
3490
+ archive(id: string): Promise<ArchivedTeam>;
3491
+ listMembers(teamId: string): Promise<{
3492
+ data: TeamMember[];
3493
+ }>;
3494
+ addMember({ teamId, input, }: {
3495
+ teamId: string;
3496
+ input: {
3497
+ userId: string;
3498
+ role?: ManagementRole;
3499
+ };
3500
+ }): Promise<{
3501
+ success: boolean;
3502
+ }>;
3503
+ removeMember({ teamId, userId, }: {
3504
+ teamId: string;
3505
+ userId: string;
3506
+ }): Promise<{
3507
+ success: boolean;
3508
+ }>;
3509
+ }
3510
+
3511
+ interface Project {
3512
+ id: string;
3513
+ name: string;
3514
+ slug: string;
3515
+ language: string;
3516
+ framework: string;
3517
+ teamId: string;
3518
+ piiRedactionLevel: string;
3519
+ createdAt: string;
3520
+ updatedAt: string;
3521
+ }
3522
+ interface CreateProjectInput {
3523
+ name: string;
3524
+ language: string;
3525
+ framework: string;
3526
+ teamId?: string;
3527
+ newTeamName?: string;
3528
+ }
3529
+ interface UpdateProjectInput {
3530
+ name?: string;
3531
+ language?: string;
3532
+ framework?: string;
3533
+ piiRedactionLevel?: "STRICT" | "ESSENTIAL" | "DISABLED";
3534
+ }
3535
+ interface ProjectWithServiceKey extends Project {
3536
+ serviceApiKey: string;
3537
+ serviceApiKeyId: string;
3538
+ }
3539
+ interface PaginatedProjects {
3540
+ data: Project[];
3541
+ pagination: {
3542
+ page: number;
3543
+ limit: number;
3544
+ total: number;
3545
+ totalPages: number;
3546
+ };
3547
+ }
3548
+ interface ArchivedProject {
3549
+ id: string;
3550
+ name: string;
3551
+ archivedAt: string;
3552
+ }
3553
+ declare class ProjectsApiError extends Error {
3554
+ readonly operation: string;
3555
+ readonly originalError?: unknown | undefined;
3556
+ constructor(message: string, operation: string, originalError?: unknown | undefined);
3557
+ }
3558
+ declare class ProjectsApiService {
3559
+ private readonly endpoint;
3560
+ private readonly apiKey;
3561
+ constructor(config?: {
3562
+ endpoint?: string;
3563
+ apiKey?: string;
3564
+ });
3565
+ private headers;
3566
+ private request;
3567
+ list(options?: {
3568
+ page?: number;
3569
+ limit?: number;
3570
+ }): Promise<PaginatedProjects>;
3571
+ get(id: string): Promise<Project>;
3572
+ create(input: CreateProjectInput): Promise<ProjectWithServiceKey>;
3573
+ update(id: string, input: UpdateProjectInput): Promise<Project>;
3574
+ archive(id: string): Promise<ArchivedProject>;
3575
+ }
3576
+
3065
3577
  interface GetTraceParams {
3066
3578
  includeSpans?: boolean;
3067
3579
  }
@@ -3139,6 +3651,21 @@ declare class LangWatch {
3139
3651
  readonly webhooks: WebhooksApiService;
3140
3652
  constructor(options?: LangWatchConstructorOptions);
3141
3653
  get apiClient(): LangwatchApiClient;
3654
+ /**
3655
+ * Teams, which group projects and the members who can reach them. These
3656
+ * routes want an organization API key.
3657
+ *
3658
+ * Built on first use rather than in the constructor: the management
3659
+ * families resolve their credential when constructed and refuse an empty
3660
+ * one, so building this eagerly would make `new LangWatch()` throw for
3661
+ * every caller that never touches a team.
3662
+ */
3663
+ get teams(): TeamsApiService;
3664
+ /**
3665
+ * Projects, including provisioning one with its own service API key. These
3666
+ * routes want an organization API key.
3667
+ */
3668
+ get projects(): ProjectsApiService;
3142
3669
  }
3143
3670
 
3144
3671
  /**
@@ -3376,4 +3903,4 @@ declare const logger: {
3376
3903
  NoOpLogger: typeof NoOpLogger;
3377
3904
  };
3378
3905
 
3379
- export { type BatchCreateRecordsResponse, type BudgetOnBreach, type BudgetScopeKind, type BudgetWindow, type CreateDatasetOptions, type CreateEvaluatorBody, type CreateFromUploadResponse, type CreateGatewayBudgetInput, type CreateGatewayBudgetScope, type CreateVirtualKeyInput, type CreateWebhookEndpointInput, type Dataset, DatasetApiError, type DatasetColumnType, type DatasetEntry, DatasetError, type DatasetListItem, type DatasetMetadata, DatasetNotFoundError, DatasetPlanLimitError, type DatasetRecordResponse, DatasetValidationError, DatasetsFacade, type DeleteRecordsResponse, type EmittedEvent, type EmittedEventsPage, type EndUserCap, type EndUserSpend, type EvaluateOptions, type EvaluationCost, EvaluationError, type EvaluationResult, type EvaluationStatus, EvaluationsApiError, EvaluationsFacade, EvaluatorCallError, EvaluatorError, type EvaluatorField, EvaluatorNotFoundError, type EvaluatorResponse, EvaluatorsApiError, EvaluatorsApiService, Experiment, ExperimentApiError, ExperimentError, type EvaluateOptions$1 as ExperimentEvaluateOptions, type EvaluationResult$1 as ExperimentEvaluationResult, type EvaluationStatus$1 as ExperimentEvaluationStatus, ExperimentInitError, type ExperimentInitOptions, type ExperimentRowResult, type ExperimentRunWithResults, ExperimentsFacade, FetchPolicy, type GatewayBudget, type GatewayBudgetPage, GatewayBudgetsApiError, GatewayBudgetsApiService, type GetDatasetOptions, type GetPromptOptions, IDEMPOTENCY_KEY_HEADER, IDEMPOTENT_REPLAY_HEADER, type IdempotentCreateOptions, LangWatch, LangWatchApiError, LangWatchHandledError, type ListDatasetsApiResponse, type ListDatasetsOptions, type ListRecordsApiResponse, type ListRecordsOptions, type LogOptions, type MutationOptions, type PaginatedResponse, type Pagination, type RunCallback, type RunContext, type RunOptions, type RunWithResultsOptions, type SpendEvent, type SpendEventStatus, SpendEventsApiError, SpendEventsApiService, type SpendEventsPage, type SpendReplayResult, type SpendSummariesPage, type SpendSummaryRow, type TargetInfo, type TargetMetadata, TargetMetadataConflictError, type TargetType, type UpdateDatasetOptions, type UpdateGatewayBudgetInput, type UpdateVirtualKeyInput, type UpdateWebhookEndpointInput, type UploadResponse, type VerifyWebhookSignatureOptions, type VirtualKey, type VirtualKeyBudgetInput, type VirtualKeyPage, type VirtualKeyRoutingMode, type VirtualKeyScope, type VirtualKeyScopeType, type VirtualKeySpendSummary, type VirtualKeyWithSecret, VirtualKeysApiError, VirtualKeysApiService, WEBHOOK_DELIVERY_ID_HEADER, WEBHOOK_EVENT_ID_HEADER, WEBHOOK_SIGNATURE_DEFAULT_TOLERANCE_SECONDS, WEBHOOK_SIGNATURE_HEADER, type WebhookDeliveryPage, type WebhookDeliveryRecord, type WebhookEndpointHealth, type WebhookEndpointSummary, type WebhookEndpointWithSecret, type WebhookEventType, type WebhookSignatureFailureCode, WebhookSignatureVerificationError, type WebhookTestResult, WebhooksApiError, WebhooksApiService, isLangWatchHandledError, logger, verifyWebhookSignature };
3906
+ export { type ArchivedProject, type ArchivedTeam, type BatchCreateRecordsResponse, type BudgetOnBreach, type BudgetScopeKind, type BudgetWindow, ComparisonError, type ComparisonMetric, type ComparisonOptions, type ComparisonStatus, type ComparisonVerdict, type CreateDatasetOptions, type CreateEvaluatorBody, type CreateFromUploadResponse, type CreateGatewayBudgetInput, type CreateGatewayBudgetScope, type CreateProjectInput, type CreateVirtualKeyInput, type CreateWebhookEndpointInput, type Dataset, DatasetApiError, type DatasetColumnType, type DatasetEntry, DatasetError, type DatasetListItem, type DatasetMetadata, DatasetNotFoundError, DatasetPlanLimitError, type DatasetRecordResponse, DatasetValidationError, DatasetsFacade, type DeleteRecordsResponse, type EmittedEvent, type EmittedEventsPage, type EndUserCap, type EndUserSpend, type EvaluateOptions, type EvaluationCost, EvaluationError, type EvaluationResult, type EvaluationStatus, EvaluationsApiError, EvaluationsFacade, EvaluatorCallError, EvaluatorError, type EvaluatorField, EvaluatorNotFoundError, type EvaluatorResponse, EvaluatorsApiError, EvaluatorsApiService, Experiment, ExperimentApiError, ExperimentError, type EvaluateOptions$1 as ExperimentEvaluateOptions, type EvaluationResult$1 as ExperimentEvaluationResult, type EvaluationStatus$1 as ExperimentEvaluationStatus, ExperimentInitError, type ExperimentInitOptions, type ExperimentRowResult, type ExperimentRunWithResults, ExperimentsFacade, FetchPolicy, type GatewayBudget, type GatewayBudgetPage, GatewayBudgetsApiError, GatewayBudgetsApiService, type GetDatasetOptions, type GetPromptOptions, IDEMPOTENCY_KEY_HEADER, IDEMPOTENT_REPLAY_HEADER, type IdempotentCreateOptions, LangWatch, LangWatchApiError, LangWatchHandledError, type ListDatasetsApiResponse, type ListDatasetsOptions, type ListRecordsApiResponse, type ListRecordsOptions, type ListTeamsResponse, type LogOptions, type MutationOptions, type PaginatedProjects, type PaginatedResponse, type Pagination, type Project, type ProjectWithServiceKey, ProjectsApiError, ProjectsApiService, type RunCallback, type RunContext, type RunOptions, type RunWithResultsOptions, type SpendEvent, type SpendEventStatus, SpendEventsApiError, SpendEventsApiService, type SpendEventsPage, type SpendFilterOptions, type SpendGroupBy, type SpendReplayResult, type SpendSummariesOptions, type SpendSummariesPage, type SpendSummaryRow, type SpendSummaryStatus, type TargetInfo, type TargetMetadata, TargetMetadataConflictError, type TargetType, type Team, type TeamMember, type TeamPagination, TeamsApiError, TeamsApiService, type UpdateDatasetOptions, type UpdateGatewayBudgetInput, type UpdateProjectInput, type UpdateVirtualKeyInput, type UpdateWebhookEndpointInput, type UploadResponse, type VerifyWebhookSignatureOptions, type VirtualKey, type VirtualKeyBudgetInput, type VirtualKeyPage, type VirtualKeyRoutingMode, type VirtualKeyScope, type VirtualKeyScopeType, type VirtualKeySpendSummary, type VirtualKeyWithSecret, VirtualKeysApiError, VirtualKeysApiService, WEBHOOK_DELIVERY_ID_HEADER, WEBHOOK_EVENT_ID_HEADER, WEBHOOK_SIGNATURE_DEFAULT_TOLERANCE_SECONDS, WEBHOOK_SIGNATURE_HEADER, type WebhookDeliveryPage, type WebhookDeliveryRecord, type WebhookEndpointHealth, type WebhookEndpointSummary, type WebhookEndpointWithSecret, type WebhookEventType, type WebhookSignatureFailureCode, WebhookSignatureVerificationError, type WebhookTestResult, WebhooksApiError, WebhooksApiService, isLangWatchHandledError, logger, verifyWebhookSignature };