@superatomai/sdk-node 0.0.88-dsp → 0.0.90-dsp

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.d.mts CHANGED
@@ -5160,6 +5160,56 @@ interface SourcePolicy {
5160
5160
  /** Grants outside the scope above. Empty or absent means none. */
5161
5161
  exceptions?: PolicyException[];
5162
5162
  }
5163
+ /**
5164
+ * Operators the constraint engine builds predicates from. A superset of
5165
+ * {@link RowFilter.op}, which the original rewriter is limited to.
5166
+ */
5167
+ type ConstraintOp = 'in' | 'not_in' | 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'like' | 'not_like' | 'is_null' | 'is_not_null';
5168
+ /**
5169
+ * One filter in a {@link ConstraintPolicy}.
5170
+ *
5171
+ * No `table`, unlike {@link RowFilter}: these are keyed by table, so a filter
5172
+ * cannot fail to match the table it was written for and leave it unfiltered.
5173
+ */
5174
+ interface ConstraintFilter {
5175
+ column: string;
5176
+ op?: ConstraintOp;
5177
+ /** Omitted only for `is_null` / `is_not_null`. */
5178
+ values?: unknown[];
5179
+ label?: string;
5180
+ }
5181
+ /**
5182
+ * What one user may see in one source, in the shape the constraint engine reads
5183
+ * (`sqlrewrite/v2/engine.py`).
5184
+ *
5185
+ * Not a superset of {@link SourcePolicy} but a different shape: it adds
5186
+ * schemas, columns and limits. A claim carries one shape or the other, never
5187
+ * both.
5188
+ */
5189
+ interface ConstraintPolicy {
5190
+ sourceId?: string | null;
5191
+ label?: string;
5192
+ /**
5193
+ * Every table is read from this schema, whatever schema the query wrote —
5194
+ * which is what makes it a restriction: there is no other schema to reach.
5195
+ * Absent means schemas are left exactly as written.
5196
+ */
5197
+ schema?: string;
5198
+ /** table → readable columns, or `null` for every column. Absent: every table. */
5199
+ readableTables?: Record<string, string[] | null>;
5200
+ /** table → filters, ANDed together. */
5201
+ rowFilters?: Record<string, ConstraintFilter[]>;
5202
+ limits?: {
5203
+ maxRows?: number;
5204
+ maxExecutionSeconds?: number;
5205
+ };
5206
+ /**
5207
+ * Why this policy could not be read. Set rather than dropping the policy:
5208
+ * a dropped policy leaves its source UNRESTRICTED, which is the opposite of
5209
+ * what a malformed restriction should mean. The gate refuses the source.
5210
+ */
5211
+ invalid?: string;
5212
+ }
5163
5213
  interface RequestContext {
5164
5214
  principal: Principal;
5165
5215
  projectId?: string;
@@ -5169,6 +5219,11 @@ interface RequestContext {
5169
5219
  * — see the backend's policy-gate.
5170
5220
  */
5171
5221
  policies?: SourcePolicy[];
5222
+ /**
5223
+ * The same restrictions in the constraint shape. Present only when the claim
5224
+ * said `version: 2`, and then `policies` is empty: one claim, one engine.
5225
+ */
5226
+ constraintPolicies?: ConstraintPolicy[];
5172
5227
  /**
5173
5228
  * The data sources this user may reach AT ALL, by source id.
5174
5229
  *
@@ -5221,6 +5276,7 @@ declare function runAsUser<T>(user: {
5221
5276
  projectId?: string;
5222
5277
  requestId?: string;
5223
5278
  policies?: SourcePolicy[];
5279
+ constraintPolicies?: ConstraintPolicy[];
5224
5280
  allowedSources?: string[] | null;
5225
5281
  graphVersion?: GraphVersion;
5226
5282
  }, fn: () => T): T;
@@ -5269,6 +5325,35 @@ declare function describeContext(ctx?: RequestContext | undefined): string;
5269
5325
  /** True when the context represents a signed-in user rather than a trusted job. */
5270
5326
  declare function isUserContext(ctx?: RequestContext | undefined): boolean;
5271
5327
 
5328
+ /**
5329
+ * The constraint policy shape (`version: 2`), read onto the request context.
5330
+ *
5331
+ * Strict, and failing CLOSED, which is the opposite of the legacy parser beside
5332
+ * it. There, dropping something malformed grants LESS. Here it grants MORE: a
5333
+ * dropped policy leaves its source with no restriction at all. So a policy that
5334
+ * cannot be read is kept, marked `invalid`, and the gate refuses the source.
5335
+ */
5336
+
5337
+ declare function constraintPoliciesFromConfig(raw: unknown): ConstraintPolicy[];
5338
+
5339
+ /**
5340
+ * The original policy shape, read out of the admin-authored per-user config.
5341
+ *
5342
+ * Every step here is defensive and DROPS what it cannot read, because the
5343
+ * config is free-form JSON typed by a human into an admin field. That is a
5344
+ * deliberate trade with a sharp edge — a typo'd policy silently becomes no
5345
+ * policy, i.e. unrestricted. The constraint shape next door takes the opposite
5346
+ * approach for exactly that reason.
5347
+ */
5348
+
5349
+ /**
5350
+ * Read access policies out of the admin-authored per-user config.
5351
+ *
5352
+ * Accepts either a single object or an array, so one user can be scoped across
5353
+ * several sources — and the object form, whose policies sit under `policies`.
5354
+ */
5355
+ declare function policiesFromConfig(config: unknown): SourcePolicy[];
5356
+
5272
5357
  /**
5273
5358
  * Deriving "who is asking" from an incoming WebSocket message.
5274
5359
  *
@@ -5283,6 +5368,8 @@ declare function isUserContext(ctx?: RequestContext | undefined): boolean;
5283
5368
  /** Everything one request's config says about what the caller may see. */
5284
5369
  interface ResolvedAccess {
5285
5370
  policies: SourcePolicy[];
5371
+ /** Set instead of `policies` when the claim said `version: 2`. */
5372
+ constraintPolicies: ConstraintPolicy[];
5286
5373
  /** `null` means every source; `[]` means none — see `RequestContext.allowedSources`. */
5287
5374
  allowedSources: string[] | null;
5288
5375
  }
@@ -5296,19 +5383,6 @@ interface ResolvedAccess {
5296
5383
  * drop EVERY row filter the customer wrote.
5297
5384
  */
5298
5385
  declare function accessFromConfig(config: unknown): ResolvedAccess;
5299
- /**
5300
- * Read access policies out of the admin-authored per-user config.
5301
- *
5302
- * The config is free-form JSON typed by a human into an admin field, so every
5303
- * step here is defensive: a malformed entry is DROPPED, never guessed at. That
5304
- * is a deliberate trade-off with a sharp edge — a typo'd policy silently
5305
- * becomes no policy, i.e. unrestricted. Validating shapes against the source
5306
- * schema (and refusing, rather than dropping) is the fix, and is not built yet.
5307
- *
5308
- * Accepts either a single object or an array, so one user can be scoped across
5309
- * several sources — and the object form, whose policies sit under `policies`.
5310
- */
5311
- declare function policiesFromConfig(config: unknown): SourcePolicy[];
5312
5386
  /**
5313
5387
  * Run `fn` with the caller's identity established.
5314
5388
  *
@@ -5655,6 +5729,13 @@ interface CodexSessionOptions extends CodingAgentSessionOptions {
5655
5729
  extraConfig?: Record<string, unknown>;
5656
5730
  approvalPolicy?: 'never' | 'on-request' | 'on-failure' | 'untrusted';
5657
5731
  }
5732
+ /**
5733
+ * codex reads only the first `project_doc_max_bytes` of the instructions file (default 32 KiB) and
5734
+ * drops the rest without a word; composed instructions run past that, losing their closing rules.
5735
+ */
5736
+ declare const CODEX_DOC_MAX_BYTES: number;
5737
+ /** The `--config` overrides for one run: per run, so no host's config.toml decides them. */
5738
+ declare function codexRunConfig(opts: Pick<CodexSessionOptions, 'mcpServers' | 'instructionsFile' | 'extraConfig'>): Record<string, unknown>;
5658
5739
  declare function createCodexSession(opts: CodexSessionOptions): CodingAgentSession;
5659
5740
 
5660
5741
  /**
@@ -6759,4 +6840,4 @@ declare class SuperatomSDK {
6759
6840
  getConversationSimilarityThreshold(): number;
6760
6841
  }
6761
6842
 
6762
- export { ALL_COLUMN_KEYS, ANSWER_COMPONENT_NAMES, type AgentConfig, type AgentEvent, type AgentResponse, type AgentRunContext, type AgentRunHandlers, type AgentRunRecord, type AgentRunResult, type AgentTrigger, type AgentUsage, type AnalyticsEventType, type AnalyticsStatus, type AnswerProvider, type AnswerProviderContext, type ApplySummary, BM25L, type BM25LOptions, type BaseLLMConfig, type BuildTriggerInput, CATEGORY_KEYS, CONTEXT_CONFIG, type CapturedLog, CleanupService, type CodexSessionOptions, type CodingAgentCollectionConfig, type CodingAgentDefinition, type CodingAgentSession, type CodingAgentSessionOptions, type CodingAgentsConfig, type ColInfo, type ColType, type CollectionHandler, type CollectionOperation, type Component, type DBUIBlock, DEFAULT_AGENT_CONFIG, DEFAULT_FMT_CONFIG, type DashboardAgentCollectionConfig, type DatabaseType, type FindingCode, type Fmt, type FmtConfig, type GeneratedFile, type GraphVersion, type Harness, type HybridSearchOptions, INSTRUCTIONS_FILE, type IncomingMessage, type KbNodesQueryFilters, type KbNodesRequestPayload, LLM, type LLMUsageEntry, type LogLevel, MainAgent, type McpServerSpec, type Message, MissingRequestContextError, type ModelStrategy, NUMERIC_KEYS, type NarrationUpdate, type OutputContract, type OutputField, type OutputValidator, type PiSessionListener, type PiSessionState, type PiTranscriptEntry, type PolicyException, type PolicyExceptionTable, type Principal, type PromptAttachment, type PromptContext, type RequestContext, type RerankedResult, type ResolvedAccess, type RowFilter, type RunAgentOptions, STORAGE_CONFIG, type ScriptComponentSpec, ScriptMatcher, type ScriptParameter, type ScriptRecipe, type ScriptRecipeMetaRow, type ScriptRecipeStore, type ScriptResult, ScriptStore, type ScriptStoreOptions, type SelectedWorkflow, type ShimDef, type ShimSummary, type ShimTarget, type SourcePolicy, type SpecToValidate, SuperatomSDK, type SuperatomSDKConfig, type T_RESPONSE, type TaskType, Thread, ThreadManager, type Tool$1 as Tool, type ToolOutputSchema, type TriggerEvent, type TriggerFireInfo, UIBlock, UILogCollector, type User, UserManager, type UsersData, type ValidationContext, type ValidationFinding, type WorkflowDescriptor, type Workspace, accessFromConfig, analyticsClient, answerCatalogForBinding, answerComponents, anthropicLLM, assertReadOnlySql, bindContext, bridgePreamble, captureContext, clearContextTokens, contextTokenCount, createCodexSession, createCodingAgentSession, dashboardConversationHistory, dataFingerprint, describeContext, describeTriggers, emitAgentEvent, extractNamedExport, formatFindingsForAgent, geminiLLM, getCodingAgent, getCodingAgentsConfig, getPiSessionState, getRequestContext, groqLLM, hybridRerank, inferColumns, isUserContext, listCodingAgents, llmUsageLogger, logger, makeFmt, mintContextToken, normalizeScriptBody, onAgentRun, onPiSessionUpdate, openaiLLM, policiesFromConfig, projectForDatasetBinding, promptLoader, queryCache, registerCodingAgentCollection, registerCodingAgents, registerDashboardAgentCollection, requireRequestContext, rerankChromaResults, rerankConversationResults, resolveContextToken, resolveScriptRecipeStore, revokeContextToken, runAsSystem, runAsUser, runCodingAgent, runScript, runWithContext, runWithMessageIdentity, startAgentTriggers, stopAgentTriggers, userPromptErrorLogger, validateComponentSpec, withCapturedContext, writeBridgeShims, writeShims };
6843
+ export { ALL_COLUMN_KEYS, ANSWER_COMPONENT_NAMES, type AgentConfig, type AgentEvent, type AgentResponse, type AgentRunContext, type AgentRunHandlers, type AgentRunRecord, type AgentRunResult, type AgentTrigger, type AgentUsage, type AnalyticsEventType, type AnalyticsStatus, type AnswerProvider, type AnswerProviderContext, type ApplySummary, BM25L, type BM25LOptions, type BaseLLMConfig, type BuildTriggerInput, CATEGORY_KEYS, CODEX_DOC_MAX_BYTES, CONTEXT_CONFIG, type CapturedLog, CleanupService, type CodexSessionOptions, type CodingAgentCollectionConfig, type CodingAgentDefinition, type CodingAgentSession, type CodingAgentSessionOptions, type CodingAgentsConfig, type ColInfo, type ColType, type CollectionHandler, type CollectionOperation, type Component, type ConstraintFilter, type ConstraintOp, type ConstraintPolicy, type DBUIBlock, DEFAULT_AGENT_CONFIG, DEFAULT_FMT_CONFIG, type DashboardAgentCollectionConfig, type DatabaseType, type FindingCode, type Fmt, type FmtConfig, type GeneratedFile, type GraphVersion, type Harness, type HybridSearchOptions, INSTRUCTIONS_FILE, type IncomingMessage, type KbNodesQueryFilters, type KbNodesRequestPayload, LLM, type LLMUsageEntry, type LogLevel, MainAgent, type McpServerSpec, type Message, MissingRequestContextError, type ModelStrategy, NUMERIC_KEYS, type NarrationUpdate, type OutputContract, type OutputField, type OutputValidator, type PiSessionListener, type PiSessionState, type PiTranscriptEntry, type PolicyException, type PolicyExceptionTable, type Principal, type PromptAttachment, type PromptContext, type RequestContext, type RerankedResult, type ResolvedAccess, type RowFilter, type RunAgentOptions, STORAGE_CONFIG, type ScriptComponentSpec, ScriptMatcher, type ScriptParameter, type ScriptRecipe, type ScriptRecipeMetaRow, type ScriptRecipeStore, type ScriptResult, ScriptStore, type ScriptStoreOptions, type SelectedWorkflow, type ShimDef, type ShimSummary, type ShimTarget, type SourcePolicy, type SpecToValidate, SuperatomSDK, type SuperatomSDKConfig, type T_RESPONSE, type TaskType, Thread, ThreadManager, type Tool$1 as Tool, type ToolOutputSchema, type TriggerEvent, type TriggerFireInfo, UIBlock, UILogCollector, type User, UserManager, type UsersData, type ValidationContext, type ValidationFinding, type WorkflowDescriptor, type Workspace, accessFromConfig, analyticsClient, answerCatalogForBinding, answerComponents, anthropicLLM, assertReadOnlySql, bindContext, bridgePreamble, captureContext, clearContextTokens, codexRunConfig, constraintPoliciesFromConfig, contextTokenCount, createCodexSession, createCodingAgentSession, dashboardConversationHistory, dataFingerprint, describeContext, describeTriggers, emitAgentEvent, extractNamedExport, formatFindingsForAgent, geminiLLM, getCodingAgent, getCodingAgentsConfig, getPiSessionState, getRequestContext, groqLLM, hybridRerank, inferColumns, isUserContext, listCodingAgents, llmUsageLogger, logger, makeFmt, mintContextToken, normalizeScriptBody, onAgentRun, onPiSessionUpdate, openaiLLM, policiesFromConfig, projectForDatasetBinding, promptLoader, queryCache, registerCodingAgentCollection, registerCodingAgents, registerDashboardAgentCollection, requireRequestContext, rerankChromaResults, rerankConversationResults, resolveContextToken, resolveScriptRecipeStore, revokeContextToken, runAsSystem, runAsUser, runCodingAgent, runScript, runWithContext, runWithMessageIdentity, startAgentTriggers, stopAgentTriggers, userPromptErrorLogger, validateComponentSpec, withCapturedContext, writeBridgeShims, writeShims };
package/dist/index.d.ts CHANGED
@@ -5160,6 +5160,56 @@ interface SourcePolicy {
5160
5160
  /** Grants outside the scope above. Empty or absent means none. */
5161
5161
  exceptions?: PolicyException[];
5162
5162
  }
5163
+ /**
5164
+ * Operators the constraint engine builds predicates from. A superset of
5165
+ * {@link RowFilter.op}, which the original rewriter is limited to.
5166
+ */
5167
+ type ConstraintOp = 'in' | 'not_in' | 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'like' | 'not_like' | 'is_null' | 'is_not_null';
5168
+ /**
5169
+ * One filter in a {@link ConstraintPolicy}.
5170
+ *
5171
+ * No `table`, unlike {@link RowFilter}: these are keyed by table, so a filter
5172
+ * cannot fail to match the table it was written for and leave it unfiltered.
5173
+ */
5174
+ interface ConstraintFilter {
5175
+ column: string;
5176
+ op?: ConstraintOp;
5177
+ /** Omitted only for `is_null` / `is_not_null`. */
5178
+ values?: unknown[];
5179
+ label?: string;
5180
+ }
5181
+ /**
5182
+ * What one user may see in one source, in the shape the constraint engine reads
5183
+ * (`sqlrewrite/v2/engine.py`).
5184
+ *
5185
+ * Not a superset of {@link SourcePolicy} but a different shape: it adds
5186
+ * schemas, columns and limits. A claim carries one shape or the other, never
5187
+ * both.
5188
+ */
5189
+ interface ConstraintPolicy {
5190
+ sourceId?: string | null;
5191
+ label?: string;
5192
+ /**
5193
+ * Every table is read from this schema, whatever schema the query wrote —
5194
+ * which is what makes it a restriction: there is no other schema to reach.
5195
+ * Absent means schemas are left exactly as written.
5196
+ */
5197
+ schema?: string;
5198
+ /** table → readable columns, or `null` for every column. Absent: every table. */
5199
+ readableTables?: Record<string, string[] | null>;
5200
+ /** table → filters, ANDed together. */
5201
+ rowFilters?: Record<string, ConstraintFilter[]>;
5202
+ limits?: {
5203
+ maxRows?: number;
5204
+ maxExecutionSeconds?: number;
5205
+ };
5206
+ /**
5207
+ * Why this policy could not be read. Set rather than dropping the policy:
5208
+ * a dropped policy leaves its source UNRESTRICTED, which is the opposite of
5209
+ * what a malformed restriction should mean. The gate refuses the source.
5210
+ */
5211
+ invalid?: string;
5212
+ }
5163
5213
  interface RequestContext {
5164
5214
  principal: Principal;
5165
5215
  projectId?: string;
@@ -5169,6 +5219,11 @@ interface RequestContext {
5169
5219
  * — see the backend's policy-gate.
5170
5220
  */
5171
5221
  policies?: SourcePolicy[];
5222
+ /**
5223
+ * The same restrictions in the constraint shape. Present only when the claim
5224
+ * said `version: 2`, and then `policies` is empty: one claim, one engine.
5225
+ */
5226
+ constraintPolicies?: ConstraintPolicy[];
5172
5227
  /**
5173
5228
  * The data sources this user may reach AT ALL, by source id.
5174
5229
  *
@@ -5221,6 +5276,7 @@ declare function runAsUser<T>(user: {
5221
5276
  projectId?: string;
5222
5277
  requestId?: string;
5223
5278
  policies?: SourcePolicy[];
5279
+ constraintPolicies?: ConstraintPolicy[];
5224
5280
  allowedSources?: string[] | null;
5225
5281
  graphVersion?: GraphVersion;
5226
5282
  }, fn: () => T): T;
@@ -5269,6 +5325,35 @@ declare function describeContext(ctx?: RequestContext | undefined): string;
5269
5325
  /** True when the context represents a signed-in user rather than a trusted job. */
5270
5326
  declare function isUserContext(ctx?: RequestContext | undefined): boolean;
5271
5327
 
5328
+ /**
5329
+ * The constraint policy shape (`version: 2`), read onto the request context.
5330
+ *
5331
+ * Strict, and failing CLOSED, which is the opposite of the legacy parser beside
5332
+ * it. There, dropping something malformed grants LESS. Here it grants MORE: a
5333
+ * dropped policy leaves its source with no restriction at all. So a policy that
5334
+ * cannot be read is kept, marked `invalid`, and the gate refuses the source.
5335
+ */
5336
+
5337
+ declare function constraintPoliciesFromConfig(raw: unknown): ConstraintPolicy[];
5338
+
5339
+ /**
5340
+ * The original policy shape, read out of the admin-authored per-user config.
5341
+ *
5342
+ * Every step here is defensive and DROPS what it cannot read, because the
5343
+ * config is free-form JSON typed by a human into an admin field. That is a
5344
+ * deliberate trade with a sharp edge — a typo'd policy silently becomes no
5345
+ * policy, i.e. unrestricted. The constraint shape next door takes the opposite
5346
+ * approach for exactly that reason.
5347
+ */
5348
+
5349
+ /**
5350
+ * Read access policies out of the admin-authored per-user config.
5351
+ *
5352
+ * Accepts either a single object or an array, so one user can be scoped across
5353
+ * several sources — and the object form, whose policies sit under `policies`.
5354
+ */
5355
+ declare function policiesFromConfig(config: unknown): SourcePolicy[];
5356
+
5272
5357
  /**
5273
5358
  * Deriving "who is asking" from an incoming WebSocket message.
5274
5359
  *
@@ -5283,6 +5368,8 @@ declare function isUserContext(ctx?: RequestContext | undefined): boolean;
5283
5368
  /** Everything one request's config says about what the caller may see. */
5284
5369
  interface ResolvedAccess {
5285
5370
  policies: SourcePolicy[];
5371
+ /** Set instead of `policies` when the claim said `version: 2`. */
5372
+ constraintPolicies: ConstraintPolicy[];
5286
5373
  /** `null` means every source; `[]` means none — see `RequestContext.allowedSources`. */
5287
5374
  allowedSources: string[] | null;
5288
5375
  }
@@ -5296,19 +5383,6 @@ interface ResolvedAccess {
5296
5383
  * drop EVERY row filter the customer wrote.
5297
5384
  */
5298
5385
  declare function accessFromConfig(config: unknown): ResolvedAccess;
5299
- /**
5300
- * Read access policies out of the admin-authored per-user config.
5301
- *
5302
- * The config is free-form JSON typed by a human into an admin field, so every
5303
- * step here is defensive: a malformed entry is DROPPED, never guessed at. That
5304
- * is a deliberate trade-off with a sharp edge — a typo'd policy silently
5305
- * becomes no policy, i.e. unrestricted. Validating shapes against the source
5306
- * schema (and refusing, rather than dropping) is the fix, and is not built yet.
5307
- *
5308
- * Accepts either a single object or an array, so one user can be scoped across
5309
- * several sources — and the object form, whose policies sit under `policies`.
5310
- */
5311
- declare function policiesFromConfig(config: unknown): SourcePolicy[];
5312
5386
  /**
5313
5387
  * Run `fn` with the caller's identity established.
5314
5388
  *
@@ -5655,6 +5729,13 @@ interface CodexSessionOptions extends CodingAgentSessionOptions {
5655
5729
  extraConfig?: Record<string, unknown>;
5656
5730
  approvalPolicy?: 'never' | 'on-request' | 'on-failure' | 'untrusted';
5657
5731
  }
5732
+ /**
5733
+ * codex reads only the first `project_doc_max_bytes` of the instructions file (default 32 KiB) and
5734
+ * drops the rest without a word; composed instructions run past that, losing their closing rules.
5735
+ */
5736
+ declare const CODEX_DOC_MAX_BYTES: number;
5737
+ /** The `--config` overrides for one run: per run, so no host's config.toml decides them. */
5738
+ declare function codexRunConfig(opts: Pick<CodexSessionOptions, 'mcpServers' | 'instructionsFile' | 'extraConfig'>): Record<string, unknown>;
5658
5739
  declare function createCodexSession(opts: CodexSessionOptions): CodingAgentSession;
5659
5740
 
5660
5741
  /**
@@ -6759,4 +6840,4 @@ declare class SuperatomSDK {
6759
6840
  getConversationSimilarityThreshold(): number;
6760
6841
  }
6761
6842
 
6762
- export { ALL_COLUMN_KEYS, ANSWER_COMPONENT_NAMES, type AgentConfig, type AgentEvent, type AgentResponse, type AgentRunContext, type AgentRunHandlers, type AgentRunRecord, type AgentRunResult, type AgentTrigger, type AgentUsage, type AnalyticsEventType, type AnalyticsStatus, type AnswerProvider, type AnswerProviderContext, type ApplySummary, BM25L, type BM25LOptions, type BaseLLMConfig, type BuildTriggerInput, CATEGORY_KEYS, CONTEXT_CONFIG, type CapturedLog, CleanupService, type CodexSessionOptions, type CodingAgentCollectionConfig, type CodingAgentDefinition, type CodingAgentSession, type CodingAgentSessionOptions, type CodingAgentsConfig, type ColInfo, type ColType, type CollectionHandler, type CollectionOperation, type Component, type DBUIBlock, DEFAULT_AGENT_CONFIG, DEFAULT_FMT_CONFIG, type DashboardAgentCollectionConfig, type DatabaseType, type FindingCode, type Fmt, type FmtConfig, type GeneratedFile, type GraphVersion, type Harness, type HybridSearchOptions, INSTRUCTIONS_FILE, type IncomingMessage, type KbNodesQueryFilters, type KbNodesRequestPayload, LLM, type LLMUsageEntry, type LogLevel, MainAgent, type McpServerSpec, type Message, MissingRequestContextError, type ModelStrategy, NUMERIC_KEYS, type NarrationUpdate, type OutputContract, type OutputField, type OutputValidator, type PiSessionListener, type PiSessionState, type PiTranscriptEntry, type PolicyException, type PolicyExceptionTable, type Principal, type PromptAttachment, type PromptContext, type RequestContext, type RerankedResult, type ResolvedAccess, type RowFilter, type RunAgentOptions, STORAGE_CONFIG, type ScriptComponentSpec, ScriptMatcher, type ScriptParameter, type ScriptRecipe, type ScriptRecipeMetaRow, type ScriptRecipeStore, type ScriptResult, ScriptStore, type ScriptStoreOptions, type SelectedWorkflow, type ShimDef, type ShimSummary, type ShimTarget, type SourcePolicy, type SpecToValidate, SuperatomSDK, type SuperatomSDKConfig, type T_RESPONSE, type TaskType, Thread, ThreadManager, type Tool$1 as Tool, type ToolOutputSchema, type TriggerEvent, type TriggerFireInfo, UIBlock, UILogCollector, type User, UserManager, type UsersData, type ValidationContext, type ValidationFinding, type WorkflowDescriptor, type Workspace, accessFromConfig, analyticsClient, answerCatalogForBinding, answerComponents, anthropicLLM, assertReadOnlySql, bindContext, bridgePreamble, captureContext, clearContextTokens, contextTokenCount, createCodexSession, createCodingAgentSession, dashboardConversationHistory, dataFingerprint, describeContext, describeTriggers, emitAgentEvent, extractNamedExport, formatFindingsForAgent, geminiLLM, getCodingAgent, getCodingAgentsConfig, getPiSessionState, getRequestContext, groqLLM, hybridRerank, inferColumns, isUserContext, listCodingAgents, llmUsageLogger, logger, makeFmt, mintContextToken, normalizeScriptBody, onAgentRun, onPiSessionUpdate, openaiLLM, policiesFromConfig, projectForDatasetBinding, promptLoader, queryCache, registerCodingAgentCollection, registerCodingAgents, registerDashboardAgentCollection, requireRequestContext, rerankChromaResults, rerankConversationResults, resolveContextToken, resolveScriptRecipeStore, revokeContextToken, runAsSystem, runAsUser, runCodingAgent, runScript, runWithContext, runWithMessageIdentity, startAgentTriggers, stopAgentTriggers, userPromptErrorLogger, validateComponentSpec, withCapturedContext, writeBridgeShims, writeShims };
6843
+ export { ALL_COLUMN_KEYS, ANSWER_COMPONENT_NAMES, type AgentConfig, type AgentEvent, type AgentResponse, type AgentRunContext, type AgentRunHandlers, type AgentRunRecord, type AgentRunResult, type AgentTrigger, type AgentUsage, type AnalyticsEventType, type AnalyticsStatus, type AnswerProvider, type AnswerProviderContext, type ApplySummary, BM25L, type BM25LOptions, type BaseLLMConfig, type BuildTriggerInput, CATEGORY_KEYS, CODEX_DOC_MAX_BYTES, CONTEXT_CONFIG, type CapturedLog, CleanupService, type CodexSessionOptions, type CodingAgentCollectionConfig, type CodingAgentDefinition, type CodingAgentSession, type CodingAgentSessionOptions, type CodingAgentsConfig, type ColInfo, type ColType, type CollectionHandler, type CollectionOperation, type Component, type ConstraintFilter, type ConstraintOp, type ConstraintPolicy, type DBUIBlock, DEFAULT_AGENT_CONFIG, DEFAULT_FMT_CONFIG, type DashboardAgentCollectionConfig, type DatabaseType, type FindingCode, type Fmt, type FmtConfig, type GeneratedFile, type GraphVersion, type Harness, type HybridSearchOptions, INSTRUCTIONS_FILE, type IncomingMessage, type KbNodesQueryFilters, type KbNodesRequestPayload, LLM, type LLMUsageEntry, type LogLevel, MainAgent, type McpServerSpec, type Message, MissingRequestContextError, type ModelStrategy, NUMERIC_KEYS, type NarrationUpdate, type OutputContract, type OutputField, type OutputValidator, type PiSessionListener, type PiSessionState, type PiTranscriptEntry, type PolicyException, type PolicyExceptionTable, type Principal, type PromptAttachment, type PromptContext, type RequestContext, type RerankedResult, type ResolvedAccess, type RowFilter, type RunAgentOptions, STORAGE_CONFIG, type ScriptComponentSpec, ScriptMatcher, type ScriptParameter, type ScriptRecipe, type ScriptRecipeMetaRow, type ScriptRecipeStore, type ScriptResult, ScriptStore, type ScriptStoreOptions, type SelectedWorkflow, type ShimDef, type ShimSummary, type ShimTarget, type SourcePolicy, type SpecToValidate, SuperatomSDK, type SuperatomSDKConfig, type T_RESPONSE, type TaskType, Thread, ThreadManager, type Tool$1 as Tool, type ToolOutputSchema, type TriggerEvent, type TriggerFireInfo, UIBlock, UILogCollector, type User, UserManager, type UsersData, type ValidationContext, type ValidationFinding, type WorkflowDescriptor, type Workspace, accessFromConfig, analyticsClient, answerCatalogForBinding, answerComponents, anthropicLLM, assertReadOnlySql, bindContext, bridgePreamble, captureContext, clearContextTokens, codexRunConfig, constraintPoliciesFromConfig, contextTokenCount, createCodexSession, createCodingAgentSession, dashboardConversationHistory, dataFingerprint, describeContext, describeTriggers, emitAgentEvent, extractNamedExport, formatFindingsForAgent, geminiLLM, getCodingAgent, getCodingAgentsConfig, getPiSessionState, getRequestContext, groqLLM, hybridRerank, inferColumns, isUserContext, listCodingAgents, llmUsageLogger, logger, makeFmt, mintContextToken, normalizeScriptBody, onAgentRun, onPiSessionUpdate, openaiLLM, policiesFromConfig, projectForDatasetBinding, promptLoader, queryCache, registerCodingAgentCollection, registerCodingAgents, registerDashboardAgentCollection, requireRequestContext, rerankChromaResults, rerankConversationResults, resolveContextToken, resolveScriptRecipeStore, revokeContextToken, runAsSystem, runAsUser, runCodingAgent, runScript, runWithContext, runWithMessageIdentity, startAgentTriggers, stopAgentTriggers, userPromptErrorLogger, validateComponentSpec, withCapturedContext, writeBridgeShims, writeShims };
package/dist/index.js CHANGED
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  ANSWER_COMPONENT_NAMES: () => ANSWER_COMPONENT_NAMES,
35
35
  BM25L: () => BM25L,
36
36
  CATEGORY_KEYS: () => CATEGORY_KEYS,
37
+ CODEX_DOC_MAX_BYTES: () => CODEX_DOC_MAX_BYTES,
37
38
  CONTEXT_CONFIG: () => CONTEXT_CONFIG,
38
39
  CleanupService: () => CleanupService,
39
40
  DEFAULT_AGENT_CONFIG: () => DEFAULT_AGENT_CONFIG,
@@ -62,6 +63,8 @@ __export(index_exports, {
62
63
  bridgePreamble: () => bridgePreamble,
63
64
  captureContext: () => captureContext,
64
65
  clearContextTokens: () => clearContextTokens,
66
+ codexRunConfig: () => codexRunConfig,
67
+ constraintPoliciesFromConfig: () => constraintPoliciesFromConfig,
65
68
  contextTokenCount: () => contextTokenCount,
66
69
  createCodexSession: () => createCodexSession,
67
70
  createCodingAgentSession: () => createCodingAgentSession,
@@ -1952,7 +1955,17 @@ function runWithContext(ctx, fn) {
1952
1955
  return getStorage().run(ctx, fn);
1953
1956
  }
1954
1957
  function runAsUser(user, fn) {
1955
- const { userId, orgId, role, projectId, requestId, policies, allowedSources, graphVersion } = user;
1958
+ const {
1959
+ userId,
1960
+ orgId,
1961
+ role,
1962
+ projectId,
1963
+ requestId,
1964
+ policies,
1965
+ constraintPolicies,
1966
+ allowedSources,
1967
+ graphVersion
1968
+ } = user;
1956
1969
  return runWithContext(
1957
1970
  // `allowedSources` is spread in only when given, so an absent restriction
1958
1971
  // stays absent rather than becoming an explicit `undefined` that a later
@@ -1962,6 +1975,7 @@ function runAsUser(user, fn) {
1962
1975
  projectId,
1963
1976
  requestId,
1964
1977
  policies,
1978
+ ...constraintPolicies?.length ? { constraintPolicies } : {},
1965
1979
  ...allowedSources !== void 0 ? { allowedSources } : {},
1966
1980
  ...graphVersion !== void 0 ? { graphVersion } : {}
1967
1981
  },
@@ -2642,42 +2656,148 @@ function buildDirectToolCacheKey(toolId, parameters) {
2642
2656
  return `et-direct:${toolId}:${stableStringify(parameters || {})}`;
2643
2657
  }
2644
2658
 
2645
- // src/handlers/request-identity.ts
2646
- function graphVersionOf(v) {
2647
- if (v === "draft") return "draft";
2648
- return Number.isInteger(v) && v > 0 ? v : void 0;
2659
+ // src/handlers/data-access/v2/policies.ts
2660
+ var CONSTRAINT_OPS = [
2661
+ "in",
2662
+ "not_in",
2663
+ "eq",
2664
+ "ne",
2665
+ "gt",
2666
+ "gte",
2667
+ "lt",
2668
+ "lte",
2669
+ "like",
2670
+ "not_like",
2671
+ "is_null",
2672
+ "is_not_null"
2673
+ ];
2674
+ var NO_VALUE_OPS = /* @__PURE__ */ new Set(["is_null", "is_not_null"]);
2675
+ function constraintPoliciesFromConfig(raw) {
2676
+ const entries = Array.isArray(raw) ? raw : [raw];
2677
+ const out = [];
2678
+ for (const entry of entries) {
2679
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
2680
+ const e = entry;
2681
+ const sourceId = typeof e.sourceId === "string" && e.sourceId ? e.sourceId : null;
2682
+ const label = typeof e.label === "string" && e.label.trim() ? e.label.trim() : void 0;
2683
+ const bad = (why) => ({ sourceId, label, invalid: why });
2684
+ let schema2;
2685
+ if (e.schema !== void 0 && e.schema !== null) {
2686
+ if (typeof e.schema !== "string" || !e.schema.trim()) {
2687
+ out.push(bad("schema must be a schema name"));
2688
+ continue;
2689
+ }
2690
+ schema2 = e.schema.trim();
2691
+ }
2692
+ let readableTables;
2693
+ let tablesBad;
2694
+ if (e.readableTables !== void 0 && e.readableTables !== null) {
2695
+ if (typeof e.readableTables !== "object" || Array.isArray(e.readableTables)) {
2696
+ out.push(bad("readableTables must be an object of table to columns"));
2697
+ continue;
2698
+ }
2699
+ readableTables = {};
2700
+ for (const [table, cols] of Object.entries(e.readableTables)) {
2701
+ if (cols === null) {
2702
+ readableTables[table] = null;
2703
+ continue;
2704
+ }
2705
+ if (!Array.isArray(cols) || cols.length === 0) {
2706
+ tablesBad = `readableTables["${table}"] must be a non-empty list or null`;
2707
+ break;
2708
+ }
2709
+ const columns = cols.filter((c) => typeof c === "string" && !!c.trim()).map((c) => c.trim());
2710
+ if (columns.length !== cols.length) {
2711
+ tablesBad = `readableTables["${table}"] has an entry that is not a column name`;
2712
+ break;
2713
+ }
2714
+ readableTables[table] = columns;
2715
+ }
2716
+ if (!tablesBad && Object.keys(readableTables).length === 0) {
2717
+ tablesBad = "readableTables names no tables \u2014 omit it to allow every table";
2718
+ }
2719
+ if (tablesBad) {
2720
+ out.push(bad(tablesBad));
2721
+ continue;
2722
+ }
2723
+ }
2724
+ const rowFilters = {};
2725
+ let filtersBad;
2726
+ const rawFilters = e.rowFilters;
2727
+ if (rawFilters !== void 0 && rawFilters !== null) {
2728
+ if (typeof rawFilters !== "object" || Array.isArray(rawFilters)) {
2729
+ filtersBad = "rowFilters must be an object keyed by table";
2730
+ } else {
2731
+ for (const [table, items] of Object.entries(rawFilters)) {
2732
+ if (readableTables && !(table in readableTables)) {
2733
+ filtersBad = `rowFilters names "${table}", which readableTables does not allow`;
2734
+ break;
2735
+ }
2736
+ if (!Array.isArray(items) || items.length === 0) {
2737
+ filtersBad = `rowFilters["${table}"] must be a non-empty list`;
2738
+ break;
2739
+ }
2740
+ const parsed = [];
2741
+ for (const item of items) {
2742
+ if (!item || typeof item !== "object") {
2743
+ filtersBad = `rowFilters["${table}"] has an entry that is not an object`;
2744
+ break;
2745
+ }
2746
+ const f = item;
2747
+ if (typeof f.column !== "string" || !f.column.trim()) {
2748
+ filtersBad = `a filter on "${table}" has no column`;
2749
+ break;
2750
+ }
2751
+ const op = typeof f.op === "string" ? f.op.toLowerCase() : "in";
2752
+ if (!CONSTRAINT_OPS.includes(op)) {
2753
+ filtersBad = `unsupported operator "${f.op}" on "${table}.${f.column}"`;
2754
+ break;
2755
+ }
2756
+ const values = Array.isArray(f.values) ? f.values : [];
2757
+ if (!NO_VALUE_OPS.has(op) && values.length === 0) {
2758
+ filtersBad = `the filter on "${table}.${f.column}" has no values`;
2759
+ break;
2760
+ }
2761
+ parsed.push({
2762
+ column: f.column.trim(),
2763
+ op,
2764
+ ...NO_VALUE_OPS.has(op) ? {} : { values },
2765
+ label: typeof f.label === "string" && f.label.trim() ? f.label.trim() : void 0
2766
+ });
2767
+ }
2768
+ if (filtersBad) break;
2769
+ rowFilters[table] = parsed;
2770
+ }
2771
+ }
2772
+ }
2773
+ if (filtersBad) {
2774
+ out.push(bad(filtersBad));
2775
+ continue;
2776
+ }
2777
+ const rawLimits = e.limits;
2778
+ const num = (v) => typeof v === "number" && Number.isInteger(v) && v > 0 ? v : void 0;
2779
+ const limits = rawLimits ? { maxRows: num(rawLimits.maxRows), maxExecutionSeconds: num(rawLimits.maxExecutionSeconds) } : void 0;
2780
+ out.push({
2781
+ sourceId,
2782
+ label,
2783
+ ...schema2 ? { schema: schema2 } : {},
2784
+ ...readableTables ? { readableTables } : {},
2785
+ ...Object.keys(rowFilters).length ? { rowFilters } : {},
2786
+ ...limits ? { limits } : {}
2787
+ });
2788
+ }
2789
+ return out;
2649
2790
  }
2791
+
2792
+ // src/handlers/data-access/shape.ts
2650
2793
  function scopedForm(config2) {
2651
2794
  if (!config2 || typeof config2 !== "object" || Array.isArray(config2)) return void 0;
2652
2795
  const c = config2;
2653
2796
  return "allowedSources" in c || "policies" in c ? c : void 0;
2654
2797
  }
2655
- function allowedSourcesFrom(value) {
2656
- if (value === void 0 || value === null) return null;
2657
- if (!Array.isArray(value)) {
2658
- if (!warnedBadSources) {
2659
- warnedBadSources = true;
2660
- logger.warn(
2661
- `[RequestIdentity] "allowedSources" is ${typeof value}, not a list of source ids \u2014 treating it as NO sources rather than all of them. Fix the config: "allowedSources": ["mssql-1a2b"].`
2662
- );
2663
- }
2664
- return [];
2665
- }
2666
- const out = [];
2667
- for (const item of value) {
2668
- if (typeof item !== "string" || !item.trim()) continue;
2669
- const id = item.trim();
2670
- if (!out.includes(id)) out.push(id);
2671
- }
2672
- return out;
2673
- }
2674
- function accessFromConfig(config2) {
2675
- const scoped = scopedForm(config2);
2676
- return {
2677
- policies: policiesFromConfig(config2),
2678
- allowedSources: scoped ? allowedSourcesFrom(scoped.allowedSources) : null
2679
- };
2680
- }
2798
+
2799
+ // src/handlers/data-access/v1/policies.ts
2800
+ var warnedUnlabelled = false;
2681
2801
  function exceptionsFromConfig(raw) {
2682
2802
  if (!Array.isArray(raw)) return [];
2683
2803
  const str = (v) => typeof v === "string" && v.trim() ? v.trim() : void 0;
@@ -2756,16 +2876,55 @@ function policiesFromConfig(config2) {
2756
2876
  }
2757
2877
  return out;
2758
2878
  }
2879
+
2880
+ // src/handlers/request-identity.ts
2881
+ function graphVersionOf(v) {
2882
+ if (v === "draft") return "draft";
2883
+ return Number.isInteger(v) && v > 0 ? v : void 0;
2884
+ }
2885
+ function allowedSourcesFrom(value) {
2886
+ if (value === void 0 || value === null) return null;
2887
+ if (!Array.isArray(value)) {
2888
+ if (!warnedBadSources) {
2889
+ warnedBadSources = true;
2890
+ logger.warn(
2891
+ `[RequestIdentity] "allowedSources" is ${typeof value}, not a list of source ids \u2014 treating it as NO sources rather than all of them. Fix the config: "allowedSources": ["mssql-1a2b"].`
2892
+ );
2893
+ }
2894
+ return [];
2895
+ }
2896
+ const out = [];
2897
+ for (const item of value) {
2898
+ if (typeof item !== "string" || !item.trim()) continue;
2899
+ const id = item.trim();
2900
+ if (!out.includes(id)) out.push(id);
2901
+ }
2902
+ return out;
2903
+ }
2904
+ function accessFromConfig(config2) {
2905
+ const scoped = scopedForm(config2);
2906
+ const allowedSources = scoped ? allowedSourcesFrom(scoped.allowedSources) : null;
2907
+ if (scoped?.version === 2) {
2908
+ return {
2909
+ policies: [],
2910
+ constraintPolicies: constraintPoliciesFromConfig(scoped.policies),
2911
+ allowedSources
2912
+ };
2913
+ }
2914
+ return { policies: policiesFromConfig(config2), constraintPolicies: [], allowedSources };
2915
+ }
2759
2916
  var warnedUntrusted = false;
2760
2917
  var warnedAnonymous = false;
2761
- var warnedUnlabelled = false;
2762
2918
  var warnedBadSources = false;
2763
2919
  var announcedVerified = false;
2764
2920
  var reportedIdMismatches = /* @__PURE__ */ new Set();
2765
2921
  function runWithMessageIdentity(message, fn) {
2766
2922
  const verified = message?.authContext;
2767
2923
  const requestId = message?.id;
2768
- const { policies, allowedSources } = verified ? accessFromConfig(verified.config) : accessFromConfig(message?.payload?.config);
2924
+ const { policies, constraintPolicies, allowedSources } = verified ? accessFromConfig(verified.config) : accessFromConfig(message?.payload?.config);
2925
+ logger.info(
2926
+ `[RequestIdentity] ${message?.type ?? "?"}: access from ${verified ? "authContext" : "payload"}${verified && verified.config == null ? " (none on it)" : ""}, allowedSources=${allowedSources === null ? "every source" : `[${allowedSources.join(", ") || "NONE"}]`}, ${constraintPolicies.length} constraint policy(ies), ${policies.length} row policy(ies)`
2927
+ );
2769
2928
  if (verified?.userId) {
2770
2929
  const claimedId = message?.payload?.userId;
2771
2930
  if (!announcedVerified) {
@@ -2790,6 +2949,7 @@ function runWithMessageIdentity(message, fn) {
2790
2949
  role: verified.role,
2791
2950
  requestId,
2792
2951
  policies,
2952
+ constraintPolicies,
2793
2953
  // `?? undefined` so "no restriction" leaves the key off the context
2794
2954
  // entirely; `[]` is passed through as the deny-everything it means.
2795
2955
  allowedSources: allowedSources ?? void 0,
@@ -2807,7 +2967,10 @@ function runWithMessageIdentity(message, fn) {
2807
2967
  "[RequestIdentity] Using the client-supplied payload.userId as the principal \u2014 the relay is not stamping a verified authContext yet, so this identity is NOT trustworthy. Fine for plumbing; do not enable policy enforcement until the relay change lands."
2808
2968
  );
2809
2969
  }
2810
- return runAsUser({ userId: claimed, requestId, policies, allowedSources: allowedSources ?? void 0 }, fn);
2970
+ return runAsUser(
2971
+ { userId: claimed, requestId, policies, constraintPolicies, allowedSources: allowedSources ?? void 0 },
2972
+ fn
2973
+ );
2811
2974
  }
2812
2975
  if (!warnedAnonymous) {
2813
2976
  warnedAnonymous = true;
@@ -24649,6 +24812,20 @@ function buildEnv(opts) {
24649
24812
  }
24650
24813
  return { ...env, ...opts.env ?? {} };
24651
24814
  }
24815
+ var CODEX_DOC_MAX_BYTES = 256 * 1024;
24816
+ function codexRunConfig(opts) {
24817
+ return {
24818
+ // Tools reach codex as MCP servers; each server's name shows up on
24819
+ // every tool event, so the runner can tell ours from codex's own.
24820
+ ...opts.mcpServers && Object.keys(opts.mcpServers).length ? { mcp_servers: opts.mcpServers } : {},
24821
+ // Per run, not ~/.codex/config.toml: a host without that line would run
24822
+ // the agent with no instructions at all. AGENTS.md still wins if present.
24823
+ ...opts.instructionsFile && opts.instructionsFile !== "AGENTS.md" ? { project_doc_fallback_filenames: [opts.instructionsFile] } : {},
24824
+ project_doc_max_bytes: CODEX_DOC_MAX_BYTES,
24825
+ // Last: a deployment's own value wins.
24826
+ ...opts.extraConfig ?? {}
24827
+ };
24828
+ }
24652
24829
  function createCodexSession(opts) {
24653
24830
  const model = opts.model ?? process.env.CODEX_AGENT_MODEL;
24654
24831
  let thread = null;
@@ -24671,21 +24848,12 @@ function createCodexSession(opts) {
24671
24848
  async function ensureThread() {
24672
24849
  if (thread) return thread;
24673
24850
  const { Codex } = await loadCodex();
24674
- const config2 = {
24675
- // Tools reach codex as MCP servers; each server's name shows up on
24676
- // every tool event, so the runner can tell ours from codex's own.
24677
- ...opts.mcpServers && Object.keys(opts.mcpServers).length ? { mcp_servers: opts.mcpServers } : {},
24678
- // Per run, not ~/.codex/config.toml: a host without that line would run
24679
- // the agent with no instructions at all. AGENTS.md still wins if present.
24680
- ...opts.instructionsFile && opts.instructionsFile !== "AGENTS.md" ? { project_doc_fallback_filenames: [opts.instructionsFile] } : {},
24681
- ...opts.extraConfig ?? {}
24682
- };
24851
+ const config2 = codexRunConfig(opts);
24683
24852
  const codex = new Codex({
24684
24853
  ...opts.apiKey ? { apiKey: opts.apiKey } : {},
24685
24854
  ...opts.baseUrl ? { baseUrl: opts.baseUrl } : {},
24686
24855
  env: buildEnv(opts),
24687
- // Only when non-empty: an empty override is pointless CLI noise.
24688
- ...Object.keys(config2).length ? { config: config2 } : {}
24856
+ config: config2
24689
24857
  });
24690
24858
  thread = resumeId ? codex.resumeThread(resumeId, threadOptions()) : codex.startThread(threadOptions());
24691
24859
  return thread;
@@ -30181,6 +30349,7 @@ var SuperatomSDK = class {
30181
30349
  ANSWER_COMPONENT_NAMES,
30182
30350
  BM25L,
30183
30351
  CATEGORY_KEYS,
30352
+ CODEX_DOC_MAX_BYTES,
30184
30353
  CONTEXT_CONFIG,
30185
30354
  CleanupService,
30186
30355
  DEFAULT_AGENT_CONFIG,
@@ -30209,6 +30378,8 @@ var SuperatomSDK = class {
30209
30378
  bridgePreamble,
30210
30379
  captureContext,
30211
30380
  clearContextTokens,
30381
+ codexRunConfig,
30382
+ constraintPoliciesFromConfig,
30212
30383
  contextTokenCount,
30213
30384
  createCodexSession,
30214
30385
  createCodingAgentSession,
package/dist/index.mjs CHANGED
@@ -1840,7 +1840,17 @@ function runWithContext(ctx, fn) {
1840
1840
  return getStorage().run(ctx, fn);
1841
1841
  }
1842
1842
  function runAsUser(user, fn) {
1843
- const { userId, orgId, role, projectId, requestId, policies, allowedSources, graphVersion } = user;
1843
+ const {
1844
+ userId,
1845
+ orgId,
1846
+ role,
1847
+ projectId,
1848
+ requestId,
1849
+ policies,
1850
+ constraintPolicies,
1851
+ allowedSources,
1852
+ graphVersion
1853
+ } = user;
1844
1854
  return runWithContext(
1845
1855
  // `allowedSources` is spread in only when given, so an absent restriction
1846
1856
  // stays absent rather than becoming an explicit `undefined` that a later
@@ -1850,6 +1860,7 @@ function runAsUser(user, fn) {
1850
1860
  projectId,
1851
1861
  requestId,
1852
1862
  policies,
1863
+ ...constraintPolicies?.length ? { constraintPolicies } : {},
1853
1864
  ...allowedSources !== void 0 ? { allowedSources } : {},
1854
1865
  ...graphVersion !== void 0 ? { graphVersion } : {}
1855
1866
  },
@@ -2530,42 +2541,148 @@ function buildDirectToolCacheKey(toolId, parameters) {
2530
2541
  return `et-direct:${toolId}:${stableStringify(parameters || {})}`;
2531
2542
  }
2532
2543
 
2533
- // src/handlers/request-identity.ts
2534
- function graphVersionOf(v) {
2535
- if (v === "draft") return "draft";
2536
- return Number.isInteger(v) && v > 0 ? v : void 0;
2544
+ // src/handlers/data-access/v2/policies.ts
2545
+ var CONSTRAINT_OPS = [
2546
+ "in",
2547
+ "not_in",
2548
+ "eq",
2549
+ "ne",
2550
+ "gt",
2551
+ "gte",
2552
+ "lt",
2553
+ "lte",
2554
+ "like",
2555
+ "not_like",
2556
+ "is_null",
2557
+ "is_not_null"
2558
+ ];
2559
+ var NO_VALUE_OPS = /* @__PURE__ */ new Set(["is_null", "is_not_null"]);
2560
+ function constraintPoliciesFromConfig(raw) {
2561
+ const entries = Array.isArray(raw) ? raw : [raw];
2562
+ const out = [];
2563
+ for (const entry of entries) {
2564
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
2565
+ const e = entry;
2566
+ const sourceId = typeof e.sourceId === "string" && e.sourceId ? e.sourceId : null;
2567
+ const label = typeof e.label === "string" && e.label.trim() ? e.label.trim() : void 0;
2568
+ const bad = (why) => ({ sourceId, label, invalid: why });
2569
+ let schema2;
2570
+ if (e.schema !== void 0 && e.schema !== null) {
2571
+ if (typeof e.schema !== "string" || !e.schema.trim()) {
2572
+ out.push(bad("schema must be a schema name"));
2573
+ continue;
2574
+ }
2575
+ schema2 = e.schema.trim();
2576
+ }
2577
+ let readableTables;
2578
+ let tablesBad;
2579
+ if (e.readableTables !== void 0 && e.readableTables !== null) {
2580
+ if (typeof e.readableTables !== "object" || Array.isArray(e.readableTables)) {
2581
+ out.push(bad("readableTables must be an object of table to columns"));
2582
+ continue;
2583
+ }
2584
+ readableTables = {};
2585
+ for (const [table, cols] of Object.entries(e.readableTables)) {
2586
+ if (cols === null) {
2587
+ readableTables[table] = null;
2588
+ continue;
2589
+ }
2590
+ if (!Array.isArray(cols) || cols.length === 0) {
2591
+ tablesBad = `readableTables["${table}"] must be a non-empty list or null`;
2592
+ break;
2593
+ }
2594
+ const columns = cols.filter((c) => typeof c === "string" && !!c.trim()).map((c) => c.trim());
2595
+ if (columns.length !== cols.length) {
2596
+ tablesBad = `readableTables["${table}"] has an entry that is not a column name`;
2597
+ break;
2598
+ }
2599
+ readableTables[table] = columns;
2600
+ }
2601
+ if (!tablesBad && Object.keys(readableTables).length === 0) {
2602
+ tablesBad = "readableTables names no tables \u2014 omit it to allow every table";
2603
+ }
2604
+ if (tablesBad) {
2605
+ out.push(bad(tablesBad));
2606
+ continue;
2607
+ }
2608
+ }
2609
+ const rowFilters = {};
2610
+ let filtersBad;
2611
+ const rawFilters = e.rowFilters;
2612
+ if (rawFilters !== void 0 && rawFilters !== null) {
2613
+ if (typeof rawFilters !== "object" || Array.isArray(rawFilters)) {
2614
+ filtersBad = "rowFilters must be an object keyed by table";
2615
+ } else {
2616
+ for (const [table, items] of Object.entries(rawFilters)) {
2617
+ if (readableTables && !(table in readableTables)) {
2618
+ filtersBad = `rowFilters names "${table}", which readableTables does not allow`;
2619
+ break;
2620
+ }
2621
+ if (!Array.isArray(items) || items.length === 0) {
2622
+ filtersBad = `rowFilters["${table}"] must be a non-empty list`;
2623
+ break;
2624
+ }
2625
+ const parsed = [];
2626
+ for (const item of items) {
2627
+ if (!item || typeof item !== "object") {
2628
+ filtersBad = `rowFilters["${table}"] has an entry that is not an object`;
2629
+ break;
2630
+ }
2631
+ const f = item;
2632
+ if (typeof f.column !== "string" || !f.column.trim()) {
2633
+ filtersBad = `a filter on "${table}" has no column`;
2634
+ break;
2635
+ }
2636
+ const op = typeof f.op === "string" ? f.op.toLowerCase() : "in";
2637
+ if (!CONSTRAINT_OPS.includes(op)) {
2638
+ filtersBad = `unsupported operator "${f.op}" on "${table}.${f.column}"`;
2639
+ break;
2640
+ }
2641
+ const values = Array.isArray(f.values) ? f.values : [];
2642
+ if (!NO_VALUE_OPS.has(op) && values.length === 0) {
2643
+ filtersBad = `the filter on "${table}.${f.column}" has no values`;
2644
+ break;
2645
+ }
2646
+ parsed.push({
2647
+ column: f.column.trim(),
2648
+ op,
2649
+ ...NO_VALUE_OPS.has(op) ? {} : { values },
2650
+ label: typeof f.label === "string" && f.label.trim() ? f.label.trim() : void 0
2651
+ });
2652
+ }
2653
+ if (filtersBad) break;
2654
+ rowFilters[table] = parsed;
2655
+ }
2656
+ }
2657
+ }
2658
+ if (filtersBad) {
2659
+ out.push(bad(filtersBad));
2660
+ continue;
2661
+ }
2662
+ const rawLimits = e.limits;
2663
+ const num = (v) => typeof v === "number" && Number.isInteger(v) && v > 0 ? v : void 0;
2664
+ const limits = rawLimits ? { maxRows: num(rawLimits.maxRows), maxExecutionSeconds: num(rawLimits.maxExecutionSeconds) } : void 0;
2665
+ out.push({
2666
+ sourceId,
2667
+ label,
2668
+ ...schema2 ? { schema: schema2 } : {},
2669
+ ...readableTables ? { readableTables } : {},
2670
+ ...Object.keys(rowFilters).length ? { rowFilters } : {},
2671
+ ...limits ? { limits } : {}
2672
+ });
2673
+ }
2674
+ return out;
2537
2675
  }
2676
+
2677
+ // src/handlers/data-access/shape.ts
2538
2678
  function scopedForm(config2) {
2539
2679
  if (!config2 || typeof config2 !== "object" || Array.isArray(config2)) return void 0;
2540
2680
  const c = config2;
2541
2681
  return "allowedSources" in c || "policies" in c ? c : void 0;
2542
2682
  }
2543
- function allowedSourcesFrom(value) {
2544
- if (value === void 0 || value === null) return null;
2545
- if (!Array.isArray(value)) {
2546
- if (!warnedBadSources) {
2547
- warnedBadSources = true;
2548
- logger.warn(
2549
- `[RequestIdentity] "allowedSources" is ${typeof value}, not a list of source ids \u2014 treating it as NO sources rather than all of them. Fix the config: "allowedSources": ["mssql-1a2b"].`
2550
- );
2551
- }
2552
- return [];
2553
- }
2554
- const out = [];
2555
- for (const item of value) {
2556
- if (typeof item !== "string" || !item.trim()) continue;
2557
- const id = item.trim();
2558
- if (!out.includes(id)) out.push(id);
2559
- }
2560
- return out;
2561
- }
2562
- function accessFromConfig(config2) {
2563
- const scoped = scopedForm(config2);
2564
- return {
2565
- policies: policiesFromConfig(config2),
2566
- allowedSources: scoped ? allowedSourcesFrom(scoped.allowedSources) : null
2567
- };
2568
- }
2683
+
2684
+ // src/handlers/data-access/v1/policies.ts
2685
+ var warnedUnlabelled = false;
2569
2686
  function exceptionsFromConfig(raw) {
2570
2687
  if (!Array.isArray(raw)) return [];
2571
2688
  const str = (v) => typeof v === "string" && v.trim() ? v.trim() : void 0;
@@ -2644,16 +2761,55 @@ function policiesFromConfig(config2) {
2644
2761
  }
2645
2762
  return out;
2646
2763
  }
2764
+
2765
+ // src/handlers/request-identity.ts
2766
+ function graphVersionOf(v) {
2767
+ if (v === "draft") return "draft";
2768
+ return Number.isInteger(v) && v > 0 ? v : void 0;
2769
+ }
2770
+ function allowedSourcesFrom(value) {
2771
+ if (value === void 0 || value === null) return null;
2772
+ if (!Array.isArray(value)) {
2773
+ if (!warnedBadSources) {
2774
+ warnedBadSources = true;
2775
+ logger.warn(
2776
+ `[RequestIdentity] "allowedSources" is ${typeof value}, not a list of source ids \u2014 treating it as NO sources rather than all of them. Fix the config: "allowedSources": ["mssql-1a2b"].`
2777
+ );
2778
+ }
2779
+ return [];
2780
+ }
2781
+ const out = [];
2782
+ for (const item of value) {
2783
+ if (typeof item !== "string" || !item.trim()) continue;
2784
+ const id = item.trim();
2785
+ if (!out.includes(id)) out.push(id);
2786
+ }
2787
+ return out;
2788
+ }
2789
+ function accessFromConfig(config2) {
2790
+ const scoped = scopedForm(config2);
2791
+ const allowedSources = scoped ? allowedSourcesFrom(scoped.allowedSources) : null;
2792
+ if (scoped?.version === 2) {
2793
+ return {
2794
+ policies: [],
2795
+ constraintPolicies: constraintPoliciesFromConfig(scoped.policies),
2796
+ allowedSources
2797
+ };
2798
+ }
2799
+ return { policies: policiesFromConfig(config2), constraintPolicies: [], allowedSources };
2800
+ }
2647
2801
  var warnedUntrusted = false;
2648
2802
  var warnedAnonymous = false;
2649
- var warnedUnlabelled = false;
2650
2803
  var warnedBadSources = false;
2651
2804
  var announcedVerified = false;
2652
2805
  var reportedIdMismatches = /* @__PURE__ */ new Set();
2653
2806
  function runWithMessageIdentity(message, fn) {
2654
2807
  const verified = message?.authContext;
2655
2808
  const requestId = message?.id;
2656
- const { policies, allowedSources } = verified ? accessFromConfig(verified.config) : accessFromConfig(message?.payload?.config);
2809
+ const { policies, constraintPolicies, allowedSources } = verified ? accessFromConfig(verified.config) : accessFromConfig(message?.payload?.config);
2810
+ logger.info(
2811
+ `[RequestIdentity] ${message?.type ?? "?"}: access from ${verified ? "authContext" : "payload"}${verified && verified.config == null ? " (none on it)" : ""}, allowedSources=${allowedSources === null ? "every source" : `[${allowedSources.join(", ") || "NONE"}]`}, ${constraintPolicies.length} constraint policy(ies), ${policies.length} row policy(ies)`
2812
+ );
2657
2813
  if (verified?.userId) {
2658
2814
  const claimedId = message?.payload?.userId;
2659
2815
  if (!announcedVerified) {
@@ -2678,6 +2834,7 @@ function runWithMessageIdentity(message, fn) {
2678
2834
  role: verified.role,
2679
2835
  requestId,
2680
2836
  policies,
2837
+ constraintPolicies,
2681
2838
  // `?? undefined` so "no restriction" leaves the key off the context
2682
2839
  // entirely; `[]` is passed through as the deny-everything it means.
2683
2840
  allowedSources: allowedSources ?? void 0,
@@ -2695,7 +2852,10 @@ function runWithMessageIdentity(message, fn) {
2695
2852
  "[RequestIdentity] Using the client-supplied payload.userId as the principal \u2014 the relay is not stamping a verified authContext yet, so this identity is NOT trustworthy. Fine for plumbing; do not enable policy enforcement until the relay change lands."
2696
2853
  );
2697
2854
  }
2698
- return runAsUser({ userId: claimed, requestId, policies, allowedSources: allowedSources ?? void 0 }, fn);
2855
+ return runAsUser(
2856
+ { userId: claimed, requestId, policies, constraintPolicies, allowedSources: allowedSources ?? void 0 },
2857
+ fn
2858
+ );
2699
2859
  }
2700
2860
  if (!warnedAnonymous) {
2701
2861
  warnedAnonymous = true;
@@ -24537,6 +24697,20 @@ function buildEnv(opts) {
24537
24697
  }
24538
24698
  return { ...env, ...opts.env ?? {} };
24539
24699
  }
24700
+ var CODEX_DOC_MAX_BYTES = 256 * 1024;
24701
+ function codexRunConfig(opts) {
24702
+ return {
24703
+ // Tools reach codex as MCP servers; each server's name shows up on
24704
+ // every tool event, so the runner can tell ours from codex's own.
24705
+ ...opts.mcpServers && Object.keys(opts.mcpServers).length ? { mcp_servers: opts.mcpServers } : {},
24706
+ // Per run, not ~/.codex/config.toml: a host without that line would run
24707
+ // the agent with no instructions at all. AGENTS.md still wins if present.
24708
+ ...opts.instructionsFile && opts.instructionsFile !== "AGENTS.md" ? { project_doc_fallback_filenames: [opts.instructionsFile] } : {},
24709
+ project_doc_max_bytes: CODEX_DOC_MAX_BYTES,
24710
+ // Last: a deployment's own value wins.
24711
+ ...opts.extraConfig ?? {}
24712
+ };
24713
+ }
24540
24714
  function createCodexSession(opts) {
24541
24715
  const model = opts.model ?? process.env.CODEX_AGENT_MODEL;
24542
24716
  let thread = null;
@@ -24559,21 +24733,12 @@ function createCodexSession(opts) {
24559
24733
  async function ensureThread() {
24560
24734
  if (thread) return thread;
24561
24735
  const { Codex } = await loadCodex();
24562
- const config2 = {
24563
- // Tools reach codex as MCP servers; each server's name shows up on
24564
- // every tool event, so the runner can tell ours from codex's own.
24565
- ...opts.mcpServers && Object.keys(opts.mcpServers).length ? { mcp_servers: opts.mcpServers } : {},
24566
- // Per run, not ~/.codex/config.toml: a host without that line would run
24567
- // the agent with no instructions at all. AGENTS.md still wins if present.
24568
- ...opts.instructionsFile && opts.instructionsFile !== "AGENTS.md" ? { project_doc_fallback_filenames: [opts.instructionsFile] } : {},
24569
- ...opts.extraConfig ?? {}
24570
- };
24736
+ const config2 = codexRunConfig(opts);
24571
24737
  const codex = new Codex({
24572
24738
  ...opts.apiKey ? { apiKey: opts.apiKey } : {},
24573
24739
  ...opts.baseUrl ? { baseUrl: opts.baseUrl } : {},
24574
24740
  env: buildEnv(opts),
24575
- // Only when non-empty: an empty override is pointless CLI noise.
24576
- ...Object.keys(config2).length ? { config: config2 } : {}
24741
+ config: config2
24577
24742
  });
24578
24743
  thread = resumeId ? codex.resumeThread(resumeId, threadOptions()) : codex.startThread(threadOptions());
24579
24744
  return thread;
@@ -30068,6 +30233,7 @@ export {
30068
30233
  ANSWER_COMPONENT_NAMES,
30069
30234
  BM25L,
30070
30235
  CATEGORY_KEYS,
30236
+ CODEX_DOC_MAX_BYTES,
30071
30237
  CONTEXT_CONFIG,
30072
30238
  CleanupService,
30073
30239
  DEFAULT_AGENT_CONFIG,
@@ -30096,6 +30262,8 @@ export {
30096
30262
  bridgePreamble,
30097
30263
  captureContext,
30098
30264
  clearContextTokens,
30265
+ codexRunConfig,
30266
+ constraintPoliciesFromConfig,
30099
30267
  contextTokenCount,
30100
30268
  createCodexSession,
30101
30269
  createCodingAgentSession,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superatomai/sdk-node",
3
- "version": "0.0.88-dsp",
3
+ "version": "0.0.90-dsp",
4
4
  "description": "Node.js TypeScript SDK for Superatom",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",