langwatch 1.3.0 → 1.5.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-GOGMRTV5.js → chunk-5ERLGHP2.js} +2 -2
  2. package/dist/chunk-5ERLGHP2.js.map +1 -0
  3. package/dist/{chunk-SOODMKTN.mjs → chunk-QZRTEEGV.mjs} +65 -27
  4. package/dist/chunk-QZRTEEGV.mjs.map +1 -0
  5. package/dist/{chunk-KUJACQJ2.js → chunk-XIN5LXHQ.js} +75 -37
  6. package/dist/chunk-XIN5LXHQ.js.map +1 -0
  7. package/dist/{chunk-7SZIBH2A.mjs → chunk-Y6XAM26B.mjs} +2 -2
  8. package/dist/chunk-Y6XAM26B.mjs.map +1 -0
  9. package/dist/cli/bundle.js +547 -408
  10. package/dist/{implementation-Cdrj3mBw.d.ts → implementation-CvPr4t60.d.ts} +1 -1
  11. package/dist/{implementation-Bd2Z0kjH.d.mts → implementation-Ro3LpjAt.d.mts} +1 -1
  12. package/dist/index.d.mts +568 -44
  13. package/dist/index.d.ts +568 -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-DzSFwVBw.d.ts → types-CHIvGRuv.d.ts} +12173 -7892
  29. package/dist/{types-ruthADbq.d.mts → types-VoDc_AXK.d.mts} +12173 -7892
  30. package/package.json +5 -2
  31. package/dist/chunk-7SZIBH2A.mjs.map +0 -1
  32. package/dist/chunk-GOGMRTV5.js.map +0 -1
  33. package/dist/chunk-KUJACQJ2.js.map +0 -1
  34. package/dist/chunk-SOODMKTN.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-Bd2Z0kjH.mjs';
2
+ export { F as FilterableBatchSpanProcessor, L as LangWatchExporter, S as SpanProcessingExcludeRule, g as getLangWatchLogger, a as getLangWatchTracer } from './implementation-Ro3LpjAt.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-ruthADbq.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-VoDc_AXK.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;
@@ -2638,7 +2859,16 @@ interface SpendEvent {
2638
2859
  };
2639
2860
  }
