@axiom-lattice/pg-stores 1.0.91 → 1.0.93

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiom-lattice/pg-stores",
3
- "version": "1.0.91",
3
+ "version": "1.0.93",
4
4
  "description": "PG stores implementation for Axiom Lattice framework",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -25,8 +25,8 @@
25
25
  "@langchain/core": "1.1.30",
26
26
  "pg": "^8.16.3",
27
27
  "uuid": "^9.0.1",
28
- "@axiom-lattice/core": "2.1.100",
29
- "@axiom-lattice/protocols": "2.1.51"
28
+ "@axiom-lattice/core": "2.1.102",
29
+ "@axiom-lattice/protocols": "2.1.53"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/jest": "^29.5.14",
@@ -19,6 +19,7 @@ import { PostgreSQLChannelInstallationStore } from "./stores/PostgreSQLChannelIn
19
19
  import { PostgreSQLA2AApiKeyStore } from "./stores/PostgreSQLA2AApiKeyStore";
20
20
  import { PostgreSQLScheduleStorage } from "./stores/PostgreSQLScheduleStorage";
21
21
  import { PostgreSQLTaskStore } from "./stores/PostgreSQLTaskStore";
22
+ import { PostgreSQLTaskWorkItemStore } from "./stores/PostgreSQLTaskWorkItemStore";
22
23
  import { MenuStore } from "./stores/MenuStore";
23
24
  import { PostgresSharedResourceStore } from "./stores/PostgresSharedResourceStore";
24
25
  import { PostgreSQLCollectionStore } from "./stores/PostgreSQLCollectionStore";
@@ -62,11 +63,12 @@ import { addWorkspaceProjectToQueue } from "./migrations/add_workspace_project_t
62
63
  import { createWorkflowTrackingTables, addStepThreadId, addWorkflowRunsTenantStatusUpdatedIndex } from "./migrations/workflow_tracking_migrations";
63
64
  import { evalMigrations } from "./migrations/eval_migrations";
64
65
  import { createA2AApiKeysTable } from "./migrations/a2a_api_key_migration";
65
- import { createTasksTable } from "./migrations/task_migration";
66
+ import { createTasksTable, addTaskFieldsMigration, addTaskProjectFieldsMigration } from "./migrations/task_migration";
66
67
  import { createMenuItemsTable } from "./migrations/menu_items_migration";
67
68
  import { addFileContentType } from "./migrations/menu_items_add_file_type";
68
69
  import { createSharedResourcesTable } from "./migrations/shared_resources_migration";
69
70
  import { createCollectionsTable } from "./migrations/collection_migrations";
71
+ import { createTaskWorkItemsMigration, addWorkItemProjectFieldsMigration } from "./migrations/task_work_items_migration";
70
72
 
