@elevasis/sdk 1.54.0 → 1.55.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.
@@ -1,4 +1,4 @@
1
- import { ProcessingStageStatusSchema, ListBuilderStageKeySchema, LLMResponseParseError, errorToString, getErrorDetails, ExecutionError2, validateEntryPoint, validateTerminalSteps, validateStepReferences, WorkflowTimeoutError, WorkflowStalledError, WorkflowCancellationError, logWorkflowStart, detectCycle, WorkflowStepError, logStepStart, validateTerminalOutput, logStepSuccess, determineNextStep, logStepFailure, logExecutionPath, logWorkflowSuccess, logWorkflowFailure, estimateTokens, allSettledWithConcurrency, truncationCharBudget, buildIterationResponseSchema } from './chunk-OT4CHFQJ.js';
1
+ import { ProcessingStageStatusSchema, ListBuilderStageKeySchema, LLMResponseParseError, errorToString, getErrorDetails, ExecutionError2, validateEntryPoint, validateTerminalSteps, validateStepReferences, WorkflowTimeoutError, WorkflowStalledError, WorkflowCancellationError, WorkflowStepTimeoutError, logWorkflowStart, detectCycle, WorkflowStepError, logStepStart, validateTerminalOutput, logStepSuccess, determineNextStep, logStepFailure, logExecutionPath, logWorkflowSuccess, logWorkflowFailure, estimateTokens, allSettledWithConcurrency, calculateCost, truncationCharBudget, buildIterationResponseSchema } from './chunk-R3J6BEPO.js';
2
2
  import { workerData, parentPort } from 'worker_threads';
3
3
  import { zodToJsonSchema } from '@alcyone-labs/zod-to-json-schema';
4
4
  import { z, ZodError } from 'zod';
@@ -65,6 +65,71 @@ var Workflow = class {
65
65
  }
66
66
  return new WorkflowCancellationError("Execution cancelled by user", { stepId, executionPath });
67
67
  }
