langwatch 1.18.0 → 1.20.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 (91) hide show
  1. package/README.md +25 -11
  2. package/dist/agent/index.d.mts +122 -79
  3. package/dist/agent/index.d.ts +122 -79
  4. package/dist/agent/index.js +523 -300
  5. package/dist/agent/index.js.map +1 -1
  6. package/dist/agent/index.mjs +522 -301
  7. package/dist/agent/index.mjs.map +1 -1
  8. package/dist/chunk-5VYEG3RS.js +117 -0
  9. package/dist/chunk-5VYEG3RS.js.map +1 -0
  10. package/dist/{chunk-O4J3ZPZY.js → chunk-5ZNEXSAB.js} +7912 -2564
  11. package/dist/chunk-5ZNEXSAB.js.map +1 -0
  12. package/dist/chunk-BDQ2RG7R.mjs +852 -0
  13. package/dist/chunk-BDQ2RG7R.mjs.map +1 -0
  14. package/dist/chunk-BL3GHEKF.js +59 -0
  15. package/dist/chunk-BL3GHEKF.js.map +1 -0
  16. package/dist/chunk-C7IWJ2GJ.mjs +59 -0
  17. package/dist/chunk-C7IWJ2GJ.mjs.map +1 -0
  18. package/dist/chunk-EQ5CFQGJ.js +852 -0
  19. package/dist/chunk-EQ5CFQGJ.js.map +1 -0
  20. package/dist/{chunk-NPEK4RSD.mjs → chunk-ET5KYCG2.mjs} +7757 -2409
  21. package/dist/chunk-ET5KYCG2.mjs.map +1 -0
  22. package/dist/{chunk-MVQJMRM6.mjs → chunk-FKYYEGJ7.mjs} +120 -112
  23. package/dist/chunk-FKYYEGJ7.mjs.map +1 -0
  24. package/dist/{chunk-JJASOJOK.js → chunk-HCK7TCSK.js} +138 -130
  25. package/dist/chunk-HCK7TCSK.js.map +1 -0
  26. package/dist/{chunk-LCG5Y2EG.js → chunk-N76BG37W.js} +15 -101
  27. package/dist/chunk-N76BG37W.js.map +1 -0
  28. package/dist/chunk-SERULD4Z.mjs +117 -0
  29. package/dist/chunk-SERULD4Z.mjs.map +1 -0
  30. package/dist/{chunk-73QOHSHU.js → chunk-WDUUAIG3.js} +2 -2
  31. package/dist/chunk-WDUUAIG3.js.map +1 -0
  32. package/dist/{chunk-WMDQVWA6.mjs → chunk-WSGVZ3J2.mjs} +22 -108
  33. package/dist/chunk-WSGVZ3J2.mjs.map +1 -0
  34. package/dist/{chunk-57L2K66L.mjs → chunk-XQ4CP2JK.mjs} +2 -2
  35. package/dist/chunk-XQ4CP2JK.mjs.map +1 -0
  36. package/dist/cli/bundle.js +766 -479
  37. package/dist/implementation-B4Z2ksnA.d.mts +261 -0
  38. package/dist/implementation-BFUgzz5C.d.ts +261 -0
  39. package/dist/index.d.mts +398 -1123
  40. package/dist/index.d.ts +398 -1123
  41. package/dist/index.js +7613 -3566
  42. package/dist/index.js.map +1 -1
  43. package/dist/index.mjs +7419 -3372
  44. package/dist/index.mjs.map +1 -1
  45. package/dist/observability-sdk/index.d.mts +16 -76
  46. package/dist/observability-sdk/index.d.ts +16 -76
  47. package/dist/observability-sdk/index.js +8 -5
  48. package/dist/observability-sdk/index.js.map +1 -1
  49. package/dist/observability-sdk/index.mjs +8 -5
  50. package/dist/observability-sdk/instrumentation/langchain/index.d.mts +3 -5
  51. package/dist/observability-sdk/instrumentation/langchain/index.d.ts +3 -5
  52. package/dist/observability-sdk/instrumentation/langchain/index.js +160 -112
  53. package/dist/observability-sdk/instrumentation/langchain/index.js.map +1 -1
  54. package/dist/observability-sdk/instrumentation/langchain/index.mjs +148 -100
  55. package/dist/observability-sdk/instrumentation/langchain/index.mjs.map +1 -1
  56. package/dist/observability-sdk/semconv/index.d.mts +37 -0
  57. package/dist/observability-sdk/semconv/index.d.ts +37 -0
  58. package/dist/observability-sdk/semconv/index.js +121 -0
  59. package/dist/observability-sdk/semconv/index.js.map +1 -0
  60. package/dist/observability-sdk/semconv/index.mjs +121 -0
  61. package/dist/observability-sdk/semconv/index.mjs.map +1 -0
  62. package/dist/observability-sdk/setup/node/index.d.mts +73 -313
  63. package/dist/observability-sdk/setup/node/index.d.ts +73 -313
  64. package/dist/observability-sdk/setup/node/index.js +6 -4
  65. package/dist/observability-sdk/setup/node/index.js.map +1 -1
  66. package/dist/observability-sdk/setup/node/index.mjs +5 -3
  67. package/dist/types-B696jWYQ.d.mts +16010 -0
  68. package/dist/types-Bo6OvFct.d.ts +16010 -0
  69. package/dist/{types-VOZv9LYO.d.mts → types-CoS5PmeU.d.mts} +22 -59
  70. package/dist/{types-VOZv9LYO.d.ts → types-CoS5PmeU.d.ts} +22 -59
  71. package/dist/{types-DLfhJb38.d.mts → types-RkiBQZ9j.d.mts} +1 -6
  72. package/dist/{types-DLfhJb38.d.ts → types-RkiBQZ9j.d.ts} +1 -6
  73. package/dist/values-1yj9l0Sa.d.mts +112 -0
  74. package/dist/values-1yj9l0Sa.d.ts +112 -0
  75. package/package.json +95 -64
  76. package/dist/chunk-57L2K66L.mjs.map +0 -1
  77. package/dist/chunk-73QOHSHU.js.map +0 -1
  78. package/dist/chunk-HY2N6TO5.mjs +0 -566
  79. package/dist/chunk-HY2N6TO5.mjs.map +0 -1
  80. package/dist/chunk-JJASOJOK.js.map +0 -1
  81. package/dist/chunk-LCG5Y2EG.js.map +0 -1
  82. package/dist/chunk-MVQJMRM6.mjs.map +0 -1
  83. package/dist/chunk-NPEK4RSD.mjs.map +0 -1
  84. package/dist/chunk-O4J3ZPZY.js.map +0 -1
  85. package/dist/chunk-UEJSGC3P.js +0 -566
  86. package/dist/chunk-UEJSGC3P.js.map +0 -1
  87. package/dist/chunk-WMDQVWA6.mjs.map +0 -1
  88. package/dist/implementation-BvX-7vox.d.ts +0 -716
  89. package/dist/implementation-CQ__V0Vc.d.mts +0 -716
  90. package/dist/types-CNEUr6Hm.d.ts +0 -36682
  91. package/dist/types-DfPAHmAh.d.mts +0 -36682
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # LangWatch TypeScript SDK
2
2
 
