@runtypelabs/sdk 9.9.1 → 9.10.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.
package/dist/index.cjs CHANGED
@@ -100,12 +100,14 @@ __export(index_exports, {
100
100
  attachRuntimeToolsToDispatchRequest: () => attachRuntimeToolsToDispatchRequest,
101
101
  buildAgentAdmissionHeaders: () => buildAgentAdmissionHeaders,
102
102
  buildEmptySessionNudge: () => buildEmptySessionNudge,
103
+ buildExecutionEventsPath: () => buildExecutionEventsPath,
103
104
  buildGeneratedRuntimeToolGateOutput: () => buildGeneratedRuntimeToolGateOutput,
104
105
  buildLedgerOffloadReference: () => buildLedgerOffloadReference,
105
106
  buildObservationMaskMarker: () => buildObservationMaskMarker,
106
107
  buildPolicyGuidance: () => buildPolicyGuidance,
107
108
  buildSendViewOffloadMarker: () => buildSendViewOffloadMarker,
108
109
  calledTool: () => calledTool,
110
+ combineAbortSignals: () => combineAbortSignals,
109
111
  compileWorkflowConfig: () => compileWorkflowConfig,
110
112
  completed: () => completed,
111
113
  computeAgentContentHash: () => computeAgentContentHash,
@@ -2832,11 +2834,12 @@ async function request(client, body) {
2832
2834
  }
2833
2835
  }
2834
2836
  async function ensureFlow(client, definition, options = {}) {
2835
- const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
2837
+ const { dryRun, onConflict, release, expectedRemoteHash, version, expectNoChanges } = options;
2836
2838
  const passthrough = {
2837
2839
  ...onConflict ? { onConflict } : {},
2838
2840
  ...release ? { release } : {},
2839
- ...expectedRemoteHash ? { expectedRemoteHash } : {}
2841
+ ...expectedRemoteHash ? { expectedRemoteHash } : {},
2842
+ ...version ? { version } : {}
2840
2843
  };
2841
2844
  const wireDefinition = { name: definition.name, steps: definition.steps };
2842
2845
  if (dryRun || expectNoChanges) {
@@ -5112,11 +5115,12 @@ var AgentsNamespace = class {
5112
5115
  */
5113
5116
  async ensure(definition, options = {}) {
5114
5117
  const client = this.getClient();
5115
- const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
5118
+ const { dryRun, onConflict, release, expectedRemoteHash, version, expectNoChanges } = options;
5116
5119
  const passthrough = {
5117
5120
  ...onConflict ? { onConflict } : {},
5118
5121
  ...release ? { release } : {},
5119
- ...expectedRemoteHash ? { expectedRemoteHash } : {}
5122
+ ...expectedRemoteHash ? { expectedRemoteHash } : {},
5123
+ ...version ? { version } : {}
5120
5124
  };
5121
5125
  if (dryRun || expectNoChanges) {
5122
5126
  const plan = await this.request(client, {
@@ -5963,542 +5967,51 @@ function normalizeDispatchRequest(request6) {
5963
5967
  return request6.flow ? { ...normalized, flow: request6.flow } : { ...normalized, agent: request6.agent };
5964
5968
  }
5965
5969
 
5966
- // src/runtype.ts
5967
- var globalConfig = {};
5968
- var globalClient = null;
5969
- var RuntypeClient = class {
5970
- constructor(config = {}) {
5971
- const baseUrl = config.baseUrl || "https://api.runtype.com";
5972
- this.apiVersion = config.apiVersion || "v1";
5973
- this.baseUrl = this.apiVersion ? `${baseUrl}/${this.apiVersion}` : baseUrl;
5974
- this.timeout = config.timeout || 3e4;
5975
- this.headers = {
5976
- "Content-Type": "application/json",
5977
- ...config.headers || {}
5978
- };
5979
- if (config.apiKey) {
5980
- this.headers.Authorization = `Bearer ${config.apiKey}`;
5981
- }
5982
- }
5983
- /**
5984
- * Set the API key for authentication
5985
- */
5986
- setApiKey(apiKey) {
5987
- this.headers.Authorization = `Bearer ${apiKey}`;
5988
- }
5989
- /**
5990
- * Generic GET request
5991
- */
5992
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts typed list-param interfaces (no index signature); `unknown` would reject them
5993
- async get(path, params) {
5994
- const url = this.buildUrl(path, params);
5995
- const response = await this.makeRequest(url, {
5996
- method: "GET",
5997
- headers: this.headers
5998
- });
5999
- return response;
6000
- }
6001
- /**
6002
- * Generic POST request
6003
- */
6004
- async post(path, data, extraHeaders) {
6005
- const url = this.buildUrl(path);
6006
- const response = await this.makeRequest(url, {
6007
- method: "POST",
6008
- headers: { ...this.headers, ...extraHeaders },
6009
- body: data ? JSON.stringify(data) : void 0
6010
- });
6011
- return response;
6012
- }
6013
- /**
6014
- * Generic PUT request
6015
- */
6016
- async put(path, data) {
6017
- const url = this.buildUrl(path);
6018
- const response = await this.makeRequest(url, {
6019
- method: "PUT",
6020
- headers: this.headers,
6021
- body: data ? JSON.stringify(data) : void 0
6022
- });
6023
- return response;
6024
- }
6025
- /**
6026
- * Generic PATCH request
6027
- */
6028
- async patch(path, data) {
6029
- const url = this.buildUrl(path);
6030
- const response = await this.makeRequest(url, {
6031
- method: "PATCH",
6032
- headers: this.headers,
6033
- body: data ? JSON.stringify(data) : void 0
6034
- });
6035
- return response;
6036
- }
6037
- /**
6038
- * Generic DELETE request
6039
- */
6040
- async delete(path) {
6041
- const url = this.buildUrl(path);
6042
- const response = await this.makeRequest(url, {
6043
- method: "DELETE",
6044
- headers: this.headers
6045
- });
6046
- return response;
6047
- }
6048
- /**
6049
- * Generic request that returns raw Response for streaming
6050
- */
6051
- async requestStream(path, options = {}) {
6052
- const url = this.buildUrl(path);
6053
- const headers = {
6054
- ...this.headers,
6055
- ...options.headers
6056
- };
6057
- return this.makeRawRequest(url, {
6058
- ...options,
6059
- headers
6060
- });
6061
- }
6062
- /**
6063
- * Dispatch flow execution (streaming).
6064
- *
6065
- * This is the sole streaming-dispatch chokepoint for the flow builders
6066
- * (`RuntypeFlowBuilder`), so it normalizes the request to the canonical
6067
- * `/v1/dispatch` wire contract here — every builder path inherits the same
6068
- * normalization the `DispatchEndpoint` applies, with no per-builder call.
6069
- */
6070
- async dispatch(config) {
6071
- const normalized = normalizeDispatchRequest(config);
6072
- const request6 = {
6073
- ...normalized,
6074
- options: {
6075
- ...normalized.options,
6076
- streamResponse: true
6077
- }
6078
- };
6079
- return this.requestStream("/dispatch", {
6080
- method: "POST",
6081
- body: JSON.stringify(request6)
6082
- });
6083
- }
6084
- /**
6085
- * Dispatch flow execution (non-streaming JSON).
6086
- *
6087
- * The non-streaming sibling of {@link dispatch}; it normalizes to the same
6088
- * canonical wire contract so builders never post a raw, un-normalized body,
6089
- * and pins `streamResponse: false` so the server returns buffered JSON.
6090
- */
6091
- async dispatchJson(config) {
6092
- const normalized = normalizeDispatchRequest(config);
6093
- return this.post("/dispatch", {
6094
- ...normalized,
6095
- options: {
6096
- ...normalized.options,
6097
- streamResponse: false
6098
- }
6099
- });
6100
- }
6101
- /** Start a normalized dispatch and return a durable handle immediately. */
6102
- async dispatchAsync(config) {
6103
- const normalized = normalizeDispatchRequest(config);
6104
- return this.post(
6105
- "/dispatch",
6106
- {
6107
- ...normalized,
6108
- options: { ...normalized.options, streamResponse: false }
6109
- },
6110
- { Prefer: "respond-async" }
6111
- );
6112
- }
6113
- async getExecutionStatus(executionId) {
6114
- return this.get(`/executions/${encodeURIComponent(executionId)}/status`);
6115
- }
6116
- /**
6117
- * Build full URL with query parameters
6118
- */
6119
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- mirrors get()'s permissive params type
6120
- buildUrl(path, params) {
6121
- const base = this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`;
6122
- const relPath = path.startsWith("/") ? path.slice(1) : path;
6123
- const url = new URL(relPath, base);
6124
- if (params) {
6125
- Object.entries(params).forEach(([key, value]) => {
6126
- if (value !== void 0 && value !== null) {
6127
- url.searchParams.set(key, String(value));
6128
- }
6129
- });
5970
+ // src/detached-reconnect.ts
5971
+ var TERMINAL_EVENTS = /* @__PURE__ */ new Set(["execution_complete", "execution_error"]);
5972
+ var DEFAULT_MAX_DETACHED_RECONNECTS = 12;
5973
+ function combineAbortSignals(...signals) {
5974
+ const present = signals.filter((signal) => Boolean(signal));
5975
+ if (present.length === 0) return void 0;
5976
+ if (present.length === 1) return present[0];
5977
+ const anySignal = AbortSignal.any;
5978
+ if (typeof anySignal === "function") return anySignal.call(AbortSignal, present);
5979
+ const controller = new AbortController();
5980
+ for (const signal of present) {
5981
+ if (signal.aborted) {
5982
+ controller.abort(signal.reason);
5983
+ break;
6130
5984
  }
6131
- return url.toString();
5985
+ signal.addEventListener("abort", () => controller.abort(signal.reason), { once: true });
6132
5986
  }
6133
- /**
6134
- * Make HTTP request with timeout and error handling
6135
- */
6136
- async makeRequest(url, options) {
6137
- const response = await this.makeRawRequest(url, options);
6138
- if (response.status === 204) {
6139
- return null;
5987
+ return controller.signal;
5988
+ }
5989
+ function observeBlock(block, into) {
5990
+ let eventName = null;
5991
+ for (const line of block.split("\n")) {
5992
+ if (line.startsWith("id:")) {
5993
+ into.lastId = line.slice(3).trim();
5994
+ continue;
6140
5995
  }
6141
- const contentType = response.headers.get("content-type");
6142
- if (contentType?.includes("application/json")) {
6143
- return response.json();
5996
+ if (line.startsWith("event:")) {
5997
+ eventName = line.slice(6).trim();
5998
+ continue;
6144
5999
  }
6145
- return response.text();
6146
- }
6147
- /**
6148
- * Make HTTP request that returns raw Response (for streaming)
6149
- */
6150
- async makeRawRequest(url, options) {
6151
- const controller = new AbortController();
6152
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
6000
+ if (!line.startsWith("data:")) continue;
6001
+ const raw = line.slice(5).trim();
6002
+ if (!raw || raw === "[DONE]") continue;
6003
+ let payload;
6153
6004
  try {
6154
- const response = await fetch(url, {
6155
- ...options,
6156
- signal: controller.signal
6157
- });
6158
- clearTimeout(timeoutId);
6159
- if (!response.ok) {
6160
- const errorText = await response.text();
6161
- throw new Error(
6162
- `API request failed: ${response.status} ${response.statusText} - ${errorText}`
6163
- );
6164
- }
6165
- return response;
6166
- } catch (error) {
6167
- clearTimeout(timeoutId);
6168
- if (error instanceof Error && error.name === "AbortError") {
6169
- throw new Error(`Request timeout after ${this.timeout}ms`, { cause: error });
6170
- }
6171
- throw error;
6172
- }
6173
- }
6174
- };
6175
- var Runtype = class {
6176
- /**
6177
- * Configure the global Runtype client
6178
- *
6179
- * Call this once at app startup to set the API key and other options.
6180
- * All subsequent calls to Runtype.flows, Runtype.batches, etc. will use this config.
6181
- *
6182
- * @example
6183
- * ```typescript
6184
- * Runtype.configure({ apiKey: process.env.RUNTYPE_API_KEY })
6185
- * ```
6186
- */
6187
- static configure(config) {
6188
- globalConfig = { ...globalConfig, ...config };
6189
- globalClient = new RuntypeClient(globalConfig);
6190
- }
6191
- /**
6192
- * Get the global client instance, creating one if needed
6193
- */
6194
- static getClient() {
6195
- if (!globalClient) {
6196
- globalClient = new RuntypeClient(globalConfig);
6005
+ const parsed = JSON.parse(raw);
6006
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) continue;
6007
+ payload = parsed;
6008
+ } catch {
6009
+ continue;
6197
6010
  }
6198
- return globalClient;
6199
- }
6200
- /**
6201
- * Create a new client instance with custom configuration
6202
- *
6203
- * Use this when you need a client with different settings than the global one.
6204
- *
6205
- * @example
6206
- * ```typescript
6207
- * const client = Runtype.createClient({ apiKey: 'different_key' })
6208
- * ```
6209
- */
6210
- static createClient(config) {
6211
- return new RuntypeClient({ ...globalConfig, ...config });
6212
- }
6213
- /**
6214
- * Flows namespace - Build and execute flows
6215
- *
6216
- * @example
6217
- * ```typescript
6218
- * // Upsert a flow (create or update)
6219
- * const result = await Runtype.flows.upsert({ name: 'My Flow' })
6220
- * .prompt({ name: 'Analyze', model: 'gpt-4o', userPrompt: '...' })
6221
- * .stream()
6222
- *
6223
- * // Use an existing flow
6224
- * const result = await Runtype.flows.use('flow_123')
6225
- * .withRecord({ name: 'Test' })
6226
- * .result()
6227
- *
6228
- * // Virtual flow (one-off, not saved)
6229
- * const result = await Runtype.flows.virtual({ name: 'Temp Flow' })
6230
- * .prompt({ ... })
6231
- * .stream()
6232
- * ```
6233
- */
6234
- static get flows() {
6235
- return new FlowsNamespace(() => this.getClient());
6236
- }
6237
- /**
6238
- * Batches namespace - Schedule and manage batch operations
6239
- *
6240
- * @example
6241
- * ```typescript
6242
- * // Schedule a batch
6243
- * const batch = await Runtype.batches.schedule({
6244
- * flowId: 'flow_123',
6245
- * recordType: 'customers',
6246
- * })
6247
- *
6248
- * // Get batch status
6249
- * const status = await Runtype.batches.get('batch_456')
6250
- *
6251
- * // Cancel a batch
6252
- * await Runtype.batches.cancel('batch_456')
6253
- *
6254
- * // List batches
6255
- * const batches = await Runtype.batches.list({ status: 'running' })
6256
- * ```
6257
- */
6258
- static get batches() {
6259
- return new BatchesNamespace(() => this.getClient());
6260
- }
6261
- /**
6262
- * Evals namespace - Run evaluations and compare models
6263
- *
6264
- * @example
6265
- * ```typescript
6266
- * // Run an eval with streaming
6267
- * const stream = await Runtype.evals.run({
6268
- * flowId: 'flow_123',
6269
- * recordType: 'test_data',
6270
- * models: [{ stepName: 'Analyze', model: 'gpt-4o' }]
6271
- * }).stream()
6272
- *
6273
- * // Submit eval as batch job
6274
- * const eval = await Runtype.evals.run({
6275
- * flowId: 'flow_123',
6276
- * recordType: 'test_data',
6277
- * models: [
6278
- * [{ stepName: 'Analyze', model: 'gpt-5.4' }],
6279
- * [{ stepName: 'Analyze', model: 'claude-opus-4-6' }],
6280
- * ]
6281
- * }).submit()
6282
- * ```
6283
- */
6284
- static get evals() {
6285
- return new EvalsNamespace(() => this.getClient());
6286
- }
6287
- /**
6288
- * Prompts namespace - Manage and execute prompts
6289
- *
6290
- * @example
6291
- * ```typescript
6292
- * // Execute a prompt with streaming
6293
- * const stream = await Runtype.prompts.run('prompt_123', {
6294
- * recordId: 'rec_456'
6295
- * }).stream()
6296
- *
6297
- * // Get complete result
6298
- * const result = await Runtype.prompts.run('prompt_123', {
6299
- * recordId: 'rec_456'
6300
- * }).result()
6301
- *
6302
- * // CRUD operations
6303
- * const prompts = await Runtype.prompts.list()
6304
- * const prompt = await Runtype.prompts.get('prompt_123')
6305
- * const newPrompt = await Runtype.prompts.create({ ... })
6306
- * await Runtype.prompts.update('prompt_123', { ... })
6307
- * await Runtype.prompts.delete('prompt_123')
6308
- * ```
6309
- */
6310
- static get prompts() {
6311
- return new PromptsNamespace(() => this.getClient());
6312
- }
6313
- /**
6314
- * Skills namespace - Manage Agent Skills (admin/control plane)
6315
- *
6316
- * @example
6317
- * ```typescript
6318
- * // Create a published skill from a SKILL.md document
6319
- * const { skill } = await Runtype.skills.create({ markdown: skillMd, publish: true })
6320
- *
6321
- * // Bind it to an agent
6322
- * await Runtype.skills.bind({ agentId: 'agent_123', skillId: skill.id })
6323
- *
6324
- * // Review agent-authored proposals
6325
- * const pending = await Runtype.skills.proposals.list()
6326
- * await Runtype.skills.proposals.approve(pending[0].id)
6327
- * ```
6328
- */
6329
- static get skills() {
6330
- return new SkillsNamespace(() => this.getClient());
6331
- }
6332
- /**
6333
- * Agents namespace - Agent config-as-code (define / ensure / pull)
6334
- *
6335
- * @example
6336
- * ```typescript
6337
- * import { defineAgent, Runtype } from '@runtypelabs/sdk'
6338
- *
6339
- * const assistant = defineAgent({
6340
- * name: 'Pricing Assistant',
6341
- * model: 'claude-sonnet-4-6',
6342
- * systemPrompt: renderPrompt(pricingData),
6343
- * })
6344
- *
6345
- * // Converge at deploy time (idempotent; one tiny probe in steady state)
6346
- * await Runtype.agents.ensure(assistant)
6347
- *
6348
- * // CI drift gate
6349
- * await Runtype.agents.ensure(assistant, { expectNoChanges: true })
6350
- *
6351
- * // Absorb a dashboard edit back into the repo
6352
- * const { definition } = await Runtype.agents.pull('Pricing Assistant')
6353
- * ```
6354
- */
6355
- static get agents() {
6356
- return new AgentsNamespace(() => this.getClient());
6357
- }
6358
- /** Poll durable handles returned by asynchronous execute operations. */
6359
- static get executions() {
6360
- return new ExecutionsNamespace(() => this.getClient());
6361
- }
6362
- /**
6363
- * Tools namespace - Tool config-as-code (define / ensure / pull)
6364
- *
6365
- * @example
6366
- * ```typescript
6367
- * import { defineTool, Runtype } from '@runtypelabs/sdk'
6368
- *
6369
- * const weather = defineTool({
6370
- * name: 'Weather Lookup',
6371
- * description: 'Fetch the current weather for a city',
6372
- * toolType: 'external',
6373
- * parametersSchema: { type: 'object', properties: { city: { type: 'string' } } },
6374
- * config: { url: 'https://api.example.com/weather', method: 'GET' },
6375
- * })
6376
- *
6377
- * // Converge at deploy time (idempotent; one tiny probe in steady state)
6378
- * await Runtype.tools.ensure(weather)
6379
- *
6380
- * // CI drift gate
6381
- * await Runtype.tools.ensure(weather, { expectNoChanges: true })
6382
- *
6383
- * // Absorb a dashboard edit back into the repo
6384
- * const { definition } = await Runtype.tools.pull('Weather Lookup')
6385
- * ```
6386
- */
6387
- static get tools() {
6388
- return new ToolsNamespace(() => this.getClient());
6389
- }
6390
- /**
6391
- * Products namespace - Product config-as-code (define / ensure / pull)
6392
- *
6393
- * Converges the top-level product record (description, icon, spec). Nested
6394
- * capabilities/surfaces/tools and the canvas UI layout state are not
6395
- * converged by ensure.
6396
- *
6397
- * @example
6398
- * ```typescript
6399
- * import { defineProduct, Runtype } from '@runtypelabs/sdk'
6400
- *
6401
- * const product = defineProduct({
6402
- * name: 'Support Copilot',
6403
- * description: 'An AI support assistant',
6404
- * icon: '🤖',
6405
- * spec: { productGoal: 'Deflect tier-1 tickets', productStage: 'beta' },
6406
- * })
6407
- *
6408
- * // Converge at deploy time (idempotent; one tiny probe in steady state)
6409
- * await Runtype.products.ensure(product)
6410
- *
6411
- * // CI drift gate
6412
- * await Runtype.products.ensure(product, { expectNoChanges: true })
6413
- *
6414
- * // Absorb a dashboard edit back into the repo
6415
- * const { definition } = await Runtype.products.pull('Support Copilot')
6416
- * ```
6417
- */
6418
- static get products() {
6419
- return new ProductsNamespace(() => this.getClient());
6420
- }
6421
- /**
6422
- * Config-as-code operations for product surfaces. `surfaces.ensure` is the
6423
- * deploy-time, non-executing converge (create-or-update a surface by name
6424
- * within a product); `surfaces.pull` is the absorb-drift direction.
6425
- *
6426
- * @example
6427
- * ```typescript
6428
- * import { Runtype, defineSurface } from '@runtypelabs/sdk'
6429
- *
6430
- * const chat = defineSurface({
6431
- * name: 'Support Chat',
6432
- * type: 'chat',
6433
- * behavior: { type: 'chat', greeting: 'Hi there!' },
6434
- * status: 'active',
6435
- * })
6436
- *
6437
- * // Converge at deploy time (idempotent; one tiny probe in steady state)
6438
- * await Runtype.surfaces.ensure('product_abc', chat)
6439
- *
6440
- * // CI drift gate
6441
- * await Runtype.surfaces.ensure('product_abc', chat, { expectNoChanges: true })
6442
- *
6443
- * // Absorb a dashboard edit back into the repo
6444
- * const { definition } = await Runtype.surfaces.pull('product_abc', 'Support Chat')
6445
- * ```
6446
- */
6447
- static get surfaces() {
6448
- return new SurfacesNamespace(() => this.getClient());
6449
- }
6450
- };
6451
-
6452
- // src/transform.ts
6453
- function transformQueryParams(params) {
6454
- const result = {};
6455
- for (const [key, value] of Object.entries(params)) {
6456
- if (value !== void 0 && value !== null) {
6457
- if (Array.isArray(value)) {
6458
- result[key] = value.join(",");
6459
- } else {
6460
- result[key] = String(value);
6461
- }
6462
- }
6463
- }
6464
- return result;
6465
- }
6466
-
6467
- // src/version.ts
6468
- var FALLBACK_VERSION = "0.0.0";
6469
- var SDK_VERSION = "9.9.1".length > 0 ? "9.9.1" : FALLBACK_VERSION;
6470
- var RUNTYPE_CLIENT_KIND = "sdk";
6471
- var SDK_USER_AGENT = `runtype-sdk/${SDK_VERSION} (typescript)`;
6472
-
6473
- // src/detached-reconnect.ts
6474
- var TERMINAL_EVENTS = /* @__PURE__ */ new Set(["execution_complete", "execution_error"]);
6475
- var DEFAULT_MAX_DETACHED_RECONNECTS = 12;
6476
- function observeBlock(block, into) {
6477
- let eventName = null;
6478
- for (const line of block.split("\n")) {
6479
- if (line.startsWith("id:")) {
6480
- into.lastId = line.slice(3).trim();
6481
- continue;
6482
- }
6483
- if (line.startsWith("event:")) {
6484
- eventName = line.slice(6).trim();
6485
- continue;
6486
- }
6487
- if (!line.startsWith("data:")) continue;
6488
- const raw = line.slice(5).trim();
6489
- if (!raw || raw === "[DONE]") continue;
6490
- let payload;
6491
- try {
6492
- const parsed = JSON.parse(raw);
6493
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) continue;
6494
- payload = parsed;
6495
- } catch {
6496
- continue;
6497
- }
6498
- if (typeof payload.executionId === "string") into.executionId = payload.executionId;
6499
- const type = typeof payload.type === "string" ? payload.type : eventName;
6500
- if (type && TERMINAL_EVENTS.has(type)) into.sawTerminal = true;
6501
- if (type === "await" && payload.awaitReason === "detached") into.sawDetach = true;
6011
+ if (typeof payload.executionId === "string") into.executionId = payload.executionId;
6012
+ const type = typeof payload.type === "string" ? payload.type : eventName;
6013
+ if (type && TERMINAL_EVENTS.has(type)) into.sawTerminal = true;
6014
+ if (type === "await" && payload.awaitReason === "detached") into.sawDetach = true;
6502
6015
  }
6503
6016
  }
6504
6017
  function withDetachedReconnect(response, reattach, options = {}) {
@@ -8705,6 +8218,13 @@ function buildEmptySessionNudge(consecutiveEmptySessions) {
8705
8218
  }
8706
8219
 
8707
8220
  // src/endpoints.ts
8221
+ function buildExecutionEventsPath(executionId, query = {}) {
8222
+ const params = new URLSearchParams();
8223
+ if (query.after) params.set("after", query.after);
8224
+ if (query.conversationId) params.set("conversationId", query.conversationId);
8225
+ const search = params.toString();
8226
+ return `/executions/${encodeURIComponent(executionId)}/events${search ? `?${search}` : ""}`;
8227
+ }
8708
8228
  var FlowsEndpoint = class {
8709
8229
  constructor(client) {
8710
8230
  this.client = client;
@@ -9388,10 +8908,15 @@ var DispatchEndpoint = class {
9388
8908
  }
9389
8909
  /**
9390
8910
  * Dispatch with streaming response
8911
+ *
8912
+ * A dispatched agent turn runs on the durable lane, so its socket can close
8913
+ * with `await` / `awaitReason: 'detached'` while the run continues. The
8914
+ * stream follows that detach through the execution-scoped events alias;
8915
+ * `autoReconnect: false` hands back the raw stream instead.
9391
8916
  */
9392
- async executeStream(data) {
8917
+ async executeStream(data, init) {
9393
8918
  const normalized = normalizeDispatchRequest(data);
9394
- return this.client.requestStream("/dispatch", {
8919
+ const response = await this.client.requestStream("/dispatch", {
9395
8920
  method: "POST",
9396
8921
  body: JSON.stringify({
9397
8922
  ...normalized,
@@ -9399,8 +8924,32 @@ var DispatchEndpoint = class {
9399
8924
  ...normalized.options,
9400
8925
  streamResponse: true
9401
8926
  }
9402
- })
8927
+ }),
8928
+ ...init?.signal ? { signal: init.signal } : {}
9403
8929
  });
8930
+ return withDetachedReconnect(
8931
+ response,
8932
+ this.buildDetachedReattach(normalized, init?.signal),
8933
+ init ?? {}
8934
+ );
8935
+ }
8936
+ /**
8937
+ * The `?after=` reattach leg a detached dispatch stream is followed with.
8938
+ *
8939
+ * Unlike an agent execute, a dispatch knows no agent id at the call site, so
8940
+ * it rejoins by execution id alone through the execution-scoped alias. The
8941
+ * cursor is the last SSE `id:` the stream delivered, forwarded verbatim.
8942
+ */
8943
+ buildDetachedReattach(data, signal) {
8944
+ return async ({ executionId, after, signal: reattachSignal }) => {
8945
+ const named = data?.conversationId;
8946
+ const conversationId = typeof named === "string" && named ? named : void 0;
8947
+ const legSignal = combineAbortSignals(signal, reattachSignal);
8948
+ return this.client.requestStream(buildExecutionEventsPath(executionId, { after, conversationId }), {
8949
+ method: "GET",
8950
+ ...legSignal ? { signal: legSignal } : {}
8951
+ }).catch(() => null);
8952
+ };
9404
8953
  }
9405
8954
  /**
9406
8955
  * Resume paused flow execution
@@ -9534,6 +9083,14 @@ var AnalyticsEndpoint = class {
9534
9083
  async getEndUserUsage(params) {
9535
9084
  return this.client.get("/analytics/end-user-usage", params);
9536
9085
  }
9086
+ /**
9087
+ * Get reliability, latency, unit economics, and eval health for the current
9088
+ * period against the preceding period of equal length, plus a derived feed of
9089
+ * notable changes.
9090
+ */
9091
+ async getProductionHealth(params) {
9092
+ return this.client.get("/analytics/production-health", params);
9093
+ }
9537
9094
  };
9538
9095
  var FlowStepsEndpoint = class {
9539
9096
  constructor(client) {
@@ -9744,7 +9301,7 @@ var ToolsEndpoint = class {
9744
9301
  return this.client.get(`/tools/builtin/${toolId}/schema`);
9745
9302
  }
9746
9303
  /**
9747
- * Deploy code to a persistent Daytona sandbox and get a preview URL
9304
+ * Deploy a Daytona preview; retention defaults to ten minutes and the URL is not durable hosting.
9748
9305
  */
9749
9306
  async deploySandbox(data) {
9750
9307
  return this.client.post("/tools/sandbox/deploy", data);
@@ -9756,7 +9313,7 @@ var ToolsEndpoint = class {
9756
9313
  return this.client.delete(`/tools/sandbox/${sandboxId}`);
9757
9314
  }
9758
9315
  /**
9759
- * Deploy code to a persistent Cloudflare Sandbox container and get a preview URL
9316
+ * Deploy a Runtype Sandbox preview; omitted retention preserves the legacy unlimited backstop.
9760
9317
  */
9761
9318
  async deployCfSandbox(data) {
9762
9319
  return this.client.post("/tools/sandbox/cf-sandbox/deploy", data);
@@ -10215,14 +9772,15 @@ var _AgentsEndpoint = class _AgentsEndpoint {
10215
9772
  * conversation-key behavior.
10216
9773
  */
10217
9774
  buildDetachedReattach(id, data, signal) {
10218
- return async ({ executionId, after }) => {
9775
+ return async ({ executionId, after, signal: reattachSignal }) => {
10219
9776
  const named = data?.conversationId;
10220
9777
  const conversationId = typeof named === "string" ? named : "";
10221
9778
  const query = new URLSearchParams({ after });
10222
9779
  if (conversationId) query.set("conversationId", conversationId);
9780
+ const legSignal = combineAbortSignals(signal, reattachSignal);
10223
9781
  return this.client.requestStream(`/agents/${id}/executions/${executionId}/events?${query.toString()}`, {
10224
9782
  method: "GET",
10225
- ...signal ? { signal } : {}
9783
+ ...legSignal ? { signal: legSignal } : {}
10226
9784
  }).catch(() => null);
10227
9785
  };
10228
9786
  }
@@ -13152,189 +12710,741 @@ var AgentVersionsEndpoint = class {
13152
12710
  return this.client.get(`/agent-versions/${agentId}/${versionId}`);
13153
12711
  }
13154
12712
  /**
13155
- * Publish a version (promote it to the agent's published version).
12713
+ * Publish a version (promote it to the agent's published version).
12714
+ */
12715
+ async publish(agentId, versionId, options = {}) {
12716
+ return this.client.post(`/agent-versions/${agentId}/publish`, {
12717
+ versionId,
12718
+ ...options
12719
+ });
12720
+ }
12721
+ };
12722
+ var FlowVersionsEndpoint = class {
12723
+ constructor(client) {
12724
+ this.client = client;
12725
+ }
12726
+ /**
12727
+ * List versions for a flow, optionally filtered by version `type`.
12728
+ */
12729
+ async list(flowId, params) {
12730
+ return this.client.get(`/flow-versions/${flowId}`, params);
12731
+ }
12732
+ /**
12733
+ * Get the published version for a flow.
12734
+ */
12735
+ async getPublished(flowId) {
12736
+ return this.client.get(`/flow-versions/${flowId}/published`);
12737
+ }
12738
+ /**
12739
+ * Get a specific version of a flow.
12740
+ */
12741
+ async get(flowId, versionId) {
12742
+ return this.client.get(`/flow-versions/${flowId}/${versionId}`);
12743
+ }
12744
+ /**
12745
+ * Publish a version (promote it to the flow's published version).
12746
+ */
12747
+ async publish(flowId, versionId, options = {}) {
12748
+ return this.client.post(`/flow-versions/${flowId}/publish`, {
12749
+ versionId,
12750
+ ...options
12751
+ });
12752
+ }
12753
+ };
12754
+ var IntegrationsEndpoint = class {
12755
+ constructor(client) {
12756
+ this.client = client;
12757
+ }
12758
+ /**
12759
+ * List all integrations with the caller's per-integration configuration status.
12760
+ */
12761
+ async list(params) {
12762
+ return this.client.get("/integrations", params);
12763
+ }
12764
+ /**
12765
+ * Get a single integration by ID.
12766
+ */
12767
+ async get(integrationId) {
12768
+ return this.client.get(`/integrations/${integrationId}`);
12769
+ }
12770
+ /**
12771
+ * List integrations within a category (e.g. `slack`, `mcp`).
12772
+ */
12773
+ async listByCategory(category) {
12774
+ return this.client.get(
12775
+ `/integrations/category/${category}`
12776
+ );
12777
+ }
12778
+ /**
12779
+ * Per-environment credential status across the caller's integrations.
12780
+ */
12781
+ async getCredentialsStatus() {
12782
+ return this.client.get("/integrations/credentials-status");
12783
+ }
12784
+ /**
12785
+ * List all tools exposed across the caller's configured integrations.
12786
+ */
12787
+ async listTools() {
12788
+ return this.client.get("/integrations/tools");
12789
+ }
12790
+ /**
12791
+ * List the tools exposed by a single integration.
12792
+ */
12793
+ async getIntegrationTools(integrationId) {
12794
+ return this.client.get(
12795
+ `/integrations/${integrationId}/tools`
12796
+ );
12797
+ }
12798
+ /**
12799
+ * Get the definition of a single tool within an integration.
12800
+ */
12801
+ async getTool(integrationId, toolName) {
12802
+ return this.client.get(`/integrations/${integrationId}/tools/${toolName}`);
12803
+ }
12804
+ /**
12805
+ * Install a Slack integration from a completed OAuth handshake.
12806
+ */
12807
+ async installSlack(data) {
12808
+ return this.client.post("/integrations/slack/install", data);
12809
+ }
12810
+ /**
12811
+ * Start the Slack "Add to Slack" OAuth handshake. Returns the Slack authorize
12812
+ * URL to open in a popup; the bot token is captured server-side by the
12813
+ * callback (never returned to the browser).
12814
+ */
12815
+ async startSlackOAuth(data) {
12816
+ return this.client.post("/oauth/slack/start", data);
12817
+ }
12818
+ /**
12819
+ * Generate the Slack app manifest for a surface, plus a link to Slack's
12820
+ * app-creation page. The manifest carries absolute API URLs derived
12821
+ * server-side, so it is always valid for Slack (relative proxy paths never
12822
+ * leak in). Slack's create-app modal ignores a manifest passed in the URL, so
12823
+ * `manifestJson` is pasted into its "From a manifest" option rather than
12824
+ * embedded in `createAppUrl`.
12825
+ */
12826
+ async generateSlackManifest(data) {
12827
+ return this.client.post("/integrations/slack/manifest", data);
12828
+ }
12829
+ /**
12830
+ * Report whether Slack has verified a surface's events URL. Slack sends that
12831
+ * challenge when an app is created from a manifest, so a `verifiedAt` newer
12832
+ * than the one read before the manifest was handed out is evidence the app
12833
+ * now exists. Markers expire after an hour.
12834
+ */
12835
+ async getSlackAppStatus(surfaceId) {
12836
+ return this.client.get(
12837
+ `/integrations/slack/app-status?surfaceId=${encodeURIComponent(surfaceId)}`
12838
+ );
12839
+ }
12840
+ };
12841
+ var BillingEndpoint = class {
12842
+ constructor(client) {
12843
+ this.client = client;
12844
+ }
12845
+ /**
12846
+ * Get the caller's subscription status, plan limits, and current usage.
12847
+ */
12848
+ async getStatus() {
12849
+ return this.client.get("/billing/status");
12850
+ }
12851
+ /**
12852
+ * Get the caller's credit grants and available/used totals.
12853
+ */
12854
+ async getCredits() {
12855
+ return this.client.get("/billing/credits");
12856
+ }
12857
+ /**
12858
+ * Get the caller's exact current UTC-month platform spend from the local
12859
+ * meter used for spend-cap enforcement. Returns 503 when that meter is unavailable.
12860
+ */
12861
+ async getCurrentSpend() {
12862
+ return this.client.get("/billing/current-spend");
12863
+ }
12864
+ /**
12865
+ * Get spend analytics. The window is controlled by either `period` or `days`
12866
+ * (1–365, defaults to 30).
12867
+ */
12868
+ async getSpendAnalytics(params) {
12869
+ return this.client.get("/billing/spend-analytics", params);
12870
+ }
12871
+ };
12872
+ var ToolApprovalGrantsEndpoint = class {
12873
+ constructor(client) {
12874
+ this.client = client;
12875
+ }
12876
+ /**
12877
+ * List active remembered tool-approval grants for the authenticated owner,
12878
+ * optionally filtered to a single agent.
12879
+ */
12880
+ async list(agentId) {
12881
+ const query = agentId ? `?agentId=${encodeURIComponent(agentId)}` : "";
12882
+ const response = await this.client.get(
12883
+ `/tool-approval-grants${query}`
12884
+ );
12885
+ return response.data;
12886
+ }
12887
+ /**
12888
+ * Revoke (soft-delete) a remembered grant so the tool prompts for approval
12889
+ * again on future dispatches.
12890
+ */
12891
+ async revoke(id) {
12892
+ return this.client.delete(`/tool-approval-grants/${id}`);
12893
+ }
12894
+ };
12895
+
12896
+ // src/runtype.ts
12897
+ var globalConfig = {};
12898
+ var globalClient = null;
12899
+ var RuntypeClient = class {
12900
+ constructor(config = {}) {
12901
+ const baseUrl = config.baseUrl || "https://api.runtype.com";
12902
+ this.apiVersion = config.apiVersion || "v1";
12903
+ this.baseUrl = this.apiVersion ? `${baseUrl}/${this.apiVersion}` : baseUrl;
12904
+ this.timeout = config.timeout || 3e4;
12905
+ this.headers = {
12906
+ "Content-Type": "application/json",
12907
+ ...config.headers || {}
12908
+ };
12909
+ if (config.apiKey) {
12910
+ this.headers.Authorization = `Bearer ${config.apiKey}`;
12911
+ }
12912
+ }
12913
+ /**
12914
+ * Set the API key for authentication
12915
+ */
12916
+ setApiKey(apiKey) {
12917
+ this.headers.Authorization = `Bearer ${apiKey}`;
12918
+ }
12919
+ /**
12920
+ * Generic GET request
12921
+ */
12922
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts typed list-param interfaces (no index signature); `unknown` would reject them
12923
+ async get(path, params) {
12924
+ const url = this.buildUrl(path, params);
12925
+ const response = await this.makeRequest(url, {
12926
+ method: "GET",
12927
+ headers: this.headers
12928
+ });
12929
+ return response;
12930
+ }
12931
+ /**
12932
+ * Generic POST request
12933
+ */
12934
+ async post(path, data, extraHeaders) {
12935
+ const url = this.buildUrl(path);
12936
+ const response = await this.makeRequest(url, {
12937
+ method: "POST",
12938
+ headers: { ...this.headers, ...extraHeaders },
12939
+ body: data ? JSON.stringify(data) : void 0
12940
+ });
12941
+ return response;
12942
+ }
12943
+ /**
12944
+ * Generic PUT request
12945
+ */
12946
+ async put(path, data) {
12947
+ const url = this.buildUrl(path);
12948
+ const response = await this.makeRequest(url, {
12949
+ method: "PUT",
12950
+ headers: this.headers,
12951
+ body: data ? JSON.stringify(data) : void 0
12952
+ });
12953
+ return response;
12954
+ }
12955
+ /**
12956
+ * Generic PATCH request
13156
12957
  */
13157
- async publish(agentId, versionId, options = {}) {
13158
- return this.client.post(`/agent-versions/${agentId}/publish`, {
13159
- versionId,
13160
- ...options
12958
+ async patch(path, data) {
12959
+ const url = this.buildUrl(path);
12960
+ const response = await this.makeRequest(url, {
12961
+ method: "PATCH",
12962
+ headers: this.headers,
12963
+ body: data ? JSON.stringify(data) : void 0
13161
12964
  });
13162
- }
13163
- };
13164
- var FlowVersionsEndpoint = class {
13165
- constructor(client) {
13166
- this.client = client;
12965
+ return response;
13167
12966
  }
13168
12967
  /**
13169
- * List versions for a flow, optionally filtered by version `type`.
12968
+ * Generic DELETE request
13170
12969
  */
13171
- async list(flowId, params) {
13172
- return this.client.get(`/flow-versions/${flowId}`, params);
12970
+ async delete(path) {
12971
+ const url = this.buildUrl(path);
12972
+ const response = await this.makeRequest(url, {
12973
+ method: "DELETE",
12974
+ headers: this.headers
12975
+ });
12976
+ return response;
13173
12977
  }
13174
12978
  /**
13175
- * Get the published version for a flow.
12979
+ * Generic request that returns raw Response for streaming
13176
12980
  */
13177
- async getPublished(flowId) {
13178
- return this.client.get(`/flow-versions/${flowId}/published`);
12981
+ async requestStream(path, options = {}) {
12982
+ const url = this.buildUrl(path);
12983
+ const headers = {
12984
+ ...this.headers,
12985
+ ...options.headers
12986
+ };
12987
+ return this.makeRawRequest(url, {
12988
+ ...options,
12989
+ headers
12990
+ });
13179
12991
  }
13180
12992
  /**
13181
- * Get a specific version of a flow.
12993
+ * Dispatch flow execution (streaming).
12994
+ *
12995
+ * This is the sole streaming-dispatch chokepoint for the flow builders
12996
+ * (`RuntypeFlowBuilder`), so it normalizes the request to the canonical
12997
+ * `/v1/dispatch` wire contract here — every builder path inherits the same
12998
+ * normalization the `DispatchEndpoint` applies, with no per-builder call.
12999
+ *
13000
+ * A dispatched agent turn runs on the durable lane, so the stream follows a
13001
+ * detach through {@link executionEvents}; pass `autoReconnect: false` to own
13002
+ * the reconnect yourself.
13182
13003
  */
13183
- async get(flowId, versionId) {
13184
- return this.client.get(`/flow-versions/${flowId}/${versionId}`);
13004
+ async dispatch(config, init) {
13005
+ const normalized = normalizeDispatchRequest(config);
13006
+ const request6 = {
13007
+ ...normalized,
13008
+ options: {
13009
+ ...normalized.options,
13010
+ streamResponse: true
13011
+ }
13012
+ };
13013
+ const response = await this.requestStream("/dispatch", {
13014
+ method: "POST",
13015
+ body: JSON.stringify(request6),
13016
+ ...init?.signal ? { signal: init.signal } : {}
13017
+ });
13018
+ const conversationId = typeof normalized.conversationId === "string" && normalized.conversationId ? normalized.conversationId : void 0;
13019
+ return withDetachedReconnect(
13020
+ response,
13021
+ async ({ executionId, after, signal: reattachSignal }) => {
13022
+ const legSignal = combineAbortSignals(init?.signal, reattachSignal);
13023
+ return this.executionEvents(executionId, {
13024
+ after,
13025
+ ...conversationId ? { conversationId } : {},
13026
+ ...legSignal ? { signal: legSignal } : {}
13027
+ }).catch(() => null);
13028
+ },
13029
+ init ?? {}
13030
+ );
13185
13031
  }
13186
13032
  /**
13187
- * Publish a version (promote it to the flow's published version).
13033
+ * Dispatch flow execution (non-streaming JSON).
13034
+ *
13035
+ * The non-streaming sibling of {@link dispatch}; it normalizes to the same
13036
+ * canonical wire contract so builders never post a raw, un-normalized body,
13037
+ * and pins `streamResponse: false` so the server returns buffered JSON.
13188
13038
  */
13189
- async publish(flowId, versionId, options = {}) {
13190
- return this.client.post(`/flow-versions/${flowId}/publish`, {
13191
- versionId,
13192
- ...options
13039
+ async dispatchJson(config) {
13040
+ const normalized = normalizeDispatchRequest(config);
13041
+ return this.post("/dispatch", {
13042
+ ...normalized,
13043
+ options: {
13044
+ ...normalized.options,
13045
+ streamResponse: false
13046
+ }
13193
13047
  });
13194
13048
  }
13195
- };
13196
- var IntegrationsEndpoint = class {
13197
- constructor(client) {
13198
- this.client = client;
13049
+ /** Start a normalized dispatch and return a durable handle immediately. */
13050
+ async dispatchAsync(config) {
13051
+ const normalized = normalizeDispatchRequest(config);
13052
+ return this.post(
13053
+ "/dispatch",
13054
+ {
13055
+ ...normalized,
13056
+ options: { ...normalized.options, streamResponse: false }
13057
+ },
13058
+ { Prefer: "respond-async" }
13059
+ );
13060
+ }
13061
+ async getExecutionStatus(executionId) {
13062
+ return this.get(`/executions/${encodeURIComponent(executionId)}/status`);
13199
13063
  }
13200
13064
  /**
13201
- * List all integrations with the caller's per-integration configuration status.
13065
+ * Rejoin a durable execution's Server-Sent Events by execution id.
13066
+ *
13067
+ * The execution-scoped alias of the agent events route, so a turn started
13068
+ * through `/v1/dispatch` reconnects without knowing which agent served it.
13069
+ * Pass the last SSE `id:` the stream delivered as `after` to replay strictly
13070
+ * past that cursor and then live-tail while the run is still going. This is
13071
+ * the same leg a detached dispatch stream follows on its own, exposed for a
13072
+ * caller that stores the cursor and reattaches later or from elsewhere.
13073
+ *
13074
+ * @example
13075
+ * ```typescript
13076
+ * const events = await client.executionEvents('aex_123', { after: '118' })
13077
+ * ```
13202
13078
  */
13203
- async list(params) {
13204
- return this.client.get("/integrations", params);
13079
+ async executionEvents(executionId, opts = {}) {
13080
+ const path = buildExecutionEventsPath(executionId, {
13081
+ ...opts.after !== void 0 ? { after: opts.after } : {},
13082
+ ...opts.conversationId !== void 0 ? { conversationId: opts.conversationId } : {}
13083
+ });
13084
+ return this.requestStream(path, {
13085
+ method: "GET",
13086
+ ...opts.signal ? { signal: opts.signal } : {}
13087
+ });
13205
13088
  }
13206
13089
  /**
13207
- * Get a single integration by ID.
13090
+ * Build full URL with query parameters
13208
13091
  */
13209
- async get(integrationId) {
13210
- return this.client.get(`/integrations/${integrationId}`);
13092
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- mirrors get()'s permissive params type
13093
+ buildUrl(path, params) {
13094
+ const base = this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`;
13095
+ const relPath = path.startsWith("/") ? path.slice(1) : path;
13096
+ const url = new URL(relPath, base);
13097
+ if (params) {
13098
+ Object.entries(params).forEach(([key, value]) => {
13099
+ if (value !== void 0 && value !== null) {
13100
+ url.searchParams.set(key, String(value));
13101
+ }
13102
+ });
13103
+ }
13104
+ return url.toString();
13211
13105
  }
13212
13106
  /**
13213
- * List integrations within a category (e.g. `slack`, `mcp`).
13107
+ * Make HTTP request with timeout and error handling
13214
13108
  */
13215
- async listByCategory(category) {
13216
- return this.client.get(
13217
- `/integrations/category/${category}`
13218
- );
13109
+ async makeRequest(url, options) {
13110
+ const response = await this.makeRawRequest(url, options);
13111
+ if (response.status === 204) {
13112
+ return null;
13113
+ }
13114
+ const contentType = response.headers.get("content-type");
13115
+ if (contentType?.includes("application/json")) {
13116
+ return response.json();
13117
+ }
13118
+ return response.text();
13219
13119
  }
13220
13120
  /**
13221
- * Per-environment credential status across the caller's integrations.
13121
+ * Make HTTP request that returns raw Response (for streaming)
13222
13122
  */
13223
- async getCredentialsStatus() {
13224
- return this.client.get("/integrations/credentials-status");
13123
+ async makeRawRequest(url, options) {
13124
+ const callerSignal = options.signal ?? void 0;
13125
+ const controller = new AbortController();
13126
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
13127
+ const signal = combineAbortSignals(callerSignal, controller.signal) ?? controller.signal;
13128
+ try {
13129
+ const response = await fetch(url, {
13130
+ ...options,
13131
+ signal
13132
+ });
13133
+ clearTimeout(timeoutId);
13134
+ if (!response.ok) {
13135
+ const errorText = await response.text();
13136
+ throw new Error(
13137
+ `API request failed: ${response.status} ${response.statusText} - ${errorText}`
13138
+ );
13139
+ }
13140
+ return response;
13141
+ } catch (error) {
13142
+ clearTimeout(timeoutId);
13143
+ if (error instanceof Error && error.name === "AbortError" && !callerSignal?.aborted) {
13144
+ throw new Error(`Request timeout after ${this.timeout}ms`, { cause: error });
13145
+ }
13146
+ throw error;
13147
+ }
13225
13148
  }
13149
+ };
13150
+ var Runtype = class {
13226
13151
  /**
13227
- * List all tools exposed across the caller's configured integrations.
13152
+ * Configure the global Runtype client
13153
+ *
13154
+ * Call this once at app startup to set the API key and other options.
13155
+ * All subsequent calls to Runtype.flows, Runtype.batches, etc. will use this config.
13156
+ *
13157
+ * @example
13158
+ * ```typescript
13159
+ * Runtype.configure({ apiKey: process.env.RUNTYPE_API_KEY })
13160
+ * ```
13228
13161
  */
13229
- async listTools() {
13230
- return this.client.get("/integrations/tools");
13162
+ static configure(config) {
13163
+ globalConfig = { ...globalConfig, ...config };
13164
+ globalClient = new RuntypeClient(globalConfig);
13231
13165
  }
13232
13166
  /**
13233
- * List the tools exposed by a single integration.
13167
+ * Get the global client instance, creating one if needed
13234
13168
  */
13235
- async getIntegrationTools(integrationId) {
13236
- return this.client.get(
13237
- `/integrations/${integrationId}/tools`
13238
- );
13169
+ static getClient() {
13170
+ if (!globalClient) {
13171
+ globalClient = new RuntypeClient(globalConfig);
13172
+ }
13173
+ return globalClient;
13239
13174
  }
13240
13175
  /**
13241
- * Get the definition of a single tool within an integration.
13176
+ * Create a new client instance with custom configuration
13177
+ *
13178
+ * Use this when you need a client with different settings than the global one.
13179
+ *
13180
+ * @example
13181
+ * ```typescript
13182
+ * const client = Runtype.createClient({ apiKey: 'different_key' })
13183
+ * ```
13242
13184
  */
13243
- async getTool(integrationId, toolName) {
13244
- return this.client.get(`/integrations/${integrationId}/tools/${toolName}`);
13185
+ static createClient(config) {
13186
+ return new RuntypeClient({ ...globalConfig, ...config });
13245
13187
  }
13246
13188
  /**
13247
- * Install a Slack integration from a completed OAuth handshake.
13189
+ * Flows namespace - Build and execute flows
13190
+ *
13191
+ * @example
13192
+ * ```typescript
13193
+ * // Upsert a flow (create or update)
13194
+ * const result = await Runtype.flows.upsert({ name: 'My Flow' })
13195
+ * .prompt({ name: 'Analyze', model: 'gpt-4o', userPrompt: '...' })
13196
+ * .stream()
13197
+ *
13198
+ * // Use an existing flow
13199
+ * const result = await Runtype.flows.use('flow_123')
13200
+ * .withRecord({ name: 'Test' })
13201
+ * .result()
13202
+ *
13203
+ * // Virtual flow (one-off, not saved)
13204
+ * const result = await Runtype.flows.virtual({ name: 'Temp Flow' })
13205
+ * .prompt({ ... })
13206
+ * .stream()
13207
+ * ```
13248
13208
  */
13249
- async installSlack(data) {
13250
- return this.client.post("/integrations/slack/install", data);
13209
+ static get flows() {
13210
+ return new FlowsNamespace(() => this.getClient());
13251
13211
  }
13252
13212
  /**
13253
- * Start the Slack "Add to Slack" OAuth handshake. Returns the Slack authorize
13254
- * URL to open in a popup; the bot token is captured server-side by the
13255
- * callback (never returned to the browser).
13213
+ * Batches namespace - Schedule and manage batch operations
13214
+ *
13215
+ * @example
13216
+ * ```typescript
13217
+ * // Schedule a batch
13218
+ * const batch = await Runtype.batches.schedule({
13219
+ * flowId: 'flow_123',
13220
+ * recordType: 'customers',
13221
+ * })
13222
+ *
13223
+ * // Get batch status
13224
+ * const status = await Runtype.batches.get('batch_456')
13225
+ *
13226
+ * // Cancel a batch
13227
+ * await Runtype.batches.cancel('batch_456')
13228
+ *
13229
+ * // List batches
13230
+ * const batches = await Runtype.batches.list({ status: 'running' })
13231
+ * ```
13256
13232
  */
13257
- async startSlackOAuth(data) {
13258
- return this.client.post("/oauth/slack/start", data);
13233
+ static get batches() {
13234
+ return new BatchesNamespace(() => this.getClient());
13259
13235
  }
13260
13236
  /**
13261
- * Generate the Slack app manifest for a surface, plus a link to Slack's
13262
- * app-creation page. The manifest carries absolute API URLs derived
13263
- * server-side, so it is always valid for Slack (relative proxy paths never
13264
- * leak in). Slack's create-app modal ignores a manifest passed in the URL, so
13265
- * `manifestJson` is pasted into its "From a manifest" option rather than
13266
- * embedded in `createAppUrl`.
13237
+ * Evals namespace - Run evaluations and compare models
13238
+ *
13239
+ * @example
13240
+ * ```typescript
13241
+ * // Run an eval with streaming
13242
+ * const stream = await Runtype.evals.run({
13243
+ * flowId: 'flow_123',
13244
+ * recordType: 'test_data',
13245
+ * models: [{ stepName: 'Analyze', model: 'gpt-4o' }]
13246
+ * }).stream()
13247
+ *
13248
+ * // Submit eval as batch job
13249
+ * const eval = await Runtype.evals.run({
13250
+ * flowId: 'flow_123',
13251
+ * recordType: 'test_data',
13252
+ * models: [
13253
+ * [{ stepName: 'Analyze', model: 'gpt-5.4' }],
13254
+ * [{ stepName: 'Analyze', model: 'claude-opus-4-6' }],
13255
+ * ]
13256
+ * }).submit()
13257
+ * ```
13267
13258
  */
13268
- async generateSlackManifest(data) {
13269
- return this.client.post("/integrations/slack/manifest", data);
13259
+ static get evals() {
13260
+ return new EvalsNamespace(() => this.getClient());
13270
13261
  }
13271
13262
  /**
13272
- * Report whether Slack has verified a surface's events URL. Slack sends that
13273
- * challenge when an app is created from a manifest, so a `verifiedAt` newer
13274
- * than the one read before the manifest was handed out is evidence the app
13275
- * now exists. Markers expire after an hour.
13263
+ * Prompts namespace - Manage and execute prompts
13264
+ *
13265
+ * @example
13266
+ * ```typescript
13267
+ * // Execute a prompt with streaming
13268
+ * const stream = await Runtype.prompts.run('prompt_123', {
13269
+ * recordId: 'rec_456'
13270
+ * }).stream()
13271
+ *
13272
+ * // Get complete result
13273
+ * const result = await Runtype.prompts.run('prompt_123', {
13274
+ * recordId: 'rec_456'
13275
+ * }).result()
13276
+ *
13277
+ * // CRUD operations
13278
+ * const prompts = await Runtype.prompts.list()
13279
+ * const prompt = await Runtype.prompts.get('prompt_123')
13280
+ * const newPrompt = await Runtype.prompts.create({ ... })
13281
+ * await Runtype.prompts.update('prompt_123', { ... })
13282
+ * await Runtype.prompts.delete('prompt_123')
13283
+ * ```
13276
13284
  */
13277
- async getSlackAppStatus(surfaceId) {
13278
- return this.client.get(
13279
- `/integrations/slack/app-status?surfaceId=${encodeURIComponent(surfaceId)}`
13280
- );
13281
- }
13282
- };
13283
- var BillingEndpoint = class {
13284
- constructor(client) {
13285
- this.client = client;
13285
+ static get prompts() {
13286
+ return new PromptsNamespace(() => this.getClient());
13286
13287
  }
13287
13288
  /**
13288
- * Get the caller's subscription status, plan limits, and current usage.
13289
+ * Skills namespace - Manage Agent Skills (admin/control plane)
13290
+ *
13291
+ * @example
13292
+ * ```typescript
13293
+ * // Create a published skill from a SKILL.md document
13294
+ * const { skill } = await Runtype.skills.create({ markdown: skillMd, publish: true })
13295
+ *
13296
+ * // Bind it to an agent
13297
+ * await Runtype.skills.bind({ agentId: 'agent_123', skillId: skill.id })
13298
+ *
13299
+ * // Review agent-authored proposals
13300
+ * const pending = await Runtype.skills.proposals.list()
13301
+ * await Runtype.skills.proposals.approve(pending[0].id)
13302
+ * ```
13289
13303
  */
13290
- async getStatus() {
13291
- return this.client.get("/billing/status");
13304
+ static get skills() {
13305
+ return new SkillsNamespace(() => this.getClient());
13292
13306
  }
13293
13307
  /**
13294
- * Get the caller's credit grants and available/used totals.
13308
+ * Agents namespace - Agent config-as-code (define / ensure / pull)
13309
+ *
13310
+ * @example
13311
+ * ```typescript
13312
+ * import { defineAgent, Runtype } from '@runtypelabs/sdk'
13313
+ *
13314
+ * const assistant = defineAgent({
13315
+ * name: 'Pricing Assistant',
13316
+ * model: 'claude-sonnet-4-6',
13317
+ * systemPrompt: renderPrompt(pricingData),
13318
+ * })
13319
+ *
13320
+ * // Converge at deploy time (idempotent; one tiny probe in steady state)
13321
+ * await Runtype.agents.ensure(assistant)
13322
+ *
13323
+ * // CI drift gate
13324
+ * await Runtype.agents.ensure(assistant, { expectNoChanges: true })
13325
+ *
13326
+ * // Absorb a dashboard edit back into the repo
13327
+ * const { definition } = await Runtype.agents.pull('Pricing Assistant')
13328
+ * ```
13295
13329
  */
13296
- async getCredits() {
13297
- return this.client.get("/billing/credits");
13330
+ static get agents() {
13331
+ return new AgentsNamespace(() => this.getClient());
13298
13332
  }
13299
- /**
13300
- * Get the caller's exact current UTC-month platform spend from the local
13301
- * meter used for spend-cap enforcement. Returns 503 when that meter is unavailable.
13302
- */
13303
- async getCurrentSpend() {
13304
- return this.client.get("/billing/current-spend");
13333
+ /** Poll durable handles returned by asynchronous execute operations. */
13334
+ static get executions() {
13335
+ return new ExecutionsNamespace(() => this.getClient());
13305
13336
  }
13306
13337
  /**
13307
- * Get spend analytics. The window is controlled by either `period` or `days`
13308
- * (1–365, defaults to 30).
13338
+ * Tools namespace - Tool config-as-code (define / ensure / pull)
13339
+ *
13340
+ * @example
13341
+ * ```typescript
13342
+ * import { defineTool, Runtype } from '@runtypelabs/sdk'
13343
+ *
13344
+ * const weather = defineTool({
13345
+ * name: 'Weather Lookup',
13346
+ * description: 'Fetch the current weather for a city',
13347
+ * toolType: 'external',
13348
+ * parametersSchema: { type: 'object', properties: { city: { type: 'string' } } },
13349
+ * config: { url: 'https://api.example.com/weather', method: 'GET' },
13350
+ * })
13351
+ *
13352
+ * // Converge at deploy time (idempotent; one tiny probe in steady state)
13353
+ * await Runtype.tools.ensure(weather)
13354
+ *
13355
+ * // CI drift gate
13356
+ * await Runtype.tools.ensure(weather, { expectNoChanges: true })
13357
+ *
13358
+ * // Absorb a dashboard edit back into the repo
13359
+ * const { definition } = await Runtype.tools.pull('Weather Lookup')
13360
+ * ```
13309
13361
  */
13310
- async getSpendAnalytics(params) {
13311
- return this.client.get("/billing/spend-analytics", params);
13312
- }
13313
- };
13314
- var ToolApprovalGrantsEndpoint = class {
13315
- constructor(client) {
13316
- this.client = client;
13362
+ static get tools() {
13363
+ return new ToolsNamespace(() => this.getClient());
13317
13364
  }
13318
13365
  /**
13319
- * List active remembered tool-approval grants for the authenticated owner,
13320
- * optionally filtered to a single agent.
13366
+ * Products namespace - Product config-as-code (define / ensure / pull)
13367
+ *
13368
+ * Converges the top-level product record (description, icon, spec). Nested
13369
+ * capabilities/surfaces/tools and the canvas UI layout state are not
13370
+ * converged by ensure.
13371
+ *
13372
+ * @example
13373
+ * ```typescript
13374
+ * import { defineProduct, Runtype } from '@runtypelabs/sdk'
13375
+ *
13376
+ * const product = defineProduct({
13377
+ * name: 'Support Copilot',
13378
+ * description: 'An AI support assistant',
13379
+ * icon: '🤖',
13380
+ * spec: { productGoal: 'Deflect tier-1 tickets', productStage: 'beta' },
13381
+ * })
13382
+ *
13383
+ * // Converge at deploy time (idempotent; one tiny probe in steady state)
13384
+ * await Runtype.products.ensure(product)
13385
+ *
13386
+ * // CI drift gate
13387
+ * await Runtype.products.ensure(product, { expectNoChanges: true })
13388
+ *
13389
+ * // Absorb a dashboard edit back into the repo
13390
+ * const { definition } = await Runtype.products.pull('Support Copilot')
13391
+ * ```
13321
13392
  */
13322
- async list(agentId) {
13323
- const query = agentId ? `?agentId=${encodeURIComponent(agentId)}` : "";
13324
- const response = await this.client.get(
13325
- `/tool-approval-grants${query}`
13326
- );
13327
- return response.data;
13393
+ static get products() {
13394
+ return new ProductsNamespace(() => this.getClient());
13328
13395
  }
13329
13396
  /**
13330
- * Revoke (soft-delete) a remembered grant so the tool prompts for approval
13331
- * again on future dispatches.
13397
+ * Config-as-code operations for product surfaces. `surfaces.ensure` is the
13398
+ * deploy-time, non-executing converge (create-or-update a surface by name
13399
+ * within a product); `surfaces.pull` is the absorb-drift direction.
13400
+ *
13401
+ * @example
13402
+ * ```typescript
13403
+ * import { Runtype, defineSurface } from '@runtypelabs/sdk'
13404
+ *
13405
+ * const chat = defineSurface({
13406
+ * name: 'Support Chat',
13407
+ * type: 'chat',
13408
+ * behavior: { type: 'chat', greeting: 'Hi there!' },
13409
+ * status: 'active',
13410
+ * })
13411
+ *
13412
+ * // Converge at deploy time (idempotent; one tiny probe in steady state)
13413
+ * await Runtype.surfaces.ensure('product_abc', chat)
13414
+ *
13415
+ * // CI drift gate
13416
+ * await Runtype.surfaces.ensure('product_abc', chat, { expectNoChanges: true })
13417
+ *
13418
+ * // Absorb a dashboard edit back into the repo
13419
+ * const { definition } = await Runtype.surfaces.pull('product_abc', 'Support Chat')
13420
+ * ```
13332
13421
  */
13333
- async revoke(id) {
13334
- return this.client.delete(`/tool-approval-grants/${id}`);
13422
+ static get surfaces() {
13423
+ return new SurfacesNamespace(() => this.getClient());
13335
13424
  }
13336
13425
  };
13337
13426
 
13427
+ // src/transform.ts
13428
+ function transformQueryParams(params) {
13429
+ const result = {};
13430
+ for (const [key, value] of Object.entries(params)) {
13431
+ if (value !== void 0 && value !== null) {
13432
+ if (Array.isArray(value)) {
13433
+ result[key] = value.join(",");
13434
+ } else {
13435
+ result[key] = String(value);
13436
+ }
13437
+ }
13438
+ }
13439
+ return result;
13440
+ }
13441
+
13442
+ // src/version.ts
13443
+ var FALLBACK_VERSION = "0.0.0";
13444
+ var SDK_VERSION = "9.10.0".length > 0 ? "9.10.0" : FALLBACK_VERSION;
13445
+ var RUNTYPE_CLIENT_KIND = "sdk";
13446
+ var SDK_USER_AGENT = `runtype-sdk/${SDK_VERSION} (typescript)`;
13447
+
13338
13448
  // src/client.ts
13339
13449
  function isObjectRecord(value) {
13340
13450
  return typeof value === "object" && value !== null;
@@ -14674,12 +14784,14 @@ var STEP_TYPE_TO_METHOD = {
14674
14784
  attachRuntimeToolsToDispatchRequest,
14675
14785
  buildAgentAdmissionHeaders,
14676
14786
  buildEmptySessionNudge,
14787
+ buildExecutionEventsPath,
14677
14788
  buildGeneratedRuntimeToolGateOutput,
14678
14789
  buildLedgerOffloadReference,
14679
14790
  buildObservationMaskMarker,
14680
14791
  buildPolicyGuidance,
14681
14792
  buildSendViewOffloadMarker,
14682
14793
  calledTool,
14794
+ combineAbortSignals,
14683
14795
  compileWorkflowConfig,
14684
14796
  completed,
14685
14797
  computeAgentContentHash,