68
+ /**
69
+ * Run one step's handler, bounded by the step's own `timeout` when it declares one.
70
+ *
71
+ * Two things have to happen for a step deadline to mean anything, and doing only one of them is
72
+ * why this is not a bare `Promise.race`:
73
+ *
74
+ * 1. The handler is handed a context whose `signal` is the step's, chained off the execution's, so
75
+ * a handler that already honours `context.signal` (every `fetch`-based one does) aborts its own
76
+ * work at the step deadline instead of running on unattended.
77
+ * 2. The race rejects regardless, because a handler that ignores its signal would otherwise hold
78
+ * the graph open until the 2-hour execution ceiling -- which is the whole thing being fixed.
79
+ *
80
+ * The chaining direction matches `startExecutionDeadline` in the API's `lifecycle.ts`: the parent's
81
+ * abort reason is propagated verbatim into the child controller, so an execution-level cancel or
82
+ * timeout still classifies as itself rather than as a step deadline.
83
+ *
84
+ * A step with no `timeout` takes the untouched path and is handed `context` itself -- no derived
85
+ * controller, no listener, no race.
86
+ */
87
+ async runStepHandler(step, input, context, executionPath) {
88
+ if (step.timeout === void 0) return step.handler(input, context);
89
+ const controller = new AbortController();
90
+ let deadlineFired = false;
91
+ const timer = setTimeout(() => {
92
+ deadlineFired = true;
93
+ controller.abort("timeout");
94
+ }, step.timeout);
95
+ let onParentAbort;
96
+ if (context.signal) {
97
+ if (context.signal.aborted) {
98
+ controller.abort(context.signal.reason);
99
+ } else {
100
+ onParentAbort = () => controller.abort(context.signal?.reason);
101
+ context.signal.addEventListener("abort", onParentAbort, { once: true });
102
+ }
103
+ }
104
+ const aborted = new Promise((_, reject) => {
105
+ controller.signal.addEventListener(
106
+ "abort",
107
+ () => {
108
+ if (deadlineFired) {
109
+ reject(
110
+ new WorkflowStepTimeoutError(`Step exceeded its timeout (${step.timeout}ms) [${step.id}:${step.name}]`, {
111
+ timeout: step.timeout,
112
+ stepId: step.id,
113
+ stepName: step.name,
114
+ executionPath
115
+ })
116
+ );
117
+ return;
118
+ }
119
+ reject(
120
+ this.abortErrorFor(context.signal, step.id, executionPath) ?? new WorkflowCancellationError("Execution cancelled by user", { stepId: step.id, executionPath })
121
+ );
122
+ },
123
+ { once: true }
124
+ );
125
+ });
126
+ try {
127
+ return await Promise.race([step.handler(input, { ...context, signal: controller.signal }), aborted]);
128
+ } finally {
129
+ clearTimeout(timer);
130
+ if (onParentAbort) context.signal?.removeEventListener("abort", onParentAbort);
131
+ }
132
+ }
68
133
  /**
69
134
  * Execute the workflow with graph-based flow control
70
135
  * Context is required for execution tracking, logging, and organization isolation
@@ -98,7 +163,7 @@ var Workflow = class {
98
163
  logStepStart(context, step.id, step.name, currentData, stepStartTime);
99
164
  try {
100
165
  const validatedInput = step.inputSchema.parse(currentData);
101
- const rawOutput = await step.handler(validatedInput, context);
166
+ const rawOutput = await this.runStepHandler(step, validatedInput, context, executionPath);
102
167
  currentData = step.outputSchema.parse(rawOutput);
103
168
  if (step.next === null && this.shouldGenerateOutput) {
104
169
  validateTerminalOutput(step.id, currentData, this.contract.outputSchema);
@@ -120,6 +185,9 @@ var Workflow = class {
120
185
  const stepEndTime = Date.now();
121
186
  const duration = stepEndTime - stepStartTime;
122
187
  logStepFailure(context, step.id, step.name, error, duration, stepStartTime, stepEndTime);
188
+ if (error instanceof WorkflowStepTimeoutError || error instanceof WorkflowTimeoutError || error instanceof WorkflowStalledError || error instanceof WorkflowCancellationError) {
189
+ throw error;
190
+ }
123
191
  const cause = error instanceof ExecutionError2 ? error : void 0;
124
192
  throw new WorkflowStepError(
125
193
  `Step failed [${step.id}:${step.name}]: ${errorToString(error)}`,
@@ -1255,6 +1323,12 @@ function normalizeSessionMessages(actions, sessionCapable) {
1255
1323
  }
1256
1324
  var NO_PROGRESS_STREAK_KEY = "agent.actions.noProgressStreak";
1257
1325
  var MAX_CONSECUTIVE_NO_PROGRESS_ITERATIONS = 2;
1326
+ var LAST_PLAN_SIGNATURE_KEY = "agent.actions.lastPlanSignature";
1327
+ var REPEATED_PLAN_STREAK_KEY = "agent.actions.repeatedPlanStreak";
1328
+ var DEFAULT_MAX_IDENTICAL_ITERATIONS = 3;
1329
+ function planSignature(actions) {
1330
+ return JSON.stringify(actions);
1331
+ }
1258
1332
  async function processActions(iterationContext, response) {
1259
1333
  const normalizedActions = normalizeSessionMessages(response.nextActions, !!iterationContext.config.sessionCapable);
1260
1334
  if (normalizedActions.length === 0) {
@@ -1278,6 +1352,31 @@ async function processActions(iterationContext, response) {
1278
1352
  }
1279
1353
  } else {
1280
1354
  iterationContext.executionContext.store.delete(NO_PROGRESS_STREAK_KEY);
1355
+ const store = iterationContext.executionContext.store;
1356
+ const signature = planSignature(normalizedActions);
1357
+ const repeated = store.get(LAST_PLAN_SIGNATURE_KEY) === signature;
1358
+ const streak = repeated ? (store.get(REPEATED_PLAN_STREAK_KEY) ?? 0) + 1 : 0;
1359
+ store.set(LAST_PLAN_SIGNATURE_KEY, signature);
1360
+ store.set(REPEATED_PLAN_STREAK_KEY, streak);
1361
+ if (repeated) {
1362
+ const ceiling = iterationContext.config.constraints?.maxIdenticalIterations ?? DEFAULT_MAX_IDENTICAL_ITERATIONS;
1363
+ iterationContext.memoryManager.addToHistory({
1364
+ type: "error",
1365
+ content: JSON.stringify({
1366
+ error: `This iteration's plan is identical to the previous one (repeated ${streak}x). Repeating it again will produce the same result. Either act on what the last result returned, or complete.`
1367
+ }),
1368
+ turnNumber: iterationContext.executionContext.sessionTurnNumber ?? null,
1369
+ iterationNumber: iterationContext.iteration,
1370
+ source: "framework"
1371
+ });
1372
+ if (streak >= ceiling) {
1373
+ throw new AgentNoProgressError(`Agent repeated an identical plan for ${streak} consecutive iterations`, {
1374
+ iteration: iterationContext.iteration,
1375
+ streak,
1376
+ ceiling
1377
+ });
1378
+ }
1379
+ }
1281
1380
  }
1282
1381
  const completeRequested = normalizedActions.some((action) => action.type === "complete");
1283
1382
  const toolCalls = [];
@@ -2139,6 +2238,14 @@ var Agent = class {
2139
2238
  while (iteration <= maxIterations) {
2140
2239
  const abortError = this.abortErrorFor(context.signal, iteration);
2141
2240
  if (abortError) throw abortError;
2241
+ const spendStop = this.spendCeilingReached(context);
2242
+ if (spendStop) {
2243
+ context.logger.warn(
2244
+ `Agent stopped at iteration ${iteration}: ${spendStop.limit} ceiling of ${spendStop.ceiling} reached (${spendStop.actual})`
2245
+ );
2246
+ this.stopReason = "spend_exhausted";
2247
+ return;
2248
+ }
2142
2249
  try {
2143
2250
  await context.onHeartbeat?.();
2144
2251
  } catch {
@@ -2162,6 +2269,33 @@ var Agent = class {
2162
2269
  }
2163
2270
  this.stopReason = "budget_exhausted";
2164
2271
  }
2272
+ /**
2273
+ * Whether a declared spend ceiling has been reached, and which one.
2274
+ *
2275
+ * Reads `ExecutionContext.aiUsageCollector` -- the same collector `ObservabilityService` persists
2276
+ * to `execution_metrics` -- so enforcement and the recorded figure can never disagree. The
2277
+ * collector was already being written on every LLM call and read only after the fact; this is the
2278
+ * first place its running total decides anything.
2279
+ *
2280
+ * Returns `null` when no ceiling is declared, or when no collector was injected. An execution
2281
+ * without a collector is not silently capped at zero -- it is uncapped, which is what it was
2282
+ * before any of this existed.
2283
+ *
2284
+ * @returns the breached ceiling, or `null` when none is.
2285
+ */
2286
+ spendCeilingReached(context) {
2287
+ const { maxCostUsd, maxTotalTokens } = this.config.constraints ?? {};
2288
+ if (maxCostUsd === void 0 && maxTotalTokens === void 0) return null;
2289
+ const summary = context.aiUsageCollector?.getSummary();
2290
+ if (!summary) return null;
2291
+ if (maxCostUsd !== void 0 && summary.totalCostUsd >= maxCostUsd) {
2292
+ return { limit: "maxCostUsd", ceiling: maxCostUsd, actual: summary.totalCostUsd };
2293
+ }
2294
+ if (maxTotalTokens !== void 0 && summary.totalTokens >= maxTotalTokens) {
2295
+ return { limit: "maxTotalTokens", ceiling: maxTotalTokens, actual: summary.totalTokens };
2296
+ }
2297
+ return null;
2298
+ }
2165
2299
  /**
2166
2300
  * Classify an aborted signal into the typed error the rest of the framework expects, regardless
2167
2301
  * of where the abort surfaced. An abort landing mid-`fetch` or mid-tool throws whatever the
@@ -2589,6 +2723,78 @@ Fix the errors and generate a valid output.
2589
2723
  }
2590
2724
  }
2591
2725
  };
2726
+
2727
+ // ../core/src/operations/observability/ai-usage-collector.ts
2728
+ var AIUsageCollector = class {
2729
+ model = "gpt-5";
2730
+ // Default, will be overwritten on first record()
2731
+ calls = [];
2732
+ callSequence = 0;
2733
+ /**
2734
+ * Record a single AI call with usage metrics
2735
+ *
2736
+ * @param usage - Token usage and latency data from LLM adapter
2737
+ * @param callType - Type discriminator (agent-reasoning, tool, etc.)
2738
+ * @param context - Optional typed context specific to callType
2739
+ */
2740
+ record(usage, callType = "other", context) {
2741
+ this.callSequence++;
2742
+ this.model = usage.model;
2743
+ const costUsd = usage.cost ?? calculateCost(
2744
+ usage.model,
2745
+ usage.inputTokens,
2746
+ usage.outputTokens,
2747
+ usage.cacheReadInputTokens,
2748
+ usage.cacheCreationInputTokens
2749
+ );
2750
+ const inputTokens = usage.inputTokens + (usage.cacheReadInputTokens ?? 0) + (usage.cacheCreationInputTokens ?? 0);
2751
+ this.calls.push({
2752
+ callSequence: this.callSequence,
2753
+ callType,
2754
+ model: usage.model,
2755
+ inputTokens,
2756
+ outputTokens: usage.outputTokens,
2757
+ costUsd,
2758
+ latencyMs: usage.latencyMs,
2759
+ context,
2760
+ ...usage.cacheReadInputTokens !== void 0 ? { cacheReadInputTokens: usage.cacheReadInputTokens } : {},
2761
+ ...usage.cacheCreationInputTokens !== void 0 ? { cacheCreationInputTokens: usage.cacheCreationInputTokens } : {},
2762
+ ...usage.inputWarnings?.length ? { inputWarnings: usage.inputWarnings } : {},
2763
+ ...usage.inputWarningsBySource?.length ? { inputWarningsBySource: usage.inputWarningsBySource } : {},
2764
+ ...usage.inputBlocked ? { inputBlocked: true } : {},
2765
+ ...usage.outputValidationError ? { outputValidationError: usage.outputValidationError } : {},
2766
+ ...usage.unvalidatedOutput ? { unvalidatedOutput: usage.unvalidatedOutput } : {},
2767
+ ...usage.strictStatus ? { strictStatus: usage.strictStatus } : {},
2768
+ ...usage.strictRefusalReasons?.length ? { strictRefusalReasons: usage.strictRefusalReasons } : {},
2769
+ ...usage.providerMs !== void 0 ? { providerMs: usage.providerMs } : {},
2770
+ ...usage.validateMs !== void 0 ? { validateMs: usage.validateMs } : {},
2771
+ ...usage.wallClockMs !== void 0 ? { wallClockMs: usage.wallClockMs } : {}
2772
+ });
2773
+ }
2774
+ /**
2775
+ * Get aggregated summary of all AI calls
2776
+ */
2777
+ getSummary() {
2778
+ const totalInputTokens = this.calls.reduce((sum, c) => sum + c.inputTokens, 0);
2779
+ const totalOutputTokens = this.calls.reduce((sum, c) => sum + c.outputTokens, 0);
2780
+ const totalCostUsd = this.calls.reduce((sum, c) => sum + c.costUsd, 0);
2781
+ return {
2782
+ model: this.model,
2783
+ totalInputTokens,
2784
+ totalOutputTokens,
2785
+ totalTokens: totalInputTokens + totalOutputTokens,
2786
+ totalCostUsd,
2787
+ callCount: this.calls.length,
2788
+ calls: this.calls
2789
+ };
2790
+ }
2791
+ /**
2792
+ * Check if any usage has been recorded
2793
+ */
2794
+ hasUsage() {
2795
+ return this.calls.length > 0;
2796
+ }
2797
+ };
2592
2798
  var RETRYABLE_CODES = /* @__PURE__ */ new Set([
2593
2799
  "rate_limit_exceeded",
2594
2800
  "network_error",
@@ -2756,11 +2962,14 @@ var platform = {
2756
2962
 
2757
2963
  // src/worker/llm-adapter.ts
2758
2964
  var PostMessageLLMAdapter = class {
2759
- constructor(provider, model) {
2965
+ constructor(provider, model, aiUsageCollector, callType) {
2760
2966
  this.provider = provider;
2761
2967
  this.model = model;
2968
+ this.aiUsageCollector = aiUsageCollector;
2969
+ this.callType = callType;
2762
2970
  }
2763
2971
  async generate(request) {
2972
+ const startedAt = Date.now();
2764
2973
  const { result, usage } = await platform.callWithUsage({
2765
2974
  tool: "llm",
2766
2975
  method: "generate",
@@ -2777,6 +2986,22 @@ var PostMessageLLMAdapter = class {
2777
2986
  maxOutputTokens: request.maxOutputTokens
2778
2987
  }
2779
2988
  });
2989
+ if (usage && this.aiUsageCollector) {
2990
+ this.aiUsageCollector.record(
2991
+ {
2992
+ model: usage.model ?? this.model,
2993
+ inputTokens: usage.inputTokens,
2994
+ outputTokens: usage.outputTokens,
2995
+ latencyMs: Date.now() - startedAt,
2996
+ ...usage.cost !== void 0 && { cost: usage.cost },
2997
+ ...usage.cacheReadInputTokens !== void 0 && { cacheReadInputTokens: usage.cacheReadInputTokens },
2998
+ ...usage.cacheCreationInputTokens !== void 0 && {
2999
+ cacheCreationInputTokens: usage.cacheCreationInputTokens
3000
+ }
3001
+ },
3002
+ this.callType
3003
+ );
3004
+ }
2780
3005
  return {
2781
3006
  output: result,
2782
3007
  ...usage && {
@@ -2791,10 +3016,11 @@ var PostMessageLLMAdapter = class {
2791
3016
  }
2792
3017
  };
2793
3018
  function createPostMessageAdapterFactory() {
2794
- return (config) => new PostMessageLLMAdapter(config.provider, config.model);
3019
+ return (config, aiUsageCollector, callType) => new PostMessageLLMAdapter(config.provider, config.model, aiUsageCollector, callType);
2795
3020
  }
3021
+ var FULL_TOKEN_HEX_LENGTH = 32;
2796
3022
  function generateHmacToken(secret, data) {
2797
- return createHmac("sha256", secret).update(data.toLowerCase().trim()).digest("hex").slice(0, 16);
3023
+ return createHmac("sha256", secret).update(data.toLowerCase().trim()).digest("hex").slice(0, FULL_TOKEN_HEX_LENGTH);
2798
3024
  }
2799
3025
  function classifyPlatformToolError(err, options = {}) {
2800
3026
  const {
@@ -4244,6 +4470,12 @@ function buildWorkerExecutionContext(params) {
4244
4470
  organizationId: params.organizationId,
4245
4471
  organizationName: params.organizationName,
4246
4472
  resourceId: params.resourceId,
4473
+ // Worker-side usage accounting. The parent keeps its own collector and remains the source of the
4474
+ // persisted `execution_metrics` row; this one exists so the agent loop — which runs in this
4475
+ // thread — can read what the turn has spent so far and stop at a declared ceiling. Without it
4476
+ // `Agent.iterate` read `undefined` on every deployed execution and treated every agent as
4477
+ // uncapped, which a local dogfood run on 2026-09-02 is what caught.
4478
+ aiUsageCollector: new AIUsageCollector(),
4247
4479
  sessionId: params.sessionId,
4248
4480
  sessionTurnNumber: params.sessionTurnNumber,
4249
4481
  conversationHistory: params.conversationHistory,
@@ -4450,19 +4682,28 @@ function startWorker(org) {
4450
4682
  const durationMs = Date.now() - startTime;
4451
4683
  const stopReason = agentInstance.getStopReason();
4452
4684
  const budgetExhausted = stopReason === "budget_exhausted";
4685
+ const spendExhausted = stopReason === "spend_exhausted";
4686
+ const stoppedShort = budgetExhausted || spendExhausted;
4453
4687
  if (budgetExhausted) {
4454
4688
  console.warn(`[SDK-WORKER] Agent '${resourceId}' exhausted its iteration budget (${durationMs}ms)`);
4689
+ } else if (spendExhausted) {
4690
+ console.warn(`[SDK-WORKER] Agent '${resourceId}' reached its cost/token ceiling (${durationMs}ms)`);
4455
4691
  } else {
4456
4692
  console.log(`[SDK-WORKER] Agent '${resourceId}' completed (${durationMs}ms)`);
4457
4693
  }
4458
4694
  parentPort.postMessage({
4459
4695
  type: "result",
4460
- status: budgetExhausted ? "failed" : "completed",
4696
+ status: stoppedShort ? "failed" : "completed",
4461
4697
  ...budgetExhausted ? {
4462
4698
  error: "Agent stopped without completing: iteration budget exhausted. Any output below was synthesized from partial work.",
4463
4699
  errorName: "AgentBudgetExhaustedError",
4464
4700
  errorCode: "agent_budget_exhausted"
4465
4701
  } : {},
4702
+ ...spendExhausted ? {
4703
+ error: "Agent stopped without completing: cost or token ceiling reached. Any output below was synthesized from partial work.",
4704
+ errorName: "AgentSpendExhaustedError",
4705
+ errorCode: "agent_spend_exhausted"
4706
+ } : {},
4466
4707
  output,
4467
4708
  stopReason,
4468
4709
  // Whether the agent emitted an assistant message this turn. `Agent` has tracked this for
@@ -814,14 +814,25 @@ var SystemEntrySchema = z.object({
814
814
  * position-derived paths. Both still exist on this schema for backward compat.
815
815
  */
816
816
  systems: z.lazy(() => z.record(z.string().trim().min(1).max(100), SystemEntrySchema)).optional(),
817
- /** @deprecated Use systems. Accepted as a compatibility alias during the ontology bridge. */
817
+ /**
818
+ * @deprecated Use systems. Accepted as a compatibility alias during the ontology bridge.
819
+ *
820
+ * Accepted on INPUT only. Parsing used to mirror `systems` into this key so that
821
+ * either spelling could be read off a parsed model, which meant every parsed System
822
+ * carried the same children twice. Readers that walked both keys then visited each
823
+ * nested System twice -- `getOrgOsRouteContractSystems` reported 11 checked paths
824
+ * against command-center's 7 real Systems and would have raised every nested-System
825
+ * failure as two failures -- and readers that walked this key alone looked correct
826
+ * while depending entirely on the mirror. Both defects were live. The mirror is gone:
827
+ * a parsed model now carries children under whichever key the author wrote, so read
828
+ * `system.systems ?? system.subsystems` (helpers.ts, validation.ts, ontology.ts,
829
+ * selectDeclaredSystems.ts, validateManifests.ts and SystemOpsView.tsx all do).
830
+ */
818
831
  subsystems: z.lazy(() => z.record(z.string().trim().min(1).max(100), SystemEntrySchema)).optional()
819
832
  }).strict().refine((system) => system.label !== void 0 || system.title !== void 0, {
820
833
  path: ["label"],
821
834
  message: "System must provide label or title"
822
- }).transform(
823
- (system) => system.systems !== void 0 && system.subsystems === void 0 ? { ...system, subsystems: system.systems } : system
824
- );
835
+ });
825
836
  z.record(z.string(), SystemEntrySchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
826
837
  message: "Each system entry id must match its map key"
827
838
  }).default({});
@@ -1992,6 +2003,8 @@ var AnthropicConfigSchema = z.discriminatedUnion("model", [
1992
2003
  AnthropicClaude5ConfigSchema,
1993
2004
  AnthropicStandardConfigSchema
1994
2005
  ]);
2006
+ var ANTHROPIC_CACHE_READ_RATE_MULTIPLIER = 0.1;
2007
+ var OPENAI_CACHE_READ_RATE_MULTIPLIER = 0.5;
1995
2008
  var GPT56_CACHE_READ_RATE_MULTIPLIER = 0.1;
1996
2009
  var CACHE_CREATION_RATE_MULTIPLIER = 1.25;
1997
2010
  var MODEL_INFO = {
@@ -2188,6 +2201,30 @@ function getModelInfo(model) {
2188
2201
  }
2189
2202
  return void 0;
2190
2203
  }
2204
+ function cacheReadRateMultiplier(model, info) {
2205
+ if (info?.cacheReadRateMultiplier !== void 0) return info.cacheReadRateMultiplier;
2206
+ return model.startsWith("claude-") ? ANTHROPIC_CACHE_READ_RATE_MULTIPLIER : OPENAI_CACHE_READ_RATE_MULTIPLIER;
2207
+ }
2208
+ function cacheCreationRateMultiplier(info) {
2209
+ return info?.cacheCreationRateMultiplier ?? CACHE_CREATION_RATE_MULTIPLIER;
2210
+ }
2211
+ function calculateCost(model, inputTokens, outputTokens, cacheReadInputTokens = 0, cacheCreationInputTokens = 0) {
2212
+ const info = getModelInfo(model);
2213
+ if (!info) {
2214
+ console.warn(
2215
+ `[CostCalculator] Unknown model '${model}' - cannot calculate cost. Available models:`,
2216
+ Object.keys(MODEL_INFO)
2217
+ );
2218
+ return 0;
2219
+ }
2220
+ const baseInputRate = info.inputCostPer1M / 100;
2221
+ const inputCostUsd = inputTokens / 1e6 * baseInputRate;
2222
+ const cacheReadCostUsd = cacheReadInputTokens / 1e6 * baseInputRate * cacheReadRateMultiplier(model, info);
2223
+ const cacheCreationCostUsd = cacheCreationInputTokens / 1e6 * baseInputRate * cacheCreationRateMultiplier(info);
2224
+ const outputCostUsd = outputTokens / 1e6 * (info.outputCostPer1M / 100);
2225
+ const totalCostUsd = inputCostUsd + cacheReadCostUsd + cacheCreationCostUsd + outputCostUsd;
2226
+ return totalCostUsd;
2227
+ }
2191
2228
  function validateModelConfig(config) {
2192
2229
  const model = config.model;
2193
2230
  if (!model) {
@@ -2615,6 +2652,18 @@ var WorkflowTimeoutError = class extends ExecutionError2 {
2615
2652
  return false;
2616
2653
  }
2617
2654
  };
2655
+ var WorkflowStepTimeoutError = class extends ExecutionError2 {
2656
+ type = "workflow_step_timeout_error";
2657
+ severity = "critical";
2658
+ category = "workflow";
2659
+ constructor(message, context) {
2660
+ super(message, context);
2661
+ }
2662
+ /** The run still had budget; a slow dependency is exactly the case a retry exists for. */
2663
+ isRetryable() {
2664
+ return true;
2665
+ }
2666
+ };
2618
2667
  var WorkflowStalledError = class extends ExecutionError2 {
2619
2668
  type = "workflow_stalled_error";
2620
2669
  severity = "critical";
@@ -5962,4 +6011,4 @@ function defineWorkflowConfig(resourceId, descriptors, actionRegistry = []) {
5962
6011
  }
5963
6012
  var ListBuilderStageKeySchema = z.string().min(1);
5964
6013
 
5965
- export { ActivityEventSchema, BuildPlanSnapshotStepSchema, ContractRefResolutionError, CrmStageKeySchema, CrmStateKeySchema, EmailSchema, ExecutionError, ExecutionError2, LLMResponseParseError, ListBuilderStageKeySchema, ProcessingStageStatusSchema, ProspectingBuildTemplateSchema, RegistryValidationError, ResourceRegistry, StepType, ToolingError, WorkflowCancellationError, WorkflowStalledError, WorkflowStepError, WorkflowTimeoutError, allSettledWithConcurrency, bindResourceDescriptor, buildIterationResponseSchema, compileBusinessOntologyValidationIndex, concurrentPool, createLeadGenStageValidators, defineContract, defineResource, defineResourceOntology, defineResources, defineSingleStepWorkflow, defineTopology, defineTopologyRelationship, defineWorkflowConfig, deriveActions, detectCycle, determineNextStep, diagnosticOutput, errorToString, estimateTokens, getErrorDetails, integrationInput, isBuiltInReadinessProfile, isZodType, logExecutionPath, logStepFailure, logStepStart, logStepSuccess, logWorkflowFailure, logWorkflowStart, logWorkflowSuccess, lookupReadinessProfile, parseTopologyNodeRef, registerReadinessProfile, resolveContractRef, runDiagnostic, splitName, topologyRef, topologyRelationship, truncationCharBudget, validateDeclaredSystemInterfaceReadiness, validateDeploymentSpec, validateEntryPoint, validateRelationships, validateResourceGovernance, validateStepReferences, validateTerminalOutput, validateTerminalSteps };
6014
+ export { ActivityEventSchema, BuildPlanSnapshotStepSchema, ContractRefResolutionError, CrmStageKeySchema, CrmStateKeySchema, EmailSchema, ExecutionError, ExecutionError2, LLMResponseParseError, ListBuilderStageKeySchema, ProcessingStageStatusSchema, ProspectingBuildTemplateSchema, RegistryValidationError, ResourceRegistry, StepType, ToolingError, WorkflowCancellationError, WorkflowStalledError, WorkflowStepError, WorkflowStepTimeoutError, WorkflowTimeoutError, allSettledWithConcurrency, bindResourceDescriptor, buildIterationResponseSchema, calculateCost, compileBusinessOntologyValidationIndex, concurrentPool, createLeadGenStageValidators, defineContract, defineResource, defineResourceOntology, defineResources, defineSingleStepWorkflow, defineTopology, defineTopologyRelationship, defineWorkflowConfig, deriveActions, detectCycle, determineNextStep, diagnosticOutput, errorToString, estimateTokens, getErrorDetails, integrationInput, isBuiltInReadinessProfile, isZodType, logExecutionPath, logStepFailure, logStepStart, logStepSuccess, logWorkflowFailure, logWorkflowStart, logWorkflowSuccess, lookupReadinessProfile, parseTopologyNodeRef, registerReadinessProfile, resolveContractRef, runDiagnostic, splitName, topologyRef, topologyRelationship, truncationCharBudget, validateDeclaredSystemInterfaceReadiness, validateDeploymentSpec, validateEntryPoint, validateRelationships, validateResourceGovernance, validateStepReferences, validateTerminalOutput, validateTerminalSteps };
package/dist/cli.cjs CHANGED
@@ -23791,14 +23791,25 @@ var init_systems = __esm({
23791
23791
  * position-derived paths. Both still exist on this schema for backward compat.
23792
23792
  */
23793
23793
  systems: external_exports.lazy(() => external_exports.record(external_exports.string().trim().min(1).max(100), SystemEntrySchema)).optional(),
23794
- /** @deprecated Use systems. Accepted as a compatibility alias during the ontology bridge. */
23794
+ /**
23795
+ * @deprecated Use systems. Accepted as a compatibility alias during the ontology bridge.
23796
+ *
23797
+ * Accepted on INPUT only. Parsing used to mirror `systems` into this key so that
23798
+ * either spelling could be read off a parsed model, which meant every parsed System
23799
+ * carried the same children twice. Readers that walked both keys then visited each
23800
+ * nested System twice -- `getOrgOsRouteContractSystems` reported 11 checked paths
23801
+ * against command-center's 7 real Systems and would have raised every nested-System
23802
+ * failure as two failures -- and readers that walked this key alone looked correct
23803
+ * while depending entirely on the mirror. Both defects were live. The mirror is gone:
23804
+ * a parsed model now carries children under whichever key the author wrote, so read
23805
+ * `system.systems ?? system.subsystems` (helpers.ts, validation.ts, ontology.ts,
23806
+ * selectDeclaredSystems.ts, validateManifests.ts and SystemOpsView.tsx all do).
23807
+ */
23795
23808
  subsystems: external_exports.lazy(() => external_exports.record(external_exports.string().trim().min(1).max(100), SystemEntrySchema)).optional()
23796
23809
  }).strict().refine((system) => system.label !== void 0 || system.title !== void 0, {
23797
23810
  path: ["label"],
23798
23811
  message: "System must provide label or title"
23799
- }).transform(
23800
- (system) => system.systems !== void 0 && system.subsystems === void 0 ? { ...system, subsystems: system.systems } : system
23801
- );
23812
+ });
23802
23813
  SystemsDomainSchema = external_exports.record(external_exports.string(), SystemEntrySchema).refine((record2) => Object.entries(record2).every(([key, entry]) => entry.id === key), {
23803
23814
  message: "Each system entry id must match its map key"
23804
23815
  }).default({});
@@ -47048,6 +47059,20 @@ var init_api2 = __esm({
47048
47059
  }
47049
47060
  });
47050
47061
 
47062
+ // ../core/src/platform/errors/index.ts
47063
+ var init_errors6 = __esm({
47064
+ "../core/src/platform/errors/index.ts"() {
47065
+ "use strict";
47066
+ }
47067
+ });
47068
+
47069
+ // ../core/src/platform/errors/disclosure.ts
47070
+ var init_disclosure = __esm({
47071
+ "../core/src/platform/errors/disclosure.ts"() {
47072
+ "use strict";
47073
+ }
47074
+ });
47075
+
47051
47076
  // ../core/src/platform/index.ts
47052
47077
  var init_platform = __esm({
47053
47078
  "../core/src/platform/index.ts"() {
@@ -47057,6 +47082,8 @@ var init_platform = __esm({
47057
47082
  init_registry();
47058
47083
  init_sse();
47059
47084
  init_api2();
47085
+ init_errors6();
47086
+ init_disclosure();
47060
47087
  }
47061
47088
  });
47062
47089
 
@@ -47424,7 +47451,7 @@ var init_sse_executions = __esm({
47424
47451
  });
47425
47452
 
47426
47453
  // ../core/src/execution/core/api-schemas.ts
47427
- var PayloadSchema, OptionalPayloadSchema, ExecutionTargetSchema, OriginTrackingSchema, ExternalExecuteRequestSchema, ExternalExecuteResponseSchema, ExecutionEngineExecuteRequestSchema, ExecutionEngineExecuteResponseSchema, CreateCommandQueueTaskSchema, SubmitDecisionSchema, ListCommandQueueTasksSchema, ListExecutionsSchema, DeleteExecutionsSchema;
47454
+ var PayloadSchema, OptionalPayloadSchema, ExecutionTargetSchema, OriginTrackingSchema, ExternalExecuteRequestSchema, ExternalExecuteResponseSchema, ExecutionEngineExecuteRequestSchema, ExecutionEngineExecuteResponseSchema, CreateCommandQueueTaskSchema, SubmitDecisionSchema, ListCommandQueueTasksSchema, ExecutionStatusSchema, ResourceIdParamSchema, ResourceExecutionParamsSchema, ListExecutionsSchema, ListAllExecutionsSchema, DeleteExecutionsSchema, PatchExecutionBodySchema;
47428
47455
  var init_api_schemas = __esm({
47429
47456
  "../core/src/execution/core/api-schemas.ts"() {
47430
47457
  "use strict";
@@ -47506,12 +47533,35 @@ var init_api_schemas = __esm({
47506
47533
  status: external_exports.enum(["pending", "approved", "rejected", "expired"]).optional(),
47507
47534
  limit: PageLimitSchema.default(20)
47508
47535
  }).strict();
47509
- ListExecutionsSchema = external_exports.object({
47510
- resourceStatus: external_exports.enum(["dev", "prod", "all"]).default("all")
47536
+ ExecutionStatusSchema = external_exports.enum(["pending", "running", "completed", "failed", "warning"]);
47537
+ ResourceIdParamSchema = external_exports.object({
47538
+ resourceId: NonEmptyStringSchema.max(255)
47511
47539
  }).strict();
47540
+ ResourceExecutionParamsSchema = external_exports.object({
47541
+ resourceId: NonEmptyStringSchema.max(255),
47542
+ executionId: NonEmptyStringSchema.max(255)
47543
+ }).strict();
47544
+ ListExecutionsSchema = external_exports.object({
47545
+ resourceStatus: external_exports.enum(["dev", "prod", "all"]).default("all"),
47546
+ limit: PageLimitSchema.default(DEFAULT_PAGE_LIMIT),
47547
+ offset: PageOffsetSchema
47548
+ });
47549
+ ListAllExecutionsSchema = external_exports.object({
47550
+ resourceId: NonEmptyStringSchema.max(255).optional(),
47551
+ status: external_exports.enum([...ExecutionStatusSchema.options, "all"]).optional(),
47552
+ resourceStatus: external_exports.enum(["dev", "prod", "all"]).optional(),
47553
+ startDate: external_exports.coerce.number().int().nonnegative().optional(),
47554
+ endDate: external_exports.coerce.number().int().nonnegative().optional(),
47555
+ limit: PageLimitSchema.default(DEFAULT_PAGE_LIMIT),
47556
+ offset: PageOffsetSchema
47557
+ });
47512
47558
  DeleteExecutionsSchema = external_exports.object({
47513
47559
  resourceStatus: external_exports.enum(["dev", "prod"]).optional()
47514
47560
  }).strict();
47561
+ PatchExecutionBodySchema = external_exports.object({
47562
+ status: external_exports.enum(["completed", "failed", "warning"]),
47563
+ error: external_exports.string().max(5e3).optional()
47564
+ }).strict();
47515
47565
  }
47516
47566
  });
47517
47567
 
@@ -48149,6 +48199,85 @@ var init_schemas6 = __esm({
48149
48199
  }
48150
48200
  });
48151
48201
 
48202
+ // ../core/src/operations/observability/api-schemas.ts
48203
+ var ErrorSeveritySchema, ExecutionIdParamSchema, ErrorIdParamSchema, ObservabilityDateRangeQuerySchema, ExecutionLogsQuerySchema, ErrorDetailsQuerySchema, ErrorDistributionQuerySchema, ErrorTrendsQuerySchema, TopFailingResourcesQuerySchema, RecentExecutionsByResourceQuerySchema, CostTrendsQuerySchema, ResourceHealthTargetSchema, ResourcesHealthBodySchema, SystemHealthResourceKindSchema, SystemHealthResourceDescriptorSchema, SystemHealthBodySchema;
48204
+ var init_api_schemas3 = __esm({
48205
+ "../core/src/operations/observability/api-schemas.ts"() {
48206
+ "use strict";
48207
+ init_zod();
48208
+ init_validation();
48209
+ ErrorSeveritySchema = external_exports.enum(["critical", "warning", "info"]);
48210
+ ExecutionIdParamSchema = external_exports.object({ executionId: NonEmptyStringSchema.max(255) }).strict();
48211
+ ErrorIdParamSchema = external_exports.object({ errorId: external_exports.string().uuid() }).strict();
48212
+ ObservabilityDateRangeQuerySchema = external_exports.object({
48213
+ startDate: TimestampSchema.optional(),
48214
+ endDate: TimestampSchema.optional()
48215
+ });
48216
+ ExecutionLogsQuerySchema = ObservabilityDateRangeQuerySchema.extend({
48217
+ page: external_exports.coerce.number().int().min(1).default(1),
48218
+ limit: PageLimitSchema.default(DEFAULT_PAGE_LIMIT),
48219
+ // Left as bounded strings rather than enums. The service passes both straight into `.eq()`, and an
48220
+ // unknown value returns an empty page rather than misbehaving — so an enum here would assert a
48221
+ // catalog this schema has no way to keep in step with the column.
48222
+ resourceType: external_exports.string().max(100).optional(),
48223
+ status: external_exports.string().max(50).optional(),
48224
+ search: external_exports.string().max(200).optional()
48225
+ });
48226
+ ErrorDetailsQuerySchema = ObservabilityDateRangeQuerySchema.extend({
48227
+ page: external_exports.coerce.number().int().min(1).default(1),
48228
+ limit: PageLimitSchema.default(DEFAULT_PAGE_LIMIT),
48229
+ errorType: external_exports.string().max(100).optional(),
48230
+ severity: ErrorSeveritySchema.optional(),
48231
+ search: external_exports.string().max(200).optional(),
48232
+ // Tri-state on the wire: 'true' and 'false' filter, anything else (including 'all', which the
48233
+ // Command Center sends) means no filter. Coercing to a boolean here would make 'all' read as true.
48234
+ resolved: external_exports.enum(["true", "false", "all"]).optional()
48235
+ });
48236
+ ErrorDistributionQuerySchema = ObservabilityDateRangeQuerySchema.extend({
48237
+ groupBy: external_exports.enum(["type", "severity"]).default("type")
48238
+ });
48239
+ ErrorTrendsQuerySchema = ObservabilityDateRangeQuerySchema.extend({
48240
+ granularity: external_exports.enum(["hour", "day"]).default("day")
48241
+ });
48242
+ TopFailingResourcesQuerySchema = ObservabilityDateRangeQuerySchema.extend({
48243
+ limit: PageLimitSchema.default(10)
48244
+ });
48245
+ RecentExecutionsByResourceQuerySchema = ObservabilityDateRangeQuerySchema.extend({
48246
+ limit: PageLimitSchema.optional()
48247
+ });
48248
+ CostTrendsQuerySchema = ObservabilityDateRangeQuerySchema.extend({
48249
+ granularity: external_exports.enum(["hour", "day"]).default("hour")
48250
+ });
48251
+ ResourceHealthTargetSchema = external_exports.object({
48252
+ entityType: NonEmptyStringSchema.max(100),
48253
+ entityId: NonEmptyStringSchema.max(255)
48254
+ }).strict();
48255
+ ResourcesHealthBodySchema = external_exports.object({
48256
+ resources: external_exports.array(ResourceHealthTargetSchema).min(1).max(20),
48257
+ startDate: TimestampSchema,
48258
+ endDate: TimestampSchema,
48259
+ granularity: external_exports.enum(["hour", "day"])
48260
+ }).strict();
48261
+ SystemHealthResourceKindSchema = external_exports.enum(["workflow", "agent", "integration", "script"]);
48262
+ SystemHealthResourceDescriptorSchema = external_exports.object({
48263
+ id: NonEmptyStringSchema.max(255),
48264
+ kind: SystemHealthResourceKindSchema,
48265
+ systemPath: external_exports.string().max(500).optional(),
48266
+ executable: external_exports.boolean().optional()
48267
+ }).strict();
48268
+ SystemHealthBodySchema = external_exports.object({
48269
+ systemPath: NonEmptyStringSchema.max(500),
48270
+ includeDescendants: external_exports.boolean().optional(),
48271
+ startDate: TimestampSchema,
48272
+ endDate: TimestampSchema,
48273
+ granularity: external_exports.enum(["hour", "day"]).optional(),
48274
+ directResources: external_exports.array(SystemHealthResourceDescriptorSchema).optional(),
48275
+ descendantResources: external_exports.array(SystemHealthResourceDescriptorSchema).optional(),
48276
+ resources: external_exports.array(SystemHealthResourceDescriptorSchema).optional()
48277
+ }).strict();
48278
+ }
48279
+ });
48280
+
48152
48281
  // ../core/src/operations/observability/utils.ts
48153
48282
  var init_utils5 = __esm({
48154
48283
  "../core/src/operations/observability/utils.ts"() {
@@ -48162,6 +48291,7 @@ var init_observability = __esm({
48162
48291
  "use strict";
48163
48292
  init_types13();
48164
48293
  init_schemas6();
48294
+ init_api_schemas3();
48165
48295
  init_utils5();
48166
48296
  }
48167
48297
  });
@@ -48192,7 +48322,7 @@ var init_types14 = __esm({
48192
48322
 
48193
48323
  // ../core/src/operations/activities/api-schemas.ts
48194
48324
  var ActivityTypeSchema, ActivityStatusSchema, MetadataSchema, CreateActivitySchema, ActivityTrendQuerySchema, ListActivitiesQuerySchema;
48195
- var init_api_schemas3 = __esm({
48325
+ var init_api_schemas4 = __esm({
48196
48326
  "../core/src/operations/activities/api-schemas.ts"() {
48197
48327
  "use strict";
48198
48328
  init_zod();
@@ -48250,7 +48380,7 @@ var init_activities = __esm({
48250
48380
  "../core/src/operations/activities/index.ts"() {
48251
48381
  "use strict";
48252
48382
  init_types14();
48253
- init_api_schemas3();
48383
+ init_api_schemas4();
48254
48384
  init_sse_events3();
48255
48385
  }
48256
48386
  });
@@ -48689,7 +48819,7 @@ var init_acquisition = __esm({
48689
48819
 
48690
48820
  // ../core/src/business/clients/api-schemas.ts
48691
48821
  var ClientStatusSchema, ClientSourceSchema, ClientIdParamsSchema, ListClientsQuerySchema, ClientRefSchema, ClientResponseSchema, ClientDealRefSchema, ClientProjectRefSchema, ClientCompanyRefSchema, ClientContactRefSchema, ClientLineageSchema, ClientDetailResponseSchema, ClientListResponseSchema, ClientStatusResponseSchema, CreateClientRequestSchema, UpdateClientRequestSchema;
48692
- var init_api_schemas4 = __esm({
48822
+ var init_api_schemas5 = __esm({
48693
48823
  "../core/src/business/clients/api-schemas.ts"() {
48694
48824
  "use strict";
48695
48825
  init_zod();
@@ -48803,7 +48933,7 @@ var init_api_schemas4 = __esm({
48803
48933
  var init_clients = __esm({
48804
48934
  "../core/src/business/clients/index.ts"() {
48805
48935
  "use strict";
48806
- init_api_schemas4();
48936
+ init_api_schemas5();
48807
48937
  }
48808
48938
  });
48809
48939
 
@@ -48951,18 +49081,26 @@ var init_provider_registry = __esm({
48951
49081
  }
48952
49082
  });
48953
49083
 
49084
+ // ../core/src/integrations/oauth/errors.ts
49085
+ var init_errors7 = __esm({
49086
+ "../core/src/integrations/oauth/errors.ts"() {
49087
+ "use strict";
49088
+ }
49089
+ });
49090
+
48954
49091
  // ../core/src/integrations/oauth/index.ts
48955
49092
  var init_oauth = __esm({
48956
49093
  "../core/src/integrations/oauth/index.ts"() {
48957
49094
  "use strict";
48958
49095
  init_types19();
48959
49096
  init_provider_registry();
49097
+ init_errors7();
48960
49098
  }
48961
49099
  });
48962
49100
 
48963
49101
  // ../core/src/integrations/credentials/api-schemas.ts
48964
49102
  var CredentialTypeSchema, CredentialValueSchema, CreateCredentialRequestSchema, CreateCredentialResponseSchema, ListCredentialsResponseSchema, UpdateCredentialParamsSchema, UpdateCredentialRequestSchema, DeleteCredentialParamsSchema, VerifyCredentialParamsSchema, VerifyCredentialResponseSchema;
48965
- var init_api_schemas5 = __esm({
49103
+ var init_api_schemas6 = __esm({
48966
49104
  "../core/src/integrations/credentials/api-schemas.ts"() {
48967
49105
  "use strict";
48968
49106
  init_zod();
@@ -49038,7 +49176,7 @@ var init_api_schemas5 = __esm({
49038
49176
  var init_credentials2 = __esm({
49039
49177
  "../core/src/integrations/credentials/index.ts"() {
49040
49178
  "use strict";
49041
- init_api_schemas5();
49179
+ init_api_schemas6();
49042
49180
  }
49043
49181
  });
49044
49182
 
@@ -49439,7 +49577,7 @@ var init_package = __esm({
49439
49577
  "package.json"() {
49440
49578
  package_default = {
49441
49579
  name: "@elevasis/sdk",
49442
- version: "1.54.0",
49580
+ version: "1.55.0",
49443
49581
  description: "SDK for building Elevasis organization resources",
49444
49582
  type: "module",
49445
49583
  bin: {
@@ -54633,7 +54771,7 @@ function formatText(results) {
54633
54771
  const divider = "-".repeat(header.length + 20);
54634
54772
  const rows = results.map((n) => {
54635
54773
  const summary = n.summary.length > 80 ? n.summary.slice(0, 77) + "..." : n.summary;
54636
- return `${n.kind.padEnd(kindWidth)} ${n.id.padEnd(idWidth)} ${n.title} \xE2\u20AC\u201D ${summary}`;
54774
+ return `${n.kind.padEnd(kindWidth)} ${n.id.padEnd(idWidth)} ${n.title} \u2014 ${summary}`;
54637
54775
  });
54638
54776
  return [header, divider, ...rows].join("\n");
54639
54777
  }
package/dist/index.d.ts CHANGED
@@ -1591,6 +1591,16 @@ interface WorkflowStep extends WorkflowStepDefinition {
1591
1591
  inputSchema: z.ZodSchema;
1592
1592
  outputSchema: z.ZodSchema;
1593
1593
  next: NextConfig;
1594
+ /**
1595
+ * How long this one step may run, in milliseconds. Omitted, the step is bounded only by the
1596
+ * execution ceiling (`DEFAULT_EXECUTION_TIMEOUT`, 2 hours), which is what every step used to get.
1597
+ *
1598
+ * `WorkflowConfig` deliberately still has no `constraints` field: a per-workflow override would
1599
+ * only restate the execution ceiling the caller already sets when it arms the deadline, whereas
1600
+ * "this HTTP step should never take more than 5 seconds" is a property of the step and has no
1601
+ * other place to live.
1602
+ */
1603
+ timeout?: number;
1594
1604
  }
1595
1605
  interface WorkflowDefinition {
1596
1606
  config: WorkflowConfig;
@@ -4387,13 +4397,6 @@ type Database = {
4387
4397
  referencedRelation: "users";
4388
4398
  referencedColumns: ["id"];
4389
4399
  },
4390
- {
4391
- foreignKeyName: "prj_notes_milestone_id_fkey";
4392
- columns: ["milestone_id"];
4393
- isOneToOne: false;
4394
- referencedRelation: "prj_milestones";
4395
- referencedColumns: ["id"];
4396
- },
4397
4400
  {
4398
4401
  foreignKeyName: "prj_notes_organization_id_fkey";
4399
4402
  columns: ["organization_id"];
@@ -4407,13 +4410,6 @@ type Database = {
4407
4410
  isOneToOne: false;
4408
4411
  referencedRelation: "prj_projects";
4409
4412
  referencedColumns: ["id"];
4410
- },
4411
- {
4412
- foreignKeyName: "prj_notes_task_id_fkey";
4413
- columns: ["task_id"];
4414
- isOneToOne: false;
4415
- referencedRelation: "prj_tasks";
4416
- referencedColumns: ["id"];
4417
4413
  }
4418
4414
  ];
4419
4415
  };
@@ -6337,8 +6333,20 @@ interface ProcessingStateEntry {
6337
6333
  type ProcessingState = Partial<Record<LeadGenStageKey, ProcessingStateEntry>>;
6338
6334
  type CompanyProcessingState = ProcessingState;
6339
6335
  type ContactProcessingState = ProcessingState;
6340
- /** @deprecated Use `processingState`. Retained only as a compile-time/read-shape bridge for external tenants. */
6341
- type LegacyPipelineStatus = unknown;
6336
+ /**
6337
+ * @deprecated Use `processingState`. Retained only as a compile-time/read-shape bridge for
6338
+ * external tenants.
6339
+ *
6340
+ * `null`, not `unknown`. The DB column is gone and every response returns null, so `unknown` was
6341
+ * describing a value that cannot occur -- it forced a narrow on a field that is always null while
6342
+ * still type-checking a comparison against a stage name that can never match. Narrowing it turns
6343
+ * that dead comparison into a compile error pointing at `processingState`, which is the migration.
6344
+ *
6345
+ * The WRITE path stays permissive on purpose: the update request schemas keep
6346
+ * `pipelineStatus: z.unknown().optional()` so a tenant still sending the old field gets a no-op
6347
+ * rather than a rejected request.
6348
+ */
6349
+ type LegacyPipelineStatus = null;
6342
6350
  /**
6343
6351
  * Enrichment data collected for a company from various sources.
6344
6352
  */
@@ -14266,6 +14274,28 @@ interface AgentConstraints {
14266
14274
  timeout?: number;
14267
14275
  maxSessionMemoryKeys?: number;
14268
14276
  maxMemoryTokens?: number;
14277
+ /**
14278
+ * Spend ceilings for the whole turn, checked between iterations against
14279
+ * `ExecutionContext.aiUsageCollector`. Both are unset by default -- `maxIterations` and `timeout`
14280
+ * bound how MANY calls and how LONG, but nothing bounded how much those calls cost, so an agent
14281
+ * that picked an expensive model or a huge context could spend without limit inside a budget it
14282
+ * was technically respecting.
14283
+ *
14284
+ * Enforced only where a collector is injected (every coordinator-run execution). An agent run
14285
+ * without one is unbounded, the same as one that declares no ceiling.
14286
+ *
14287
+ * Note that **sync nested executions share the parent's collector**, so these ceilings cover the
14288
+ * agent and everything it invokes synchronously. That is the behaviour a spend ceiling should
14289
+ * have, but it does mean a parent's ceiling can be reached by a child's spend.
14290
+ */
14291
+ maxCostUsd?: number;
14292
+ maxTotalTokens?: number;
14293
+ /**
14294
+ * How many times the agent may emit a byte-identical plan in a row before the turn is stopped
14295
+ * (default 3, in `processActions`). Raise it for an agent whose job legitimately involves
14296
+ * repeating itself -- polling one endpoint until it reports ready is the case this exists for.
14297
+ */
14298
+ maxIdenticalIterations?: number;
14269
14299
  }
14270
14300
  interface AgentDefinition {
14271
14301
  config: AgentConfig;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { ActivityEventSchema, BuildPlanSnapshotStepSchema, ProspectingBuildTemplateSchema as BuildTemplateSchema, ContractRefResolutionError, CrmStageKeySchema, CrmStateKeySchema, EmailSchema, ExecutionError, ListBuilderStageKeySchema, ProcessingStageStatusSchema, RegistryValidationError, ResourceRegistry, StepType, ToolingError, bindResourceDescriptor, compileBusinessOntologyValidationIndex, concurrentPool, createLeadGenStageValidators, defineContract, defineResource, defineResourceOntology, defineResources, defineSingleStepWorkflow, defineTopology, defineTopologyRelationship, defineWorkflowConfig, deriveActions, diagnosticOutput, integrationInput, isBuiltInReadinessProfile, isZodType, lookupReadinessProfile, parseTopologyNodeRef, registerReadinessProfile, resolveContractRef, runDiagnostic, splitName, topologyRef, topologyRelationship, validateDeclaredSystemInterfaceReadiness, validateResourceGovernance } from './chunk-OT4CHFQJ.js';
1
+ export { ActivityEventSchema, BuildPlanSnapshotStepSchema, ProspectingBuildTemplateSchema as BuildTemplateSchema, ContractRefResolutionError, CrmStageKeySchema, CrmStateKeySchema, EmailSchema, ExecutionError, ListBuilderStageKeySchema, ProcessingStageStatusSchema, RegistryValidationError, ResourceRegistry, StepType, ToolingError, bindResourceDescriptor, compileBusinessOntologyValidationIndex, concurrentPool, createLeadGenStageValidators, defineContract, defineResource, defineResourceOntology, defineResources, defineSingleStepWorkflow, defineTopology, defineTopologyRelationship, defineWorkflowConfig, deriveActions, diagnosticOutput, integrationInput, isBuiltInReadinessProfile, isZodType, lookupReadinessProfile, parseTopologyNodeRef, registerReadinessProfile, resolveContractRef, runDiagnostic, splitName, topologyRef, topologyRelationship, validateDeclaredSystemInterfaceReadiness, validateResourceGovernance } from './chunk-R3J6BEPO.js';
2
2
  export { projectDeploymentSpec, projectTopologyRelationships, toSdkResourceDescriptor, withPlatformAgentResourceDescriptor, withPlatformAgentResourceDescriptors, withPlatformIntegrationResourceDescriptor, withPlatformIntegrationResourceDescriptors, withPlatformResourceDescriptor, withPlatformResourceDescriptors } from './chunk-QF2RNYYX.js';
@@ -1,5 +1,5 @@
1
- import { executeWorkflow } from '../chunk-ZAVFBZHM.js';
2
- import { validateDeploymentSpec, validateRelationships } from '../chunk-OT4CHFQJ.js';
1
+ import { executeWorkflow } from '../chunk-72ZGICTR.js';
2
+ import { validateDeploymentSpec, validateRelationships } from '../chunk-R3J6BEPO.js';
3
3
  import '../chunk-QF2RNYYX.js';
4
4
  import { vi } from 'vitest';
5
5
 
@@ -14,6 +14,15 @@ interface TokenUsage {
14
14
  outputTokens: number;
15
15
  cost?: number;
16
16
  model?: string;
17
+ /**
18
+ * Anthropic excludes cache reads and writes from the wire `input_tokens`, and `AIUsageCollector`
19
+ * adds them back when it records a call. They are forwarded here so the worker-side collector the
20
+ * spend ceiling reads folds them in exactly as the parent's does — without them the worker's token
21
+ * total silently runs below the figure `execution_metrics` persists, and a `maxTotalTokens` ceiling
22
+ * would be enforced against the smaller number.
23
+ */
24
+ cacheReadInputTokens?: number;
25
+ cacheCreationInputTokens?: number;
17
26
  }
18
27
  /** Resolved credential returned by platform.getCredential() */
19
28
  interface PlatformCredential {
@@ -1,3 +1,3 @@
1
- export { ListBuilderResultSchema, ListBuilderResultsSchema, PlatformToolError, acqDb, approval, artifacts, classifyPlatformToolError, content, createAdapter, createAnymailfinderAdapter, createApifyAdapter, createAttioAdapter, createCaptionGenerationWorkflow, createCaptureInstagramMetricsWorkflow, createClickUpAdapter, createDropboxAdapter, createGmailAdapter, createGoogleSheetsAdapter, createImageAnalysisWorkflow, createInstagramAdapter, createInstantlyAdapter, createMillionVerifierAdapter, createPublishInstagramWorkflow, createResendAdapter, createSignatureApiAdapter, createStripeAdapter, createTombaAdapter, crm, email, executeWorkflow, execution, generateHmacToken, list, listBuilderWorkflow, llm, notifications, pdf, platform, projects, scheduler, startWorker, storage, toContentMetrics } from '../chunk-ZAVFBZHM.js';
2
- import '../chunk-OT4CHFQJ.js';
1
+ export { ListBuilderResultSchema, ListBuilderResultsSchema, PlatformToolError, acqDb, approval, artifacts, classifyPlatformToolError, content, createAdapter, createAnymailfinderAdapter, createApifyAdapter, createAttioAdapter, createCaptionGenerationWorkflow, createCaptureInstagramMetricsWorkflow, createClickUpAdapter, createDropboxAdapter, createGmailAdapter, createGoogleSheetsAdapter, createImageAnalysisWorkflow, createInstagramAdapter, createInstantlyAdapter, createMillionVerifierAdapter, createPublishInstagramWorkflow, createResendAdapter, createSignatureApiAdapter, createStripeAdapter, createTombaAdapter, crm, email, executeWorkflow, execution, generateHmacToken, list, listBuilderWorkflow, llm, notifications, pdf, platform, projects, scheduler, startWorker, storage, toContentMetrics } from '../chunk-72ZGICTR.js';
2
+ import '../chunk-R3J6BEPO.js';
3
3
  import '../chunk-QF2RNYYX.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevasis/sdk",
3
- "version": "1.54.0",
3
+ "version": "1.55.0",
4
4
  "description": "SDK for building Elevasis organization resources",
5
5
  "type": "module",
6
6
  "bin": {
@@ -63,9 +63,9 @@
63
63
  "typescript": "5.9.2",
64
64
  "vitest": "^3.2.4",
65
65
  "zod": "^4.1.0",
66
- "@repo/core": "0.70.0",
67
- "@repo/typescript-config": "0.0.0",
68
- "@repo/eslint-config": "0.0.0"
66
+ "@repo/core": "0.71.0",
67
+ "@repo/eslint-config": "0.0.0",
68
+ "@repo/typescript-config": "0.0.0"
69
69
  },
70
70
  "license": "MIT",
71
71
  "engines": {
@@ -27,7 +27,7 @@ Pure query layer over the organization graph. Browser-safe (no Node APIs); share
27
27
 
28
28
  ## JSON envelope
29
29
 
30
- `formatJson` returns `{ path, mount, args, results }` — the same wrapped envelope used by `pnpm exec elevasis knowledge:ls --json` and `pnpm exec elevasis-sdk knowledge:ls --json`.
30
+ `formatJson` returns `{ path, mount, args, results }` the same wrapped envelope used by `pnpm exec elevasis knowledge:ls --json` and `pnpm exec elevasis-sdk knowledge:ls --json`.
31
31
 
32
32
  `governs` and `governedBy` accept either bare or graph-namespaced ids (`knowledge.foo` or `knowledge:knowledge.foo`).
33
33
 
@@ -51,7 +51,7 @@ Resource identity is authored inside `OrganizationModel.resources`. Runtime work
51
51
 
52
52
  ## System Shape
53
53
 
54
- `OrganizationModel.systems` is the canonical semantic domain map. Hierarchy is authored with recursive `systems`; dotted paths such as `sales.crm` are derived from position in that tree. `subsystems` is a deprecated compatibility alias — it is still accepted and kept in sync with `systems` during parse, but new authoring should use `systems`. `parentSystemId` and `id` remain accepted compatibility fields during the migration.
54
+ `OrganizationModel.systems` is the canonical semantic domain map. Hierarchy is authored with recursive `systems`; dotted paths such as `sales.crm` are derived from position in that tree. `subsystems` is a deprecated compatibility alias — it is still accepted on input, but new authoring should use `systems`. Parsing does **not** copy `systems` into it: children come back under whichever key the author wrote, so read `system.systems ?? system.subsystems` rather than assuming either key is populated. `parentSystemId` and `id` remain accepted compatibility fields during the migration.
55
55
 
56
56
  {/* doc-snippet:skip: illustrative excerpt, not a standalone compilable file */}
57
57
 
@@ -51,6 +51,7 @@ Lead gen is a layered platform surface, not one component. Shared packages own s
51
51
  | `useLeadGenConfig`, `LeadGenBuildConfig`, build-state helpers | `@elevasis/ui/features/lead-gen` | Provider-backed derivation of stage catalog, build templates, default build steps, default template id, and export workflow id |
52
52
  | `ListActionsProvider`, `useListActions`, `ListBuilderWorkflow`, `ListBuilderRegistry`, `LeadGenActionKey` | `@elevasis/ui/features/lead-gen` | List Builder workflow registry, slot-based field contracts, and project-owned action wiring |
53
53
  | `LeadGenRouteShell` | `@elevasis/ui/features/lead-gen` | Route shell helper (contact/company detail surfaces are now `ContactDetailPage` / `CompanyDetailPage` from `@elevasis/ui/features/crm`) |
54
+ | `EMPLOYEE_RANGES`, `EmployeeRange` | `@elevasis/ui/features/lead-gen` | Apollo's own employee-count brackets for an Apollo import form. Wire values are Apollo's; relabel by mapping, never by redeclaring |
54
55
  | `useLists`, `useList`, `useListsTelemetry`, `useListProgress`, `useListExecutions`, `useCreateList`, `useUpdateList`, `useUpdateListConfig`, `useDeleteList` | `@elevasis/ui/hooks` | Headless list and telemetry data access |
55
56
  | `useWorkflowExecution`, `useExecutionSSE`, `useAddCompaniesToList`, `useRemoveCompaniesFromList`, `useAddContactsToList` | `@elevasis/ui/hooks` | List Builder workflow triggering, live execution tailing, and list membership mutations |
56
57
  | `useCompanies`, `useCompany`, `useContacts`, `useContact` | `@elevasis/ui/hooks` | Acquisition company/contact data access |
@@ -208,7 +209,7 @@ function RootLayoutComponent() {
208
209
 
209
210
  Data sourcing mode is list-wide. Read `list.pipelineConfig.dataMode` or the workflow-side `list.getConfig()` result when a workflow must choose mock versus live sourcing. Do not add per-action `mock` / `live` controls for Apollo, crawl, enrichment, or scoring steps. Export mode is separate: `preview` versus `export` controls whether a destination write happens.
210
211
 
211
- Each registry entry declares a Zod `schema` and a `layout` of declarative field hints (`StepConfigLayout<Input>`). The shared `StepConfigForm` renders the layout, validates against the schema, and wires `value`/`onChange` for you — no per-action React components. The List Builder right column renders the form as `Configuration | Advanced | Runs` tabs with a sticky action footer. Omit the `advanced:` section when a step has none.
212
+ Each registry entry declares a Zod `schema` and a `layout` of declarative field hints (`StepConfigLayout<Input>`). The shared `StepConfigForm` renders the layout, validates against the schema, and wires `value`/`onChange` for you no per-action React components. The List Builder right column renders the form as `Configuration | Advanced | Runs` tabs with a sticky action footer. Omit the `advanced:` section when a step has none.
212
213
 
213
214
  Available field component variants: `textinput`, `textarea`, `numberinput`, `switch`, `segmented`, `select`, `multiselect`, `tags`, `json`. Field hints support `label`, `description`, `placeholder`, `min`/`max`/`step` (numbers), `options` (selects), and `when: (values) => boolean` for conditional visibility.
214
215
 
@@ -3142,45 +3142,45 @@ export const AcqSubstrateSchemas = {
3142
3142
  ### `Stateful`
3143
3143
 
3144
3144
  ```typescript
3145
- /**
3146
- * Stateful trait — the (pipeline_key, stage_key, state_key, activity_log) quartet
3147
- * applied to acq_deals (CRM HITL, shipped 2026-04-27) and being generalized to
3148
- * acq_lists / acq_list_members / acq_list_companies via Track B.
3149
- */
3150
- export interface Stateful {
3151
- pipeline_key: string
3152
- stage_key: string
3153
- state_key: string
3154
- activity_log: ActivityEvent[]
3145
+ /**
3146
+ * Stateful trait — the (pipeline_key, stage_key, state_key, activity_log) quartet
3147
+ * applied to acq_deals (CRM HITL, shipped 2026-04-27) and being generalized to
3148
+ * acq_lists / acq_list_members / acq_list_companies via Track B.
3149
+ */
3150
+ export interface Stateful {
3151
+ pipeline_key: string
3152
+ stage_key: string
3153
+ state_key: string
3154
+ activity_log: ActivityEvent[]
3155
3155
  }
3156
3156
  ```
3157
3157
 
3158
3158
  ### `TransitionItem`
3159
3159
 
3160
3160
  ```typescript
3161
- /** Generic transition shape — concrete per-entity transitionItem implementations satisfy this. */
3162
- export type TransitionItem<T extends Stateful, TEvent extends ActivityEvent> = (
3163
- item: T,
3164
- transition: { stage_key?: string; state_key?: string; event: TEvent }
3161
+ /** Generic transition shape — concrete per-entity transitionItem implementations satisfy this. */
3162
+ export type TransitionItem<T extends Stateful, TEvent extends ActivityEvent> = (
3163
+ item: T,
3164
+ transition: { stage_key?: string; state_key?: string; event: TEvent }
3165
3165
  ) => T
3166
3166
  ```
3167
3167
 
3168
3168
  ### `DeriveActions`
3169
3169
 
3170
3170
  ```typescript
3171
- /** Generic action-derivation shape — concrete per-entity deriveActions implementations satisfy this. */
3171
+ /** Generic action-derivation shape — concrete per-entity deriveActions implementations satisfy this. */
3172
3172
  export type DeriveActions<T extends Stateful, TAction> = (item: T) => TAction[]
3173
3173
  ```
3174
3174
 
3175
3175
  ### `StatefulSchema`
3176
3176
 
3177
3177
  ```typescript
3178
- export const StatefulSchema = z.object({
3179
- pipeline_key: z.string(),
3180
- stage_key: z.string(),
3181
- state_key: z.string(),
3182
- activity_log: z.array(ActivityEventSchema)
3183
- })
3178
+ export const StatefulSchema = z.object({
3179
+ pipeline_key: z.string(),
3180
+ stage_key: z.string(),
3181
+ state_key: z.string(),
3182
+ activity_log: z.array(ActivityEventSchema)
3183
+ }) satisfies z.ZodType<Stateful>
3184
3184
  ```
3185
3185
 
3186
3186
  ### `StatefulStateDefinition`