3
3
  <p align="center">
4
- <img src="https://github.com/langwatch/langwatch/blob/main/assets/logo-header.webp?raw=true" alt="LangWatch Logo" />
4
+ <img src="https://github.com/langwatch/langwatch/blob/main/.github/assets/logo-header.webp?raw=true" alt="LangWatch Logo" />
5
5
  </p>
6
6
 
7
7
  <p align="center">
@@ -40,6 +40,8 @@ LangWatch helps you monitor, debug, and optimize your LLM/GenAI applications. Th
40
40
  npm install langwatch
41
41
  ```
42
42
 
43
+ `@opentelemetry/api` is a peer dependency (npm installs it for you). A custom `metricReader` or `instrumentations` needs `@opentelemetry/sdk-metrics` or `@opentelemetry/instrumentation` installed in your app.
44
+
43
45
  ---
44
46
 
45
47
  ## 🚀 Getting Started
@@ -74,6 +76,7 @@ span.end();
74
76
  const tracer = getLangWatchTracer("my-app");
75
77
  ```
76
78
  - **Start a span and record input/output:**
79
+
77
80
  ```ts
78
81
  const span = tracer.startSpan("call-llm");
79
82
  span.setType("llm");
@@ -81,9 +84,11 @@ span.end();
81
84
  span.setOutput("Model response"); // Main way to record output
82
85
  span.end();
83
86
  ```