2640
2861
  interface SpendSummaryRow {
2862
+ /**
2863
+ * The FIRST grouping dimension's value. Unchanged from when a rollup could
2864
+ * only be grouped one way, so existing code keeps reading what it did. With
2865
+ * two dimensions, two rows can share a key: read `group` to tell them apart.
2866
+ */
2641
2867
  key: string;
2868
+ /** Every grouping dimension by name, e.g. `{ model: "gpt-5-mini" }`. */
2869
+ group: Record<string, string>;
2870
+ /** Start of the time bucket in the requested zone, null when unbucketed. */
2871
+ bucket_start: string | null;
2642
2872
  /** Priced outcomes (confirmed and failed). */
2643
2873
  event_count: number;
2644
2874
  /** Unpriced settled requests, counted separately: never in cost sums. */
@@ -2662,6 +2892,75 @@ interface SpendSummaryRow {
2662
2892
  * `success` and `error` are the coarse outcome pair over those.
2663
2893
  */
2664
2894
  type SpendEventStatus = "success" | "error" | "admitted" | "confirmed" | "failed" | "settled";
2895
+ /**
2896
+ * The states a ROLLUP can be filtered by. A rollup sums the cost of requests
2897
+ * past admission, so `admitted` is refused there rather than answered with a
2898
+ * zero; list the events to see those. Derived by exclusion so the two stay one
2899
+ * vocabulary.
2900
+ */
2901
+ type SpendSummaryStatus = Exclude<SpendEventStatus, "admitted">;
2902
+ /** A dimension a rollup can be grouped by. */
2903
+ type SpendGroupBy = "virtual_key" | "end_user" | "project" | "model" | "provider" | "principal" | "request_type";
2904
+ /**
2905
+ * The filters BOTH spend reads accept. A reconciliation checksums the rollups
2906
+ * and diffs the events when a checksum disagrees, so the two take the same
2907
+ * vocabulary and a divergence can be walked on exactly the narrowing that
2908
+ * produced it.
2909
+ *
2910
+ * Every field takes one value or many; many means "any of these". Naming two
2911
+ * different fields narrows.
2912
+ */
2913
+ interface SpendFilterOptions {
2914
+ projectId?: string | string[];
2915
+ /** Resolved to the projects the team owns. A team with none matches nothing. */
2916
+ teamId?: string | string[];
2917
+ /** Your own id for a virtual key. One nobody minted matches nothing. */
2918
+ externalId?: string | string[];
2919
+ virtualKeyId?: string | string[];
2920
+ endUserId?: string | string[];
2921
+ principalUserId?: string | string[];
2922
+ model?: string | string[];
2923
+ providerKey?: string | string[];
2924
+ requestType?: string | string[];
2925
+ label?: string | string[];
2926
+ /**
2927
+ * Your own request metadata, e.g. `{ customer_tier: "gold" }`. Several
2928
+ * values for one key widen it; several keys narrow.
2929
+ */
2930
+ metadata?: Record<string, string | string[]>;
2931
+ status?: SpendEventStatus;
2932
+ }
2933
+ /**
2934
+ * What a rollup is grouped by, and over what window.
2935
+ *
2936
+ * Grouping by `model` or `provider`, or into time buckets, is REFUSED with
2937
+ * `gateway_spend_group_by_unstable` over a window recent enough that outcomes
2938
+ * can still arrive: until a request settles, the model and provider recorded
2939
+ * against it are the ones that were asked for, and they are replaced by the
2940
+ * ones that actually served it. A page walk over a group that can move counts
2941
+ * some requests twice and misses others.
2942
+ *
2943
+ * Reconcile closed periods and this never fires. For a live view where an
2944
+ * approximate shape is enough, send `allowUnstable`.
2945
+ */
2946
+ interface SpendSummariesOptions extends Omit<SpendFilterOptions, "status"> {
2947
+ /**
2948
+ * One lifecycle status, minus `admitted`: a rollup sums the cost of requests
2949
+ * past admission, and an admitted request has none yet. List the events for
2950
+ * those.
2951
+ */
2952
+ status?: SpendSummaryStatus;
2953
+ /** One or two dimensions. Two rows can share `key`; read `group`. */
2954
+ groupBy: SpendGroupBy | SpendGroupBy[];
2955
+ from: number;
2956
+ to: number;
2957
+ /** Adds a time column. Counts as movable, so the same refusal applies. */
2958
+ bucket?: "none" | "hour" | "day";
2959
+ /** IANA zone the bucket boundary falls on, e.g. "Europe/Amsterdam". */
2960
+ timezone?: string;
2961
+ /** Serve a movable grouping anyway, accepting an inexact walk. */
2962
+ allowUnstable?: boolean;
2963
+ }
2665
2964
  interface SpendSummariesPage {
2666
2965
  data: SpendSummaryRow[];
2667
2966
  /**
@@ -2734,6 +3033,14 @@ declare class SpendEventsApiError extends Error {
2734
3033
  * query filter rather than scoping on a header, so the project belongs to the
2735
3034
  * call, not to the client.
2736
3035
  *
3036
+ * The key MUST be an organization API key (`sk-lw-{id}_{secret}`, from
3037
+ * Settings > API Keys). A project API key is refused before any permission is
3038
+ * consulted, with `credential_class_mismatch`, and no header makes it work:
3039
+ * these are organization-scoped routes and a project key names one project.
3040
+ * The same organization key also reaches the project-scoped surfaces when
3041
+ * given `X-Project-Id`, so one key covers both families and a project key
3042
+ * covers only one.
3043
+ *
2737
3044
  * Neither collection on this service offers an eager whole-set read. The
2738
3045
  * ledger is unbounded, and materialising a window of it is the very
2739
3046
  * under-counting and out-of-memory footgun the page docstrings warn about:
@@ -2756,17 +3063,12 @@ declare class SpendEventsApiService {
2756
3063
  * stops on the first page silently under-counts the window, so read every
2757
3064
  * page or stream them with `iterate()`.
2758
3065
  */
2759
- listPage(options: {
3066
+ listPage(options: SpendFilterOptions & {
2760
3067
  /** Required: the pull is a ranged read by contract. */
2761
3068
  from: number;
2762
3069
  to: number;
2763
3070
  cursor?: string;
2764
3071
  limit?: number;
2765
- virtualKeyId?: string;
2766
- endUserId?: string;
2767
- projectId?: string;
2768
- model?: string;
2769
- status?: SpendEventStatus;
2770
3072
  }): Promise<SpendEventsPage>;
2771
3073
  /**
2772
3074
  * Every spend event in the window, one row at a time, fetching each page
@@ -2777,17 +3079,12 @@ declare class SpendEventsApiService {
2777
3079
  * collect it into an array. Raises rather than looping forever on a cursor
2778
3080
  * chain that never ends.
2779
3081
  */
2780
- iterate(options: {
3082
+ iterate(options: SpendFilterOptions & {
2781
3083
  /** Required: the pull is a ranged read by contract. */
2782
3084
  from: number;
2783
3085
  to: number;
2784
3086
  cursor?: string;
2785
3087
  limit?: number;
2786
- virtualKeyId?: string;
2787
- endUserId?: string;
2788
- projectId?: string;
2789
- model?: string;
2790
- status?: SpendEventStatus;
2791
3088
  }): AsyncGenerator<SpendEvent>;
2792
3089
  /**
2793
3090
  * ONE page of per-key spend rollups for a window, paged by group key
@@ -2798,13 +3095,7 @@ declare class SpendEventsApiService {
2798
3095
  * reconciler that reads only the first page silently under-counts every
2799
3096
  * tenant past the limit.
2800
3097
  */
2801
- summariesPage(options: {
2802
- groupBy: "virtual_key" | "end_user";
2803
- from: number;
2804
- to: number;
2805
- projectId?: string;
2806
- /** Narrow the rollup to one key, exact match. */
2807
- virtualKeyId?: string;
3098
+ summariesPage(options: SpendSummariesOptions & {
2808
3099
  cursor?: string;
2809
3100
  limit?: number;
2810
3101
  }): Promise<SpendSummariesPage>;
@@ -2816,13 +3107,7 @@ declare class SpendEventsApiService {
2816
3107
  * covers, so there is deliberately no eager whole-set read here either: a
2817
3108
  * checksum that quietly covers part of the window is worse than none.
2818
3109
  */
2819
- iterSummaries(options: {
2820
- groupBy: "virtual_key" | "end_user";
2821
- from: number;
2822
- to: number;
2823
- projectId?: string;
2824
- /** Narrow the rollup to one key, exact match. */
2825
- virtualKeyId?: string;
3110
+ iterSummaries(options: SpendSummariesOptions & {
2826
3111
  cursor?: string;
2827
3112
  limit?: number;
2828
3113
  }): AsyncGenerator<SpendSummaryRow>;
@@ -2846,9 +3131,43 @@ declare class SpendEventsApiService {
2846
3131
  }): Promise<EndUserSpend>;
2847
3132
  }
2848
3133
 
3134
+ /** Where an endpoint delivers. */
3135
+ type WebhookDestinationKind = "http" | "sqs";
3136
+ /** The queue an `sqs` endpoint delivers to, as any read surface sees it: the
3137
+ * secret half of a static key pair is never returned. */
3138
+ interface WebhookSqsDestination {
3139
+ queue_url: string;
3140
+ /** Read off the queue URL, never configured beside it. */
3141
+ region: string;
3142
+ /** Whose queue it is. */
3143
+ account_id: string;
3144
+ queue_name: string;
3145
+ credential_mode: "assume_role" | "static" | "ambient";
3146
+ role_arn: string | null;
3147
+ /** Generated at save time, to paste into the role's trust policy. */
3148
+ external_id: string | null;
3149
+ access_key_id: string | null;
3150
+ }
3151
+ /** The queue half of a create or update body. */
3152
+ interface WebhookSqsDestinationInput {
3153
+ queue_url: string;
3154
+ /** The role to assume, with an external id we generate. The recommended
3155
+ * way to grant access: nothing long-lived is stored, and the customer
3156
+ * revokes by editing their own trust policy. */
3157
+ role_arn?: string;
3158
+ external_id?: string;
3159
+ /** A static key pair instead. The secret is stored encrypted and never
3160
+ * returned. */
3161
+ access_key_id?: string;
3162
+ secret_access_key?: string;
3163
+ }
2849
3164
  interface WebhookEndpointSummary {
2850
3165
  id: string;
2851
- url: string;
3166
+ destination_kind: WebhookDestinationKind;
3167
+ /** The receiver URL on an `http` endpoint, null on every other kind. */
3168
+ url: string | null;
3169
+ /** The queue on an `sqs` endpoint, null on every other kind. */
3170
+ sqs: WebhookSqsDestination | null;
2852
3171
  max_batch_size: number;
2853
3172
  max_batch_delay_ms: number;
2854
3173
  max_in_flight: number;
@@ -2866,9 +3185,8 @@ interface WebhookEndpointWithSecret extends WebhookEndpointSummary {
2866
3185
  /** Present only on create and roll-secret responses; never again. */
2867
3186
  secret: string;
2868
3187
  }
2869
- /** The POST body, exactly as the wire takes it. */
2870
- interface CreateWebhookEndpointInput {
2871
- url: string;
3188
+ /** Everything a create body carries that is not the destination. */
3189
+ interface CreateWebhookEndpointBase {
2872
3190
  enabled_events: string[];
2873
3191
  /** Envelopes per delivery. The receiver always gets an array. */
2874
3192
  max_batch_size?: number;
@@ -2877,9 +3195,39 @@ interface CreateWebhookEndpointInput {
2877
3195
  /** Concurrent in-flight deliveries to this endpoint. */
2878
3196
  max_in_flight?: number;
2879
3197
  }
3198
+ /**
3199
+ * The POST body, exactly as the wire takes it.
3200
+ *
3201
+ * A destination is one kind and one address, so the two are a union rather
3202
+ * than independent optional fields: the type refuses `{destination_kind:
3203
+ * "sqs"}` with no queue, and `{url, sqs}` together, which is what the server
3204
+ * refuses too. `destination_kind` is optional only on the http branch, where
3205
+ * absent has always meant http.
3206
+ */
3207
+ type WebhookDestinationInput = {
3208
+ destination_kind?: "http";
3209
+ url: string;
3210
+ sqs?: never;
3211
+ } | {
3212
+ destination_kind: "sqs";
3213
+ sqs: WebhookSqsDestinationInput;
3214
+ url?: never;
3215
+ };
3216
+ type CreateWebhookEndpointInput = CreateWebhookEndpointBase & WebhookDestinationInput;
2880
3217
  /** The PATCH body, exactly as the wire takes it. Omitted fields are left alone. */
2881
3218
  interface UpdateWebhookEndpointInput {
2882
3219
  url?: string;
3220
+ /** Only the queue's own fields; the destination kind cannot change, because
3221
+ * batches already planned against the old transport are in flight. Create
3222
+ * a new endpoint and archive this one once it has drained. A credential
3223
+ * field sent as null is CLEARED; omitted keeps what is stored. */
3224
+ sqs?: Partial<{
3225
+ queue_url: string;
3226
+ role_arn: string | null;
3227
+ external_id: string | null;
3228
+ access_key_id: string | null;
3229
+ secret_access_key: string | null;
3230
+ }>;
2883
3231
  enabled_events?: string[];
2884
3232
  status?: "active" | "disabled";
2885
3233
  max_batch_size?: number;
@@ -2954,6 +3302,13 @@ declare class WebhooksApiError extends Error {
2954
3302
  * rejected by the server. The surface is anchored on the organization alone,
2955
3303
  * so there is no project id to give this client.
2956
3304
  *
3305
+ * The key MUST be an organization API key (`sk-lw-{id}_{secret}`, from
3306
+ * Settings > API Keys). A project API key is refused with
3307
+ * `credential_class_mismatch` before any permission is consulted, and no
3308
+ * header makes it work. The same organization key also reaches the
3309
+ * project-scoped surfaces when given `X-Project-Id`, so one key covers both
3310
+ * families and a project key covers only one.
3311
+ *
2957
3312
  * The endpoint entity and the create/update bodies mirror the wire verbatim,
2958
3313
  * so their fields are lowercase snake_case: virtual keys and gateway budgets
2959
3314
  * already take the wire body as it is, and translating field by field here
@@ -3020,10 +3375,11 @@ declare class WebhooksApiService {
3020
3375
  * that missed a delivery reads the window back from here. Walk the whole
3021
3376
  * window with `iterEvents()`.
3022
3377
  */
3023
- eventsPage(options?: {
3378
+ eventsPage(options: {
3024
3379
  type?: string;
3025
- from?: number;
3026
- to?: number;
3380
+ /** Required: the log is a ranged read by contract. Epoch milliseconds. */
3381
+ from: number;
3382
+ to: number;
3027
3383
  cursor?: string;
3028
3384
  limit?: number;
3029
3385
  }): Promise<EmittedEventsPage>;
@@ -3031,10 +3387,11 @@ declare class WebhooksApiService {
3031
3387
  * Every emitted event matching the filter, one at a time, fetching each
3032
3388
  * page only when the consumer reaches it.
3033
3389
  */
3034
- iterEvents(options?: {
3390
+ iterEvents(options: {
3035
3391
  type?: string;
3036
- from?: number;
3037
- to?: number;
3392
+ /** Required: the log is a ranged read by contract. Epoch milliseconds. */
3393
+ from: number;
3394
+ to: number;
3038
3395
  cursor?: string;
3039
3396
  limit?: number;
3040
3397
  }): AsyncGenerator<EmittedEvent>;
@@ -3047,6 +3404,158 @@ declare class WebhooksApiService {
3047
3404
  getEvent(id: string): Promise<EmittedEvent>;
3048
3405
  }
3049
3406
 
3407
+ /**
3408
+ * The vocabulary the management REST families share on the wire.
3409
+ *
3410
+ * A role binding grants a scoped role, and the same three words appear on
3411
+ * roles, role bindings, groups, teams and API keys. Declared once here so the
3412
+ * CLI's flag parsers validate against one list rather than five copies that
3413
+ * can disagree with the platform.
3414
+ */
3415
+ /** The role a binding grants at its scope. `CUSTOM` defers to a custom role. */
3416
+ declare const MANAGEMENT_ROLES: readonly ["ADMIN", "MEMBER", "VIEWER", "CUSTOM"];
3417
+ type ManagementRole = (typeof MANAGEMENT_ROLES)[number];
3418
+
3419
+ interface Team {
3420
+ id: string;
3421
+ name: string;
3422
+ slug: string;
3423
+ organizationId: string;
3424
+ createdAt: string;
3425
+ updatedAt: string;
3426
+ }
3427
+ interface TeamPagination {
3428
+ page: number;
3429
+ limit: number;
3430
+ total: number;
3431
+ }
3432
+ interface ListTeamsResponse {
3433
+ data: Team[];
3434
+ pagination: TeamPagination;
3435
+ }
3436
+ interface ArchivedTeam {
3437
+ id: string;
3438
+ name: string;
3439
+ archivedAt: string | null;
3440
+ }
3441
+ interface TeamMember {
3442
+ userId: string | null;
3443
+ name: string | null;
3444
+ email: string | null;
3445
+ role: ManagementRole;
3446
+ }
3447
+ declare class TeamsApiError extends Error {
3448
+ readonly operation: string;
3449
+ readonly originalError?: unknown | undefined;
3450
+ constructor(message: string, operation: string, originalError?: unknown | undefined);
3451
+ }
3452
+ declare class TeamsApiService {
3453
+ #private;
3454
+ constructor(config?: {
3455
+ endpoint?: string;
3456
+ apiKey?: string;
3457
+ });
3458
+ list(options?: {
3459
+ page?: number;
3460
+ limit?: number;
3461
+ }): Promise<ListTeamsResponse>;
3462
+ get(id: string): Promise<Team>;
3463
+ create(input: {
3464
+ name: string;
3465
+ }): Promise<Team>;
3466
+ update({ id, input, }: {
3467
+ id: string;
3468
+ input: {
3469
+ name?: string;
3470
+ };
3471
+ }): Promise<Team>;
3472
+ archive(id: string): Promise<ArchivedTeam>;
3473
+ listMembers(teamId: string): Promise<{
3474
+ data: TeamMember[];
3475
+ }>;
3476
+ addMember({ teamId, input, }: {
3477
+ teamId: string;
3478
+ input: {
3479
+ userId: string;
3480
+ role?: ManagementRole;
3481
+ };
3482
+ }): Promise<{
3483
+ success: boolean;
3484
+ }>;
3485
+ removeMember({ teamId, userId, }: {
3486
+ teamId: string;
3487
+ userId: string;
3488
+ }): Promise<{
3489
+ success: boolean;
3490
+ }>;
3491
+ }
3492
+
3493
+ interface Project {
3494
+ id: string;
3495
+ name: string;
3496
+ slug: string;
3497
+ language: string;
3498
+ framework: string;
3499
+ teamId: string;
3500
+ piiRedactionLevel: string;
3501
+ createdAt: string;
3502
+ updatedAt: string;
3503
+ }
3504
+ interface CreateProjectInput {
3505
+ name: string;
3506
+ language: string;
3507
+ framework: string;
3508
+ teamId?: string;
3509
+ newTeamName?: string;
3510
+ }
3511
+ interface UpdateProjectInput {
3512
+ name?: string;
3513
+ language?: string;
3514
+ framework?: string;
3515
+ piiRedactionLevel?: "STRICT" | "ESSENTIAL" | "DISABLED";
3516
+ }
3517
+ interface ProjectWithServiceKey extends Project {
3518
+ serviceApiKey: string;
3519
+ serviceApiKeyId: string;
3520
+ }
3521
+ interface PaginatedProjects {
3522
+ data: Project[];
3523
+ pagination: {
3524
+ page: number;
3525
+ limit: number;
3526
+ total: number;
3527
+ totalPages: number;
3528
+ };
3529
+ }
3530
+ interface ArchivedProject {
3531
+ id: string;
3532
+ name: string;
3533
+ archivedAt: string;
3534
+ }
3535
+ declare class ProjectsApiError extends Error {
3536
+ readonly operation: string;
3537
+ readonly originalError?: unknown | undefined;
3538
+ constructor(message: string, operation: string, originalError?: unknown | undefined);
3539
+ }
3540
+ declare class ProjectsApiService {
3541
+ private readonly endpoint;
3542
+ private readonly apiKey;
3543
+ constructor(config?: {
3544
+ endpoint?: string;
3545
+ apiKey?: string;
3546
+ });
3547
+ private headers;
3548
+ private request;
3549
+ list(options?: {
3550
+ page?: number;
3551
+ limit?: number;
3552
+ }): Promise<PaginatedProjects>;
3553
+ get(id: string): Promise<Project>;
3554
+ create(input: CreateProjectInput): Promise<ProjectWithServiceKey>;
3555
+ update(id: string, input: UpdateProjectInput): Promise<Project>;
3556
+ archive(id: string): Promise<ArchivedProject>;
3557
+ }
3558
+
3050
3559
  interface GetTraceParams {
3051
3560
  includeSpans?: boolean;
3052
3561
  }
@@ -3124,6 +3633,21 @@ declare class LangWatch {
3124
3633
  readonly webhooks: WebhooksApiService;
3125
3634
  constructor(options?: LangWatchConstructorOptions);
3126
3635
  get apiClient(): LangwatchApiClient;
3636
+ /**
3637
+ * Teams, which group projects and the members who can reach them. These
3638
+ * routes want an organization API key.
3639
+ *
3640
+ * Built on first use rather than in the constructor: the management
3641
+ * families resolve their credential when constructed and refuse an empty
3642
+ * one, so building this eagerly would make `new LangWatch()` throw for
3643
+ * every caller that never touches a team.
3644
+ */
3645
+ get teams(): TeamsApiService;
3646
+ /**
3647
+ * Projects, including provisioning one with its own service API key. These
3648
+ * routes want an organization API key.
3649
+ */
3650
+ get projects(): ProjectsApiService;
3127
3651
  }
3128
3652
 
3129
3653
  /**
@@ -3361,4 +3885,4 @@ declare const logger: {
3361
3885
  NoOpLogger: typeof NoOpLogger;
3362
3886
  };
3363
3887
 
3364
- 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 };
3888
+ 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 };