@axiom-lattice/pg-stores 5.0.0 → 5.0.2

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,5 +1,5 @@
1
1
 
2
- > @axiom-lattice/pg-stores@5.0.0 build /home/runner/work/agentic/agentic/packages/pg-stores
2
+ > @axiom-lattice/pg-stores@5.0.2 build /home/runner/work/agentic/agentic/packages/pg-stores
3
3
  > tsup src/index.ts --format cjs,esm --dts --sourcemap
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -8,13 +8,13 @@
8
8
  CLI Target: es2020
9
9
  CJS Build start
10
10
  ESM Build start
11
- ESM dist/index.mjs 524.15 KB
12
- ESM dist/index.mjs.map 970.33 KB
13
- ESM ⚡️ Build success in 1448ms
14
- CJS dist/index.js 533.89 KB
15
- CJS dist/index.js.map 970.64 KB
16
- CJS ⚡️ Build success in 1451ms
11
+ CJS dist/index.js 533.98 KB
12
+ CJS dist/index.js.map 970.75 KB
13
+ CJS ⚡️ Build success in 1274ms
14
+ ESM dist/index.mjs 524.22 KB
15
+ ESM dist/index.mjs.map 970.44 KB
16
+ ESM ⚡️ Build success in 1353ms
17
17
  DTS Build start
18
- DTS ⚡️ Build success in 15489ms
18
+ DTS ⚡️ Build success in 15828ms
19
19
  DTS dist/index.d.ts 112.00 KB
20
20
  DTS dist/index.d.mts 112.00 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,207 @@
1
1
  # @axiom-lattice/pg-stores
2
2
 