87
+
84
88
  > **Note:** `setInput` and `setOutput` are the primary methods to record input/output. Use `setInputString`/`setOutputString` for plain text, or pass any serializable value.
85
89
 
86
90
  - **Use withActiveSpan for automatic error handling:**
91
+
87
92
  ```ts
88
93
  await tracer.withActiveSpan("my-operation", async (span) => {
89
94
  span.setType("llm");
@@ -94,19 +99,27 @@ span.end();
94
99
  ```
95
100
 
96
101
  - **Record an evaluation directly on a span:**
102
+
97
103
  ```ts
98
104
  span.addEvaluation({ name: "My Eval", passed: true, score: 1.0 });
99
105
  ```
106
+
100
107
  > **Note:** This associates evaluation results with a specific span (operation or model call).
101
108
 
102
109
  - **(Optional) Add GenAI message events:**
110
+
103
111
  ```ts
104
112
  span.addGenAISystemMessageEvent({ content: "You are a helpful assistant." });
105
113
  span.addGenAIUserMessageEvent({ content: "Hello!" });
106
114
  span.addGenAIAssistantMessageEvent({ content: "Hi! How can I help you?" });
107
115
  span.addGenAIToolMessageEvent({ content: "Tool result", id: "tool-1" });
108
- span.addGenAIChoiceEvent({ finish_reason: "stop", index: 0, message: { content: "Response" } });
116
+ span.addGenAIChoiceEvent({
117
+ finish_reason: "stop",
118
+ index: 0,
119
+ message: { content: "Response" },
120
+ });
109
121
  ```
122
+
110
123
  > **Advanced:** The `addGenAI...` methods are optional and mainly for advanced/manual instrumentation. Most users do not need these unless you want fine-grained message event logs.
111
124
 
112
125
  - **RAG context, metrics, and model information:**
@@ -126,6 +139,7 @@ span.end();
126
139
  const compiledPrompt = await getPrompt("prompt-id", { user: "Alice" });
127
140
  ```
128
141
  - **Fetch a specific prompt version:**
142
+
129
143
  ```ts
130
144
  import { getPromptVersion } from "langwatch/prompt";