71
73
  export async function createPgStoreConfig(connectionString: string) {
72
74
  const pool = new Pool({ connectionString });
@@ -118,6 +120,10 @@ export async function createPgStoreConfig(connectionString: string) {
118
120
  mm.register(createSharedResourcesTable); // v135
119
121
  mm.register(addFileContentType); // v136
120
122
  mm.register(createCollectionsTable); // v137
123
+ mm.register(addTaskFieldsMigration); // v139
124
+ mm.register(createTaskWorkItemsMigration); // v138
125
+ mm.register(addTaskProjectFieldsMigration); // v140
126
+ mm.register(addWorkItemProjectFieldsMigration); // v140
121
127
  mm.register(createConnectionConfigsTable); // v160
122
128
  mm.register(addWorkflowRunsTenantStatusUpdatedIndex); // v161
123
129
 
@@ -130,6 +136,8 @@ export async function createPgStoreConfig(connectionString: string) {
130
136
 
131
137
  const opts = { pool };
132
138
 
139
+ const taskWorkItemStore = new PostgreSQLTaskWorkItemStore(pool);
140
+
133
141
  return {
134
142
  workspace: new PostgreSQLWorkspaceStore(opts),
135
143
  project: new PostgreSQLProjectStore(opts),
@@ -148,6 +156,7 @@ export async function createPgStoreConfig(connectionString: string) {
148
156
  workflowTracking: new PostgreSQLWorkflowTrackingStore(opts),
149
157
  threadMessageQueue: new ThreadMessageQueueStore(opts),
150
158
  task: new PostgreSQLTaskStore(opts),
159
+ taskWorkItem: taskWorkItemStore,
151
160
  a2aApiKey: new PostgreSQLA2AApiKeyStore(opts),
152
161
  schedule: new PostgreSQLScheduleStorage(opts),
153
162
  menu: new MenuStore(opts),
@@ -49,3 +49,34 @@ export const createTasksTable: Migration = {
49
49
  await client.query("DROP TABLE IF EXISTS lattice_tasks");
50
50
  },
51
51
  };
52
+
53
+ export const addTaskFieldsMigration: Migration = {
54
+ version: 139,
55
+ name: "add_task_fields_require_review_deps_result_failure",
56
+ up: async (client: PoolClient) => {
57
+ await client.query(`
58
+ ALTER TABLE lattice_tasks
59
+ ADD COLUMN IF NOT EXISTS require_review BOOLEAN DEFAULT FALSE,
60
+ ADD COLUMN IF NOT EXISTS dependencies JSONB,
61
+ ADD COLUMN IF NOT EXISTS result TEXT,
62
+ ADD COLUMN IF NOT EXISTS failure_reason TEXT
63
+ `);
64
+ },
65
+ };
66
+
67
+ export const addTaskProjectFieldsMigration: Migration = {
68
+ version: 140,
69
+ name: "add_task_project_workspace_fields",
70
+ up: async (client: PoolClient) => {
71
+ await client.query(`
72
+ ALTER TABLE lattice_tasks
73
+ ADD COLUMN IF NOT EXISTS workspace_id TEXT,
74
+ ADD COLUMN IF NOT EXISTS project_id TEXT
75
+ `);
76
+
77
+ await client.query(`
78
+ CREATE INDEX IF NOT EXISTS idx_tasks_project
79
+ ON lattice_tasks (tenant_id, project_id)
80
+ `);
81
+ },
82
+ };
@@ -0,0 +1,51 @@
1
+ import type { PoolClient } from "pg";
2
+ import type { Migration } from "./migration";
3
+
4
+ export const createTaskWorkItemsMigration: Migration = {
5
+ version: 138,
6
+ name: "create_task_work_items_table",
7
+ up: async (client: PoolClient) => {
8
+ await client.query(`
9
+ CREATE TABLE IF NOT EXISTS lattice_task_work_items (
10
+ id TEXT NOT NULL,
11
+ tenant_id TEXT NOT NULL,
12
+ task_id TEXT NOT NULL,
13
+ action TEXT NOT NULL,
14
+ actor TEXT NOT NULL,
15
+ thread_id TEXT,
16
+ summary TEXT,
17
+ detail JSONB,
18
+ attempt INTEGER,
19
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
20
+ PRIMARY KEY (tenant_id, id)
21
+ )
22
+ `);
23
+
24
+ await client.query(`
25
+ CREATE INDEX IF NOT EXISTS idx_task_work_items_task_id
26
+ ON lattice_task_work_items (tenant_id, task_id)
27
+ `);
28
+
29
+ await client.query(`
30
+ CREATE INDEX IF NOT EXISTS idx_task_work_items_action
31
+ ON lattice_task_work_items (tenant_id, task_id, action)
32
+ `);
33
+ },
34
+ };
35
+
36
+ export const addWorkItemProjectFieldsMigration: Migration = {
37
+ version: 140,
38
+ name: "add_task_work_item_project_fields",
39
+ up: async (client: PoolClient) => {
40
+ await client.query(`
41
+ ALTER TABLE lattice_task_work_items
42
+ ADD COLUMN IF NOT EXISTS workspace_id TEXT,
43
+ ADD COLUMN IF NOT EXISTS project_id TEXT
44
+ `);
45
+
46
+ await client.query(`
47
+ CREATE INDEX IF NOT EXISTS idx_task_work_items_project
48
+ ON lattice_task_work_items (tenant_id, project_id)
49
+ `);
50
+ },
51
+ };
@@ -12,7 +12,7 @@ import type {
12
12
  TaskListFilter,
13
13
  } from "@axiom-lattice/protocols";
14
14
  import { MigrationManager } from "../migrations/migration";
15
- import { createTasksTable } from "../migrations/task_migration";
15
+ import { createTasksTable, addTaskFieldsMigration, addTaskProjectFieldsMigration } from "../migrations/task_migration";
16
16
  import { v4 as uuidv4 } from "uuid";
17
17
 
18
18
  interface TaskRow {
@@ -29,6 +29,12 @@ interface TaskRow {
29
29
  parent_id: string | null;
30
30
  source_id: string | null;
31
31
  context: Record<string, unknown> | null;
32
+ require_review: boolean | null;
33
+ dependencies: string[] | null;
34
+ result: string | null;
35
+ failure_reason: string | null;
36
+ workspace_id: string | null;
37
+ project_id: string | null;
32
38
  created_at: string;
33
39
  updated_at: string;
34
40
  }
@@ -48,6 +54,12 @@ function mapRowToTask(row: TaskRow): TaskItem {
48
54
  parentId: row.parent_id ?? undefined,
49
55
  sourceId: row.source_id ?? undefined,
50
56
  context: row.context ?? undefined,
57
+ requireReview: row.require_review ?? undefined,
58
+ dependencies: row.dependencies ?? undefined,
59
+ result: row.result ?? undefined,
60
+ failureReason: row.failure_reason ?? undefined,
61
+ workspaceId: row.workspace_id ?? undefined,
62
+ projectId: row.project_id ?? undefined,
51
63
  createdAt: new Date(row.created_at),
52
64
  updatedAt: new Date(row.updated_at),
53
65
  };
@@ -85,6 +97,8 @@ export class PostgreSQLTaskStore implements TaskStore {
85
97
 
86
98
  this.migrationManager = new MigrationManager(this.pool);
87
99
  this.migrationManager.register(createTasksTable);
100
+ this.migrationManager.register(addTaskFieldsMigration);
101
+ this.migrationManager.register(addTaskProjectFieldsMigration);
88
102
 
89
103
  if (options.autoMigrate !== false) {
90
104
  this.initialize().catch((error) => {
@@ -123,8 +137,8 @@ export class PostgreSQLTaskStore implements TaskStore {
123
137
  const now = new Date().toISOString();
124
138
 
125
139
  await this.pool.query(
126
- `INSERT INTO lattice_tasks (id, tenant_id, owner_type, owner_id, title, description, status, priority, due_date, metadata, parent_id, source_id, context, created_at, updated_at)
127
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)`,
140
+ `INSERT INTO lattice_tasks (id, tenant_id, owner_type, owner_id, title, description, status, priority, due_date, metadata, parent_id, source_id, context, require_review, dependencies, result, failure_reason, workspace_id, project_id, created_at, updated_at)
141
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21)`,
128
142
  [
129
143
  id,
130
144
  params.tenantId,
@@ -139,6 +153,12 @@ export class PostgreSQLTaskStore implements TaskStore {
139
153
  params.parentId || null,
140
154
  params.sourceId || null,
141
155
  params.context ? JSON.stringify(params.context) : null,
156
+ params.requireReview ?? null,
157
+ params.dependencies ? JSON.stringify(params.dependencies) : null,
158
+ params.result ?? null,
159
+ params.failureReason ?? null,
160
+ params.workspaceId || null,
161
+ params.projectId || null,
142
162
  now,
143
163
  now,
144
164
  ],
@@ -172,13 +192,24 @@ export class PostgreSQLTaskStore implements TaskStore {
172
192
  params.push(filter.ownerId);
173
193
  }
174
194
  if (filter.status) {
175
- conditions.push(`status = $${paramIndex++}`);
176
- params.push(filter.status);
195
+ const statuses = filter.status.split(',').map(s => s.trim()).filter(Boolean);
196
+ const placeholders = statuses.map((_, i) => `$${paramIndex + i}`).join(', ');
197
+ conditions.push(`status IN (${placeholders})`);
198
+ params.push(...statuses);
199
+ paramIndex += statuses.length;
177
200
  }
178
201
  if (filter.priority) {
179
202
  conditions.push(`priority = $${paramIndex++}`);
180
203
  params.push(filter.priority);
181
204
  }
205
+ if (filter.workspaceId) {
206
+ conditions.push(`workspace_id = $${paramIndex++}`);
207
+ params.push(filter.workspaceId);
208
+ }
209
+ if (filter.projectId) {
210
+ conditions.push(`project_id = $${paramIndex++}`);
211
+ params.push(filter.projectId);
212
+ }
182
213
  if (filter.parentId) {
183
214
  conditions.push(`parent_id = $${paramIndex++}`);
184
215
  params.push(filter.parentId);
@@ -265,6 +296,30 @@ export class PostgreSQLTaskStore implements TaskStore {
265
296
  setClauses.push(`owner_id = $${paramIndex++}`);
266
297
  params.push(updates.ownerId);
267
298
  }
299
+ if (updates.requireReview !== undefined) {
300
+ setClauses.push(`require_review = $${paramIndex++}`);
301
+ params.push(updates.requireReview);
302
+ }
303
+ if (updates.dependencies !== undefined) {
304
+ setClauses.push(`dependencies = $${paramIndex++}`);
305
+ params.push(JSON.stringify(updates.dependencies));
306
+ }
307
+ if (updates.result !== undefined) {
308
+ setClauses.push(`result = $${paramIndex++}`);
309
+ params.push(updates.result);
310
+ }
311
+ if (updates.failureReason !== undefined) {
312
+ setClauses.push(`failure_reason = $${paramIndex++}`);
313
+ params.push(updates.failureReason);
314
+ }
315
+ if (updates.workspaceId !== undefined) {
316
+ setClauses.push(`workspace_id = $${paramIndex++}`);
317
+ params.push(updates.workspaceId);
318
+ }
319
+ if (updates.projectId !== undefined) {
320
+ setClauses.push(`project_id = $${paramIndex++}`);
321
+ params.push(updates.projectId);
322
+ }
268
323
 
269
324
  if (setClauses.length === 0) {
270
325
  return existing;
@@ -0,0 +1,67 @@
1
+ import type { Pool } from "pg";
2
+ import type { TaskWorkItemStore, TaskWorkItem, CreateWorkItemRequest, TaskWorkItemListFilter } from "@axiom-lattice/protocols";
3
+ import { v4 } from "uuid";
4
+
5
+ export class PostgreSQLTaskWorkItemStore implements TaskWorkItemStore {
6
+ constructor(private pool: Pool) {}
7
+
8
+ async create(params: CreateWorkItemRequest): Promise<TaskWorkItem> {
9
+ const id = v4();
10
+ const result = await this.pool.query(
11
+ `INSERT INTO lattice_task_work_items
12
+ (id, tenant_id, task_id, action, actor, thread_id, summary, detail, attempt, workspace_id, project_id)
13
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
14
+ RETURNING *`,
15
+ [
16
+ id, params.tenantId, params.taskId, params.action, params.actor,
17
+ params.threadId || null, params.summary || null,
18
+ params.detail ? JSON.stringify(params.detail) : null,
19
+ params.attempt || null,
20
+ params.workspaceId || null,
21
+ params.projectId || null,
22
+ ]
23
+ );
24
+ return this.rowToItem(result.rows[0]);
25
+ }
26
+
27
+ async list(filter: TaskWorkItemListFilter): Promise<TaskWorkItem[]> {
28
+ let query = `SELECT * FROM lattice_task_work_items WHERE tenant_id = $1 AND task_id = $2`;
29
+ const params: unknown[] = [filter.tenantId, filter.taskId];
30
+
31
+ if (filter.action) {
32
+ query += ` AND action = $${params.length + 1}`;
33
+ params.push(filter.action);
34
+ }
35
+
36
+ query += ` ORDER BY created_at ASC`;
37
+
38
+ if (filter.limit) {
39
+ query += ` LIMIT $${params.length + 1}`;
40
+ params.push(filter.limit);
41
+ }
42
+ if (filter.offset) {
43
+ query += ` OFFSET $${params.length + 1}`;
44
+ params.push(filter.offset);
45
+ }
46
+
47
+ const result = await this.pool.query(query, params);
48
+ return result.rows.map((row: Record<string, unknown>) => this.rowToItem(row));
49
+ }
50
+
51
+ private rowToItem(row: Record<string, unknown>): TaskWorkItem {
52
+ return {
53
+ id: row.id as string,
54
+ taskId: row.task_id as string,
55
+ tenantId: row.tenant_id as string,
56
+ action: row.action as string,
57
+ actor: row.actor as string,
58
+ threadId: row.thread_id as string | undefined,
59
+ summary: row.summary as string | undefined,
60
+ detail: row.detail as Record<string, unknown> | undefined,
61
+ attempt: row.attempt as number | undefined,
62
+ workspaceId: row.workspace_id as string | undefined,
63
+ projectId: row.project_id as string | undefined,
64
+ createdAt: new Date(row.created_at as string),
65
+ };
66
+ }
67
+ }
@@ -261,8 +261,8 @@ export class PostgreSQLTenantStore implements TenantStore {
261
261
  }
262
262
 
263
263
  if (updates.metadata !== undefined) {
264
- updateFields.push(`metadata = $${paramIndex++}`);
265
- updateValues.push(updates.metadata);
264
+ updateFields.push(`metadata = COALESCE(lattice_tenants.metadata, '{}'::jsonb) || $${paramIndex++}::jsonb`);
265
+ updateValues.push(JSON.stringify(updates.metadata));
266
266
  }
267
267
 
268
268
  if (updateFields.length === 0) {