3
+ ## 5.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - a756acb: feat(model-providers): a tenant's own providers become its entire model supply
8
+
9
+ - A tenant that has at least one provider row no longer falls back to the
10
+ deployment (`default`) namespace. `resolveModelLatticeForTenant`,
11
+ `hasModelLatticeForTenant` (+ sync variant), `listModelLatticesForTenant`,
12
+ the embeddings client and both STT clients return a miss instead, and
13
+ `list_models` reports only the tenant's own models.
14
+ - `tenantHasOwnModelSupply` / `tenantHasOwnModelSupplySync` (new in core) read
15
+ the provider store; the sync variant uses a 30 s observation cache, and a
16
+ store failure fails closed (treats the tenant as owning its supply).
17
+ - `ModelProviderService.catalog` lists deployment models only while the tenant
18
+ has no provider, so a provider with no synced models shows an empty catalog
19
+ rather than rows that cannot run.
20
+ - The last remaining provider cannot be deleted: the service returns
21
+ `LAST_PROVIDER_NOT_DELETABLE` (409), and the panel disables the action.
22
+ Removing a provider now requires a second one to exist first.
23
+ - eval runs no longer take the first listed model as a judge fallback when the
24
+ tenant owns its supply; they fail with a message pointing at Model Providers.
25
+ - The panel derives the platform/own switch from `providers.length > 0`, shows
26
+ a read-only deployment description when nothing is configured, and keeps a
27
+ `X/3` default-model summary with per-kind status once providers exist.
28
+
29
+ - Updated dependencies [a756acb]
30
+ - @axiom-lattice/core@12.1.0
31
+ - @axiom-lattice/protocols@7.1.0
32
+
33
+ ## 5.0.1
34
+
35
+ ### Patch Changes
36
+
37
+ - 3c95be1: This changeset consolidates all pending release notes into a single release entry. All packages are released as patch versions for this consolidated release.
38
+
39
+ ## Pending changes
40
+
41
+ ### chat-cursor-expired-auto-recovery
42
+
43
+ Console chat now silently recovers from chunk-stream `CURSOR_EXPIRED`: it reloads durable messages, reconnects without the expired cursor, and only shows a localized retry prompt when recovery fails or exceeds the bounded recovery budget.
44
+
45
+ ### chat-quick-prompts-generic
46
+
47
+ Make `Chating` empty-state content generic by default: the question is now "How can I help you today?", the built-in data-analysis dataset is opt-in via `showQuickAnalysis`, and all quick prompts use one `QuickPromptCategory[]` shape rendered below the composer in both empty and non-empty states. Adds `quickPromptsData` / `quickPromptsTitle` props, keeps the shell `quickPromptsData` as a fallback, and exports `BusinessAnalysisPrompts`, `QuickPrompts`, `buildDataAnalysisPrompts`, and the `BusinessAnalysisPromptsProps` type. Also removes the empty→active send transition animation.
48
+
49
+ ### chat-quick-prompts-hardening
50
+
51
+ Fix chat quick prompts:
52
+
53
+ - Sender labels and descriptions are no longer duplicated, including description-only prompts and whitespace-only labels.
54
+ - Effective sender prompt text is trimmed; fully blank or whitespace-only prompts are dropped and whitespace-only descriptions are suppressed.
55
+ - The renderer honors `disabled` for generated items and guards the click and More handlers.
56
+ - Simple-mode item keys are collision-safe across categories.
57
+ - An explicit `title` takes precedence over the category title.
58
+ - Single-category items inherit the category icon when they have none.
59
+
60
+ ### fix-abort-notice-task-detail-overflow
61
+
62
+ Preserve the neutral "Response stopped." notice after a user aborts a run: terminal stream events from that same run no longer clear it immediately, while a new run's output still clears it.
63
+
64
+ Also fix task-detail horizontal overflow on narrow layouts by wrapping activity metadata and removing the mobile subtask row negative margin.
65
+
66
+ ### fix-client-sdk-delete-content-type
67
+
68
+ Fix bodyless `DELETE` requests sending `Content-Type: application/json`. `makeRequest` strips the header for bodyless deletes, but `fetchWithTimeout` merged `this.headers` back in and silently restored it, so delete requests could be rejected by servers that treat a declared JSON content type as requiring a body. `fetchWithTimeout` now trusts the already-merged request headers from `makeRequest`.
69
+
70
+ `WorkspaceClient.request` had the same problem: it always merged `this.headers` (including `Content-Type: application/json`) into every request. Bodyless `deleteWorkspace` / `deleteProject` calls now strip the `content-type` header case-insensitively from the merged map, including a lowercase `content-type` supplied through `ClientConfig.headers`.
71
+
72
+ ### fix-filesystem-write-edit-symlink-parent
73
+
74
+ Fix `FilesystemBackend` virtual-mode confinement for writes and edits: both operations now validate the resolved parent directory against the virtual root (mirroring reads and deletes), so a symlinked parent that points outside the root can no longer be used to create or modify files outside the sandbox.
75
+
76
+ Writes additionally validate the nearest existing ancestor before recursive directory creation. A nested path such as `/outside-link/created-dir/escaped.txt` is rejected before `fs.mkdir(..., { recursive: true })` runs, so no directories are created outside the virtual root either.
77
+
78
+ Directory listing and search are hardened too: in virtual mode the requested `lsInfo` directory, `globInfo` search base, and `grepRaw` base must resolve inside the root; symlink entries are hidden from scans; `globInfo`/grep fallback stop following symlinks; and ripgrep runs with `--no-follow`.
79
+
80
+ Symlink behavior is intentionally split between root scans and direct access. A symlink whose target stays inside the root is hidden from directory listings and recursive scans, but a direct `lsInfo`, `globInfo`, or `grepRaw` call whose resolved base stays inside the root is allowed, and direct file reads through an inside-root symlink remain allowed. A symlink whose target leaves the root is rejected for direct listing/search/read and is neither listed nor searched.
81
+
82
+ Residual limitations:
83
+
84
+ - Plain Node file APIs cannot make "validate ancestor, then create directory/file" atomic. The checks close the symlinked-parent escape and nested-directory side effect, but a concurrent attacker who can swap path components between the ancestor check and the create/open calls could still win a TOCTOU race. Directory-level isolation (or an OS primitive with `openat`/`O_NOFOLLOW`-style semantics for every component) would be required to eliminate that race completely.
85
+ - Hard-link escapes remain possible: hard links share inode data and cannot be distinguished from ordinary files by path checks, so a hard link inside the root can still expose content outside it.
86
+
87
+ ### fix-inmemory-workflow-run-id-collision
88
+
89
+ Fix `InMemoryWorkflowTrackingStore.createWorkflowRun` ID collisions: the generated ID is now `${threadId}_${Date.now()}_${randomUUID()}` (matching the PostgreSQL and Local stores) instead of `${threadId}_${Date.now()}`, so two runs started on the same thread within the same millisecond no longer overwrite each other in the backing `Map` (which also silently reset the earlier run's steps). Added a unit test that pins `Date.now()` and asserts both runs exist with distinct IDs and isolated steps.
90
+
91
+ ### fix-local-store-workflow-and-schedule
92
+
93
+ Fix four local-store defects found while adding coverage:
94
+
95
+ - `LocalWorkflowTrackingStore` could not be constructed: its DDL used `ALTER TABLE ... ADD COLUMN IF NOT EXISTS`, which SQLite does not support, so every constructor call threw. The `thread_id` backfill now uses the same `PRAGMA table_info` guard as the other local stores.
96
+ - `LocalWorkflowTrackingStore.createWorkflowRun` generated `${threadId}_${Date.now()}`, so two runs on the same thread within the same millisecond collided on the primary key. IDs are now `${threadId}_${Date.now()}_${randomUUID()}`, matching the PostgreSQL store.
97
+ - `LocalScheduleStorage.getAllTasks` emitted `OFFSET` without `LIMIT` when only an offset was supplied, which SQLite rejects. It now emits `LIMIT -1` first, matching `LocalWorkflowTrackingStore.queryWorkflowRuns`.
98
+ - **Security parity:** `LocalMetricsServerConfigStore` stored `apiKey`/`password` in plaintext while the PostgreSQL store encrypted them. Both fields are now encrypted on create/update (partial updates still preserve the stored ciphertext) and decrypted on read. Legacy plaintext rows are preserved unchanged on read and encrypted on the next config write; a value that looks encrypted but cannot be decrypted with the current key degrades to `""` via `safeDecrypt`, matching PostgreSQL.
99
+
100
+ **Upgrade note:** the legacy-row heuristic is shape-based. A plaintext secret that itself happens to look like canonical ciphertext (valid base64 of at least the salt+IV+tag length) cannot be distinguished from encrypted data, so it is treated as ciphertext and may read back as an empty string. There is no safe way to tell the two apart after the fact; re-enter any such metric-server secret once after upgrading. Other plaintext secrets are read unchanged and encrypted on the next write.
101
+
102
+ ### fix-opensandbox-concurrent-ensure-dedup
103
+
104
+ Fix `ensureSandbox` concurrency and `listSandboxes` status filtering.
105
+
106
+ `ensureSandbox` now keeps the early in-flight fast path, then re-checks both the cache and the in-flight create map after the asynchronous metadata lookup. A caller that was suspended during metadata recovery can no longer create a duplicate sandbox when another caller finishes first, and waiters on a failed create reject and leave `pendingCreates` cleared so a later call retries instead of hanging.
107
+
108
+ `listSandboxes` now translates the lowercase API status filter to the SDK's capitalized lifecycle states: `running` → `Running`, `stopped` → `Paused`, `crashed` → `Failed`, and `unknown` omits the states filter instead of sending an invalid state. Returned items are mapped back to the same API vocabulary instead of leaking raw SDK states: `Running` → `running`, `Paused`/`Stopping`/`Stopped`/`Terminated` → `stopped`, `Failed`/`Error` → `crashed`, and everything else → `unknown` (previously `Paused` and `Failed` came back as `paused`/`failed`, outside the response schema's allowed values).
109
+
110
+ `mapVolumes` now validates named volume definitions with the same conservative name validator used by the volume-fs routes, so a traversal name such as `../../escape` is rejected with `HttpError(400, INVALID_VOLUME_NAME)` before it can resolve outside `VOLUME_BASE_PATH` or become a PVC `subPath`. Bind volumes are unchanged and still accept arbitrary host source paths.
111
+
112
+ ### fix-pg-eval-result-and-project-defaults
113
+
114
+ Fix two `PostgreSQLEvalStore` contract gaps. `updateRunResult` now includes `interrupted` in its `RETURNING` list, so updating that field returns the new value instead of a stale `false` (follow-up reads already agreed with the database). `createProject` now defaults an omitted `judgeModelConfig` (and defensively an undefined `targetServerConfig`) to `{}` instead of writing SQL `NULL` into a `NOT NULL` JSONB column, matching the protocol's optional `judgeModelConfig`. Added DB-backed integration tests for both cases.
115
+
116
+ ### fix-pg-skill-get-sub-skills
117
+
118
+ Fix `PostgreSQLSkillStore.getSubSkills` so it returns the skills whose `subSkills` list contains the requested parent. The query bound `JSON.stringify([parentName])`, which made the JSONB containment compare against the JSON string `"[\"parent\"]"` instead of the array element `"parent"`, so it never matched. It now binds the bare parent name while keeping the lookup tenant-scoped. Added DB-backed integration coverage for the skill store, including cross-tenant isolation.
119
+
120
+ ### fix-pg-workflow-run-id-collision
121
+
122
+ Fix `PostgreSQLWorkflowTrackingStore.createWorkflowRun` ID collisions: the generated ID is now `${threadId}_${Date.now()}_${randomUUID()}` instead of `${threadId}_${Date.now()}`, so two runs started on the same thread within the same millisecond no longer collide on the primary key. The thread prefix is kept for readability. Added a DB-backed integration test that pins `Date.now()` to a fixed value and asserts both runs exist with distinct IDs.
123
+
124
+ ### fix-publish-target-json-schema
125
+
126
+ Fix `publish_target` for OpenAI-compatible function calling. The Zod schema now has an object root (instead of a root `oneOf` from `discriminatedUnion`), so providers no longer reject it with `schema must be a JSON Schema of 'type: "object"', got 'type: null'`.
127
+
128
+ ### fix-review-regressions
129
+
130
+ Fix review regressions across skills, SQL and filesystem backends:
131
+
132
+ - `FileSystemSkillStore.listSkillResources` falls back to the dirent `path` when `parentPath` is unavailable on older Node versions.
133
+ - `list_tables_sql` quotes mixed-case / non-simple identifiers only on PostgreSQL so its output round-trips through `info_sql`/`getTableInfo`; MySQL keeps raw names because its lookup is exact (unquoted input is still lowercased).
134
+ - `FilesystemBackend.write` creates a missing virtual root before validating ancestors.
135
+ - `query_checker_sql` flags data-modifying CTE `UPDATE`/`DELETE` without a `WHERE`, without misreading `FOR NO KEY UPDATE`.
136
+
137
+ Note: a cancelled workflow thread remains terminal by design — every later input on that thread (including a would-be new turn) is intentionally blocked; this wave does not change workflow abort semantics.
138
+
139
+ ### fix-sql-query-checker-schema-qualified
140
+
141
+ Harden `query_checker_sql` and fix schema-qualified PostgreSQL table lookups.
142
+
143
+ - `ISqlDatabase` gains an optional `explainQuery(query)` method. `PostgresDatabase` implements it with both guards required for safe validation: parenthesized options (`{ text: "EXPLAIN (FORMAT JSON) " + query, queryMode: "extended" }`). The parenthesized option list prevents a user query from starting with `ANALYZE` (or another EXPLAIN option) and turning validation into execution; extended query mode rejects multi-statement input server-side before any tail statement runs. Either guard alone is insufficient. `query_checker_sql` calls `explainQuery` for Postgres validation and never calls `executeQuery` for EXPLAIN; when `explainQuery` is unavailable it skips database validation instead of falling back to simple-mode execution. A server-side validation rejection now makes the overall verdict unsafe.
144
+ - `query_checker_sql` uses a SQL lexer that blanks single-quoted strings (including doubled quotes and E-string backslash escapes), double-quoted identifiers, dollar-quoted strings (`$$...$$`, `$tag$...$tag$`, only at token boundaries), line comments, and nested block comments. The normalized text drives both multi-statement detection and the unqualified-DML check. DML detection looks only at the statement's top-level `UPDATE`/`DELETE` and requires a depth-zero `WHERE` after it, so subquery/CTE `WHERE` clauses, `SELECT ... FOR UPDATE`, `INSERT ... ON CONFLICT DO UPDATE`, and `CREATE TABLE ... ON DELETE/ON UPDATE` do not mask or create a full-table-DML finding.
145
+ - The lexer is advisory/diagnostic rather than a full SQL parser: it does not implement every PostgreSQL literal/identifier form and can misclassify unusual or malformed input. The execution-safety boundary is the server-side parenthesized-options EXPLAIN in extended mode whenever Postgres validation runs; if the adapter lacks `explainQuery`, no server-side validation is performed.
146
+ - `PostgresDatabase.getTableInfo` now lowercases unquoted schema/table parts, preserves quoted identifier case, safely quotes schema-qualified names such as `sales.orders`, filters column and PK/FK metadata by schema (including constraint joins), and reads sample rows from the qualified table.
147
+
148
+ ### fix-wechat-client-request-contract
149
+
150
+ Fix `WeChatClient` request and stream handling:
151
+
152
+ - `makeRequest` dropped per-request headers. It built the merged header map (Content-Type, Authorization, config headers, caller headers, tenant) but passed only the workspace headers to `wechatRequest`, so headers supplied through `request()` / `chat.abort()` (including `x-axiom-affinity`) never reached `wx.request`. It now forwards the fully merged header map with precedence defaults < config < workspace < per-request, so workspace context overrides config headers.
153
+ - `resumeStream` omitted the required `assistant_id` body field, so the gateway rejected resumes with 400. It now includes `assistant_id`, matching the main `Client.resumeStream`.
154
+ - `resumeStream` and `streamRun` omitted workspace/project context. Both now merge `getWorkspaceHeaders()` into their request headers and send `Accept: text/event-stream`.
155
+ - `resumeStream` ignored `ResumeStreamOptions.lastEventId`. A trimmed, non-empty value is now sent as `Last-Event-ID`, matching `Client.resumeStream`.
156
+ - Streaming chunks are now decoded with a per-request `TextDecoder` (`{ stream: true }`) and a pending-line buffer, so JSON frames and multibyte UTF-8 characters split across chunks are no longer dropped or corrupted. Both `data: {...}` and `data:{...}` frames are accepted. On completion the pending final line is flushed, so a last `data:` line without a trailing newline is emitted.
157
+ - `resumeStream` and `streamRun` now inspect the stream response status: 401 surfaces `AuthenticationError` and other non-2xx statuses surface `ApiError` via `onError`, and chunks/completion are suppressed. The error body is parsed from objects, JSON strings, or plain text (`error` / `message`), falling back to `HTTP error! Status: <code>`. A transport `fail` is terminal, so the subsequent `complete` no longer calls `onComplete` or fetches agent state.
158
+ - Aborting through the returned stop function no longer surfaces the WeChat `fail` callback as `onError`, matching the web `Client`; aborts also suppress completion and agent-state fetching. A late completion reported through `success` after abort/terminal is ignored as well.
159
+ - `wechatRequest` now uses the same error-body extractor for 401 and other non-2xx responses, so gateway envelopes like `{ success: false, error: "..." }` surface their `error` (not only `message`).
160
+ - Bodyless `DELETE` requests no longer send `Content-Type: application/json`, matching the web `Client`.
161
+ - Missing `wx` / `wx.request` now raises a descriptive error instead of a raw `TypeError`.
162
+
163
+ ### fix-workspace-client-errors
164
+
165
+ Fix two `WorkspaceClient` error-handling gaps:
166
+
167
+ - `request()` now reads the gateway wire contract's `error` field (`{ success: false, error: "..." }`) before falling back to `message` and the HTTP status, matching `uploadFile`, `downloadFolder`, and `Client`. Previously only `message` was read, so gateway errors surfaced as `HTTP error! Status: 404`.
168
+ - `createWorkspace`, `getWorkspace`, `updateWorkspace`, `createProject`, `getProject`, and `updateProject` now throw a clear `Error` when a successful envelope omits `data`, instead of returning `undefined` through a non-null assertion. `readFile` and `browseFilesystem` get the same treatment (`Failed to read file` / `Failed to browse filesystem`). List methods keep their empty-array fallback.
169
+
170
+ ### harden-menu-item-update-patch
171
+
172
+ Security hardening for menu item updates: PUT `/api/menu-items/:id` now strips server-owned `id` and `tenantId` fields from the patch before calling the registry, so a caller cannot move an item to another tenant or rewrite its id. Normal clients that send a full persisted item back are unaffected; only the mutable fields are applied.
173
+
174
+ ### harden-microsandbox-volume-fs-confinement
175
+
176
+ Harden volume filesystem route confinement. Volume names are now validated against a conservative pattern before host path resolution, guest paths reject lexical traversal, backslashes and NUL bytes, reads/downloads/listings verify the real path stays inside the volume root, and writes/uploads/mkdir verify the nearest existing ancestor before recursive directory creation so symlinked parents cannot create or modify files outside the volume. Uploads also reject malformed base64 instead of silently decoding it.
177
+ This is a deterministic symlink/path hardening, not an atomic guarantee: a concurrent writer with volume access can still race validation and I/O (TOCTOU), and hard links to outside inodes are not detectable by path checks. Guest paths containing any `..` segment (even `a/../b`) are now rejected, and uploads accept only standard base64 (no base64url/whitespace-wrapped input).
178
+
179
+ ### harden-opensandbox-volume-fs-confinement
180
+
181
+ Harden volume filesystem route confinement. Volume names are now validated against a conservative pattern before host path resolution, guest paths reject lexical traversal and backslashes, reads/downloads/listings verify the real path stays inside the volume root, and writes/uploads verify the nearest existing ancestor before recursive directory creation so symlinked parents cannot create or modify files outside the volume. Uploads also reject malformed base64 instead of silently decoding it.
182
+ This is a deterministic symlink/path hardening, not an atomic guarantee: a concurrent writer with volume access can still race validation and I/O (TOCTOU), and hard links to outside inodes are not detectable by path checks. Guest paths containing any `..` segment (even `a/../b`) are now rejected, and uploads accept only standard base64 (no base64url/whitespace-wrapped input).
183
+
184
+ ### remove-processing-agents
185
+
186
+ Remove the deprecated PROCESSING agent type and topology middleware. WORKFLOW agents are the only orchestration type.
187
+
188
+ - Removed `AgentType.PROCESSING`, `ProcessingAgentConfig`, `isProcessingAgentConfig`, the PROCESSING builder/agent, and the disabled `create_processing_agent` / `update_processing_agent` tools.
189
+ - Removed `topologyMiddleware`, the topology middleware editor/default config, the Topology Automation view, and related i18n.
190
+ - Removed `/api/workflows/definitions` and `/api/assistants/:assistantId/workflows/definitions`; workflow run/inbox tracking remains.
191
+ - `CreateWorkflowModal` now creates WORKFLOW agents only.
192
+
193
+ ### tenant-plugin-schema-root
194
+
195
+ Reject tenant sandbox plugin tools whose JSON Schema root is not `type: "object"`. OpenAI-compatible function calling requires an object root; allowing `string`/`array` roots produced runtime `type: null` failures.
196
+
197
+ ### workflow-skill-store-fixes
198
+
199
+ Fix workflow abort detection and filesystem skill resource listing. The input node now lets the "workflow was cancelled before restart" error escape instead of swallowing it in the tracking-store catch, and `FileSystemSkillStore.listSkillResources` reads Node's recursive `Dirent.parentPath` instead of the removed `.path` property. Added workflow, skill-manager, and skill-store lifecycle coverage.
200
+
201
+ - Updated dependencies [3c95be1]
202
+ - @axiom-lattice/core@12.0.1
203
+ - @axiom-lattice/protocols@7.0.1
204
+
3
205
  ## 5.0.0
