@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.mjs CHANGED
@@ -37,6 +37,7 @@ var UNIFIED_EVENT_TYPES = /* @__PURE__ */ new Set([
37
37
  "approval_complete",
38
38
  "await",
39
39
  "error",
40
+ "context_notice",
40
41
  "ping",
41
42
  "custom"
42
43
  ]);
@@ -2635,11 +2636,12 @@ async function request(client, body) {
2635
2636
  }
2636
2637
  }
2637
2638
  async function ensureFlow(client, definition, options = {}) {
2638
- const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
2639
+ const { dryRun, onConflict, release, expectedRemoteHash, version, expectNoChanges } = options;
2639
2640
  const passthrough = {
2640
2641
  ...onConflict ? { onConflict } : {},
2641
2642
  ...release ? { release } : {},
2642
- ...expectedRemoteHash ? { expectedRemoteHash } : {}
2643
+ ...expectedRemoteHash ? { expectedRemoteHash } : {},
2644
+ ...version ? { version } : {}
2643
2645
  };
2644
2646
  const wireDefinition = { name: definition.name, steps: definition.steps };
2645
2647
  if (dryRun || expectNoChanges) {
@@ -4915,11 +4917,12 @@ var AgentsNamespace = class {
4915
4917
  */
4916
4918
  async ensure(definition, options = {}) {
4917
4919
  const client = this.getClient();
4918
- const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
4920
+ const { dryRun, onConflict, release, expectedRemoteHash, version, expectNoChanges } = options;
4919
4921
  const passthrough = {
4920
4922
  ...onConflict ? { onConflict } : {},
4921
4923
  ...release ? { release } : {},
4922
- ...expectedRemoteHash ? { expectedRemoteHash } : {}
4924
+ ...expectedRemoteHash ? { expectedRemoteHash } : {},
4925
+ ...version ? { version } : {}
4923
4926
  };
4924
4927
  if (dryRun || expectNoChanges) {
4925
4928
  const plan = await this.request(client, {
@@ -5766,542 +5769,51 @@ function normalizeDispatchRequest(request6) {
5766
5769
  return request6.flow ? { ...normalized, flow: request6.flow } : { ...normalized, agent: request6.agent };
5767
5770
  }
5768
5771
 
5769
- // src/runtype.ts
5770
- var globalConfig = {};
5771
- var globalClient = null;
5772
- var RuntypeClient = class {
5773
- constructor(config = {}) {
5774
- const baseUrl = config.baseUrl || "https://api.runtype.com";
5775
- this.apiVersion = config.apiVersion || "v1";
5776
- this.baseUrl = this.apiVersion ? `${baseUrl}/${this.apiVersion}` : baseUrl;
5777
- this.timeout = config.timeout || 3e4;
5778
- this.headers = {
5779
- "Content-Type": "application/json",
5780
- ...config.headers || {}
5781
- };
5782
- if (config.apiKey) {
5783
- this.headers.Authorization = `Bearer ${config.apiKey}`;
5784
- }
5785
- }
5786
- /**
5787
- * Set the API key for authentication
5788
- */
5789
- setApiKey(apiKey) {
5790
- this.headers.Authorization = `Bearer ${apiKey}`;
5791
- }
5792
- /**
5793
- * Generic GET request
5794
- */
5795
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts typed list-param interfaces (no index signature); `unknown` would reject them
5796
- async get(path, params) {
5797
- const url = this.buildUrl(path, params);
5798
- const response = await this.makeRequest(url, {
5799
- method: "GET",
5800
- headers: this.headers
5801
- });
5802
- return response;
5803
- }
5804
- /**
5805
- * Generic POST request
5806
- */
5807
- async post(path, data, extraHeaders) {
5808
- const url = this.buildUrl(path);
5809
- const response = await this.makeRequest(url, {
5810
- method: "POST",
5811
- headers: { ...this.headers, ...extraHeaders },
5812
- body: data ? JSON.stringify(data) : void 0
5813
- });
5814
- return response;
5815
- }
5816
- /**
5817
- * Generic PUT request
5818
- */
5819
- async put(path, data) {
5820
- const url = this.buildUrl(path);
5821
- const response = await this.makeRequest(url, {
5822
- method: "PUT",
5823
- headers: this.headers,
5824
- body: data ? JSON.stringify(data) : void 0
5825
- });
5826
- return response;
5827
- }
5828
- /**
5829
- * Generic PATCH request
5830
- */
5831
- async patch(path, data) {
5832
- const url = this.buildUrl(path);
5833
- const response = await this.makeRequest(url, {
5834
- method: "PATCH",
5835
- headers: this.headers,
5836
- body: data ? JSON.stringify(data) : void 0
5837
- });
5838
- return response;
5839
- }
5840
- /**
5841
- * Generic DELETE request
5842
- */
5843
- async delete(path) {
5844
- const url = this.buildUrl(path);
5845
- const response = await this.makeRequest(url, {
5846
- method: "DELETE",
5847
- headers: this.headers
5848
- });
5849
- return response;
5850
- }
5851
- /**
5852
- * Generic request that returns raw Response for streaming
5853
- */
5854
- async requestStream(path, options = {}) {
5855
- const url = this.buildUrl(path);
5856
- const headers = {
5857
- ...this.headers,
5858
- ...options.headers
5859
- };
5860
- return this.makeRawRequest(url, {
5861
- ...options,
5862
- headers
5863
- });
5864
- }
5865
- /**
5866
- * Dispatch flow execution (streaming).
5867
- *
5868
- * This is the sole streaming-dispatch chokepoint for the flow builders
5869
- * (`RuntypeFlowBuilder`), so it normalizes the request to the canonical
5870
- * `/v1/dispatch` wire contract here — every builder path inherits the same
5871
- * normalization the `DispatchEndpoint` applies, with no per-builder call.
5872
- */
5873
- async dispatch(config) {
5874
- const normalized = normalizeDispatchRequest(config);
5875
- const request6 = {
5876
- ...normalized,
5877
- options: {
5878
- ...normalized.options,
5879
- streamResponse: true
5880
- }
5881
- };
5882
- return this.requestStream("/dispatch", {
5883
- method: "POST",
5884
- body: JSON.stringify(request6)
5885
- });
5886
- }
5887
- /**
5888
- * Dispatch flow execution (non-streaming JSON).
5889
- *
5890
- * The non-streaming sibling of {@link dispatch}; it normalizes to the same
5891
- * canonical wire contract so builders never post a raw, un-normalized body,
5892
- * and pins `streamResponse: false` so the server returns buffered JSON.
5893
- */
5894
- async dispatchJson(config) {
5895
- const normalized = normalizeDispatchRequest(config);
5896
- return this.post("/dispatch", {
5897
- ...normalized,
5898
- options: {
5899
- ...normalized.options,
5900
- streamResponse: false
5901
- }
5902
- });
5903
- }
5904
- /** Start a normalized dispatch and return a durable handle immediately. */
5905
- async dispatchAsync(config) {
5906
- const normalized = normalizeDispatchRequest(config);
5907
- return this.post(
5908
- "/dispatch",
5909
- {
5910
- ...normalized,
5911
- options: { ...normalized.options, streamResponse: false }
5912
- },
5913
- { Prefer: "respond-async" }
5914
- );
5915
- }
5916
- async getExecutionStatus(executionId) {
5917
- return this.get(`/executions/${encodeURIComponent(executionId)}/status`);
5918
- }
5919
- /**
5920
- * Build full URL with query parameters
5921
- */
5922
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- mirrors get()'s permissive params type
5923
- buildUrl(path, params) {
5924
- const base = this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`;
5925
- const relPath = path.startsWith("/") ? path.slice(1) : path;
5926
- const url = new URL(relPath, base);
5927
- if (params) {
5928
- Object.entries(params).forEach(([key, value]) => {
5929
- if (value !== void 0 && value !== null) {
5930
- url.searchParams.set(key, String(value));
5931
- }
5932
- });
5772
+ // src/detached-reconnect.ts
5773
+ var TERMINAL_EVENTS = /* @__PURE__ */ new Set(["execution_complete", "execution_error"]);
5774
+ var DEFAULT_MAX_DETACHED_RECONNECTS = 12;
5775
+ function combineAbortSignals(...signals) {
5776
+ const present = signals.filter((signal) => Boolean(signal));
5777
+ if (present.length === 0) return void 0;
5778
+ if (present.length === 1) return present[0];
5779
+ const anySignal = AbortSignal.any;
5780
+ if (typeof anySignal === "function") return anySignal.call(AbortSignal, present);
5781
+ const controller = new AbortController();
5782
+ for (const signal of present) {
5783
+ if (signal.aborted) {
5784
+ controller.abort(signal.reason);
5785
+ break;
5933
5786
  }
5934
- return url.toString();
5787
+ signal.addEventListener("abort", () => controller.abort(signal.reason), { once: true });
5935
5788
  }
5936
- /**
5937
- * Make HTTP request with timeout and error handling
5938
- */
5939
- async makeRequest(url, options) {
5940
- const response = await this.makeRawRequest(url, options);
5941
- if (response.status === 204) {
5942
- return null;
5789
+ return controller.signal;
5790
+ }
5791
+ function observeBlock(block, into) {
5792
+ let eventName = null;
5793
+ for (const line of block.split("\n")) {
5794
+ if (line.startsWith("id:")) {
5795
+ into.lastId = line.slice(3).trim();
5796
+ continue;
5943
5797
  }
5944
- const contentType = response.headers.get("content-type");
5945
- if (contentType?.includes("application/json")) {
5946
- return response.json();
5798
+ if (line.startsWith("event:")) {
5799
+ eventName = line.slice(6).trim();
5800
+ continue;
5947
5801
  }
5948
- return response.text();
5949
- }
5950
- /**
5951
- * Make HTTP request that returns raw Response (for streaming)
5952
- */
5953
- async makeRawRequest(url, options) {
5954
- const controller = new AbortController();
5955
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
5802
+ if (!line.startsWith("data:")) continue;
5803
+ const raw = line.slice(5).trim();
5804
+ if (!raw || raw === "[DONE]") continue;
5805
+ let payload;
5956
5806
  try {
5957
- const response = await fetch(url, {
5958
- ...options,
5959
- signal: controller.signal
5960
- });
5961
- clearTimeout(timeoutId);
5962
- if (!response.ok) {
5963
- const errorText = await response.text();
5964
- throw new Error(
5965
- `API request failed: ${response.status} ${response.statusText} - ${errorText}`
5966
- );
5967
- }
5968
- return response;
5969
- } catch (error) {
5970
- clearTimeout(timeoutId);
5971
- if (error instanceof Error && error.name === "AbortError") {
5972
- throw new Error(`Request timeout after ${this.timeout}ms`, { cause: error });
5973
- }
5974
- throw error;
5975
- }
5976
- }
5977
- };
5978
- var Runtype = class {
5979
- /**
5980
- * Configure the global Runtype client
5981
- *
5982
- * Call this once at app startup to set the API key and other options.
5983
- * All subsequent calls to Runtype.flows, Runtype.batches, etc. will use this config.
5984
- *
5985
- * @example
5986
- * ```typescript
5987
- * Runtype.configure({ apiKey: process.env.RUNTYPE_API_KEY })
5988
- * ```
5989
- */
5990
- static configure(config) {
5991
- globalConfig = { ...globalConfig, ...config };
5992
- globalClient = new RuntypeClient(globalConfig);
5993
- }
5994
- /**
5995
- * Get the global client instance, creating one if needed
5996
- */
5997
- static getClient() {
5998
- if (!globalClient) {
5999
- globalClient = new RuntypeClient(globalConfig);
5807
+ const parsed = JSON.parse(raw);
5808
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) continue;
5809
+ payload = parsed;
5810
+ } catch {
5811
+ continue;
6000
5812
  }
6001
- return globalClient;
6002
- }
6003
- /**
6004
- * Create a new client instance with custom configuration
6005
- *
6006
- * Use this when you need a client with different settings than the global one.
6007
- *
6008
- * @example
6009
- * ```typescript
6010
- * const client = Runtype.createClient({ apiKey: 'different_key' })
6011
- * ```
6012
- */
6013
- static createClient(config) {
6014
- return new RuntypeClient({ ...globalConfig, ...config });
6015
- }
6016
- /**
6017
- * Flows namespace - Build and execute flows
6018
- *
6019
- * @example
6020
- * ```typescript
6021
- * // Upsert a flow (create or update)
6022
- * const result = await Runtype.flows.upsert({ name: 'My Flow' })
6023
- * .prompt({ name: 'Analyze', model: 'gpt-4o', userPrompt: '...' })
6024
- * .stream()
6025
- *
6026
- * // Use an existing flow
6027
- * const result = await Runtype.flows.use('flow_123')
6028
- * .withRecord({ name: 'Test' })
6029
- * .result()
6030
- *
6031
- * // Virtual flow (one-off, not saved)
6032
- * const result = await Runtype.flows.virtual({ name: 'Temp Flow' })
6033
- * .prompt({ ... })
6034
- * .stream()
6035
- * ```
6036
- */
6037
- static get flows() {
6038
- return new FlowsNamespace(() => this.getClient());
6039
- }
6040
- /**
6041
- * Batches namespace - Schedule and manage batch operations
6042
- *
6043
- * @example
6044
- * ```typescript
6045
- * // Schedule a batch
6046
- * const batch = await Runtype.batches.schedule({
6047
- * flowId: 'flow_123',
6048
- * recordType: 'customers',
6049
- * })
6050
- *
6051
- * // Get batch status
6052
- * const status = await Runtype.batches.get('batch_456')
6053
- *
6054
- * // Cancel a batch
6055
- * await Runtype.batches.cancel('batch_456')
6056
- *
6057
- * // List batches
6058
- * const batches = await Runtype.batches.list({ status: 'running' })
6059
- * ```
6060
- */
6061
- static get batches() {
6062
- return new BatchesNamespace(() => this.getClient());
6063
- }
6064
- /**
6065
- * Evals namespace - Run evaluations and compare models
6066
- *
6067
- * @example
6068
- * ```typescript
6069
- * // Run an eval with streaming
6070
- * const stream = await Runtype.evals.run({
6071
- * flowId: 'flow_123',
6072
- * recordType: 'test_data',
6073
- * models: [{ stepName: 'Analyze', model: 'gpt-4o' }]
6074
- * }).stream()
6075
- *
6076
- * // Submit eval as batch job
6077
- * const eval = await Runtype.evals.run({
6078
- * flowId: 'flow_123',
6079
- * recordType: 'test_data',
6080
- * models: [
6081
- * [{ stepName: 'Analyze', model: 'gpt-5.4' }],
6082
- * [{ stepName: 'Analyze', model: 'claude-opus-4-6' }],
6083
- * ]
6084
- * }).submit()
6085
- * ```
6086
- */
6087
- static get evals() {
6088
- return new EvalsNamespace(() => this.getClient());
6089
- }
6090
- /**
6091
- * Prompts namespace - Manage and execute prompts
6092
- *
6093
- * @example
6094
- * ```typescript
6095
- * // Execute a prompt with streaming
6096
- * const stream = await Runtype.prompts.run('prompt_123', {
6097
- * recordId: 'rec_456'
6098
- * }).stream()
6099
- *
6100
- * // Get complete result
6101
- * const result = await Runtype.prompts.run('prompt_123', {
6102
- * recordId: 'rec_456'
6103
- * }).result()
6104
- *
6105
- * // CRUD operations
6106
- * const prompts = await Runtype.prompts.list()
6107
- * const prompt = await Runtype.prompts.get('prompt_123')
6108
- * const newPrompt = await Runtype.prompts.create({ ... })
6109
- * await Runtype.prompts.update('prompt_123', { ... })
6110
- * await Runtype.prompts.delete('prompt_123')
6111
- * ```
6112
- */
6113
- static get prompts() {
6114
- return new PromptsNamespace(() => this.getClient());
6115
- }
6116
- /**
6117
- * Skills namespace - Manage Agent Skills (admin/control plane)
6118
- *
6119
- * @example
6120
- * ```typescript
6121
- * // Create a published skill from a SKILL.md document
6122
- * const { skill } = await Runtype.skills.create({ markdown: skillMd, publish: true })
6123
- *
6124
- * // Bind it to an agent
6125
- * await Runtype.skills.bind({ agentId: 'agent_123', skillId: skill.id })
6126
- *
6127
- * // Review agent-authored proposals
6128
- * const pending = await Runtype.skills.proposals.list()
6129
- * await Runtype.skills.proposals.approve(pending[0].id)
6130
- * ```
6131
- */
6132
- static get skills() {
6133
- return new SkillsNamespace(() => this.getClient());
6134
- }
6135
- /**
6136
- * Agents namespace - Agent config-as-code (define / ensure / pull)
6137
- *
6138
- * @example
6139
- * ```typescript
6140
- * import { defineAgent, Runtype } from '@runtypelabs/sdk'
6141
- *
6142
- * const assistant = defineAgent({
6143
- * name: 'Pricing Assistant',
6144
- * model: 'claude-sonnet-4-6',
6145
- * systemPrompt: renderPrompt(pricingData),
6146
- * })
6147
- *
6148
- * // Converge at deploy time (idempotent; one tiny probe in steady state)
6149
- * await Runtype.agents.ensure(assistant)
6150
- *
6151
- * // CI drift gate
6152
- * await Runtype.agents.ensure(assistant, { expectNoChanges: true })
6153
- *
6154
- * // Absorb a dashboard edit back into the repo
6155
- * const { definition } = await Runtype.agents.pull('Pricing Assistant')
6156
- * ```
6157
- */
6158
- static get agents() {
6159
- return new AgentsNamespace(() => this.getClient());
6160
- }
6161
- /** Poll durable handles returned by asynchronous execute operations. */
6162
- static get executions() {
6163
- return new ExecutionsNamespace(() => this.getClient());
6164
- }
6165
- /**
6166
- * Tools namespace - Tool config-as-code (define / ensure / pull)
6167
- *
6168
- * @example
6169
- * ```typescript
6170
- * import { defineTool, Runtype } from '@runtypelabs/sdk'
6171
- *
6172
- * const weather = defineTool({
6173
- * name: 'Weather Lookup',
6174
- * description: 'Fetch the current weather for a city',
6175
- * toolType: 'external',
6176
- * parametersSchema: { type: 'object', properties: { city: { type: 'string' } } },
6177
- * config: { url: 'https://api.example.com/weather', method: 'GET' },
6178
- * })
6179
- *
6180
- * // Converge at deploy time (idempotent; one tiny probe in steady state)
6181
- * await Runtype.tools.ensure(weather)
6182
- *
6183
- * // CI drift gate
6184
- * await Runtype.tools.ensure(weather, { expectNoChanges: true })
6185
- *
6186
- * // Absorb a dashboard edit back into the repo
6187
- * const { definition } = await Runtype.tools.pull('Weather Lookup')
6188
- * ```
6189
- */
6190
- static get tools() {
6191
- return new ToolsNamespace(() => this.getClient());
6192
- }
6193
- /**
6194
- * Products namespace - Product config-as-code (define / ensure / pull)
6195
- *
6196
- * Converges the top-level product record (description, icon, spec). Nested
6197
- * capabilities/surfaces/tools and the canvas UI layout state are not
6198
- * converged by ensure.
6199
- *
6200
- * @example
6201
- * ```typescript
6202
- * import { defineProduct, Runtype } from '@runtypelabs/sdk'
6203
- *
6204
- * const product = defineProduct({
6205
- * name: 'Support Copilot',
6206
- * description: 'An AI support assistant',
6207
- * icon: '🤖',
6208
- * spec: { productGoal: 'Deflect tier-1 tickets', productStage: 'beta' },
6209
- * })
6210
- *
6211
- * // Converge at deploy time (idempotent; one tiny probe in steady state)
6212
- * await Runtype.products.ensure(product)
6213
- *
6214
- * // CI drift gate
6215
- * await Runtype.products.ensure(product, { expectNoChanges: true })
6216
- *
6217
- * // Absorb a dashboard edit back into the repo
6218
- * const { definition } = await Runtype.products.pull('Support Copilot')
6219
- * ```
6220
- */
6221
- static get products() {
6222
- return new ProductsNamespace(() => this.getClient());
6223
- }
6224
- /**
6225
- * Config-as-code operations for product surfaces. `surfaces.ensure` is the
6226
- * deploy-time, non-executing converge (create-or-update a surface by name
6227
- * within a product); `surfaces.pull` is the absorb-drift direction.
6228
- *
6229
- * @example
6230
- * ```typescript
6231
- * import { Runtype, defineSurface } from '@runtypelabs/sdk'
6232
- *
6233
- * const chat = defineSurface({
6234
- * name: 'Support Chat',
6235
- * type: 'chat',
6236
- * behavior: { type: 'chat', greeting: 'Hi there!' },
6237
- * status: 'active',
6238
- * })
6239
- *
6240
- * // Converge at deploy time (idempotent; one tiny probe in steady state)
6241
- * await Runtype.surfaces.ensure('product_abc', chat)
6242
- *
6243
- * // CI drift gate
6244
- * await Runtype.surfaces.ensure('product_abc', chat, { expectNoChanges: true })
6245
- *
6246
- * // Absorb a dashboard edit back into the repo
6247
- * const { definition } = await Runtype.surfaces.pull('product_abc', 'Support Chat')
6248
- * ```
6249
- */
6250
- static get surfaces() {
6251
- return new SurfacesNamespace(() => this.getClient());
6252
- }
6253
- };
6254
-
6255
- // src/transform.ts
6256
- function transformQueryParams(params) {
6257
- const result = {};
6258
- for (const [key, value] of Object.entries(params)) {
6259
- if (value !== void 0 && value !== null) {
6260
- if (Array.isArray(value)) {
6261
- result[key] = value.join(",");
6262
- } else {
6263
- result[key] = String(value);
6264
- }
6265
- }
6266
- }
6267
- return result;
6268
- }
6269
-
6270
- // src/version.ts
6271
- var FALLBACK_VERSION = "0.0.0";
6272
- var SDK_VERSION = "9.9.0".length > 0 ? "9.9.0" : FALLBACK_VERSION;
6273
- var RUNTYPE_CLIENT_KIND = "sdk";
6274
- var SDK_USER_AGENT = `runtype-sdk/${SDK_VERSION} (typescript)`;
6275
-
6276
- // src/detached-reconnect.ts
6277
- var TERMINAL_EVENTS = /* @__PURE__ */ new Set(["execution_complete", "execution_error"]);
6278
- var DEFAULT_MAX_DETACHED_RECONNECTS = 12;
6279
- function observeBlock(block, into) {
6280
- let eventName = null;
6281
- for (const line of block.split("\n")) {
6282
- if (line.startsWith("id:")) {
6283
- into.lastId = line.slice(3).trim();
6284
- continue;
6285
- }
6286
- if (line.startsWith("event:")) {
6287
- eventName = line.slice(6).trim();
6288
- continue;
6289
- }
6290
- if (!line.startsWith("data:")) continue;
6291
- const raw = line.slice(5).trim();
6292
- if (!raw || raw === "[DONE]") continue;
6293
- let payload;
6294
- try {
6295
- const parsed = JSON.parse(raw);
6296
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) continue;
6297
- payload = parsed;
6298
- } catch {
6299
- continue;
6300
- }
6301
- if (typeof payload.executionId === "string") into.executionId = payload.executionId;
6302
- const type = typeof payload.type === "string" ? payload.type : eventName;
6303
- if (type && TERMINAL_EVENTS.has(type)) into.sawTerminal = true;
6304
- if (type === "await" && payload.awaitReason === "detached") into.sawDetach = true;
5813
+ if (typeof payload.executionId === "string") into.executionId = payload.executionId;
5814
+ const type = typeof payload.type === "string" ? payload.type : eventName;
5815
+ if (type && TERMINAL_EVENTS.has(type)) into.sawTerminal = true;
5816
+ if (type === "await" && payload.awaitReason === "detached") into.sawDetach = true;
6305
5817
  }
6306
5818
  }
6307
5819
  function withDetachedReconnect(response, reattach, options = {}) {
@@ -8508,6 +8020,13 @@ function buildEmptySessionNudge(consecutiveEmptySessions) {
8508
8020
  }
8509
8021
 
8510
8022
  // src/endpoints.ts
8023
+ function buildExecutionEventsPath(executionId, query = {}) {
8024
+ const params = new URLSearchParams();
8025
+ if (query.after) params.set("after", query.after);
8026
+ if (query.conversationId) params.set("conversationId", query.conversationId);
8027
+ const search = params.toString();
8028
+ return `/executions/${encodeURIComponent(executionId)}/events${search ? `?${search}` : ""}`;
8029
+ }
8511
8030
  var FlowsEndpoint = class {
8512
8031
  constructor(client) {
8513
8032
  this.client = client;
@@ -9191,10 +8710,15 @@ var DispatchEndpoint = class {
9191
8710
  }
9192
8711
  /**
9193
8712
  * Dispatch with streaming response
8713
+ *
8714
+ * A dispatched agent turn runs on the durable lane, so its socket can close
8715
+ * with `await` / `awaitReason: 'detached'` while the run continues. The
8716
+ * stream follows that detach through the execution-scoped events alias;
8717
+ * `autoReconnect: false` hands back the raw stream instead.
9194
8718
  */
9195
- async executeStream(data) {
8719
+ async executeStream(data, init) {
9196
8720
  const normalized = normalizeDispatchRequest(data);
9197
- return this.client.requestStream("/dispatch", {
8721
+ const response = await this.client.requestStream("/dispatch", {
9198
8722
  method: "POST",
9199
8723
  body: JSON.stringify({
9200
8724
  ...normalized,
@@ -9202,8 +8726,32 @@ var DispatchEndpoint = class {
9202
8726
  ...normalized.options,
9203
8727
  streamResponse: true
9204
8728
  }
9205
- })
8729
+ }),
8730
+ ...init?.signal ? { signal: init.signal } : {}
9206
8731
  });
8732
+ return withDetachedReconnect(
8733
+ response,
8734
+ this.buildDetachedReattach(normalized, init?.signal),
8735
+ init ?? {}
8736
+ );
8737
+ }
8738
+ /**
8739
+ * The `?after=` reattach leg a detached dispatch stream is followed with.
8740
+ *
8741
+ * Unlike an agent execute, a dispatch knows no agent id at the call site, so
8742
+ * it rejoins by execution id alone through the execution-scoped alias. The
8743
+ * cursor is the last SSE `id:` the stream delivered, forwarded verbatim.
8744
+ */
8745
+ buildDetachedReattach(data, signal) {
8746
+ return async ({ executionId, after, signal: reattachSignal }) => {
8747
+ const named = data?.conversationId;
8748
+ const conversationId = typeof named === "string" && named ? named : void 0;
8749
+ const legSignal = combineAbortSignals(signal, reattachSignal);
8750
+ return this.client.requestStream(buildExecutionEventsPath(executionId, { after, conversationId }), {
8751
+ method: "GET",
8752
+ ...legSignal ? { signal: legSignal } : {}
8753
+ }).catch(() => null);
8754
+ };
9207
8755
  }
9208
8756
  /**
9209
8757
  * Resume paused flow execution
@@ -9337,6 +8885,14 @@ var AnalyticsEndpoint = class {
9337
8885
  async getEndUserUsage(params) {
9338
8886
  return this.client.get("/analytics/end-user-usage", params);
9339
8887
  }
8888
+ /**
8889
+ * Get reliability, latency, unit economics, and eval health for the current
8890
+ * period against the preceding period of equal length, plus a derived feed of
8891
+ * notable changes.
8892
+ */
8893
+ async getProductionHealth(params) {
8894
+ return this.client.get("/analytics/production-health", params);
8895
+ }
9340
8896
  };
9341
8897
  var FlowStepsEndpoint = class {
9342
8898
  constructor(client) {
@@ -9547,7 +9103,7 @@ var ToolsEndpoint = class {
9547
9103
  return this.client.get(`/tools/builtin/${toolId}/schema`);
9548
9104
  }
9549
9105
  /**
9550
- * Deploy code to a persistent Daytona sandbox and get a preview URL
9106
+ * Deploy a Daytona preview; retention defaults to ten minutes and the URL is not durable hosting.
9551
9107
  */
9552
9108
  async deploySandbox(data) {
9553
9109
  return this.client.post("/tools/sandbox/deploy", data);
@@ -9559,7 +9115,7 @@ var ToolsEndpoint = class {
9559
9115
  return this.client.delete(`/tools/sandbox/${sandboxId}`);
9560
9116
  }
9561
9117
  /**
9562
- * Deploy code to a persistent Cloudflare Sandbox container and get a preview URL
9118
+ * Deploy a Runtype Sandbox preview; omitted retention preserves the legacy unlimited backstop.
9563
9119
  */
9564
9120
  async deployCfSandbox(data) {
9565
9121
  return this.client.post("/tools/sandbox/cf-sandbox/deploy", data);
@@ -10018,14 +9574,15 @@ var _AgentsEndpoint = class _AgentsEndpoint {
10018
9574
  * conversation-key behavior.
10019
9575
  */
10020
9576
  buildDetachedReattach(id, data, signal) {
10021
- return async ({ executionId, after }) => {
9577
+ return async ({ executionId, after, signal: reattachSignal }) => {
10022
9578
  const named = data?.conversationId;
10023
9579
  const conversationId = typeof named === "string" ? named : "";
10024
9580
  const query = new URLSearchParams({ after });
10025
9581
  if (conversationId) query.set("conversationId", conversationId);
9582
+ const legSignal = combineAbortSignals(signal, reattachSignal);
10026
9583
  return this.client.requestStream(`/agents/${id}/executions/${executionId}/events?${query.toString()}`, {
10027
9584
  method: "GET",
10028
- ...signal ? { signal } : {}
9585
+ ...legSignal ? { signal: legSignal } : {}
10029
9586
  }).catch(() => null);
10030
9587
  };
10031
9588
  }
@@ -12955,189 +12512,741 @@ var AgentVersionsEndpoint = class {
12955
12512
  return this.client.get(`/agent-versions/${agentId}/${versionId}`);
12956
12513
  }
12957
12514
  /**
12958
- * Publish a version (promote it to the agent's published version).
12515
+ * Publish a version (promote it to the agent's published version).
12516
+ */
12517
+ async publish(agentId, versionId, options = {}) {
12518
+ return this.client.post(`/agent-versions/${agentId}/publish`, {
12519
+ versionId,
12520
+ ...options
12521
+ });
12522
+ }
12523
+ };
12524
+ var FlowVersionsEndpoint = class {
12525
+ constructor(client) {
12526
+ this.client = client;
12527
+ }
12528
+ /**
12529
+ * List versions for a flow, optionally filtered by version `type`.
12530
+ */
12531
+ async list(flowId, params) {
12532
+ return this.client.get(`/flow-versions/${flowId}`, params);
12533
+ }
12534
+ /**
12535
+ * Get the published version for a flow.
12536
+ */
12537
+ async getPublished(flowId) {
12538
+ return this.client.get(`/flow-versions/${flowId}/published`);
12539
+ }
12540
+ /**
12541
+ * Get a specific version of a flow.
12542
+ */
12543
+ async get(flowId, versionId) {
12544
+ return this.client.get(`/flow-versions/${flowId}/${versionId}`);
12545
+ }
12546
+ /**
12547
+ * Publish a version (promote it to the flow's published version).
12548
+ */
12549
+ async publish(flowId, versionId, options = {}) {
12550
+ return this.client.post(`/flow-versions/${flowId}/publish`, {
12551
+ versionId,
12552
+ ...options
12553
+ });
12554
+ }
12555
+ };
12556
+ var IntegrationsEndpoint = class {
12557
+ constructor(client) {
12558
+ this.client = client;
12559
+ }
12560
+ /**
12561
+ * List all integrations with the caller's per-integration configuration status.
12562
+ */
12563
+ async list(params) {
12564
+ return this.client.get("/integrations", params);
12565
+ }
12566
+ /**
12567
+ * Get a single integration by ID.
12568
+ */
12569
+ async get(integrationId) {
12570
+ return this.client.get(`/integrations/${integrationId}`);
12571
+ }
12572
+ /**
12573
+ * List integrations within a category (e.g. `slack`, `mcp`).
12574
+ */
12575
+ async listByCategory(category) {
12576
+ return this.client.get(
12577
+ `/integrations/category/${category}`
12578
+ );
12579
+ }
12580
+ /**
12581
+ * Per-environment credential status across the caller's integrations.
12582
+ */
12583
+ async getCredentialsStatus() {
12584
+ return this.client.get("/integrations/credentials-status");
12585
+ }
12586
+ /**
12587
+ * List all tools exposed across the caller's configured integrations.
12588
+ */
12589
+ async listTools() {
12590
+ return this.client.get("/integrations/tools");
12591
+ }
12592
+ /**
12593
+ * List the tools exposed by a single integration.
12594
+ */
12595
+ async getIntegrationTools(integrationId) {
12596
+ return this.client.get(
12597
+ `/integrations/${integrationId}/tools`
12598
+ );
12599
+ }
12600
+ /**
12601
+ * Get the definition of a single tool within an integration.
12602
+ */
12603
+ async getTool(integrationId, toolName) {
12604
+ return this.client.get(`/integrations/${integrationId}/tools/${toolName}`);
12605
+ }
12606
+ /**
12607
+ * Install a Slack integration from a completed OAuth handshake.
12608
+ */
12609
+ async installSlack(data) {
12610
+ return this.client.post("/integrations/slack/install", data);
12611
+ }
12612
+ /**
12613
+ * Start the Slack "Add to Slack" OAuth handshake. Returns the Slack authorize
12614
+ * URL to open in a popup; the bot token is captured server-side by the
12615
+ * callback (never returned to the browser).
12616
+ */
12617
+ async startSlackOAuth(data) {
12618
+ return this.client.post("/oauth/slack/start", data);
12619
+ }
12620
+ /**
12621
+ * Generate the Slack app manifest for a surface, plus a link to Slack's
12622
+ * app-creation page. The manifest carries absolute API URLs derived
12623
+ * server-side, so it is always valid for Slack (relative proxy paths never
12624
+ * leak in). Slack's create-app modal ignores a manifest passed in the URL, so
12625
+ * `manifestJson` is pasted into its "From a manifest" option rather than
12626
+ * embedded in `createAppUrl`.
12627
+ */
12628
+ async generateSlackManifest(data) {
12629
+ return this.client.post("/integrations/slack/manifest", data);
12630
+ }
12631
+ /**
12632
+ * Report whether Slack has verified a surface's events URL. Slack sends that
12633
+ * challenge when an app is created from a manifest, so a `verifiedAt` newer
12634
+ * than the one read before the manifest was handed out is evidence the app
12635
+ * now exists. Markers expire after an hour.
12636
+ */
12637
+ async getSlackAppStatus(surfaceId) {
12638
+ return this.client.get(
12639
+ `/integrations/slack/app-status?surfaceId=${encodeURIComponent(surfaceId)}`
12640
+ );
12641
+ }
12642
+ };
12643
+ var BillingEndpoint = class {
12644
+ constructor(client) {
12645
+ this.client = client;
12646
+ }
12647
+ /**
12648
+ * Get the caller's subscription status, plan limits, and current usage.
12649
+ */
12650
+ async getStatus() {
12651
+ return this.client.get("/billing/status");
12652
+ }
12653
+ /**
12654
+ * Get the caller's credit grants and available/used totals.
12655
+ */
12656
+ async getCredits() {
12657
+ return this.client.get("/billing/credits");
12658
+ }
12659
+ /**
12660
+ * Get the caller's exact current UTC-month platform spend from the local
12661
+ * meter used for spend-cap enforcement. Returns 503 when that meter is unavailable.
12662
+ */
12663
+ async getCurrentSpend() {
12664
+ return this.client.get("/billing/current-spend");
12665
+ }
12666
+ /**
12667
+ * Get spend analytics. The window is controlled by either `period` or `days`
12668
+ * (1–365, defaults to 30).
12669
+ */
12670
+ async getSpendAnalytics(params) {
12671
+ return this.client.get("/billing/spend-analytics", params);
12672
+ }
12673
+ };
12674
+ var ToolApprovalGrantsEndpoint = class {
12675
+ constructor(client) {
12676
+ this.client = client;
12677
+ }
12678
+ /**
12679
+ * List active remembered tool-approval grants for the authenticated owner,
12680
+ * optionally filtered to a single agent.
12681
+ */
12682
+ async list(agentId) {
12683
+ const query = agentId ? `?agentId=${encodeURIComponent(agentId)}` : "";
12684
+ const response = await this.client.get(
12685
+ `/tool-approval-grants${query}`
12686
+ );
12687
+ return response.data;
12688
+ }
12689
+ /**
12690
+ * Revoke (soft-delete) a remembered grant so the tool prompts for approval
12691
+ * again on future dispatches.
12692
+ */
12693
+ async revoke(id) {
12694
+ return this.client.delete(`/tool-approval-grants/${id}`);
12695
+ }
12696
+ };
12697
+
12698
+ // src/runtype.ts
12699
+ var globalConfig = {};
12700
+ var globalClient = null;
12701
+ var RuntypeClient = class {
12702
+ constructor(config = {}) {
12703
+ const baseUrl = config.baseUrl || "https://api.runtype.com";
12704
+ this.apiVersion = config.apiVersion || "v1";
12705
+ this.baseUrl = this.apiVersion ? `${baseUrl}/${this.apiVersion}` : baseUrl;
12706
+ this.timeout = config.timeout || 3e4;
12707
+ this.headers = {
12708
+ "Content-Type": "application/json",
12709
+ ...config.headers || {}
12710
+ };
12711
+ if (config.apiKey) {
12712
+ this.headers.Authorization = `Bearer ${config.apiKey}`;
12713
+ }
12714
+ }
12715
+ /**
12716
+ * Set the API key for authentication
12717
+ */
12718
+ setApiKey(apiKey) {
12719
+ this.headers.Authorization = `Bearer ${apiKey}`;
12720
+ }
12721
+ /**
12722
+ * Generic GET request
12723
+ */
12724
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts typed list-param interfaces (no index signature); `unknown` would reject them
12725
+ async get(path, params) {
12726
+ const url = this.buildUrl(path, params);
12727
+ const response = await this.makeRequest(url, {
12728
+ method: "GET",
12729
+ headers: this.headers
12730
+ });
12731
+ return response;
12732
+ }
12733
+ /**
12734
+ * Generic POST request
12735
+ */
12736
+ async post(path, data, extraHeaders) {
12737
+ const url = this.buildUrl(path);
12738
+ const response = await this.makeRequest(url, {
12739
+ method: "POST",
12740
+ headers: { ...this.headers, ...extraHeaders },
12741
+ body: data ? JSON.stringify(data) : void 0
12742
+ });
12743
+ return response;
12744
+ }
12745
+ /**
12746
+ * Generic PUT request
12747
+ */
12748
+ async put(path, data) {
12749
+ const url = this.buildUrl(path);
12750
+ const response = await this.makeRequest(url, {
12751
+ method: "PUT",
12752
+ headers: this.headers,
12753
+ body: data ? JSON.stringify(data) : void 0
12754
+ });
12755
+ return response;
12756
+ }
12757
+ /**
12758
+ * Generic PATCH request
12959
12759
  */
12960
- async publish(agentId, versionId, options = {}) {
12961
- return this.client.post(`/agent-versions/${agentId}/publish`, {
12962
- versionId,
12963
- ...options
12760
+ async patch(path, data) {
12761
+ const url = this.buildUrl(path);
12762
+ const response = await this.makeRequest(url, {
12763
+ method: "PATCH",
12764
+ headers: this.headers,
12765
+ body: data ? JSON.stringify(data) : void 0
12964
12766
  });
12965
- }
12966
- };
12967
- var FlowVersionsEndpoint = class {
12968
- constructor(client) {
12969
- this.client = client;
12767
+ return response;
12970
12768
  }
12971
12769
  /**
12972
- * List versions for a flow, optionally filtered by version `type`.
12770
+ * Generic DELETE request
12973
12771
  */
12974
- async list(flowId, params) {
12975
- return this.client.get(`/flow-versions/${flowId}`, params);
12772
+ async delete(path) {
12773
+ const url = this.buildUrl(path);
12774
+ const response = await this.makeRequest(url, {
12775
+ method: "DELETE",
12776
+ headers: this.headers
12777
+ });
12778
+ return response;
12976
12779
  }
12977
12780
  /**
12978
- * Get the published version for a flow.
12781
+ * Generic request that returns raw Response for streaming
12979
12782
  */
12980
- async getPublished(flowId) {
12981
- return this.client.get(`/flow-versions/${flowId}/published`);
12783
+ async requestStream(path, options = {}) {
12784
+ const url = this.buildUrl(path);
12785
+ const headers = {
12786
+ ...this.headers,
12787
+ ...options.headers
12788
+ };
12789
+ return this.makeRawRequest(url, {
12790
+ ...options,
12791
+ headers
12792
+ });
12982
12793
  }
12983
12794
  /**
12984
- * Get a specific version of a flow.
12795
+ * Dispatch flow execution (streaming).
12796
+ *
12797
+ * This is the sole streaming-dispatch chokepoint for the flow builders
12798
+ * (`RuntypeFlowBuilder`), so it normalizes the request to the canonical
12799
+ * `/v1/dispatch` wire contract here — every builder path inherits the same
12800
+ * normalization the `DispatchEndpoint` applies, with no per-builder call.
12801
+ *
12802
+ * A dispatched agent turn runs on the durable lane, so the stream follows a
12803
+ * detach through {@link executionEvents}; pass `autoReconnect: false` to own
12804
+ * the reconnect yourself.
12985
12805
  */
12986
- async get(flowId, versionId) {
12987
- return this.client.get(`/flow-versions/${flowId}/${versionId}`);
12806
+ async dispatch(config, init) {
12807
+ const normalized = normalizeDispatchRequest(config);
12808
+ const request6 = {
12809
+ ...normalized,
12810
+ options: {
12811
+ ...normalized.options,
12812
+ streamResponse: true
12813
+ }
12814
+ };
12815
+ const response = await this.requestStream("/dispatch", {
12816
+ method: "POST",
12817
+ body: JSON.stringify(request6),
12818
+ ...init?.signal ? { signal: init.signal } : {}
12819
+ });
12820
+ const conversationId = typeof normalized.conversationId === "string" && normalized.conversationId ? normalized.conversationId : void 0;
12821
+ return withDetachedReconnect(
12822
+ response,
12823
+ async ({ executionId, after, signal: reattachSignal }) => {
12824
+ const legSignal = combineAbortSignals(init?.signal, reattachSignal);
12825
+ return this.executionEvents(executionId, {
12826
+ after,
12827
+ ...conversationId ? { conversationId } : {},
12828
+ ...legSignal ? { signal: legSignal } : {}
12829
+ }).catch(() => null);
12830
+ },
12831
+ init ?? {}
12832
+ );
12988
12833
  }
12989
12834
  /**
12990
- * Publish a version (promote it to the flow's published version).
12835
+ * Dispatch flow execution (non-streaming JSON).
12836
+ *
12837
+ * The non-streaming sibling of {@link dispatch}; it normalizes to the same
12838
+ * canonical wire contract so builders never post a raw, un-normalized body,
12839
+ * and pins `streamResponse: false` so the server returns buffered JSON.
12991
12840
  */
12992
- async publish(flowId, versionId, options = {}) {
12993
- return this.client.post(`/flow-versions/${flowId}/publish`, {
12994
- versionId,
12995
- ...options
12841
+ async dispatchJson(config) {
12842
+ const normalized = normalizeDispatchRequest(config);
12843
+ return this.post("/dispatch", {
12844
+ ...normalized,
12845
+ options: {
12846
+ ...normalized.options,
12847
+ streamResponse: false
12848
+ }
12996
12849
  });
12997
12850
  }
12998
- };
12999
- var IntegrationsEndpoint = class {
13000
- constructor(client) {
13001
- this.client = client;
12851
+ /** Start a normalized dispatch and return a durable handle immediately. */
12852
+ async dispatchAsync(config) {
12853
+ const normalized = normalizeDispatchRequest(config);
12854
+ return this.post(
12855
+ "/dispatch",
12856
+ {
12857
+ ...normalized,
12858
+ options: { ...normalized.options, streamResponse: false }
12859
+ },
12860
+ { Prefer: "respond-async" }
12861
+ );
12862
+ }
12863
+ async getExecutionStatus(executionId) {
12864
+ return this.get(`/executions/${encodeURIComponent(executionId)}/status`);
13002
12865
  }
13003
12866
  /**
13004
- * List all integrations with the caller's per-integration configuration status.
12867
+ * Rejoin a durable execution's Server-Sent Events by execution id.
12868
+ *
12869
+ * The execution-scoped alias of the agent events route, so a turn started
12870
+ * through `/v1/dispatch` reconnects without knowing which agent served it.
12871
+ * Pass the last SSE `id:` the stream delivered as `after` to replay strictly
12872
+ * past that cursor and then live-tail while the run is still going. This is
12873
+ * the same leg a detached dispatch stream follows on its own, exposed for a
12874
+ * caller that stores the cursor and reattaches later or from elsewhere.
12875
+ *
12876
+ * @example
12877
+ * ```typescript
12878
+ * const events = await client.executionEvents('aex_123', { after: '118' })
12879
+ * ```
13005
12880
  */
13006
- async list(params) {
13007
- return this.client.get("/integrations", params);
12881
+ async executionEvents(executionId, opts = {}) {
12882
+ const path = buildExecutionEventsPath(executionId, {
12883
+ ...opts.after !== void 0 ? { after: opts.after } : {},
12884
+ ...opts.conversationId !== void 0 ? { conversationId: opts.conversationId } : {}
12885
+ });
12886
+ return this.requestStream(path, {
12887
+ method: "GET",
12888
+ ...opts.signal ? { signal: opts.signal } : {}
12889
+ });
13008
12890
  }
13009
12891
  /**
13010
- * Get a single integration by ID.
12892
+ * Build full URL with query parameters
13011
12893
  */
13012
- async get(integrationId) {
13013
- return this.client.get(`/integrations/${integrationId}`);
12894
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- mirrors get()'s permissive params type
12895
+ buildUrl(path, params) {
12896
+ const base = this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`;
12897
+ const relPath = path.startsWith("/") ? path.slice(1) : path;
12898
+ const url = new URL(relPath, base);
12899
+ if (params) {
12900
+ Object.entries(params).forEach(([key, value]) => {
12901
+ if (value !== void 0 && value !== null) {
12902
+ url.searchParams.set(key, String(value));
12903
+ }
12904
+ });
12905
+ }
12906
+ return url.toString();
13014
12907
  }
13015
12908
  /**
13016
- * List integrations within a category (e.g. `slack`, `mcp`).
12909
+ * Make HTTP request with timeout and error handling
13017
12910
  */
13018
- async listByCategory(category) {
13019
- return this.client.get(
13020
- `/integrations/category/${category}`
13021
- );
12911
+ async makeRequest(url, options) {
12912
+ const response = await this.makeRawRequest(url, options);
12913
+ if (response.status === 204) {
12914
+ return null;
12915
+ }
12916
+ const contentType = response.headers.get("content-type");
12917
+ if (contentType?.includes("application/json")) {
12918
+ return response.json();
12919
+ }
12920
+ return response.text();
13022
12921
  }
13023
12922
  /**
13024
- * Per-environment credential status across the caller's integrations.
12923
+ * Make HTTP request that returns raw Response (for streaming)
13025
12924
  */
13026
- async getCredentialsStatus() {
13027
- return this.client.get("/integrations/credentials-status");
12925
+ async makeRawRequest(url, options) {
12926
+ const callerSignal = options.signal ?? void 0;
12927
+ const controller = new AbortController();
12928
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
12929
+ const signal = combineAbortSignals(callerSignal, controller.signal) ?? controller.signal;
12930
+ try {
12931
+ const response = await fetch(url, {
12932
+ ...options,
12933
+ signal
12934
+ });
12935
+ clearTimeout(timeoutId);
12936
+ if (!response.ok) {
12937
+ const errorText = await response.text();
12938
+ throw new Error(
12939
+ `API request failed: ${response.status} ${response.statusText} - ${errorText}`
12940
+ );
12941
+ }
12942
+ return response;
12943
+ } catch (error) {
12944
+ clearTimeout(timeoutId);
12945
+ if (error instanceof Error && error.name === "AbortError" && !callerSignal?.aborted) {
12946
+ throw new Error(`Request timeout after ${this.timeout}ms`, { cause: error });
12947
+ }
12948
+ throw error;
12949
+ }
13028
12950
  }
12951
+ };
12952
+ var Runtype = class {
13029
12953
  /**
13030
- * List all tools exposed across the caller's configured integrations.
12954
+ * Configure the global Runtype client
12955
+ *
12956
+ * Call this once at app startup to set the API key and other options.
12957
+ * All subsequent calls to Runtype.flows, Runtype.batches, etc. will use this config.
12958
+ *
12959
+ * @example
12960
+ * ```typescript
12961
+ * Runtype.configure({ apiKey: process.env.RUNTYPE_API_KEY })
12962
+ * ```
13031
12963
  */
13032
- async listTools() {
13033
- return this.client.get("/integrations/tools");
12964
+ static configure(config) {
12965
+ globalConfig = { ...globalConfig, ...config };
12966
+ globalClient = new RuntypeClient(globalConfig);
13034
12967
  }
13035
12968
  /**
13036
- * List the tools exposed by a single integration.
12969
+ * Get the global client instance, creating one if needed
13037
12970
  */
13038
- async getIntegrationTools(integrationId) {
13039
- return this.client.get(
13040
- `/integrations/${integrationId}/tools`
13041
- );
12971
+ static getClient() {
12972
+ if (!globalClient) {
12973
+ globalClient = new RuntypeClient(globalConfig);
12974
+ }
12975
+ return globalClient;
13042
12976
  }
13043
12977
  /**
13044
- * Get the definition of a single tool within an integration.
12978
+ * Create a new client instance with custom configuration
12979
+ *
12980
+ * Use this when you need a client with different settings than the global one.
12981
+ *
12982
+ * @example
12983
+ * ```typescript
12984
+ * const client = Runtype.createClient({ apiKey: 'different_key' })
12985
+ * ```
13045
12986
  */
13046
- async getTool(integrationId, toolName) {
13047
- return this.client.get(`/integrations/${integrationId}/tools/${toolName}`);
12987
+ static createClient(config) {
12988
+ return new RuntypeClient({ ...globalConfig, ...config });
13048
12989
  }
13049
12990
  /**
13050
- * Install a Slack integration from a completed OAuth handshake.
12991
+ * Flows namespace - Build and execute flows
12992
+ *
12993
+ * @example
12994
+ * ```typescript
12995
+ * // Upsert a flow (create or update)
12996
+ * const result = await Runtype.flows.upsert({ name: 'My Flow' })
12997
+ * .prompt({ name: 'Analyze', model: 'gpt-4o', userPrompt: '...' })
12998
+ * .stream()
12999
+ *
13000
+ * // Use an existing flow
13001
+ * const result = await Runtype.flows.use('flow_123')
13002
+ * .withRecord({ name: 'Test' })
13003
+ * .result()
13004
+ *
13005
+ * // Virtual flow (one-off, not saved)
13006
+ * const result = await Runtype.flows.virtual({ name: 'Temp Flow' })
13007
+ * .prompt({ ... })
13008
+ * .stream()
13009
+ * ```
13051
13010
  */
13052
- async installSlack(data) {
13053
- return this.client.post("/integrations/slack/install", data);
13011
+ static get flows() {
13012
+ return new FlowsNamespace(() => this.getClient());
13054
13013
  }
13055
13014
  /**
13056
- * Start the Slack "Add to Slack" OAuth handshake. Returns the Slack authorize
13057
- * URL to open in a popup; the bot token is captured server-side by the
13058
- * callback (never returned to the browser).
13015
+ * Batches namespace - Schedule and manage batch operations
13016
+ *
13017
+ * @example
13018
+ * ```typescript
13019
+ * // Schedule a batch
13020
+ * const batch = await Runtype.batches.schedule({
13021
+ * flowId: 'flow_123',
13022
+ * recordType: 'customers',
13023
+ * })
13024
+ *
13025
+ * // Get batch status
13026
+ * const status = await Runtype.batches.get('batch_456')
13027
+ *
13028
+ * // Cancel a batch
13029
+ * await Runtype.batches.cancel('batch_456')
13030
+ *
13031
+ * // List batches
13032
+ * const batches = await Runtype.batches.list({ status: 'running' })
13033
+ * ```
13059
13034
  */
13060
- async startSlackOAuth(data) {
13061
- return this.client.post("/oauth/slack/start", data);
13035
+ static get batches() {
13036
+ return new BatchesNamespace(() => this.getClient());
13062
13037
  }
13063
13038
  /**
13064
- * Generate the Slack app manifest for a surface, plus a link to Slack's
13065
- * app-creation page. The manifest carries absolute API URLs derived
13066
- * server-side, so it is always valid for Slack (relative proxy paths never
13067
- * leak in). Slack's create-app modal ignores a manifest passed in the URL, so
13068
- * `manifestJson` is pasted into its "From a manifest" option rather than
13069
- * embedded in `createAppUrl`.
13039
+ * Evals namespace - Run evaluations and compare models
13040
+ *
13041
+ * @example
13042
+ * ```typescript
13043
+ * // Run an eval with streaming
13044
+ * const stream = await Runtype.evals.run({
13045
+ * flowId: 'flow_123',
13046
+ * recordType: 'test_data',
13047
+ * models: [{ stepName: 'Analyze', model: 'gpt-4o' }]
13048
+ * }).stream()
13049
+ *
13050
+ * // Submit eval as batch job
13051
+ * const eval = await Runtype.evals.run({
13052
+ * flowId: 'flow_123',
13053
+ * recordType: 'test_data',
13054
+ * models: [
13055
+ * [{ stepName: 'Analyze', model: 'gpt-5.4' }],
13056
+ * [{ stepName: 'Analyze', model: 'claude-opus-4-6' }],
13057
+ * ]
13058
+ * }).submit()
13059
+ * ```
13070
13060
  */
13071
- async generateSlackManifest(data) {
13072
- return this.client.post("/integrations/slack/manifest", data);
13061
+ static get evals() {
13062
+ return new EvalsNamespace(() => this.getClient());
13073
13063
  }
13074
13064
  /**
13075
- * Report whether Slack has verified a surface's events URL. Slack sends that
13076
- * challenge when an app is created from a manifest, so a `verifiedAt` newer
13077
- * than the one read before the manifest was handed out is evidence the app
13078
- * now exists. Markers expire after an hour.
13065
+ * Prompts namespace - Manage and execute prompts
13066
+ *
13067
+ * @example
13068
+ * ```typescript
13069
+ * // Execute a prompt with streaming
13070
+ * const stream = await Runtype.prompts.run('prompt_123', {
13071
+ * recordId: 'rec_456'
13072
+ * }).stream()
13073
+ *
13074
+ * // Get complete result
13075
+ * const result = await Runtype.prompts.run('prompt_123', {
13076
+ * recordId: 'rec_456'
13077
+ * }).result()
13078
+ *
13079
+ * // CRUD operations
13080
+ * const prompts = await Runtype.prompts.list()
13081
+ * const prompt = await Runtype.prompts.get('prompt_123')
13082
+ * const newPrompt = await Runtype.prompts.create({ ... })
13083
+ * await Runtype.prompts.update('prompt_123', { ... })
13084
+ * await Runtype.prompts.delete('prompt_123')
13085
+ * ```
13079
13086
  */
13080
- async getSlackAppStatus(surfaceId) {
13081
- return this.client.get(
13082
- `/integrations/slack/app-status?surfaceId=${encodeURIComponent(surfaceId)}`
13083
- );
13084
- }
13085
- };
13086
- var BillingEndpoint = class {
13087
- constructor(client) {
13088
- this.client = client;
13087
+ static get prompts() {
13088
+ return new PromptsNamespace(() => this.getClient());
13089
13089
  }
13090
13090
  /**
13091
- * Get the caller's subscription status, plan limits, and current usage.
13091
+ * Skills namespace - Manage Agent Skills (admin/control plane)
13092
+ *
13093
+ * @example
13094
+ * ```typescript
13095
+ * // Create a published skill from a SKILL.md document
13096
+ * const { skill } = await Runtype.skills.create({ markdown: skillMd, publish: true })
13097
+ *
13098
+ * // Bind it to an agent
13099
+ * await Runtype.skills.bind({ agentId: 'agent_123', skillId: skill.id })
13100
+ *
13101
+ * // Review agent-authored proposals
13102
+ * const pending = await Runtype.skills.proposals.list()
13103
+ * await Runtype.skills.proposals.approve(pending[0].id)
13104
+ * ```
13092
13105
  */
13093
- async getStatus() {
13094
- return this.client.get("/billing/status");
13106
+ static get skills() {
13107
+ return new SkillsNamespace(() => this.getClient());
13095
13108
  }
13096
13109
  /**
13097
- * Get the caller's credit grants and available/used totals.
13110
+ * Agents namespace - Agent config-as-code (define / ensure / pull)
13111
+ *
13112
+ * @example
13113
+ * ```typescript
13114
+ * import { defineAgent, Runtype } from '@runtypelabs/sdk'
13115
+ *
13116
+ * const assistant = defineAgent({
13117
+ * name: 'Pricing Assistant',
13118
+ * model: 'claude-sonnet-4-6',
13119
+ * systemPrompt: renderPrompt(pricingData),
13120
+ * })
13121
+ *
13122
+ * // Converge at deploy time (idempotent; one tiny probe in steady state)
13123
+ * await Runtype.agents.ensure(assistant)
13124
+ *
13125
+ * // CI drift gate
13126
+ * await Runtype.agents.ensure(assistant, { expectNoChanges: true })
13127
+ *
13128
+ * // Absorb a dashboard edit back into the repo
13129
+ * const { definition } = await Runtype.agents.pull('Pricing Assistant')
13130
+ * ```
13098
13131
  */
13099
- async getCredits() {
13100
- return this.client.get("/billing/credits");
13132
+ static get agents() {
13133
+ return new AgentsNamespace(() => this.getClient());
13101
13134
  }
13102
- /**
13103
- * Get the caller's exact current UTC-month platform spend from the local
13104
- * meter used for spend-cap enforcement. Returns 503 when that meter is unavailable.
13105
- */
13106
- async getCurrentSpend() {
13107
- return this.client.get("/billing/current-spend");
13135
+ /** Poll durable handles returned by asynchronous execute operations. */
13136
+ static get executions() {
13137
+ return new ExecutionsNamespace(() => this.getClient());
13108
13138
  }
13109
13139
  /**
13110
- * Get spend analytics. The window is controlled by either `period` or `days`
13111
- * (1–365, defaults to 30).
13140
+ * Tools namespace - Tool config-as-code (define / ensure / pull)
13141
+ *
13142
+ * @example
13143
+ * ```typescript
13144
+ * import { defineTool, Runtype } from '@runtypelabs/sdk'
13145
+ *
13146
+ * const weather = defineTool({
13147
+ * name: 'Weather Lookup',
13148
+ * description: 'Fetch the current weather for a city',
13149
+ * toolType: 'external',
13150
+ * parametersSchema: { type: 'object', properties: { city: { type: 'string' } } },
13151
+ * config: { url: 'https://api.example.com/weather', method: 'GET' },
13152
+ * })
13153
+ *
13154
+ * // Converge at deploy time (idempotent; one tiny probe in steady state)
13155
+ * await Runtype.tools.ensure(weather)
13156
+ *
13157
+ * // CI drift gate
13158
+ * await Runtype.tools.ensure(weather, { expectNoChanges: true })
13159
+ *
13160
+ * // Absorb a dashboard edit back into the repo
13161
+ * const { definition } = await Runtype.tools.pull('Weather Lookup')
13162
+ * ```
13112
13163
  */
13113
- async getSpendAnalytics(params) {
13114
- return this.client.get("/billing/spend-analytics", params);
13115
- }
13116
- };
13117
- var ToolApprovalGrantsEndpoint = class {
13118
- constructor(client) {
13119
- this.client = client;
13164
+ static get tools() {
13165
+ return new ToolsNamespace(() => this.getClient());
13120
13166
  }
13121
13167
  /**
13122
- * List active remembered tool-approval grants for the authenticated owner,
13123
- * optionally filtered to a single agent.
13168
+ * Products namespace - Product config-as-code (define / ensure / pull)
13169
+ *
13170
+ * Converges the top-level product record (description, icon, spec). Nested
13171
+ * capabilities/surfaces/tools and the canvas UI layout state are not
13172
+ * converged by ensure.
13173
+ *
13174
+ * @example
13175
+ * ```typescript
13176
+ * import { defineProduct, Runtype } from '@runtypelabs/sdk'
13177
+ *
13178
+ * const product = defineProduct({
13179
+ * name: 'Support Copilot',
13180
+ * description: 'An AI support assistant',
13181
+ * icon: '🤖',
13182
+ * spec: { productGoal: 'Deflect tier-1 tickets', productStage: 'beta' },
13183
+ * })
13184
+ *
13185
+ * // Converge at deploy time (idempotent; one tiny probe in steady state)
13186
+ * await Runtype.products.ensure(product)
13187
+ *
13188
+ * // CI drift gate
13189
+ * await Runtype.products.ensure(product, { expectNoChanges: true })
13190
+ *
13191
+ * // Absorb a dashboard edit back into the repo
13192
+ * const { definition } = await Runtype.products.pull('Support Copilot')
13193
+ * ```
13124
13194
  */
13125
- async list(agentId) {
13126
- const query = agentId ? `?agentId=${encodeURIComponent(agentId)}` : "";
13127
- const response = await this.client.get(
13128
- `/tool-approval-grants${query}`
13129
- );
13130
- return response.data;
13195
+ static get products() {
13196
+ return new ProductsNamespace(() => this.getClient());
13131
13197
  }
13132
13198
  /**
13133
- * Revoke (soft-delete) a remembered grant so the tool prompts for approval
13134
- * again on future dispatches.
13199
+ * Config-as-code operations for product surfaces. `surfaces.ensure` is the
13200
+ * deploy-time, non-executing converge (create-or-update a surface by name
13201
+ * within a product); `surfaces.pull` is the absorb-drift direction.
13202
+ *
13203
+ * @example
13204
+ * ```typescript
13205
+ * import { Runtype, defineSurface } from '@runtypelabs/sdk'
13206
+ *
13207
+ * const chat = defineSurface({
13208
+ * name: 'Support Chat',
13209
+ * type: 'chat',
13210
+ * behavior: { type: 'chat', greeting: 'Hi there!' },
13211
+ * status: 'active',
13212
+ * })
13213
+ *
13214
+ * // Converge at deploy time (idempotent; one tiny probe in steady state)
13215
+ * await Runtype.surfaces.ensure('product_abc', chat)
13216
+ *
13217
+ * // CI drift gate
13218
+ * await Runtype.surfaces.ensure('product_abc', chat, { expectNoChanges: true })
13219
+ *
13220
+ * // Absorb a dashboard edit back into the repo
13221
+ * const { definition } = await Runtype.surfaces.pull('product_abc', 'Support Chat')
13222
+ * ```
13135
13223
  */
13136
- async revoke(id) {
13137
- return this.client.delete(`/tool-approval-grants/${id}`);
13224
+ static get surfaces() {
13225
+ return new SurfacesNamespace(() => this.getClient());
13138
13226
  }
13139
13227
  };
13140
13228
 
13229
+ // src/transform.ts
13230
+ function transformQueryParams(params) {
13231
+ const result = {};
13232
+ for (const [key, value] of Object.entries(params)) {
13233
+ if (value !== void 0 && value !== null) {
13234
+ if (Array.isArray(value)) {
13235
+ result[key] = value.join(",");
13236
+ } else {
13237
+ result[key] = String(value);
13238
+ }
13239
+ }
13240
+ }
13241
+ return result;
13242
+ }
13243
+
13244
+ // src/version.ts
13245
+ var FALLBACK_VERSION = "0.0.0";
13246
+ var SDK_VERSION = "9.10.0".length > 0 ? "9.10.0" : FALLBACK_VERSION;
13247
+ var RUNTYPE_CLIENT_KIND = "sdk";
13248
+ var SDK_USER_AGENT = `runtype-sdk/${SDK_VERSION} (typescript)`;
13249
+
13141
13250
  // src/client.ts
13142
13251
  function isObjectRecord(value) {
13143
13252
  return typeof value === "object" && value !== null;
@@ -14476,12 +14585,14 @@ export {
14476
14585
  attachRuntimeToolsToDispatchRequest,
14477
14586
  buildAgentAdmissionHeaders,
14478
14587
  buildEmptySessionNudge,
14588
+ buildExecutionEventsPath,
14479
14589
  buildGeneratedRuntimeToolGateOutput,
14480
14590
  buildLedgerOffloadReference,
14481
14591
  buildObservationMaskMarker,
14482
14592
  buildPolicyGuidance,
14483
14593
  buildSendViewOffloadMarker,
14484
14594
  calledTool,
14595
+ combineAbortSignals,
14485
14596
  compileWorkflowConfig,
14486
14597
  completed,
14487
14598
  computeAgentContentHash,