131
145
  const compiledPrompt = await getPromptVersion("prompt-id", "version-id", {
@@ -142,17 +156,18 @@ span.end();
142
156
  import { runEvaluation } from "langwatch/evaluation";
143
157
  const result = await runEvaluation({
144
158
  slug: "helpfulness",
145
- data: { input: "Hi", output: "Hello!" }
159
+ data: { input: "Hi", output: "Hello!" },
146
160
  });
147
161
  ```
148
162
  - **Record a custom evaluation:**
163
+
149
164
  ```ts
150
165
  await tracer.withActiveSpan("my-operation", async (span) => {
151
166
  span.addEvaluation({
152
167
  name: "Manual Eval",
153
168
  passed: true,
154
169
  score: 0.9,
155
- details: "Looks good!"
170
+ details: "Looks good!",
156
171
  });
157
172
  });
158
173
  ```
@@ -197,16 +212,12 @@ const exporter = new LangWatchTraceExporter({
197
212
  ```ts
198
213
  // Include only specific scopes
199
214
  const exporter = new LangWatchTraceExporter({
200
- filters: [
201
- { include: { instrumentationScopeName: [{ equals: "ai" }] } },
202
- ],
215
+ filters: [{ include: { instrumentationScopeName: [{ equals: "ai" }] } }],
203
216
  });
204
217
 
205
218
  // Exclude spans by name pattern
206
219
  const exporter = new LangWatchTraceExporter({
207
- filters: [
208
- { exclude: { name: [{ startsWith: "internal." }] } },
209
- ],
220
+ filters: [{ exclude: { name: [{ startsWith: "internal." }] } }],
210
221
  });
211
222
 
212
223
  // Combine filters (AND pipeline)
@@ -221,6 +232,7 @@ const exporter = new LangWatchTraceExporter({
221
232
  **Learn more:** See the [Filtering Spans Tutorial](https://docs.langwatch.ai/integration/typescript/tutorials/filtering-spans) for comprehensive examples and best practices.
222
233
 
223
234
  ### Custom OpenTelemetry Integration
235
+
224
236
  ```ts
225
237
  import { FilterableBatchSpanProcessor, LangWatchExporter } from "langwatch";
226
238
 
@@ -229,11 +241,12 @@ const processor = new FilterableBatchSpanProcessor(
229
241
  apiKey: "your-api-key",
230
242
  endpoint: "https://custom.langwatch.com",
231
243
  }),
232
- excludeRules
244
+ excludeRules,
233
245
  );
234
246
  ```
235
247
 
236
248
  ### Span Processing Rules
249
+
237
250
  ```ts
238
251
  const excludeRules: SpanProcessingExcludeRule[] = [
239
252
  { attribute: "http.url", value: "/health" },
@@ -242,6 +255,7 @@ const excludeRules: SpanProcessingExcludeRule[] = [
242
255
  ```
243
256
 
244
257
  ### Manual Instrumentation
258
+
245
259
  ```ts
246
260
  import { semconv } from "langwatch/observability";
247
261
 
@@ -6,14 +6,7 @@ interface Logger {
6
6
  }
7
7
 
8
8
  /**
9
- * The frames the SDK and the platform exchange over the agent socket.
10
- *
11
- * Every frame is one JSON text message with a `type` and the protocol
12
- * version. The shapes here match the contract table in ADR-128 and the
13
- * platform's own frame module; the validators are small and hand-written
14
- * because this file is part of the public `langwatch/agent` surface, where no
15
- * schema library may cross as a value.
16
- *
9
+ * Frames exchanged over the agent socket; shapes match ADR-128.
17
10
  * @see dev/docs/adr/128-connected-agents.md
18
11
  */
19
12
  declare const PROTOCOL_VERSION = 1;
@@ -27,39 +20,22 @@ interface AgentMessage {
27
20
  type AgentParameterValue = string | number | boolean;
28
21
  /** A JSON Schema object as the SDK sends it in `register`. */
29
22
  type JsonSchemaObject = Record<string, unknown>;
23
+ /** The scenario hooks an agent declares (ADR-180). */
24
+ interface AgentHooks {
25
+ setup: boolean;
26
+ teardown: boolean;
27
+ }
28
+ /** The test data a scenario's setup made, as a JSON object. */
29
+ type ScenarioState = Record<string, unknown>;
30
+ interface CallRun {
31
+ scenarioRunId?: string;
32
+ scenarioName?: string;
33
+ batchRunId?: string;
34
+ }
30
35
 
31
36
  /**
32
- * The connection the client speaks over, behind one small interface so the
33
- * client never depends on how the frames travel.
34
- *
35
- * Two transports carry the same frames. The WebSocket is the default and it
36
- * needs the `ws` package: the platform authenticates from the request
37
- * headers of the upgrade, and no global `WebSocket` constructor can send
38
- * them. HTTP long polling is for a network that blocks WebSockets: one POST
39
- * registers, a GET waits for the next frames, a POST carries the answers. It
40
- * speaks through the global `fetch` (Node 20+).
41
- */
42
- declare const AGENT_TRANSPORTS: readonly ["websocket", "http"];
43
- type AgentTransport = (typeof AGENT_TRANSPORTS)[number];
44
- /**
45
- * The transport to start with: the explicit option, then
46
- * `LANGWATCH_AGENT_TRANSPORT`, else the WebSocket. Anything that is not
47
- * `http` is the WebSocket, which falls back to HTTP on its own when the
48
- * upgrade is refused.
49
- */
50
- declare function resolveTransport({ explicit, env, }: {
51
- explicit?: string;
52
- env?: NodeJS.ProcessEnv;
53
- }): AgentTransport;
54
-
55
- /**
56
- * The run parameters an agent declares, and the values a call supplies.
57
- *
58
- * Three forms are accepted: a definition map, any Standard JSON Schema object
59
- * (read through `"~standard".jsonSchema`, so zod 4, valibot and arktype work
60
- * without this package importing them), or a plain JSON Schema. A schema
61
- * library instance that offers no JSON Schema converter is refused with the
62
- * three forms named, because the SDK never takes a zod instance as a value.
37
+ * Run parameters: three forms accepted (definition map, Standard JSON Schema,
38
+ * or plain JSON Schema); no direct library instances.
63
39
  */
64
40
 
65
41
  /** The scalar types a run parameter may hold. */
@@ -78,9 +54,8 @@ interface ParameterDefinition {
78
54
  type ParameterDefinitions = Record<string, ParameterDefinition>;
79
55
  /**
80
56
  * The Standard JSON Schema converter an object exposes under `"~standard"`.
81
- * Method syntax on purpose: a library narrows `target` to its own union, and
82
- * a method parameter is checked bivariantly, so zod 4, valibot and arktype
83
- * all fit without the SDK naming any of them.
57
+ * Method syntax on purpose: a method parameter is checked bivariantly, so
58
+ * zod 4, valibot and arktype all fit without the SDK naming any of them.
84
59
  */
85
60
  interface StandardJsonSchemaConverter {
86
61
  input?(options: {
@@ -93,21 +68,20 @@ interface StandardJsonSchemaConverter {
93
68
  /** One problem a Standard Schema `validate` reports. */
94
69
  interface StandardSchemaIssue {
95
70
  readonly message: string;
96
- readonly path?: ReadonlyArray<PropertyKey | {
71
+ readonly path?: readonly (PropertyKey | {
97
72
  readonly key: PropertyKey;
98
- }> | undefined;
73
+ })[] | undefined;
99
74
  }
100
75
  type StandardSchemaResult<O> = {
101
76
  readonly value: O;
102
77
  readonly issues?: undefined;
103
78
  } | {
104
- readonly issues: ReadonlyArray<StandardSchemaIssue>;
79
+ readonly issues: readonly StandardSchemaIssue[];
105
80
  };
106
81
  /**
107
- * Any object that implements the Standard JSON Schema interface. When it also
108
- * implements Standard Schema (`validate`), the values of every call go
109
- * through it before the handler runs, so a zod 4 schema validates, fills its
110
- * defaults and types `params` in one place.
82
+ * Any object implementing the Standard JSON Schema interface. When it also
83
+ * implements Standard Schema (`validate`), every call's values pass through
84
+ * it first, so a zod 4 schema validates, fills defaults and types `params`.
111
85
  */
112
86
  interface StandardJsonSchema<O = unknown> {
113
87
  readonly "~standard": {
@@ -120,14 +94,16 @@ interface StandardJsonSchema<O = unknown> {
120
94
  } | undefined;
121
95
  };
122
96
  }
97
+ /** The `output` field of a Standard Schema `types` entry, narrowed to a param record. */
98
+ type StandardOutputOf<T> = NonNullable<T> extends {
99
+ readonly output: infer O;
100
+ } ? O extends Record<string, unknown> ? O : Record<string, AgentParameterValue> : Record<string, AgentParameterValue>;
123
101
  /** The `params` type a Standard Schema object gives the handler: its parsed output. */
124
102
  type InferStandardOutput<S> = S extends {
125
103
  readonly "~standard": {
126
104
  readonly types?: infer T;
127
105
  };
128
- } ? [NonNullable<T>] extends [never] ? Record<string, AgentParameterValue> : NonNullable<T> extends {
129
- readonly output: infer O;
130
- } ? O extends Record<string, unknown> ? O : Record<string, AgentParameterValue> : Record<string, AgentParameterValue> : Record<string, AgentParameterValue>;
106
+ } ? [NonNullable<T>] extends [never] ? Record<string, AgentParameterValue> : StandardOutputOf<T> : Record<string, AgentParameterValue>;
131
107
  /** Every form `parameters` accepts. */
132
108
  type ParameterInput = ParameterDefinitions | StandardJsonSchema | JsonSchemaObject;
133
109
  /** One parameter as the platform lists it, derived from the schema. */
@@ -155,26 +131,42 @@ declare function toParameterSchema(input: ParameterInput | undefined): JsonSchem
155
131
  */
156
132
  declare function parameterSpecsFromSchema(schema: JsonSchemaObject): ParameterSpec[];
157
133
 
134
+ /**
135
+ * Connection abstraction for frame transport (WebSocket default, HTTP fallback).
136
+ */
137
+ declare const AGENT_TRANSPORTS: readonly ["websocket", "http"];
138
+ type AgentTransport = (typeof AGENT_TRANSPORTS)[number];
139
+ /**
140
+ * The transport to start with: the explicit option, then
141
+ * `LANGWATCH_AGENT_TRANSPORT`, else the WebSocket, which falls back to HTTP
142
+ * on its own when the upgrade is refused.
143
+ */
144
+ declare function resolveTransport({ explicit, env, }: {
145
+ explicit?: string;
146
+ env?: NodeJS.ProcessEnv;
147
+ }): AgentTransport;
148
+
158
149
  /**
159
150
  * `connectAgent`: the function that runs an agent becomes a simulation target.
160
- *
161
- * The wrapper resolves the environment and the parameter schema at definition,
162
- * registers the agent with the process-wide client, and returns a function
163
- * that is directly callable (for unit tests and local runs) and exposes
164
- * `disconnect()`.
165
- *
166
151
  * @see specs/typescript-sdk/agent-wrapper.feature
167
152
  */
168
153
 
169
154
  /** The default call timeout, and the cap the platform enforces. */
170
155
  declare const DEFAULT_TIMEOUT_MS = 120000;
171
156
  declare const MAX_TIMEOUT_MS = 300000;
172
- /** What a handler may return: a string, one message, a list of messages, or an output with a session. */
157
+ /**
158
+ * What a handler may return: a string, one message, a list of messages, or an
159
+ * output with a session.
160
+ */
173
161
  type AgentOutput = string | AgentMessage | AgentMessage[];
174
- /** The output of one turn plus the session the agent keeps for the next turn of the same thread. */
162
+ /**
163
+ * The output of one turn, the session the agent keeps for the next turn of the
164
+ * same thread, and an update to the scenario's state.
165
+ */
175
166
  interface AgentResult {
176
167
  output: AgentOutput;
177
168
  session?: unknown;
169
+ state?: ScenarioState;
178
170
  }
179
171
  type AgentReply = AgentOutput | AgentResult;
180
172
  /** The one object a handler receives on every turn. */
@@ -185,36 +177,57 @@ interface AgentCall<P = Record<string, AgentParameterValue>> {
185
177
  newMessages: AgentMessage[];
186
178
  /** The platform's conversation id. */
187
179
  threadId: string;
188
- /** The value the handler returned as `session` on the previous turn of this thread, null on the first. */
180
+ /**
181
+ * The value the handler returned as `session` on the previous turn of this
182
+ * thread, null on the first.
183
+ */
189
184
  session: unknown;
185
+ /** The scenario's state: what setup returned, as the latest turn updated it; null without one. */
186
+ state: ScenarioState | null;
190
187
  /** The run parameters, validated and with defaults filled. */
191
188
  params: P;
192
- /** The trace id of the turn, so the agent's own spans join it. Empty when the call carries none. */
189
+ /**
190
+ * The trace id of the turn, so the agent's own spans join it. Empty when the
191
+ * call carries none.
192
+ */
193
193
  traceId: string;
194
194
  }
195
195
  type AgentHandler<P> = (call: AgentCall<P>) => AgentReply | Promise<AgentReply>;
196
+ /** The scenario run a hook is called for. */
197
+ type ScenarioRun = CallRun;
198
+ type HookAnswer = ScenarioState | undefined | void;
199
+ /** Makes the test data before the first turn and returns it as the state. */
200
+ type SetupHook<P> = (run: ScenarioRun, params: P) => HookAnswer | Promise<HookAnswer>;
201
+ /** Removes the test data after the last turn; what it returns is shown on the run. */
202
+ type TeardownHook<P> = (run: ScenarioRun, state: ScenarioState | null, params: P) => HookAnswer | Promise<HookAnswer>;
203
+ /** `agent.scenario`: declares the hooks the platform runs around a scenario's turns (ADR-180). */
204
+ interface ScenarioHooks<P> {
205
+ setup: (hook: SetupHook<P>) => void;
206
+ teardown: (hook: TeardownHook<P>) => void;
207
+ }
196
208
  /** What a direct call of the wrapped function takes: messages, and anything else is optional. */
197
209
  interface DirectAgentCall<P> {
198
210
  messages: AgentMessage[];
199
211
  newMessages?: AgentMessage[];
200
212
  threadId?: string;
201
213
  session?: unknown;
214
+ state?: ScenarioState | null;
202
215
  params?: Partial<P>;
203
216
  traceId?: string;
204
217
  }
205
218
  interface ConnectAgentOptions<P extends ParameterInput = ParameterDefinitions> {
206
219
  /** The agent name. One row per name and environment on the platform. */
207
220
  name: string;
208
- /** Resolved from LANGWATCH_AGENT_ENVIRONMENT, APP_ENV, ENVIRONMENT, NODE_ENV, else development. */
221
+ /**
222
+ * Resolved from LANGWATCH_AGENT_ENVIRONMENT, APP_ENV, ENVIRONMENT, NODE_ENV,
223
+ * else development.
224
+ */
209
225
  environment?: string;
210
226
  /** A definition map, a Standard JSON Schema object, or a JSON Schema object. */
211
227
  parameters?: P;
212
228
  /**
213
- * Whether this process connects. Takes any boolean, so one expression can
214
- * gate the deployments that connect. Without it the default is true, except
215
- * when CI is truthy; a value given here replaces that rule rather than adding
216
- * to it, so keep the CI half: `process.env.APP_ENV !== "production" && !process.env.CI`.
217
- * LANGWATCH_AGENT_CONNECT=0 always disables.
229
+ * Whether this process connects. Takes any boolean, so one expression can gate the
230
+ * deployments that connect.
218
231
  */
219
232
  enabled?: boolean;
220
233
  /** Names this instance in the platform. Also LANGWATCH_AGENT_INSTANCE_LABEL. */
@@ -232,37 +245,53 @@ interface ConnectAgentOptions<P extends ParameterInput = ParameterDefinitions> {
232
245
  apiKey?: string;
233
246
  endpoint?: string;
234
247
  projectId?: string;
235
- /** `websocket` (default, falls back to HTTP when the upgrade is refused) or `http`. Also LANGWATCH_AGENT_TRANSPORT. */
248
+ /**
249
+ * `websocket` (default, falls back to HTTP when the upgrade is refused) or
250
+ * `http`. Also LANGWATCH_AGENT_TRANSPORT.
251
+ */
236
252
  transport?: AgentTransport;
237
253
  logger?: Logger;
238
254
  }
239
- /** The wrapped function: callable, and connected until `disconnect()`. */
240
- interface ConnectedAgent<P> {
255
+ /**
256
+ * The wrapped function: callable, and connected until `disconnect()`. `HookP`
257
+ * is `P` for every caller; only the implementation signature widens it, since
258
+ * the hook params are covariant and the call params are not.
259
+ */
260
+ interface ConnectedAgent<P, HookP = P> {
241
261
  (call: DirectAgentCall<P>): Promise<AgentResult>;
242
262
  readonly name: string;
243
263
  readonly environment: string;
244
264
  /** The parameter schema as registered. */
245
265
  readonly parameters: JsonSchemaObject;
266
+ /**
267
+ * Declares setup and teardown. Declared before the process yields, they ride
268
+ * on the first register; declared later, the agents register again.
269
+ */
270
+ readonly scenario: ScenarioHooks<HookP>;
246
271
  /** Send deregister and close the socket when this was the last agent of the process. */
247
272
  disconnect: () => Promise<void>;
248
273
  }
249
274
  type Widen<V> = V extends string ? string : V extends number ? number : V extends boolean ? boolean : V;
250
- type ParameterValueOf<D extends ParameterDefinition> = D extends {
251
- options: readonly (infer O extends string)[];
252
- } ? O : D extends {
275
+ /** The value type when neither `options` nor `type` pin one down: widened from `default`. */
276
+ type ParameterValueFallback<D extends ParameterDefinition> = D extends {
277
+ default: infer V;
278
+ } ? Widen<V> : string;
279
+ /** The value type driven by the declared `type`, falling back to `default`'s widened type. */
280
+ type ParameterValueByType<D extends ParameterDefinition> = D extends {
253
281
  type: "number";
254
282
  } ? number : D extends {
255
283
  type: "boolean";
256
284
  } ? boolean : D extends {
257
285
  type: "string";
258
- } ? string : D extends {
259
- default: infer V;
260
- } ? Widen<V> : string;
286
+ } ? string : ParameterValueFallback<D>;
287
+ type ParameterValueOf<D extends ParameterDefinition> = D extends {
288
+ options: readonly (infer O extends string)[];
289
+ } ? O : ParameterValueByType<D>;
261
290
  /** The `params` type a definition map gives the handler. */
262
291
  type InferParameters<P extends ParameterDefinitions> = {
263
292
  [K in keyof P]: ParameterValueOf<P[K]>;
264
293
  };
265
- /** One of the four reply shapes as the `{ output, session }` the result frame carries. */
294
+ /** One of the four reply shapes as the `{ output, session, state }` the result frame carries. */
266
295
  declare function normalizeReply(reply: unknown): AgentResult;
267
296
  /**
268
297
  * A schema library object (zod 4, valibot, arktype: anything with Standard
@@ -275,6 +304,20 @@ declare function connectAgent<const S extends StandardJsonSchema>(options: Conne
275
304
  declare function connectAgent<const P extends ParameterDefinitions = Record<string, never>>(options: ConnectAgentOptions<P>, handler: AgentHandler<InferParameters<P>>): ConnectedAgent<InferParameters<P>>;
276
305
  declare function connectAgent(options: ConnectAgentOptions<JsonSchemaObject>, handler: AgentHandler<Record<string, AgentParameterValue>>): ConnectedAgent<Record<string, AgentParameterValue>>;
277
306
 
307
+ /**
308
+ * The state a scenario hook or a turn answers with: a JSON object under the
309
+ * platform's cap (ADR-180).
310
+ * @see dev/docs/adr/180-scenario-run-hooks.md
311
+ */
312
+
313
+ /** The cap on a state and on teardown's returned object, the `session` cap. */
314
+ declare const STATE_MAX_BYTES: number;
315
+ /** A state the platform would refuse, answered with its own error code. */
316
+ declare class AgentStateError extends Error {
317
+ readonly code: "agent_call_failed" | "agent_payload_too_large";
318
+ constructor(code: "agent_call_failed" | "agent_payload_too_large", message: string);
319
+ }
320
+
278
321
  /**
279
322
  * Who and where a connected agent is: its environment, its instance identity
280
323
  * and the endpoint it connects to. Every read of the machine is defensive, so
@@ -308,4 +351,4 @@ declare function resolveConnectUrl(endpoint?: string | null): string;
308
351
  */
309
352
  declare function resolveHttpConnectUrl(endpoint?: string | null): string;
310
353
 
311
- export { AGENT_TRANSPORTS, type AgentCall, type AgentHandler, type AgentMessage, type AgentOutput, AgentParameterError, type AgentParameterValue, type AgentReply, type AgentResult, type AgentTransport, type ConnectAgentOptions, type ConnectedAgent, DEFAULT_TIMEOUT_MS, type DirectAgentCall, type InferParameters, type JsonSchemaObject, MAX_TIMEOUT_MS, PROTOCOL_VERSION, type ParameterDefinition, type ParameterDefinitions, type ParameterInput, type ParameterSpec, type ParameterType, type StandardJsonSchema, connectAgent, normalizeReply, parameterSpecsFromSchema, resolveConnectUrl, resolveEnvironment, resolveHttpConnectUrl, resolveTransport, sanitizeEnvironment, toParameterSchema };
354
+ export { AGENT_TRANSPORTS, type AgentCall, type AgentHandler, type AgentHooks, type AgentMessage, type AgentOutput, AgentParameterError, type AgentParameterValue, type AgentReply, type AgentResult, AgentStateError, type AgentTransport, type ConnectAgentOptions, type ConnectedAgent, DEFAULT_TIMEOUT_MS, type DirectAgentCall, type InferParameters, type JsonSchemaObject, MAX_TIMEOUT_MS, PROTOCOL_VERSION, type ParameterDefinition, type ParameterDefinitions, type ParameterInput, type ParameterSpec, type ParameterType, STATE_MAX_BYTES, type ScenarioHooks, type ScenarioRun, type ScenarioState, type SetupHook, type StandardJsonSchema, type TeardownHook, connectAgent, normalizeReply, parameterSpecsFromSchema, resolveConnectUrl, resolveEnvironment, resolveHttpConnectUrl, resolveTransport, sanitizeEnvironment, toParameterSchema };