4
206
 
5
207
  ### Major Changes
package/dist/index.js CHANGED
@@ -3638,6 +3638,7 @@ var PostgreSQLUserTenantLinkStore = class {
3638
3638
  };
3639
3639
 
3640
3640
  // src/stores/PostgreSQLWorkflowTrackingStore.ts
3641
+ var import_node_crypto = require("crypto");
3641
3642
  var import_pg11 = require("pg");
3642
3643
 
3643
3644
  // src/migrations/workflow_tracking_migrations.ts
@@ -3798,7 +3799,7 @@ var PostgreSQLWorkflowTrackingStore = class {
3798
3799
  async createWorkflowRun(request) {
3799
3800
  await this.ensureInitialized();
3800
3801
  const now = /* @__PURE__ */ new Date();
3801
- const id = `${request.threadId}_${Date.now()}`;
3802
+ const id = `${request.threadId}_${Date.now()}_${(0, import_node_crypto.randomUUID)()}`;
3802
3803
  await this.pool.query(
3803
3804
  `INSERT INTO lattice_workflow_runs (id, tenant_id, assistant_id, thread_id, status, topology_edges, total_edges, completed_edges, metadata, started_at, created_at, updated_at)
3804
3805
  VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`,
@@ -4684,8 +4685,8 @@ var PostgreSQLEvalStore = class {
4684
4685
  data.name,
4685
4686
  data.description || null,
4686
4687
  data.version || null,
4687
- JSON.stringify(data.judgeModelConfig),
4688
- JSON.stringify(data.targetServerConfig),
4688
+ JSON.stringify(data.judgeModelConfig ?? {}),
4689
+ JSON.stringify(data.targetServerConfig ?? {}),
4689
4690
  data.concurrency ?? 3,
4690
4691
  data.reportConfig === void 0 ? null : JSON.stringify(data.reportConfig)
4691
4692
  ]
@@ -5188,7 +5189,7 @@ var PostgreSQLEvalStore = class {
5188
5189
  AND run_id IN (SELECT id FROM lattice_eval_runs WHERE tenant_id = $${i + 1})
5189
5190
  RETURNING id, run_id, suite_name, case_id,
5190
5191
  pass, score, summary, dimension_results,
5191
- duration_ms, messages, logs, error, created_at`,
5192
+ duration_ms, messages, logs, error, interrupted, created_at`,
5192
5193
  vals
5193
5194
  );
5194
5195
  return rows.length ? this.mapRowToRunResult(rows[0]) : null;
@@ -9863,7 +9864,7 @@ var PGVectorStoreProvider = class {
9863
9864
  );
9864
9865
  if (!embeddings) {
9865
9866
  throw new Error(
9866
- `No embedding model "${embeddingKey}" registered for tenant "${tenantId}", and no tenant or deployment default. Configure one in the model service panel.`
9867
+ `No embedding model "${embeddingKey}" registered for tenant "${tenantId}", and no default model available. Configure one in the model service panel.`
9867
9868
  );
9868
9869
  }
9869
9870
  return import_pgvector.PGVectorStore.initialize(embeddings, {
@@ -11947,7 +11948,7 @@ var PostgreSQLProjectRoomReadStateStore = class {
11947
11948
  };
11948
11949
 
11949
11950
  // src/stores/PostgreSQLUserPushSubscriptionStore.ts
11950
- var import_node_crypto = require("crypto");
11951
+ var import_node_crypto2 = require("crypto");
11951
11952
  var columns4 = "id, tenant_id, user_id, endpoint, p256dh, auth, user_agent, created_at";
11952
11953
  function mapRow7(row) {
11953
11954
  if (typeof row.id !== "string" || typeof row.tenant_id !== "string" || typeof row.user_id !== "string" || typeof row.endpoint !== "string" || typeof row.p256dh !== "string" || typeof row.auth !== "string" || !(row.created_at instanceof Date) || Number.isNaN(row.created_at.getTime())) {
@@ -11984,7 +11985,7 @@ var PostgreSQLUserPushSubscriptionStore = class {
11984
11985
  ON CONFLICT (tenant_id, user_id, endpoint) DO UPDATE
11985
11986
  SET p256dh = EXCLUDED.p256dh, auth = EXCLUDED.auth, user_agent = EXCLUDED.user_agent
11986
11987
  RETURNING ${columns4}`,
11987
- [(0, import_node_crypto.randomUUID)(), input.tenantId, input.userId, input.endpoint, input.keys.p256dh, input.keys.auth, input.userAgent ?? null]
11988
+ [(0, import_node_crypto2.randomUUID)(), input.tenantId, input.userId, input.endpoint, input.keys.p256dh, input.keys.auth, input.userAgent ?? null]
11988
11989
  );
11989
11990
  return mapRow7(result.rows[0]);
11990
11991
  }
@@ -15203,7 +15204,7 @@ var PostgreSQLSkillStore = class {
15203
15204
  WHERE tenant_id = $1 AND sub_skills @> to_jsonb($2::text)
15204
15205
  ORDER BY created_at DESC
15205
15206
  `,
15206
- [tenantId, JSON.stringify([parentSkillName])]
15207
+ [tenantId, parentSkillName]
15207
15208
  );
15208
15209
  return result.rows.map(this.mapRowToSkill);
15209
15210
  }