@runtypelabs/sdk 9.9.0 → 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,
@@ -233,6 +235,7 @@ var UNIFIED_EVENT_TYPES = /* @__PURE__ */ new Set([
233
235
  "approval_complete",
234
236
  "await",
235
237
  "error",
238
+ "context_notice",
236
239
  "ping",
237
240
  "custom"
238
241
  ]);
@@ -2831,11 +2834,12 @@ async function request(client, body) {
2831
2834
  }
2832
2835
  }
2833
2836
  async function ensureFlow(client, definition, options = {}) {
2834
- const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
2837
+ const { dryRun, onConflict, release, expectedRemoteHash, version, expectNoChanges } = options;
2835
2838
  const passthrough = {
2836
2839
  ...onConflict ? { onConflict } : {},
2837
2840
  ...release ? { release } : {},
2838
- ...expectedRemoteHash ? { expectedRemoteHash } : {}
2841
+ ...expectedRemoteHash ? { expectedRemoteHash } : {},
2842
+ ...version ? { version } : {}
2839
2843
  };
2840
2844
  const wireDefinition = { name: definition.name, steps: definition.steps };
2841
2845
  if (dryRun || expectNoChanges) {
@@ -5111,11 +5115,12 @@ var AgentsNamespace = class {
5111
5115
  */
5112
5116
  async ensure(definition, options = {}) {
5113
5117
  const client = this.getClient();
5114
- const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
5118
+ const { dryRun, onConflict, release, expectedRemoteHash, version, expectNoChanges } = options;
5115
5119
  const passthrough = {
5116
5120
  ...onConflict ? { onConflict } : {},
5117
5121
  ...release ? { release } : {},
5118
- ...expectedRemoteHash ? { expectedRemoteHash } : {}
5122
+ ...expectedRemoteHash ? { expectedRemoteHash } : {},
5123
+ ...version ? { version } : {}
5119
5124
  };
5120
5125
  if (dryRun || expectNoChanges) {
5121
5126
  const plan = await this.request(client, {
@@ -5962,542 +5967,51 @@ function normalizeDispatchRequest(request6) {
5962
5967
  return request6.flow ? { ...normalized, flow: request6.flow } : { ...normalized, agent: request6.agent };
5963
5968
  }
5964
5969
 
5965
- // src/runtype.ts
5966
- var globalConfig = {};
5967
- var globalClient = null;
5968
- var RuntypeClient = class {
5969
- constructor(config = {}) {
5970
- const baseUrl = config.baseUrl || "https://api.runtype.com";
5971
- this.apiVersion = config.apiVersion || "v1";
5972
- this.baseUrl = this.apiVersion ? `${baseUrl}/${this.apiVersion}` : baseUrl;
5973
- this.timeout = config.timeout || 3e4;
5974
- this.headers = {
5975
- "Content-Type": "application/json",
5976
- ...config.headers || {}
5977
- };
5978
- if (config.apiKey) {
5979
- this.headers.Authorization = `Bearer ${config.apiKey}`;
5980
- }
5981
- }
5982
- /**
5983
- * Set the API key for authentication
5984
- */
5985
- setApiKey(apiKey) {
5986
- this.headers.Authorization = `Bearer ${apiKey}`;
5987
- }
5988
- /**
5989
- * Generic GET request
5990
- */
5991
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts typed list-param interfaces (no index signature); `unknown` would reject them
5992
- async get(path, params) {
5993
- const url = this.buildUrl(path, params);
5994
- const response = await this.makeRequest(url, {
5995
- method: "GET",
5996
- headers: this.headers
5997
- });
5998
- return response;
5999
- }
6000
- /**
6001
- * Generic POST request
6002
- */
6003
- async post(path, data, extraHeaders) {
6004
- const url = this.buildUrl(path);
6005
- const response = await this.makeRequest(url, {
6006
- method: "POST",
6007
- headers: { ...this.headers, ...extraHeaders },
6008
- body: data ? JSON.stringify(data) : void 0
6009
- });
6010
- return response;
6011
- }
6012
- /**
6013
- * Generic PUT request
6014
- */
6015
- async put(path, data) {
6016
- const url = this.buildUrl(path);
6017
- const response = await this.makeRequest(url, {
6018
- method: "PUT",
6019
- headers: this.headers,
6020
- body: data ? JSON.stringify(data) : void 0
6021
- });
6022
- return response;
6023
- }
6024
- /**
6025
- * Generic PATCH request
6026
- */
6027
- async patch(path, data) {
6028
- const url = this.buildUrl(path);
6029
- const response = await this.makeRequest(url, {
6030
- method: "PATCH",
6031
- headers: this.headers,
6032
- body: data ? JSON.stringify(data) : void 0
6033
- });
6034
- return response;
6035
- }
6036
- /**
6037
- * Generic DELETE request
6038
- */
6039
- async delete(path) {
6040
- const url = this.buildUrl(path);
6041
- const response = await this.makeRequest(url, {
6042
- method: "DELETE",
6043
- headers: this.headers
6044
- });
6045
- return response;
6046
- }
6047
- /**
6048
- * Generic request that returns raw Response for streaming
6049
- */
6050
- async requestStream(path, options = {}) {
6051
- const url = this.buildUrl(path);
6052
- const headers = {
6053
- ...this.headers,
6054
- ...options.headers
6055
- };
6056
- return this.makeRawRequest(url, {
6057
- ...options,
6058
- headers
6059
- });
6060
- }
6061
- /**
6062
- * Dispatch flow execution (streaming).
6063
- *
6064
- * This is the sole streaming-dispatch chokepoint for the flow builders
6065
- * (`RuntypeFlowBuilder`), so it normalizes the request to the canonical
6066
- * `/v1/dispatch` wire contract here — every builder path inherits the same
6067
- * normalization the `DispatchEndpoint` applies, with no per-builder call.
6068
- */
6069
- async dispatch(config) {
6070
- const normalized = normalizeDispatchRequest(config);
6071
- const request6 = {
6072
- ...normalized,
6073
- options: {
6074
- ...normalized.options,
6075
- streamResponse: true
6076
- }
6077
- };
6078
- return this.requestStream("/dispatch", {
6079
- method: "POST",
6080
- body: JSON.stringify(request6)
6081
- });
6082
- }
6083
- /**
6084
- * Dispatch flow execution (non-streaming JSON).
6085
- *
6086
- * The non-streaming sibling of {@link dispatch}; it normalizes to the same
6087
- * canonical wire contract so builders never post a raw, un-normalized body,
6088
- * and pins `streamResponse: false` so the server returns buffered JSON.
6089
- */
6090
- async dispatchJson(config) {
6091
- const normalized = normalizeDispatchRequest(config);
6092
- return this.post("/dispatch", {
6093
- ...normalized,
6094
- options: {
6095
- ...normalized.options,
6096
- streamResponse: false
6097
- }
6098
- });
6099
- }
6100
- /** Start a normalized dispatch and return a durable handle immediately. */
6101
- async dispatchAsync(config) {
6102
- const normalized = normalizeDispatchRequest(config);
6103
- return this.post(
6104
- "/dispatch",
6105
- {
6106
- ...normalized,
6107
- options: { ...normalized.options, streamResponse: false }
6108
- },
6109
- { Prefer: "respond-async" }
6110
- );
6111
- }
6112
- async getExecutionStatus(executionId) {
6113
- return this.get(`/executions/${encodeURIComponent(executionId)}/status`);
6114
- }
6115
- /**
6116
- * Build full URL with query parameters
6117
- */
6118
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- mirrors get()'s permissive params type
6119
- buildUrl(path, params) {
6120
- const base = this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`;
6121
- const relPath = path.startsWith("/") ? path.slice(1) : path;
6122
- const url = new URL(relPath, base);
6123
- if (params) {
6124
- Object.entries(params).forEach(([key, value]) => {
6125
- if (value !== void 0 && value !== null) {
6126
- url.searchParams.set(key, String(value));
6127
- }
6128
- });
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;
6129
5984
  }
6130
- return url.toString();
5985
+ signal.addEventListener("abort", () => controller.abort(signal.reason), { once: true });
6131
5986
  }
6132
- /**
6133
- * Make HTTP request with timeout and error handling
6134
- */
6135
- async makeRequest(url, options) {
6136
- const response = await this.makeRawRequest(url, options);
6137
- if (response.status === 204) {
6138
- 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;
6139
5995
  }
6140
- const contentType = response.headers.get("content-type");
6141
- if (contentType?.includes("application/json")) {
6142
- return response.json();
5996
+ if (line.startsWith("event:")) {
5997
+ eventName = line.slice(6).trim();
5998
+ continue;
6143
5999
  }
6144
- return response.text();
6145
- }
6146
- /**
6147
- * Make HTTP request that returns raw Response (for streaming)
6148
- */
6149
- async makeRawRequest(url, options) {
6150
- const controller = new AbortController();
6151
- 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;
6152
6004
  try {
6153
- const response = await fetch(url, {
6154
- ...options,
6155
- signal: controller.signal
6156
- });
6157
- clearTimeout(timeoutId);
6158
- if (!response.ok) {
6159
- const errorText = await response.text();
6160
- throw new Error(
6161
- `API request failed: ${response.status} ${response.statusText} - ${errorText}`
6162
- );
6163
- }
6164
- return response;
6165
- } catch (error) {
6166
- clearTimeout(timeoutId);
6167
- if (error instanceof Error && error.name === "AbortError") {
6168
- throw new Error(`Request timeout after ${this.timeout}ms`, { cause: error });
6169
- }
6170
- throw error;
6171
- }
6172
- }
6173
- };
6174
- var Runtype = class {
6175
- /**
6176
- * Configure the global Runtype client
6177
- *
6178
- * Call this once at app startup to set the API key and other options.
6179
- * All subsequent calls to Runtype.flows, Runtype.batches, etc. will use this config.
6180
- *
6181
- * @example
6182
- * ```typescript
6183
- * Runtype.configure({ apiKey: process.env.RUNTYPE_API_KEY })
6184
- * ```
6185
- */
6186
- static configure(config) {
6187
- globalConfig = { ...globalConfig, ...config };
6188
- globalClient = new RuntypeClient(globalConfig);
6189
- }
6190
- /**
6191
- * Get the global client instance, creating one if needed
6192
- */
6193
- static getClient() {
6194
- if (!globalClient) {
6195
- 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;
6196
6010
  }
6197
- return globalClient;
6198
- }
6199
- /**
6200
- * Create a new client instance with custom configuration
6201
- *
6202
- * Use this when you need a client with different settings than the global one.
6203
- *
6204
- * @example
6205
- * ```typescript
6206
- * const client = Runtype.createClient({ apiKey: 'different_key' })
6207
- * ```
6208
- */
6209
- static createClient(config) {
6210
- return new RuntypeClient({ ...globalConfig, ...config });
6211
- }
6212
- /**
6213
- * Flows namespace - Build and execute flows
6214
- *
6215
- * @example
6216
- * ```typescript
6217
- * // Upsert a flow (create or update)
6218
- * const result = await Runtype.flows.upsert({ name: 'My Flow' })
6219
- * .prompt({ name: 'Analyze', model: 'gpt-4o', userPrompt: '...' })
6220
- * .stream()
6221
- *
6222
- * // Use an existing flow
6223
- * const result = await Runtype.flows.use('flow_123')
6224
- * .withRecord({ name: 'Test' })
6225
- * .result()
6226
- *
6227
- * // Virtual flow (one-off, not saved)
6228
- * const result = await Runtype.flows.virtual({ name: 'Temp Flow' })
6229
- * .prompt({ ... })
6230
- * .stream()
6231
- * ```
6232
- */
6233
- static get flows() {
6234
- return new FlowsNamespace(() => this.getClient());
6235
- }
6236
- /**
6237
- * Batches namespace - Schedule and manage batch operations
6238
- *
6239
- * @example
6240
- * ```typescript
6241
- * // Schedule a batch
6242
- * const batch = await Runtype.batches.schedule({
6243
- * flowId: 'flow_123',
6244
- * recordType: 'customers',
6245
- * })
6246
- *
6247
- * // Get batch status
6248
- * const status = await Runtype.batches.get('batch_456')
6249
- *
6250
- * // Cancel a batch
6251
- * await Runtype.batches.cancel('batch_456')
6252
- *
6253
- * // List batches
6254
- * const batches = await Runtype.batches.list({ status: 'running' })
6255
- * ```
6256
- */
6257
- static get batches() {
6258
- return new BatchesNamespace(() => this.getClient());
6259
- }
6260
- /**
6261
- * Evals namespace - Run evaluations and compare models
6262
- *
6263
- * @example
6264
- * ```typescript
6265
- * // Run an eval with streaming
6266
- * const stream = await Runtype.evals.run({
6267
- * flowId: 'flow_123',
6268
- * recordType: 'test_data',
6269
- * models: [{ stepName: 'Analyze', model: 'gpt-4o' }]
6270
- * }).stream()
6271
- *
6272
- * // Submit eval as batch job
6273
- * const eval = await Runtype.evals.run({
6274
- * flowId: 'flow_123',
6275
- * recordType: 'test_data',
6276
- * models: [
6277
- * [{ stepName: 'Analyze', model: 'gpt-5.4' }],
6278
- * [{ stepName: 'Analyze', model: 'claude-opus-4-6' }],
6279
- * ]
6280
- * }).submit()
6281
- * ```
6282
- */
6283
- static get evals() {
6284
- return new EvalsNamespace(() => this.getClient());
6285
- }
6286
- /**
6287
- * Prompts namespace - Manage and execute prompts
6288
- *
6289
- * @example
6290
- * ```typescript
6291
- * // Execute a prompt with streaming
6292
- * const stream = await Runtype.prompts.run('prompt_123', {
6293
- * recordId: 'rec_456'
6294
- * }).stream()
6295
- *
6296
- * // Get complete result
6297
- * const result = await Runtype.prompts.run('prompt_123', {
6298
- * recordId: 'rec_456'
6299
- * }).result()
6300
- *
6301
- * // CRUD operations
6302
- * const prompts = await Runtype.prompts.list()
6303
- * const prompt = await Runtype.prompts.get('prompt_123')
6304
- * const newPrompt = await Runtype.prompts.create({ ... })
6305
- * await Runtype.prompts.update('prompt_123', { ... })
6306
- * await Runtype.prompts.delete('prompt_123')
6307
- * ```
6308
- */
6309
- static get prompts() {
6310
- return new PromptsNamespace(() => this.getClient());
6311
- }
6312
- /**
6313
- * Skills namespace - Manage Agent Skills (admin/control plane)
6314
- *
6315
- * @example
6316
- * ```typescript
6317
- * // Create a published skill from a SKILL.md document
6318
- * const { skill } = await Runtype.skills.create({ markdown: skillMd, publish: true })
6319
- *
6320
- * // Bind it to an agent
6321
- * await Runtype.skills.bind({ agentId: 'agent_123', skillId: skill.id })
6322
- *
6323
- * // Review agent-authored proposals
6324
- * const pending = await Runtype.skills.proposals.list()
6325
- * await Runtype.skills.proposals.approve(pending[0].id)
6326
- * ```
6327
- */
6328
- static get skills() {
6329
- return new SkillsNamespace(() => this.getClient());
6330
- }
6331
- /**
6332
- * Agents namespace - Agent config-as-code (define / ensure / pull)
6333
- *
6334
- * @example
6335
- * ```typescript
6336
- * import { defineAgent, Runtype } from '@runtypelabs/sdk'
6337
- *
6338
- * const assistant = defineAgent({
6339
- * name: 'Pricing Assistant',
6340
- * model: 'claude-sonnet-4-6',
6341
- * systemPrompt: renderPrompt(pricingData),
6342
- * })
6343
- *
6344
- * // Converge at deploy time (idempotent; one tiny probe in steady state)
6345
- * await Runtype.agents.ensure(assistant)
6346
- *
6347
- * // CI drift gate
6348
- * await Runtype.agents.ensure(assistant, { expectNoChanges: true })
6349
- *
6350
- * // Absorb a dashboard edit back into the repo
6351
- * const { definition } = await Runtype.agents.pull('Pricing Assistant')
6352
- * ```
6353
- */
6354
- static get agents() {
6355
- return new AgentsNamespace(() => this.getClient());
6356
- }
6357
- /** Poll durable handles returned by asynchronous execute operations. */
6358
- static get executions() {
6359
- return new ExecutionsNamespace(() => this.getClient());
6360
- }
6361
- /**
6362
- * Tools namespace - Tool config-as-code (define / ensure / pull)
6363
- *
6364
- * @example
6365
- * ```typescript
6366
- * import { defineTool, Runtype } from '@runtypelabs/sdk'
6367
- *
6368
- * const weather = defineTool({
6369
- * name: 'Weather Lookup',
6370
- * description: 'Fetch the current weather for a city',
6371
- * toolType: 'external',
6372
- * parametersSchema: { type: 'object', properties: { city: { type: 'string' } } },
6373
- * config: { url: 'https://api.example.com/weather', method: 'GET' },
6374
- * })
6375
- *
6376
- * // Converge at deploy time (idempotent; one tiny probe in steady state)
6377
- * await Runtype.tools.ensure(weather)
6378
- *
6379
- * // CI drift gate
6380
- * await Runtype.tools.ensure(weather, { expectNoChanges: true })
6381
- *
6382
- * // Absorb a dashboard edit back into the repo
6383
- * const { definition } = await Runtype.tools.pull('Weather Lookup')
6384
- * ```
6385
- */
6386
- static get tools() {
6387
- return new ToolsNamespace(() => this.getClient());
6388
- }
6389
- /**
6390
- * Products namespace - Product config-as-code (define / ensure / pull)
6391
- *
6392
- * Converges the top-level product record (description, icon, spec). Nested
6393
- * capabilities/surfaces/tools and the canvas UI layout state are not
6394
- * converged by ensure.
6395
- *
6396
- * @example
6397
- * ```typescript
6398
- * import { defineProduct, Runtype } from '@runtypelabs/sdk'
6399
- *
6400
- * const product = defineProduct({
6401
- * name: 'Support Copilot',
6402
- * description: 'An AI support assistant',
6403
- * icon: '🤖',
6404
- * spec: { productGoal: 'Deflect tier-1 tickets', productStage: 'beta' },
6405
- * })
6406
- *
6407
- * // Converge at deploy time (idempotent; one tiny probe in steady state)
6408
- * await Runtype.products.ensure(product)
6409
- *
6410
- * // CI drift gate
6411
- * await Runtype.products.ensure(product, { expectNoChanges: true })
6412
- *
6413
- * // Absorb a dashboard edit back into the repo
6414
- * const { definition } = await Runtype.products.pull('Support Copilot')
6415
- * ```
6416
- */
6417
- static get products() {
6418
- return new ProductsNamespace(() => this.getClient());
6419
- }
6420
- /**
6421
- * Config-as-code operations for product surfaces. `surfaces.ensure` is the
6422
- * deploy-time, non-executing converge (create-or-update a surface by name
6423
- * within a product); `surfaces.pull` is the absorb-drift direction.
6424
- *
6425
- * @example
6426
- * ```typescript
6427
- * import { Runtype, defineSurface } from '@runtypelabs/sdk'
6428
- *
6429
- * const chat = defineSurface({
6430
- * name: 'Support Chat',
6431
- * type: 'chat',
6432
- * behavior: { type: 'chat', greeting: 'Hi there!' },
6433
- * status: 'active',
6434
- * })
6435
- *
6436
- * // Converge at deploy time (idempotent; one tiny probe in steady state)
6437
- * await Runtype.surfaces.ensure('product_abc', chat)
6438
- *
6439
- * // CI drift gate
6440
- * await Runtype.surfaces.ensure('product_abc', chat, { expectNoChanges: true })
6441
- *
6442
- * // Absorb a dashboard edit back into the repo
6443
- * const { definition } = await Runtype.surfaces.pull('product_abc', 'Support Chat')
6444
- * ```
6445
- */
6446
- static get surfaces() {
6447
- return new SurfacesNamespace(() => this.getClient());
6448
- }
6449
- };
6450
-
6451
- // src/transform.ts
6452
- function transformQueryParams(params) {
6453
- const result = {};
6454
- for (const [key, value] of Object.entries(params)) {
6455
- if (value !== void 0 && value !== null) {
6456
- if (Array.isArray(value)) {
6457
- result[key] = value.join(",");
6458
- } else {
6459
- result[key] = String(value);
6460
- }
6461
- }
6462
- }
6463
- return result;
6464
- }
6465
-
6466
- // src/version.ts
6467
- var FALLBACK_VERSION = "0.0.0";
6468
- var SDK_VERSION = "9.9.0".length > 0 ? "9.9.0" : FALLBACK_VERSION;
6469
- var RUNTYPE_CLIENT_KIND = "sdk";
6470
- var SDK_USER_AGENT = `runtype-sdk/${SDK_VERSION} (typescript)`;
6471
-
6472
- // src/detached-reconnect.ts
6473
- var TERMINAL_EVENTS = /* @__PURE__ */ new Set(["execution_complete", "execution_error"]);
6474
- var DEFAULT_MAX_DETACHED_RECONNECTS = 12;
6475
- function observeBlock(block, into) {
6476
- let eventName = null;
6477
- for (const line of block.split("\n")) {
6478
- if (line.startsWith("id:")) {
6479
- into.lastId = line.slice(3).trim();
6480
- continue;
6481
- }
6482
- if (line.startsWith("event:")) {
6483
- eventName = line.slice(6).trim();
6484
- continue;
6485
- }
6486
- if (!line.startsWith("data:")) continue;
6487
- const raw = line.slice(5).trim();
6488
- if (!raw || raw === "[DONE]") continue;
6489
- let payload;
6490
- try {
6491
- const parsed = JSON.parse(raw);
6492
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) continue;
6493
- payload = parsed;
6494
- } catch {
6495
- continue;
6496
- }
6497
- if (typeof payload.executionId === "string") into.executionId = payload.executionId;
6498
- const type = typeof payload.type === "string" ? payload.type : eventName;
6499
- if (type && TERMINAL_EVENTS.has(type)) into.sawTerminal = true;
6500
- 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;
6501
6015
  }
6502
6016
  }
6503
6017
  function withDetachedReconnect(response, reattach, options = {}) {
@@ -8704,6 +8218,13 @@ function buildEmptySessionNudge(consecutiveEmptySessions) {
8704
8218
  }
8705
8219
 
8706
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
+ }
8707
8228
  var FlowsEndpoint = class {
8708
8229
  constructor(client) {
8709
8230
  this.client = client;
@@ -9387,10 +8908,15 @@ var DispatchEndpoint = class {
9387
8908
  }
9388
8909
  /**
9389
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.
9390
8916
  */
9391
- async executeStream(data) {
8917
+ async executeStream(data, init) {
9392
8918
  const normalized = normalizeDispatchRequest(data);
9393
- return this.client.requestStream("/dispatch", {
8919
+ const response = await this.client.requestStream("/dispatch", {
9394
8920
  method: "POST",
9395
8921
  body: JSON.stringify({
9396
8922
  ...normalized,
@@ -9398,8 +8924,32 @@ var DispatchEndpoint = class {
9398
8924
  ...normalized.options,
9399
8925
  streamResponse: true
9400
8926
  }
9401
- })
8927
+ }),
8928
+ ...init?.signal ? { signal: init.signal } : {}
9402
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
+ };
9403
8953
  }
9404
8954
  /**
9405
8955
  * Resume paused flow execution
@@ -9533,6 +9083,14 @@ var AnalyticsEndpoint = class {
9533
9083
  async getEndUserUsage(params) {
9534
9084
  return this.client.get("/analytics/end-user-usage", params);
9535
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
+ }
9536
9094
  };
9537
9095
  var FlowStepsEndpoint = class {
9538
9096
  constructor(client) {
@@ -9743,7 +9301,7 @@ var ToolsEndpoint = class {
9743
9301
  return this.client.get(`/tools/builtin/${toolId}/schema`);
9744
9302
  }
9745
9303
  /**
9746
- * 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.
9747
9305
  */
9748
9306
  async deploySandbox(data) {
9749
9307
  return this.client.post("/tools/sandbox/deploy", data);
@@ -9755,7 +9313,7 @@ var ToolsEndpoint = class {
9755
9313
  return this.client.delete(`/tools/sandbox/${sandboxId}`);
9756
9314
  }
9757
9315
  /**
9758
- * 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.
9759
9317
  */
9760
9318
  async deployCfSandbox(data) {
9761
9319
  return this.client.post("/tools/sandbox/cf-sandbox/deploy", data);
@@ -10214,14 +9772,15 @@ var _AgentsEndpoint = class _AgentsEndpoint {
10214
9772
  * conversation-key behavior.
10215
9773
  */
10216
9774
  buildDetachedReattach(id, data, signal) {
10217
- return async ({ executionId, after }) => {
9775
+ return async ({ executionId, after, signal: reattachSignal }) => {
10218
9776
  const named = data?.conversationId;
10219
9777
  const conversationId = typeof named === "string" ? named : "";
10220
9778
  const query = new URLSearchParams({ after });
10221
9779
  if (conversationId) query.set("conversationId", conversationId);
9780
+ const legSignal = combineAbortSignals(signal, reattachSignal);
10222
9781
  return this.client.requestStream(`/agents/${id}/executions/${executionId}/events?${query.toString()}`, {
10223
9782
  method: "GET",
10224
- ...signal ? { signal } : {}
9783
+ ...legSignal ? { signal: legSignal } : {}
10225
9784
  }).catch(() => null);
10226
9785
  };
10227
9786
  }
@@ -13151,189 +12710,741 @@ var AgentVersionsEndpoint = class {
13151
12710
  return this.client.get(`/agent-versions/${agentId}/${versionId}`);
13152
12711
  }
13153
12712
  /**
13154
- * 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
13155
12957
  */
13156
- async publish(agentId, versionId, options = {}) {
13157
- return this.client.post(`/agent-versions/${agentId}/publish`, {
13158
- versionId,
13159
- ...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
13160
12964
  });
13161
- }
13162
- };
13163
- var FlowVersionsEndpoint = class {
13164
- constructor(client) {
13165
- this.client = client;
12965
+ return response;
13166
12966
  }
13167
12967
  /**
13168
- * List versions for a flow, optionally filtered by version `type`.
12968
+ * Generic DELETE request
13169
12969
  */
13170
- async list(flowId, params) {
13171
- 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;
13172
12977
  }
13173
12978
  /**
13174
- * Get the published version for a flow.
12979
+ * Generic request that returns raw Response for streaming
13175
12980
  */
13176
- async getPublished(flowId) {
13177
- 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
+ });
13178
12991
  }
13179
12992
  /**
13180
- * 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.
13181
13003
  */
13182
- async get(flowId, versionId) {
13183
- 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
+ );
13184
13031
  }
13185
13032
  /**
13186
- * 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.
13187
13038
  */
13188
- async publish(flowId, versionId, options = {}) {
13189
- return this.client.post(`/flow-versions/${flowId}/publish`, {
13190
- versionId,
13191
- ...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
+ }
13192
13047
  });
13193
13048
  }
13194
- };
13195
- var IntegrationsEndpoint = class {
13196
- constructor(client) {
13197
- 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`);
13198
13063
  }
13199
13064
  /**
13200
- * 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
+ * ```
13201
13078
  */
13202
- async list(params) {
13203
- 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
+ });
13204
13088
  }
13205
13089
  /**
13206
- * Get a single integration by ID.
13090
+ * Build full URL with query parameters
13207
13091
  */
13208
- async get(integrationId) {
13209
- 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();
13210
13105
  }
13211
13106
  /**
13212
- * List integrations within a category (e.g. `slack`, `mcp`).
13107
+ * Make HTTP request with timeout and error handling
13213
13108
  */
13214
- async listByCategory(category) {
13215
- return this.client.get(
13216
- `/integrations/category/${category}`
13217
- );
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();
13218
13119
  }
13219
13120
  /**
13220
- * Per-environment credential status across the caller's integrations.
13121
+ * Make HTTP request that returns raw Response (for streaming)
13221
13122
  */
13222
- async getCredentialsStatus() {
13223
- 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
+ }
13224
13148
  }
13149
+ };
13150
+ var Runtype = class {
13225
13151
  /**
13226
- * 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
+ * ```
13227
13161
  */
13228
- async listTools() {
13229
- return this.client.get("/integrations/tools");
13162
+ static configure(config) {
13163
+ globalConfig = { ...globalConfig, ...config };
13164
+ globalClient = new RuntypeClient(globalConfig);
13230
13165
  }
13231
13166
  /**
13232
- * List the tools exposed by a single integration.
13167
+ * Get the global client instance, creating one if needed
13233
13168
  */
13234
- async getIntegrationTools(integrationId) {
13235
- return this.client.get(
13236
- `/integrations/${integrationId}/tools`
13237
- );
13169
+ static getClient() {
13170
+ if (!globalClient) {
13171
+ globalClient = new RuntypeClient(globalConfig);
13172
+ }
13173
+ return globalClient;
13238
13174
  }
13239
13175
  /**
13240
- * 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
+ * ```
13241
13184
  */
13242
- async getTool(integrationId, toolName) {
13243
- return this.client.get(`/integrations/${integrationId}/tools/${toolName}`);
13185
+ static createClient(config) {
13186
+ return new RuntypeClient({ ...globalConfig, ...config });
13244
13187
  }
13245
13188
  /**
13246
- * 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
+ * ```
13247
13208
  */
13248
- async installSlack(data) {
13249
- return this.client.post("/integrations/slack/install", data);
13209
+ static get flows() {
13210
+ return new FlowsNamespace(() => this.getClient());
13250
13211
  }
13251
13212
  /**
13252
- * Start the Slack "Add to Slack" OAuth handshake. Returns the Slack authorize
13253
- * URL to open in a popup; the bot token is captured server-side by the
13254
- * 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
+ * ```
13255
13232
  */
13256
- async startSlackOAuth(data) {
13257
- return this.client.post("/oauth/slack/start", data);
13233
+ static get batches() {
13234
+ return new BatchesNamespace(() => this.getClient());
13258
13235
  }
13259
13236
  /**
13260
- * Generate the Slack app manifest for a surface, plus a link to Slack's
13261
- * app-creation page. The manifest carries absolute API URLs derived
13262
- * server-side, so it is always valid for Slack (relative proxy paths never
13263
- * leak in). Slack's create-app modal ignores a manifest passed in the URL, so
13264
- * `manifestJson` is pasted into its "From a manifest" option rather than
13265
- * 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
+ * ```
13266
13258
  */
13267
- async generateSlackManifest(data) {
13268
- return this.client.post("/integrations/slack/manifest", data);
13259
+ static get evals() {
13260
+ return new EvalsNamespace(() => this.getClient());
13269
13261
  }
13270
13262
  /**
13271
- * Report whether Slack has verified a surface's events URL. Slack sends that
13272
- * challenge when an app is created from a manifest, so a `verifiedAt` newer
13273
- * than the one read before the manifest was handed out is evidence the app
13274
- * 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
+ * ```
13275
13284
  */
13276
- async getSlackAppStatus(surfaceId) {
13277
- return this.client.get(
13278
- `/integrations/slack/app-status?surfaceId=${encodeURIComponent(surfaceId)}`
13279
- );
13280
- }
13281
- };
13282
- var BillingEndpoint = class {
13283
- constructor(client) {
13284
- this.client = client;
13285
+ static get prompts() {
13286
+ return new PromptsNamespace(() => this.getClient());
13285
13287
  }
13286
13288
  /**
13287
- * 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
+ * ```
13288
13303
  */
13289
- async getStatus() {
13290
- return this.client.get("/billing/status");
13304
+ static get skills() {
13305
+ return new SkillsNamespace(() => this.getClient());
13291
13306
  }
13292
13307
  /**
13293
- * 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
+ * ```
13294
13329
  */
13295
- async getCredits() {
13296
- return this.client.get("/billing/credits");
13330
+ static get agents() {
13331
+ return new AgentsNamespace(() => this.getClient());
13297
13332
  }
13298
- /**
13299
- * Get the caller's exact current UTC-month platform spend from the local
13300
- * meter used for spend-cap enforcement. Returns 503 when that meter is unavailable.
13301
- */
13302
- async getCurrentSpend() {
13303
- 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());
13304
13336
  }
13305
13337
  /**
13306
- * Get spend analytics. The window is controlled by either `period` or `days`
13307
- * (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
+ * ```
13308
13361
  */
13309
- async getSpendAnalytics(params) {
13310
- return this.client.get("/billing/spend-analytics", params);
13311
- }
13312
- };
13313
- var ToolApprovalGrantsEndpoint = class {
13314
- constructor(client) {
13315
- this.client = client;
13362
+ static get tools() {
13363
+ return new ToolsNamespace(() => this.getClient());
13316
13364
  }
13317
13365
  /**
13318
- * List active remembered tool-approval grants for the authenticated owner,
13319
- * 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
+ * ```
13320
13392
  */
13321
- async list(agentId) {
13322
- const query = agentId ? `?agentId=${encodeURIComponent(agentId)}` : "";
13323
- const response = await this.client.get(
13324
- `/tool-approval-grants${query}`
13325
- );
13326
- return response.data;
13393
+ static get products() {
13394
+ return new ProductsNamespace(() => this.getClient());
13327
13395
  }
13328
13396
  /**
13329
- * Revoke (soft-delete) a remembered grant so the tool prompts for approval
13330
- * 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
+ * ```
13331
13421
  */
13332
- async revoke(id) {
13333
- return this.client.delete(`/tool-approval-grants/${id}`);
13422
+ static get surfaces() {
13423
+ return new SurfacesNamespace(() => this.getClient());
13334
13424
  }
13335
13425
  };
13336
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
+
13337
13448
  // src/client.ts
13338
13449
  function isObjectRecord(value) {
13339
13450
  return typeof value === "object" && value !== null;
@@ -14673,12 +14784,14 @@ var STEP_TYPE_TO_METHOD = {
14673
14784
  attachRuntimeToolsToDispatchRequest,
14674
14785
  buildAgentAdmissionHeaders,
14675
14786
  buildEmptySessionNudge,
14787
+ buildExecutionEventsPath,
14676
14788
  buildGeneratedRuntimeToolGateOutput,
14677
14789
  buildLedgerOffloadReference,
14678
14790
  buildObservationMaskMarker,
14679
14791
  buildPolicyGuidance,
14680
14792
  buildSendViewOffloadMarker,
14681
14793
  calledTool,
14794
+ combineAbortSignals,
14682
14795
  compileWorkflowConfig,
14683
14796
  completed,
14684
14797
  computeAgentContentHash,