@elevasis/sdk 1.40.0 → 1.41.1

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/cli.cjs CHANGED
@@ -45834,7 +45834,7 @@ function wrapAction(commandName, fn) {
45834
45834
  // package.json
45835
45835
  var package_default = {
45836
45836
  name: "@elevasis/sdk",
45837
- version: "1.40.0",
45837
+ version: "1.41.1",
45838
45838
  description: "SDK for building Elevasis organization resources",
45839
45839
  type: "module",
45840
45840
  bin: {
package/dist/index.d.ts CHANGED
@@ -502,6 +502,15 @@ interface ModelConfig {
502
502
  modelOptions?: ModelSpecificOptions;
503
503
  }
504
504
 
505
+ /**
506
+ * What happened to `strict` on a request, recorded per call rather than inferred.
507
+ *
508
+ * `applied` and `notAttempted` are the two states that a refusal-only field cannot tell apart —
509
+ * both leave `strictRefusalReasons` empty. Recording the verdict positively is what makes "was
510
+ * this agent's output actually enforced?" answerable from an `ai_calls` row.
511
+ */
512
+ type StrictStatus = 'applied' | 'refused' | 'compileRejected' | 'notAttempted';
513
+
505
514
  declare const ResourceGovernanceStatusSchema: z.ZodEnum<{
506
515
  active: "active";
507
516
  deprecated: "deprecated";
@@ -1029,6 +1038,7 @@ interface WorkflowDefinition {
1029
1038
  * Generic LLM Types
1030
1039
  * Universal interfaces for LLM interaction across all resource types
1031
1040
  */
1041
+
1032
1042
  /**
1033
1043
  * Standard chat message format
1034
1044
  * Compatible with OpenAI, Anthropic, and other providers
@@ -1062,6 +1072,35 @@ interface LLMGenerateResponse<T = unknown> {
1062
1072
  totalTokens: number;
1063
1073
  };
1064
1074
  cost?: number;
1075
+ /**
1076
+ * What actually happened to `strict` on the request that produced this response. Every server
1077
+ * adapter sets it on every call, so the value is a statement rather than an inference:
1078
+ *
1079
+ * - `applied` — the request carried `strict: true` and the grammar was in effect
1080
+ * - `refused` — `toStrictSchema` could not express the schema, so the request went out unstrict
1081
+ * - `compileRejected` — the schema passed `toStrictSchema` but the provider's grammar compiler
1082
+ * rejected it at request time, and the call was retried unstrict
1083
+ * - `notAttempted` — this adapter does not send strict at all (OpenAI, Google, OpenRouter)
1084
+ *
1085
+ * This exists because `strictRefusalReasons` alone cannot answer the question. Its absence means
1086
+ * "strict held" OR "nothing ever tried", and a prod run that recorded zero refusals while
1087
+ * returning an array-typed field as a string is exactly the case where the difference matters.
1088
+ *
1089
+ * Internal-only, like `usage` — `UniversalLLMAdapter` lifts it onto the `ai_calls` row and
1090
+ * strips it before the response reaches callers.
1091
+ */
1092
+ strictStatus?: StrictStatus;
1093
+ /**
1094
+ * Why this call went out WITHOUT `strict`, on an adapter that tried to send it with one.
1095
+ *
1096
+ * The detail behind a `refused` / `compileRejected` `strictStatus` — the short, stable reason
1097
+ * strings `toStrictSchema` computes. Read `strictStatus` to answer "was it enforced"; read this
1098
+ * to answer "why not".
1099
+ *
1100
+ * Internal-only, like `usage` — `UniversalLLMAdapter` lifts it onto the `ai_calls` row and
1101
+ * strips it before the response reaches callers.
1102
+ */
1103
+ strictRefusalReasons?: string[];
1065
1104
  }
1066
1105
  /**
1067
1106
  * LLM Adapter interface
@@ -1093,6 +1132,14 @@ interface LLMAdapter {
1093
1132
  * Memory types mirror action types for clarity and filtering
1094
1133
  */
1095
1134
  type MemoryEntryType = 'context' | 'input' | 'reasoning' | 'tool-result' | 'delegation-result' | 'error';
1135
+ /**
1136
+ * Who authored an entry's content.
1137
+ *
1138
+ * This is what lets the assembled prompt tell framework-authored text apart from text that
1139
+ * originated outside the trust boundary. `'framework'` content is ours; the other three are not
1140
+ * and are rendered inside the JSON data envelope (see `MemoryManager.toContextParts`).
1141
+ */
1142
+ type MemoryEntrySource = 'framework' | 'user' | 'tool' | 'model';
1096
1143
  /**
1097
1144
  * Memory entry - represents a single entry in agent memory
1098
1145
  * Stored in agent memory, translated by adapters to vendor-specific formats
@@ -1103,6 +1150,16 @@ interface MemoryEntry {
1103
1150
  timestamp: number;
1104
1151
  turnNumber: number | null;
1105
1152
  iterationNumber: number | null;
1153
+ /**
1154
+ * Provenance. **Optional on purpose** — `undefined` means unknown, which is what every
1155
+ * pre-existing snapshot and every not-yet-redeployed tenant bundle produces. Read sites MUST
1156
+ * test `== null`, never `=== undefined`: the `inTurnScope` predicate in `manager.ts` is the
1157
+ * cautionary precedent, where a `=== undefined` check silently dropped every `null`-stamped
1158
+ * entry. `isMemoryEntry` is deliberately NOT tightened to require this field; doing so would
1159
+ * make every stored snapshot fail validation, and `restoreSessionMemory` fails open by
1160
+ * starting the agent with empty memory rather than throwing.
1161
+ */
1162
+ source?: MemoryEntrySource;
1106
1163
  }
1107
1164
  /**
1108
1165
  * Agent memory - Self-orchestrated memory with session + working storage
@@ -1130,8 +1187,17 @@ interface MemoryStatus {
1130
1187
  sessionMemoryKeys: number;
1131
1188
  sessionMemoryLimit: number;
1132
1189
  currentKeys: string[];
1190
+ sessionMemoryTokens: number;
1191
+ sessionMemoryTokenLimit: number;
1192
+ /**
1193
+ * History tokens as a percentage of `historyBudget` — history ALONE, not history plus session
1194
+ * memory. It previously reported the combined total under this name, so session memory growth
1195
+ * read as history pressure and triggered history compaction that could not relieve it.
1196
+ */
1133
1197
  historyPercent: number;
1134
1198
  historyTokens: number;
1199
+ historyBudget: number;
1200
+ totalTokens: number;
1135
1201
  tokenBudget: number;
1136
1202
  }
1137
1203
  /**
@@ -1148,6 +1214,20 @@ interface MemoryConstraints {
1148
1214
  * Agent provides strings, framework handles wrapping and auto-compaction
1149
1215
  */
1150
1216
 
1217
+ /**
1218
+ * The framework's own framing message and the untrusted data envelope, as separate strings.
1219
+ *
1220
+ * They are separate because the model must be able to tell them apart, and so must the input
1221
+ * sanitizer: the framing is framework-authored and trusted, the envelope is not. Concatenating
1222
+ * them — which is what this replaced — made that distinction undecidable at the adapter and left
1223
+ * the framework's own section headers inside the region scanned for delimiter injection.
1224
+ */
1225
+ interface MemoryContextParts {
1226
+ /** Framework-authored. Memory status and a description of the envelope. Carries NO stored content. */
1227
+ framing: string;
1228
+ /** Every stored fragment, JSON-encoded and source-tagged. Untrusted. */
1229
+ dataEnvelope: string;
1230
+ }
1151
1231
  /**
1152
1232
  * Memory Manager - Agent memory orchestration
1153
1233
  * Provides ultra-simple API for agents (strings only)
@@ -1164,7 +1244,7 @@ declare class MemoryManager {
1164
1244
  * @param key - Session memory key
1165
1245
  * @param content - String content from agent
1166
1246
  */
1167
- set(key: string, content: string): void;
1247
+ set(key: string, content: string, source?: MemoryEntrySource): void;
1168
1248
  /**
1169
1249
  * Get session memory entry content
1170
1250
  * @param key - Session memory key
@@ -1193,6 +1273,15 @@ declare class MemoryManager {
1193
1273
  * Emergency fallback if agent exceeds limits
1194
1274
  */
1195
1275
  enforceHardLimits(): void;
1276
+ /**
1277
+ * Evict oldest session memory entries until the pool fits its token limit.
1278
+ *
1279
+ * Key count and token count are different constraints: 25 short keys are fine, 25 large ones
1280
+ * are not. Eviction is oldest-first by timestamp, matching the key-count path, and always
1281
+ * leaves at least one entry so a single oversized key degrades to "one key" rather than to
1282
+ * "memory silently emptied".
1283
+ */
1284
+ private enforceSessionMemoryTokenLimit;
1196
1285
  /**
1197
1286
  * Get history length (for logging and introspection)
1198
1287
  * @returns Number of entries in history
@@ -1216,14 +1305,29 @@ declare class MemoryManager {
1216
1305
  */
1217
1306
  getSnapshot(): AgentMemory | undefined;
1218
1307
  /**
1219
- * Build context string for LLM
1220
- * Serializes sessionmemory + history memory with clear sections
1221
- * Shows current iteration entries FIRST (reverse chronological) for LLM attention
1308
+ * Build the framework framing and the untrusted data envelope for an LLM call.
1309
+ *
1310
+ * These are two separate strings because they are two different trust levels, and they used to
1311
+ * be one. Concatenated, the framework's own `=== ... ===` section headers sat in the same string
1312
+ * as stored tool output and user text, so the input sanitizer matched its own scaffolding on
1313
+ * every call and nothing downstream could tell which half a match came from. Splitting them
1314
+ * makes that distinction structural: the framing is ours, the envelope is not.
1315
+ *
1316
+ * The envelope is JSON, which additionally neutralizes the anchored-delimiter attack class —
1317
+ * `JSON.stringify` escapes newlines, so a stored fragment cannot produce a line that starts
1318
+ * with `===` no matter what it contains.
1319
+ *
1320
+ * The current turn's own input is deliberately NOT in either string. It travels as its own
1321
+ * `role:'user'` message (see `buildAgentMessages`), which is the whole point: a model asked to
1322
+ * treat "everything in this block" as data was also being handed the live question inside that
1323
+ * block.
1324
+ *
1325
+ * Shows current iteration entries FIRST (reverse chronological) for LLM attention.
1326
+ *
1222
1327
  * @param currentIteration - Current iteration number (0 = pre-iteration)
1223
1328
  * @param currentTurn - Current turn number (optional, for session context filtering)
1224
- * @returns Formatted memory context for LLM prompt
1225
1329
  */
1226
- toContext(currentIteration: number, currentTurn?: number): string;
1330
+ toContextParts(currentIteration: number, currentTurn?: number): MemoryContextParts;
1227
1331
  }
1228
1332
 
1229
1333
  /**
@@ -1422,6 +1526,12 @@ interface IterationContext {
1422
1526
  modelConfig: ModelConfig;
1423
1527
  adapterFactory: LLMAdapterFactory;
1424
1528
  knowledgeMap?: KnowledgeMap;
1529
+ /**
1530
+ * The validated input for this execution, serialized. It travels here because the model gets
1531
+ * it as its own `role:'user'` message; nothing else in this context carried it, so the input
1532
+ * had to be read back out of memory history and shipped inside the memory block.
1533
+ */
1534
+ currentInput: string;
1425
1535
  }
1426
1536
 
1427
1537
  type Json = string | number | boolean | null | {
@@ -4168,6 +4278,7 @@ type Database = {
4168
4278
  deleted_at: string | null;
4169
4279
  ended_at: string | null;
4170
4280
  memory_snapshot: Json;
4281
+ memory_version: number;
4171
4282
  metadata: Json | null;
4172
4283
  organization_id: string;
4173
4284
  resource_id: string;
@@ -4184,6 +4295,7 @@ type Database = {
4184
4295
  deleted_at?: string | null;
4185
4296
  ended_at?: string | null;
4186
4297
  memory_snapshot: Json;
4298
+ memory_version?: number;
4187
4299
  metadata?: Json | null;
4188
4300
  organization_id: string;
4189
4301
  resource_id: string;
@@ -4200,6 +4312,7 @@ type Database = {
4200
4312
  deleted_at?: string | null;
4201
4313
  ended_at?: string | null;
4202
4314
  memory_snapshot?: Json;
4315
+ memory_version?: number;
4203
4316
  metadata?: Json | null;
4204
4317
  organization_id?: string;
4205
4318
  resource_id?: string;
@@ -4537,9 +4650,14 @@ type Database = {
4537
4650
  p_session_id: string;
4538
4651
  };
4539
4652
  Returns: {
4653
+ context_window_size: number;
4540
4654
  created_at: string;
4655
+ cumulative_input_tokens: number;
4656
+ cumulative_output_tokens: number;
4657
+ deleted_at: string;
4541
4658
  ended_at: string;
4542
4659
  memory_snapshot: Json;
4660
+ memory_version: number;
4543
4661
  metadata: Json;
4544
4662
  organization_id: string;
4545
4663
  resource_id: string;
@@ -4581,6 +4699,18 @@ type Database = {
4581
4699
  };
4582
4700
  Returns: boolean;
4583
4701
  };
4702
+ increment_session_tokens: {
4703
+ Args: {
4704
+ p_input_tokens: number;
4705
+ p_output_tokens: number;
4706
+ p_session_id: string;
4707
+ };
4708
+ Returns: {
4709
+ context_window_size: number;
4710
+ cumulative_input_tokens: number;
4711
+ cumulative_output_tokens: number;
4712
+ }[];
4713
+ };
4584
4714
  is_org_member: {
4585
4715
  Args: {
4586
4716
  org_id: string;
@@ -11072,6 +11202,25 @@ declare class MetricsCollector {
11072
11202
  buildExecutionMetrics(metricsConfig?: ResourceMetricsConfig): ExecutionMetricsSummary;
11073
11203
  }
11074
11204
 
11205
+ /**
11206
+ * Which `role:'user'` message slot a sanitizer warning came from, derived from the request's
11207
+ * message array (no new plumbing from callers):
11208
+ * - `'memory-context'` — the framework's framing message, identified by the `=== MEMORY STATUS ===`
11209
+ * banner. Framework-authored and trusted; it is no longer scanned at all, so this source should
11210
+ * not appear for agent calls. Retained because stale tenant bundles still emit the old combined
11211
+ * block, and their rows must stay readable.
11212
+ * - `'data-envelope'` — the JSON envelope carrying every stored fragment. Untrusted, and the slot
11213
+ * where a match is genuine signal.
11214
+ * - `'input'` — the turn's own input, on its own message. Also untrusted.
11215
+ * - `'history'` — replayed prior turns. Untrusted, but already screened at their own front door,
11216
+ * so warnings here are recorded and never block (see `screenInput`).
11217
+ */
11218
+ type InputWarningSource = 'memory-context' | 'data-envelope' | 'history' | 'input';
11219
+ /** Per-source breakdown of sanitizer warnings, so a memory-context echo is distinguishable from a genuine hit. */
11220
+ interface SourcedInputWarnings {
11221
+ source: InputWarningSource;
11222
+ warnings: string[];
11223
+ }
11075
11224
  interface BaseAICall {
11076
11225
  callSequence: number;
11077
11226
  callType: 'agent-reasoning' | 'agent-completion' | 'workflow-step' | 'tool' | 'other';
@@ -11081,6 +11230,71 @@ interface BaseAICall {
11081
11230
  costUsd: number;
11082
11231
  latencyMs: number;
11083
11232
  context?: AICallContext;
11233
+ /**
11234
+ * Distinct prompt-injection pattern types detected in the request's user-role messages.
11235
+ * Present only when the input sanitizer matched something. Non-blocking matches ride along on
11236
+ * the successful call's row; a blocked call records a row of its own (see `inputBlocked`).
11237
+ *
11238
+ * Flat union across all `role:'user'` messages — unchanged shape, kept for existing readers.
11239
+ * See `inputWarningsBySource` for the per-slot breakdown.
11240
+ */
11241
+ inputWarnings?: string[];
11242
+ /**
11243
+ * Additive breakdown of `inputWarnings` by message slot (see `InputWarningSource`). Present only
11244
+ * when at least one source produced a warning. Existing readers that only look at the flat
11245
+ * `inputWarnings` array are unaffected.
11246
+ */
11247
+ inputWarningsBySource?: SourcedInputWarnings[];
11248
+ /**
11249
+ * True when the sanitizer blocked the request and no provider call was made.
11250
+ * Such a row carries zero tokens, zero cost, and zero latency — it exists so a hard,
11251
+ * user-visible failure is observable at all. Before this, a blocked call produced no row.
11252
+ */
11253
+ inputBlocked?: boolean;
11254
+ /**
11255
+ * The validator's message when the provider responded but its output failed `responseSchema`
11256
+ * validation (e.g. `missing required field 'nextActions'`). Present only on such a row.
11257
+ *
11258
+ * This is NOT the blocked-input case: the provider DID respond and tokens WERE spent, so the row
11259
+ * carries real `inputTokens`, `outputTokens`, cost and latency. It is a paid call that produced
11260
+ * nothing usable, and before this it produced no row at all.
11261
+ *
11262
+ * One row per failed attempt — the adapter retries a validation failure up to `LLM_MAX_ATTEMPTS`,
11263
+ * so a turn that exhausts its retries records three. Reading `inputTokens` across these rows is
11264
+ * what measures malformed-output rate against context size rather than inferring it.
11265
+ *
11266
+ * Existing readers that only look at the fields above are unaffected.
11267
+ */
11268
+ outputValidationError?: string;
11269
+ /**
11270
+ * The raw model output that failed validation, JSON-stringified and truncated to a bounded
11271
+ * length. Truncation is visible in the value itself (a trailing `…[truncated: N chars total]`),
11272
+ * never silent. Present only alongside `outputValidationError`.
11273
+ */
11274
+ unvalidatedOutput?: string;
11275
+ /**
11276
+ * What happened to `strict` structured output on this call — `applied`, `refused`,
11277
+ * `compileRejected`, or `notAttempted`. Every server adapter sets it, so this is the field that
11278
+ * answers "is this agent's output actually being enforced?" without reading source.
11279
+ *
11280
+ * It replaces an inference that turned out to be unsound. `strictRefusalReasons` alone records
11281
+ * only refusals, so an empty row meant "strict held" OR "this adapter never tries" — and a prod
11282
+ * run recorded zero refusals while a call returned an array-typed field as a string, which a
11283
+ * grammar makes impossible. The absence proved nothing, because the deployed API had no way to
11284
+ * write the field at all.
11285
+ *
11286
+ * Absent on rows written before this field existed; that absence is itself diagnostic (the API
11287
+ * predates the change). Existing readers that only look at the fields above are unaffected.
11288
+ */
11289
+ strictStatus?: StrictStatus;
11290
+ /**
11291
+ * Why this call went out without `strict`, when a strict-capable adapter refused the schema. The
11292
+ * detail behind `strictStatus: 'refused' | 'compileRejected'` — read `strictStatus` for whether
11293
+ * it was enforced, this for why not.
11294
+ *
11295
+ * Existing readers that only look at the fields above are unaffected.
11296
+ */
11297
+ strictRefusalReasons?: string[];
11084
11298
  }
11085
11299
  type AICallContext = AgentReasoningContext | AgentCompletionContext | WorkflowStepContext | ToolCallContext | OtherCallContext;
11086
11300
  interface AgentReasoningContext {
@@ -11126,6 +11340,20 @@ interface LLMUsageData {
11126
11340
  latencyMs: number;
11127
11341
  /** Actual cost from provider in USD (when available, e.g., OpenRouter) */
11128
11342
  cost?: number;
11343
+ /** Distinct prompt-injection pattern types detected in the request's user-role messages */
11344
+ inputWarnings?: string[];
11345
+ /** Additive per-source breakdown of `inputWarnings` — see `SourcedInputWarnings` */
11346
+ inputWarningsBySource?: SourcedInputWarnings[];
11347
+ /** True when the sanitizer blocked the request and no provider call was made */
11348
+ inputBlocked?: boolean;
11349
+ /** Validator message when the provider responded but the output failed `responseSchema` validation */
11350
+ outputValidationError?: string;
11351
+ /** Raw model output that failed validation — JSON-stringified, truncated, truncation marked inline */
11352
+ unvalidatedOutput?: string;
11353
+ /** What happened to `strict` on this call — set by every server adapter, refusal or not */
11354
+ strictStatus?: StrictStatus;
11355
+ /** Why the call went out unstrict, when a strict-capable adapter refused the schema */
11356
+ strictRefusalReasons?: string[];
11129
11357
  }
11130
11358
  interface AIUsageSummary {
11131
11359
  model: LLMModel;