@axiom-lattice/pg-stores 1.0.70 → 1.0.72

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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- import { Pool as Pool20 } from "pg";
2
+ import { Pool as Pool22 } from "pg";
3
3
 
4
4
  // src/stores/PostgreSQLThreadStore.ts
5
5
  import { Pool } from "pg";
@@ -603,6 +603,30 @@ var changeAssistantPrimaryKey = {
603
603
  }
604
604
  };
605
605
 
606
+ // src/migrations/assistant_owner_user_migration.ts
607
+ var addAssistantOwnerUserId = {
608
+ version: 132,
609
+ name: "add_assistant_owner_user_id",
610
+ up: async (client) => {
611
+ await client.query(`
612
+ ALTER TABLE lattice_assistants
613
+ ADD COLUMN IF NOT EXISTS owner_user_id VARCHAR(255)
614
+ `);
615
+ await client.query(`
616
+ CREATE INDEX IF NOT EXISTS idx_lattice_assistants_owner_user_id
617
+ ON lattice_assistants(owner_user_id)
618
+ `);
619
+ },
620
+ down: async (client) => {
621
+ await client.query(
622
+ "DROP INDEX IF EXISTS idx_lattice_assistants_owner_user_id"
623
+ );
624
+ await client.query(
625
+ "ALTER TABLE lattice_assistants DROP COLUMN IF EXISTS owner_user_id"
626
+ );
627
+ }
628
+ };
629
+
606
630
  // src/stores/PostgreSQLAssistantStore.ts
607
631
  var PostgreSQLAssistantStore = class {
608
632
  constructor(options) {
@@ -618,6 +642,7 @@ var PostgreSQLAssistantStore = class {
618
642
  this.migrationManager.register(createAssistantsTable);
619
643
  this.migrationManager.register(addAssistantTenantId);
620
644
  this.migrationManager.register(changeAssistantPrimaryKey);
645
+ this.migrationManager.register(addAssistantOwnerUserId);
621
646
  if (options.autoMigrate !== false) {
622
647
  this.initialize().catch((error) => {
623
648
  console.error("Failed to initialize PostgreSQLAssistantStore:", error);
@@ -653,7 +678,7 @@ var PostgreSQLAssistantStore = class {
653
678
  await this.ensureInitialized();
654
679
  const result = await this.pool.query(
655
680
  `
656
- SELECT id, tenant_id, name, description, graph_definition, created_at, updated_at
681
+ SELECT id, tenant_id, name, description, graph_definition, owner_user_id, created_at, updated_at
657
682
  FROM lattice_assistants
658
683
  WHERE tenant_id = $1
659
684
  ORDER BY created_at DESC
@@ -669,7 +694,7 @@ var PostgreSQLAssistantStore = class {
669
694
  await this.ensureInitialized();
670
695
  const result = await this.pool.query(
671
696
  `
672
- SELECT id, tenant_id, name, description, graph_definition, created_at, updated_at
697
+ SELECT id, tenant_id, name, description, graph_definition, owner_user_id, created_at, updated_at
673
698
  FROM lattice_assistants
674
699
  WHERE tenant_id = $1 AND id = $2
675
700
  `,
@@ -688,12 +713,13 @@ var PostgreSQLAssistantStore = class {
688
713
  const now = /* @__PURE__ */ new Date();
689
714
  await this.pool.query(
690
715
  `
691
- INSERT INTO lattice_assistants (id, tenant_id, name, description, graph_definition, created_at, updated_at)
692
- VALUES ($1, $2, $3, $4, $5, $6, $7)
716
+ INSERT INTO lattice_assistants (id, tenant_id, name, description, graph_definition, owner_user_id, created_at, updated_at)
717
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
693
718
  ON CONFLICT (id, tenant_id) DO UPDATE SET
694
719
  name = EXCLUDED.name,
695
720
  description = EXCLUDED.description,
696
721
  graph_definition = EXCLUDED.graph_definition,
722
+ owner_user_id = EXCLUDED.owner_user_id,
697
723
  updated_at = EXCLUDED.updated_at
698
724
  `,
699
725
  [
@@ -702,6 +728,7 @@ var PostgreSQLAssistantStore = class {
702
728
  data.name,
703
729
  data.description || null,
704
730
  JSON.stringify(data.graphDefinition),
731
+ data.ownerUserId || null,
705
732
  now,
706
733
  now
707
734
  ]
@@ -712,6 +739,7 @@ var PostgreSQLAssistantStore = class {
712
739
  name: data.name,
713
740
  description: data.description,
714
741
  graphDefinition: data.graphDefinition,
742
+ ownerUserId: data.ownerUserId,
715
743
  createdAt: now,
716
744
  updatedAt: now
717
745
  };
@@ -740,6 +768,10 @@ var PostgreSQLAssistantStore = class {
740
768
  updateFields.push(`graph_definition = $${paramIndex++}`);
741
769
  updateValues.push(JSON.stringify(updates.graphDefinition));
742
770
  }
771
+ if (updates.ownerUserId !== void 0) {
772
+ updateFields.push(`owner_user_id = $${paramIndex++}`);
773
+ updateValues.push(updates.ownerUserId || null);
774
+ }
743
775
  if (updateFields.length === 0) {
744
776
  return existing;
745
777
  }
@@ -786,6 +818,23 @@ var PostgreSQLAssistantStore = class {
786
818
  );
787
819
  return result.rows.length > 0;
788
820
  }
821
+ /**
822
+ * Get assistant by owner user ID
823
+ */
824
+ async getByOwner(tenantId, userId) {
825
+ await this.ensureInitialized();
826
+ const result = await this.pool.query(
827
+ `
828
+ SELECT id, tenant_id, name, description, graph_definition, owner_user_id, created_at, updated_at
829
+ FROM lattice_assistants
830
+ WHERE tenant_id = $1 AND owner_user_id = $2
831
+ LIMIT 1
832
+ `,
833
+ [tenantId, userId]
834
+ );
835
+ if (result.rows.length === 0) return null;
836
+ return this.mapRowToAssistant(result.rows[0]);
837
+ }
789
838
  /**
790
839
  * Dispose resources and close the connection pool
791
840
  * Should be called when the store is no longer needed
@@ -813,6 +862,7 @@ var PostgreSQLAssistantStore = class {
813
862
  name: row.name,
814
863
  description: row.description || void 0,
815
864
  graphDefinition: typeof row.graph_definition === "string" ? JSON.parse(row.graph_definition) : row.graph_definition,
865
+ ownerUserId: row.owner_user_id || void 0,
816
866
  createdAt: row.created_at,
817
867
  updatedAt: row.updated_at
818
868
  };
@@ -3009,6 +3059,22 @@ var createWorkflowTrackingTables = {
3009
3059
  `);
3010
3060
  }
3011
3061
  };
3062
+ var addStepThreadId = {
3063
+ name: "add_step_thread_id",
3064
+ version: 113,
3065
+ up: async (client) => {
3066
+ await client.query(`
3067
+ ALTER TABLE lattice_workflow_steps
3068
+ ADD COLUMN IF NOT EXISTS thread_id VARCHAR(255);
3069
+ `);
3070
+ },
3071
+ down: async (client) => {
3072
+ await client.query(`
3073
+ ALTER TABLE lattice_workflow_steps
3074
+ DROP COLUMN IF EXISTS thread_id;
3075
+ `);
3076
+ }
3077
+ };
3012
3078
 
3013
3079
  // src/stores/PostgreSQLWorkflowTrackingStore.ts
3014
3080
  var PostgreSQLWorkflowTrackingStore = class {
@@ -3022,6 +3088,7 @@ var PostgreSQLWorkflowTrackingStore = class {
3022
3088
  }
3023
3089
  this.migrationManager = new MigrationManager(this.pool);
3024
3090
  this.migrationManager.register(createWorkflowTrackingTables);
3091
+ this.migrationManager.register(addStepThreadId);
3025
3092
  if (options.autoMigrate !== false) {
3026
3093
  this.initialize().catch((error) => {
3027
3094
  console.error("Failed to initialize PostgreSQLWorkflowTrackingStore:", error);
@@ -3154,8 +3221,8 @@ var PostgreSQLWorkflowTrackingStore = class {
3154
3221
  const now = /* @__PURE__ */ new Date();
3155
3222
  const id = `step_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
3156
3223
  await this.pool.query(
3157
- `INSERT INTO lattice_workflow_steps (id, run_id, tenant_id, step_type, step_name, edge_from, edge_to, edge_purpose, input, status, started_at, created_at, updated_at)
3158
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`,
3224
+ `INSERT INTO lattice_workflow_steps (id, run_id, tenant_id, step_type, step_name, edge_from, edge_to, edge_purpose, input, thread_id, status, started_at, created_at, updated_at)
3225
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)`,
3159
3226
  [
3160
3227
  id,
3161
3228
  request.runId,
@@ -3166,6 +3233,7 @@ var PostgreSQLWorkflowTrackingStore = class {
3166
3233
  request.edgeTo || null,
3167
3234
  request.edgePurpose || null,
3168
3235
  request.input ? JSON.stringify(request.input) : null,
3236
+ request.threadId || null,
3169
3237
  "running",
3170
3238
  now,
3171
3239
  now,
@@ -3178,6 +3246,7 @@ var PostgreSQLWorkflowTrackingStore = class {
3178
3246
  tenantId: request.tenantId,
3179
3247
  stepType: request.stepType,
3180
3248
  stepName: request.stepName,
3249
+ threadId: request.threadId,
3181
3250
  edgeFrom: request.edgeFrom,
3182
3251
  edgeTo: request.edgeTo,
3183
3252
  edgePurpose: request.edgePurpose,
@@ -3188,6 +3257,25 @@ var PostgreSQLWorkflowTrackingStore = class {
3188
3257
  updatedAt: now
3189
3258
  };
3190
3259
  }
3260
+ async upsertRunStep(request) {
3261
+ await this.ensureInitialized();
3262
+ const result = await this.pool.query(
3263
+ `SELECT * FROM lattice_workflow_steps WHERE run_id = $1 AND step_type = $2 AND step_name = $3`,
3264
+ [request.runId, request.stepType, request.stepName]
3265
+ );
3266
+ if (result.rows.length > 0) {
3267
+ const existing = this.mapRowToRunStep(result.rows[0]);
3268
+ if (!existing.threadId && request.threadId) {
3269
+ await this.pool.query(
3270
+ `UPDATE lattice_workflow_steps SET thread_id = $1, updated_at = $2 WHERE run_id = $3 AND id = $4`,
3271
+ [request.threadId, /* @__PURE__ */ new Date(), request.runId, existing.id]
3272
+ );
3273
+ existing.threadId = request.threadId;
3274
+ }
3275
+ return existing;
3276
+ }
3277
+ return this.createRunStep(request);
3278
+ }
3191
3279
  async updateRunStep(runId, stepId, updates) {
3192
3280
  await this.ensureInitialized();
3193
3281
  const now = /* @__PURE__ */ new Date();
@@ -3272,6 +3360,7 @@ var PostgreSQLWorkflowTrackingStore = class {
3272
3360
  tenantId: row.tenant_id,
3273
3361
  stepType: row.step_type,
3274
3362
  stepName: row.step_name,
3363
+ threadId: row.thread_id,
3275
3364
  edgeFrom: row.edge_from,
3276
3365
  edgeTo: row.edge_to,
3277
3366
  edgePurpose: row.edge_purpose,
@@ -4324,6 +4413,30 @@ var alterMessageQueueIdColumn = {
4324
4413
  }
4325
4414
  };
4326
4415
 
4416
+ // src/migrations/add_workspace_project_to_queue.ts
4417
+ var addWorkspaceProjectToQueue = {
4418
+ version: 131,
4419
+ name: "add_workspace_project_to_queue",
4420
+ up: async (client) => {
4421
+ await client.query(`
4422
+ ALTER TABLE lattice_thread_message_queue
4423
+ ADD COLUMN IF NOT EXISTS workspace_id VARCHAR(255)
4424
+ `);
4425
+ await client.query(`
4426
+ ALTER TABLE lattice_thread_message_queue
4427
+ ADD COLUMN IF NOT EXISTS project_id VARCHAR(255)
4428
+ `);
4429
+ },
4430
+ down: async (client) => {
4431
+ await client.query(
4432
+ "ALTER TABLE lattice_thread_message_queue DROP COLUMN IF EXISTS workspace_id"
4433
+ );
4434
+ await client.query(
4435
+ "ALTER TABLE lattice_thread_message_queue DROP COLUMN IF EXISTS project_id"
4436
+ );
4437
+ }
4438
+ };
4439
+
4327
4440
  // src/stores/ThreadMessageQueueStore.ts
4328
4441
  var ThreadMessageQueueStore = class {
4329
4442
  constructor(options) {
@@ -4340,6 +4453,7 @@ var ThreadMessageQueueStore = class {
4340
4453
  this.migrationManager.register(addPriorityAndCommandColumns);
4341
4454
  this.migrationManager.register(addCustomRunConfigColumn);
4342
4455
  this.migrationManager.register(alterMessageQueueIdColumn);
4456
+ this.migrationManager.register(addWorkspaceProjectToQueue);
4343
4457
  if (options.autoMigrate !== false) {
4344
4458
  this.initialize().catch((error) => {
4345
4459
  console.error("Failed to initialize ThreadMessageQueueStore:", error);
@@ -4369,7 +4483,7 @@ var ThreadMessageQueueStore = class {
4369
4483
  * Add message to queue
4370
4484
  */
4371
4485
  async addMessage(params) {
4372
- const { threadId, tenantId, assistantId, content, type = "human", priority = 0, command, custom_run_config, id } = params;
4486
+ const { threadId, tenantId, assistantId, workspaceId, projectId, content, type = "human", priority = 0, command, custom_run_config, id } = params;
4373
4487
  const seqResult = await this.pool.query(
4374
4488
  `SELECT COALESCE(MAX(sequence_order), 0) + 1 as next_seq
4375
4489
  FROM lattice_thread_message_queue
@@ -4379,10 +4493,10 @@ var ThreadMessageQueueStore = class {
4379
4493
  const nextSeq = seqResult.rows[0].next_seq;
4380
4494
  const result = await this.pool.query(
4381
4495
  `INSERT INTO lattice_thread_message_queue
4382
- (id, thread_id, tenant_id, assistant_id, message_content, message_type, sequence_order, priority, command, custom_run_config)
4383
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
4496
+ (id, thread_id, tenant_id, assistant_id, workspace_id, project_id, message_content, message_type, sequence_order, priority, command, custom_run_config)
4497
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
4384
4498
  RETURNING *`,
4385
- [id || crypto.randomUUID(), threadId, tenantId, assistantId, JSON.stringify(content), type, nextSeq, priority, command ? JSON.stringify(command) : null, custom_run_config ? JSON.stringify(custom_run_config) : null]
4499
+ [id || crypto.randomUUID(), threadId, tenantId, assistantId, workspaceId || null, projectId || null, JSON.stringify(content), type, nextSeq, priority, command ? JSON.stringify(command) : null, custom_run_config ? JSON.stringify(custom_run_config) : null]
4386
4500
  );
4387
4501
  return this.rowToMessage(result.rows[0]);
4388
4502
  }
@@ -4391,7 +4505,7 @@ var ThreadMessageQueueStore = class {
4391
4505
  * Uses priority=100 to ensure message is processed first
4392
4506
  */
4393
4507
  async addMessageAtHead(params) {
4394
- const { threadId, tenantId, assistantId, content, type = "human", command, custom_run_config, id } = params;
4508
+ const { threadId, tenantId, assistantId, workspaceId, projectId, content, type = "human", command, custom_run_config, id } = params;
4395
4509
  const resolvedTenantId = tenantId;
4396
4510
  const resolvedAssistantId = assistantId;
4397
4511
  const seqResult = await this.pool.query(
@@ -4403,10 +4517,10 @@ var ThreadMessageQueueStore = class {
4403
4517
  const nextSeq = seqResult.rows[0].next_seq;
4404
4518
  const result = await this.pool.query(
4405
4519
  `INSERT INTO lattice_thread_message_queue
4406
- (id, thread_id, tenant_id, assistant_id, message_content, message_type, sequence_order, priority, command, custom_run_config)
4407
- VALUES ($1, $2, $3, $4, $5, $6, $7, 100, $8, $9)
4520
+ (id, thread_id, tenant_id, assistant_id, workspace_id, project_id, message_content, message_type, sequence_order, priority, command, custom_run_config)
4521
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, 100, $10, $11)
4408
4522
  RETURNING *`,
4409
- [id || crypto.randomUUID(), threadId, resolvedTenantId, resolvedAssistantId, JSON.stringify(content), type, nextSeq, command ? JSON.stringify(command) : null, custom_run_config ? JSON.stringify(custom_run_config) : null]
4523
+ [id || crypto.randomUUID(), threadId, resolvedTenantId, resolvedAssistantId, workspaceId || null, projectId || null, JSON.stringify(content), type, nextSeq, command ? JSON.stringify(command) : null, custom_run_config ? JSON.stringify(custom_run_config) : null]
4410
4524
  );
4411
4525
  return this.rowToMessage(result.rows[0]);
4412
4526
  }
@@ -4450,7 +4564,7 @@ var ThreadMessageQueueStore = class {
4450
4564
  */
4451
4565
  async getThreadsWithPendingMessages() {
4452
4566
  const result = await this.pool.query(
4453
- `SELECT DISTINCT tenant_id, assistant_id, thread_id
4567
+ `SELECT DISTINCT ON (thread_id) tenant_id, assistant_id, thread_id, workspace_id, project_id
4454
4568
  FROM lattice_thread_message_queue
4455
4569
  WHERE status IN ('pending', 'processing')
4456
4570
  ORDER BY thread_id`
@@ -4458,7 +4572,9 @@ var ThreadMessageQueueStore = class {
4458
4572
  return result.rows.map((row) => ({
4459
4573
  tenantId: row.tenant_id,
4460
4574
  assistantId: row.assistant_id,
4461
- threadId: row.thread_id
4575
+ threadId: row.thread_id,
4576
+ workspaceId: row.workspace_id || void 0,
4577
+ projectId: row.project_id || void 0
4462
4578
  }));
4463
4579
  }
4464
4580
  /**
@@ -4885,6 +5001,25 @@ var PostgreSQLChannelInstallationStore = class {
4885
5001
  );
4886
5002
  return result.rows.map((row) => this.mapRowToInstallation(row));
4887
5003
  }
5004
+ async getAllInstallations(channel) {
5005
+ await this.ensureInitialized();
5006
+ const result = channel ? await this.pool.query(
5007
+ `
5008
+ SELECT id, tenant_id, channel, name, config, enabled, fallback_agent_id, reject_when_no_binding, created_at, updated_at
5009
+ FROM lattice_channel_installations
5010
+ WHERE channel = $1
5011
+ ORDER BY created_at DESC
5012
+ `,
5013
+ [channel]
5014
+ ) : await this.pool.query(
5015
+ `
5016
+ SELECT id, tenant_id, channel, name, config, enabled, fallback_agent_id, reject_when_no_binding, created_at, updated_at
5017
+ FROM lattice_channel_installations
5018
+ ORDER BY created_at DESC
5019
+ `
5020
+ );
5021
+ return result.rows.map((row) => this.mapRowToInstallation(row));
5022
+ }
4888
5023
  async createInstallation(tenantId, installationId, data) {
4889
5024
  await this.ensureInitialized();
4890
5025
  const now = /* @__PURE__ */ new Date();
@@ -5800,33 +5935,501 @@ var PostgreSQLScheduleStorage = class {
5800
5935
  }
5801
5936
  };
5802
5937
 
5938
+ // src/stores/PostgreSQLTaskStore.ts
5939
+ import { Pool as Pool18 } from "pg";
5940
+
5941
+ // src/migrations/task_migration.ts
5942
+ var createTasksTable = {
5943
+ version: 133,
5944
+ name: "create_lattice_tasks_table",
5945
+ up: async (client) => {
5946
+ await client.query(`
5947
+ CREATE TABLE IF NOT EXISTS lattice_tasks (
5948
+ id VARCHAR(255) PRIMARY KEY,
5949
+ tenant_id VARCHAR(255) NOT NULL,
5950
+ owner_type VARCHAR(10) NOT NULL DEFAULT 'user',
5951
+ owner_id VARCHAR(255) NOT NULL,
5952
+ title VARCHAR(500) NOT NULL,
5953
+ description TEXT,
5954
+ status VARCHAR(20) NOT NULL DEFAULT 'pending',
5955
+ priority VARCHAR(10) NOT NULL DEFAULT 'medium',
5956
+ due_date VARCHAR(50),
5957
+ metadata JSONB,
5958
+ parent_id VARCHAR(255),
5959
+ source_id VARCHAR(255),
5960
+ context JSONB,
5961
+ created_at VARCHAR(50) NOT NULL,
5962
+ updated_at VARCHAR(50) NOT NULL
5963
+ )
5964
+ `);
5965
+ await client.query(`
5966
+ CREATE INDEX IF NOT EXISTS idx_lattice_tasks_tenant_id
5967
+ ON lattice_tasks(tenant_id)
5968
+ `);
5969
+ await client.query(`
5970
+ CREATE INDEX IF NOT EXISTS idx_lattice_tasks_owner
5971
+ ON lattice_tasks(tenant_id, owner_type, owner_id)
5972
+ `);
5973
+ await client.query(`
5974
+ CREATE INDEX IF NOT EXISTS idx_lattice_tasks_status
5975
+ ON lattice_tasks(tenant_id, status)
5976
+ `);
5977
+ await client.query(`
5978
+ CREATE INDEX IF NOT EXISTS idx_lattice_tasks_parent_id
5979
+ ON lattice_tasks(tenant_id, parent_id)
5980
+ `);
5981
+ },
5982
+ down: async (client) => {
5983
+ await client.query("DROP TABLE IF EXISTS lattice_tasks");
5984
+ }
5985
+ };
5986
+
5987
+ // src/stores/PostgreSQLTaskStore.ts
5988
+ import { v4 as uuidv42 } from "uuid";
5989
+ function mapRowToTask(row) {
5990
+ return {
5991
+ id: row.id,
5992
+ tenantId: row.tenant_id,
5993
+ ownerType: row.owner_type,
5994
+ ownerId: row.owner_id,
5995
+ title: row.title,
5996
+ description: row.description ?? void 0,
5997
+ status: row.status,
5998
+ priority: row.priority,
5999
+ dueDate: row.due_date ?? void 0,
6000
+ metadata: row.metadata ?? void 0,
6001
+ parentId: row.parent_id ?? void 0,
6002
+ sourceId: row.source_id ?? void 0,
6003
+ context: row.context ?? void 0,
6004
+ createdAt: new Date(row.created_at),
6005
+ updatedAt: new Date(row.updated_at)
6006
+ };
6007
+ }
6008
+ var PostgreSQLTaskStore = class {
6009
+ constructor(options) {
6010
+ this.initialized = false;
6011
+ this.ownsPool = true;
6012
+ this.initPromise = null;
6013
+ if (typeof options.poolConfig === "string") {
6014
+ this.pool = new Pool18({ connectionString: options.poolConfig });
6015
+ } else {
6016
+ this.pool = new Pool18(options.poolConfig);
6017
+ }
6018
+ this.migrationManager = new MigrationManager(this.pool);
6019
+ this.migrationManager.register(createTasksTable);
6020
+ if (options.autoMigrate !== false) {
6021
+ this.initialize().catch((error) => {
6022
+ console.error("Failed to initialize PostgreSQLTaskStore:", error);
6023
+ throw error;
6024
+ });
6025
+ }
6026
+ }
6027
+ async initialize() {
6028
+ if (this.initialized) {
6029
+ return;
6030
+ }
6031
+ if (this.initPromise) {
6032
+ return this.initPromise;
6033
+ }
6034
+ this.initPromise = (async () => {
6035
+ try {
6036
+ await this.migrationManager.migrate();
6037
+ this.initialized = true;
6038
+ } finally {
6039
+ this.initPromise = null;
6040
+ }
6041
+ })();
6042
+ return this.initPromise;
6043
+ }
6044
+ async create(params) {
6045
+ await this.ensureInitialized();
6046
+ const id = uuidv42();
6047
+ const now = (/* @__PURE__ */ new Date()).toISOString();
6048
+ await this.pool.query(
6049
+ `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)
6050
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)`,
6051
+ [
6052
+ id,
6053
+ params.tenantId,
6054
+ params.ownerType,
6055
+ params.ownerId,
6056
+ params.title,
6057
+ params.description || null,
6058
+ params.status || "pending",
6059
+ params.priority || "medium",
6060
+ params.dueDate || null,
6061
+ params.metadata ? JSON.stringify(params.metadata) : null,
6062
+ params.parentId || null,
6063
+ params.sourceId || null,
6064
+ params.context ? JSON.stringify(params.context) : null,
6065
+ now,
6066
+ now
6067
+ ]
6068
+ );
6069
+ return await this.getById(params.tenantId, id);
6070
+ }
6071
+ async getById(tenantId, id) {
6072
+ await this.ensureInitialized();
6073
+ const result = await this.pool.query(
6074
+ `SELECT * FROM lattice_tasks WHERE tenant_id = $1 AND id = $2`,
6075
+ [tenantId, id]
6076
+ );
6077
+ if (result.rows.length === 0) return null;
6078
+ return mapRowToTask(result.rows[0]);
6079
+ }
6080
+ async list(filter) {
6081
+ await this.ensureInitialized();
6082
+ const conditions = [`tenant_id = $1`];
6083
+ const params = [filter.tenantId];
6084
+ let paramIndex = 2;
6085
+ if (filter.ownerType) {
6086
+ conditions.push(`owner_type = $${paramIndex++}`);
6087
+ params.push(filter.ownerType);
6088
+ }
6089
+ if (filter.ownerId) {
6090
+ conditions.push(`owner_id = $${paramIndex++}`);
6091
+ params.push(filter.ownerId);
6092
+ }
6093
+ if (filter.status) {
6094
+ conditions.push(`status = $${paramIndex++}`);
6095
+ params.push(filter.status);
6096
+ }
6097
+ if (filter.priority) {
6098
+ conditions.push(`priority = $${paramIndex++}`);
6099
+ params.push(filter.priority);
6100
+ }
6101
+ if (filter.parentId) {
6102
+ conditions.push(`parent_id = $${paramIndex++}`);
6103
+ params.push(filter.parentId);
6104
+ }
6105
+ if (filter.sourceId) {
6106
+ conditions.push(`source_id = $${paramIndex++}`);
6107
+ params.push(filter.sourceId);
6108
+ }
6109
+ if (filter.metadata) {
6110
+ for (const [key, value] of Object.entries(filter.metadata)) {
6111
+ const safeKey = key.replace(/[^a-zA-Z0-9_]/g, "");
6112
+ if (safeKey) {
6113
+ conditions.push(`metadata->>'${safeKey}' = $${paramIndex++}`);
6114
+ params.push(String(value));
6115
+ }
6116
+ }
6117
+ }
6118
+ const where = conditions.join(" AND ");
6119
+ const limit = filter.limit || 100;
6120
+ const offset = filter.offset || 0;
6121
+ const result = await this.pool.query(
6122
+ `SELECT * FROM lattice_tasks WHERE ${where} ORDER BY created_at DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`,
6123
+ [...params, limit, offset]
6124
+ );
6125
+ return result.rows.map((r) => mapRowToTask(r));
6126
+ }
6127
+ async update(tenantId, id, updates) {
6128
+ await this.ensureInitialized();
6129
+ const existing = await this.getById(tenantId, id);
6130
+ if (!existing) return null;
6131
+ const setClauses = [];
6132
+ const params = [];
6133
+ let paramIndex = 1;
6134
+ if (updates.title !== void 0) {
6135
+ setClauses.push(`title = $${paramIndex++}`);
6136
+ params.push(updates.title);
6137
+ }
6138
+ if (updates.description !== void 0) {
6139
+ setClauses.push(`description = $${paramIndex++}`);
6140
+ params.push(updates.description);
6141
+ }
6142
+ if (updates.status !== void 0) {
6143
+ setClauses.push(`status = $${paramIndex++}`);
6144
+ params.push(updates.status);
6145
+ }
6146
+ if (updates.priority !== void 0) {
6147
+ setClauses.push(`priority = $${paramIndex++}`);
6148
+ params.push(updates.priority);
6149
+ }
6150
+ if (updates.dueDate !== void 0) {
6151
+ setClauses.push(`due_date = $${paramIndex++}`);
6152
+ params.push(updates.dueDate);
6153
+ }
6154
+ if (updates.metadata !== void 0) {
6155
+ setClauses.push(`metadata = $${paramIndex++}`);
6156
+ params.push(JSON.stringify(updates.metadata));
6157
+ }
6158
+ if (updates.parentId !== void 0) {
6159
+ setClauses.push(`parent_id = $${paramIndex++}`);
6160
+ params.push(updates.parentId);
6161
+ }
6162
+ if (updates.sourceId !== void 0) {
6163
+ setClauses.push(`source_id = $${paramIndex++}`);
6164
+ params.push(updates.sourceId);
6165
+ }
6166
+ if (updates.context !== void 0) {
6167
+ setClauses.push(`context = $${paramIndex++}`);
6168
+ params.push(JSON.stringify(updates.context));
6169
+ }
6170
+ if (updates.ownerType !== void 0) {
6171
+ setClauses.push(`owner_type = $${paramIndex++}`);
6172
+ params.push(updates.ownerType);
6173
+ }
6174
+ if (updates.ownerId !== void 0) {
6175
+ setClauses.push(`owner_id = $${paramIndex++}`);
6176
+ params.push(updates.ownerId);
6177
+ }
6178
+ if (setClauses.length === 0) {
6179
+ return existing;
6180
+ }
6181
+ setClauses.push(`updated_at = $${paramIndex++}`);
6182
+ params.push((/* @__PURE__ */ new Date()).toISOString());
6183
+ params.push(tenantId, id);
6184
+ await this.pool.query(
6185
+ `UPDATE lattice_tasks SET ${setClauses.join(", ")} WHERE tenant_id = $${paramIndex++} AND id = $${paramIndex++}`,
6186
+ params
6187
+ );
6188
+ return this.getById(tenantId, id);
6189
+ }
6190
+ async delete(tenantId, id) {
6191
+ await this.ensureInitialized();
6192
+ const result = await this.pool.query(
6193
+ `DELETE FROM lattice_tasks WHERE tenant_id = $1 AND id = $2`,
6194
+ [tenantId, id]
6195
+ );
6196
+ return (result.rowCount ?? 0) > 0;
6197
+ }
6198
+ async dispose() {
6199
+ if (this.ownsPool && this.pool) {
6200
+ await this.pool.end();
6201
+ }
6202
+ }
6203
+ async ensureInitialized() {
6204
+ if (!this.initialized) {
6205
+ await this.initialize();
6206
+ }
6207
+ }
6208
+ };
6209
+
6210
+ // src/stores/MenuStore.ts
6211
+ import { Pool as Pool19 } from "pg";
6212
+
6213
+ // src/migrations/menu_items_migration.ts
6214
+ var createMenuItemsTable = {
6215
+ version: 134,
6216
+ name: "create_menu_items_table",
6217
+ up: async (client) => {
6218
+ await client.query(`
6219
+ CREATE TABLE IF NOT EXISTS lattice_menu_items (
6220
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
6221
+ tenant_id VARCHAR(255) NOT NULL,
6222
+ menu_target VARCHAR(20) NOT NULL CHECK (menu_target IN ('sidebar', 'workspace')),
6223
+ "group" VARCHAR(100),
6224
+ name VARCHAR(255) NOT NULL,
6225
+ icon VARCHAR(50),
6226
+ sort_order INT NOT NULL DEFAULT 0,
6227
+ content_type VARCHAR(20) NOT NULL CHECK (content_type IN ('agent', 'html', 'custom')),
6228
+ content_config JSONB NOT NULL DEFAULT '{}',
6229
+ enabled BOOLEAN NOT NULL DEFAULT true,
6230
+ created_at TIMESTAMP NOT NULL DEFAULT NOW(),
6231
+ updated_at TIMESTAMP NOT NULL DEFAULT NOW()
6232
+ )
6233
+ `);
6234
+ await client.query(`
6235
+ CREATE INDEX IF NOT EXISTS idx_menu_items_tenant_target
6236
+ ON lattice_menu_items(tenant_id, menu_target)
6237
+ `);
6238
+ await client.query(`
6239
+ CREATE INDEX IF NOT EXISTS idx_menu_items_sort
6240
+ ON lattice_menu_items(tenant_id, menu_target, sort_order)
6241
+ `);
6242
+ },
6243
+ down: async (client) => {
6244
+ await client.query("DROP TABLE IF EXISTS lattice_menu_items");
6245
+ }
6246
+ };
6247
+
6248
+ // src/stores/MenuStore.ts
6249
+ var MenuStore = class {
6250
+ constructor(options) {
6251
+ this.initialized = false;
6252
+ this.initPromise = null;
6253
+ this.pool = typeof options.poolConfig === "string" ? new Pool19({ connectionString: options.poolConfig }) : new Pool19(options.poolConfig);
6254
+ this.migrationManager = new MigrationManager(this.pool);
6255
+ this.migrationManager.register(createMenuItemsTable);
6256
+ if (options.autoMigrate !== false) {
6257
+ this.initialize().catch((error) => {
6258
+ console.error("Failed to initialize MenuStore:", error);
6259
+ throw error;
6260
+ });
6261
+ }
6262
+ }
6263
+ async initialize() {
6264
+ if (this.initialized) return;
6265
+ if (this.initPromise) return this.initPromise;
6266
+ this.initPromise = (async () => {
6267
+ try {
6268
+ await this.migrationManager.migrate();
6269
+ this.initialized = true;
6270
+ } finally {
6271
+ this.initPromise = null;
6272
+ }
6273
+ })();
6274
+ return this.initPromise;
6275
+ }
6276
+ async list(params) {
6277
+ await this.ensureInitialized();
6278
+ const conditions = ["tenant_id = $1"];
6279
+ const values = [params.tenantId];
6280
+ let idx = 2;
6281
+ if (params.menuTarget) {
6282
+ conditions.push(`menu_target = $${idx++}`);
6283
+ values.push(params.menuTarget);
6284
+ }
6285
+ const result = await this.pool.query(
6286
+ `SELECT * FROM lattice_menu_items
6287
+ WHERE ${conditions.join(" AND ")}
6288
+ AND enabled = true
6289
+ ORDER BY sort_order ASC`,
6290
+ values
6291
+ );
6292
+ return result.rows.map((r) => this.mapRowToMenuItem(r));
6293
+ }
6294
+ async getById(id) {
6295
+ await this.ensureInitialized();
6296
+ const result = await this.pool.query(
6297
+ `SELECT * FROM lattice_menu_items WHERE id = $1`,
6298
+ [id]
6299
+ );
6300
+ if (result.rows.length === 0) return null;
6301
+ return this.mapRowToMenuItem(result.rows[0]);
6302
+ }
6303
+ async create(input) {
6304
+ await this.ensureInitialized();
6305
+ const result = await this.pool.query(
6306
+ `INSERT INTO lattice_menu_items
6307
+ (tenant_id, menu_target, "group", name, icon, sort_order, content_type, content_config)
6308
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
6309
+ RETURNING *`,
6310
+ [
6311
+ input.tenantId,
6312
+ input.menuTarget,
6313
+ input.group || null,
6314
+ input.name,
6315
+ input.icon || null,
6316
+ input.sortOrder ?? 0,
6317
+ input.contentType,
6318
+ JSON.stringify(input.contentConfig)
6319
+ ]
6320
+ );
6321
+ return this.mapRowToMenuItem(result.rows[0]);
6322
+ }
6323
+ async update(id, patch) {
6324
+ await this.ensureInitialized();
6325
+ const existing = await this.pool.query(
6326
+ `SELECT * FROM lattice_menu_items WHERE id = $1`,
6327
+ [id]
6328
+ );
6329
+ if (existing.rows.length === 0) {
6330
+ throw new Error(`MenuItem ${id} not found`);
6331
+ }
6332
+ const row = existing.rows[0];
6333
+ const setClauses = [];
6334
+ const values = [];
6335
+ let idx = 1;
6336
+ if (patch.group !== void 0) {
6337
+ setClauses.push(`"group" = $${idx++}`);
6338
+ values.push(patch.group);
6339
+ }
6340
+ if (patch.name !== void 0) {
6341
+ setClauses.push(`name = $${idx++}`);
6342
+ values.push(patch.name);
6343
+ }
6344
+ if (patch.icon !== void 0) {
6345
+ setClauses.push(`icon = $${idx++}`);
6346
+ values.push(patch.icon);
6347
+ }
6348
+ if (patch.sortOrder !== void 0) {
6349
+ setClauses.push(`sort_order = $${idx++}`);
6350
+ values.push(patch.sortOrder);
6351
+ }
6352
+ if (patch.contentConfig !== void 0) {
6353
+ setClauses.push(`content_config = $${idx++}`);
6354
+ values.push(JSON.stringify(patch.contentConfig));
6355
+ }
6356
+ if (patch.enabled !== void 0) {
6357
+ setClauses.push(`enabled = $${idx++}`);
6358
+ values.push(patch.enabled);
6359
+ }
6360
+ if (setClauses.length === 0) {
6361
+ return this.mapRowToMenuItem(row);
6362
+ }
6363
+ setClauses.push(`updated_at = NOW()`);
6364
+ values.push(id);
6365
+ const result = await this.pool.query(
6366
+ `UPDATE lattice_menu_items SET ${setClauses.join(", ")} WHERE id = $${idx}
6367
+ RETURNING *`,
6368
+ values
6369
+ );
6370
+ return this.mapRowToMenuItem(result.rows[0]);
6371
+ }
6372
+ async delete(id) {
6373
+ await this.ensureInitialized();
6374
+ await this.pool.query(`DELETE FROM lattice_menu_items WHERE id = $1`, [id]);
6375
+ }
6376
+ async ensureInitialized() {
6377
+ if (!this.initialized) {
6378
+ await this.initialize();
6379
+ }
6380
+ }
6381
+ mapRowToMenuItem(row) {
6382
+ return {
6383
+ id: row.id,
6384
+ tenantId: row.tenant_id,
6385
+ menuTarget: row.menu_target,
6386
+ group: row.group || void 0,
6387
+ name: row.name,
6388
+ icon: row.icon || void 0,
6389
+ sortOrder: row.sort_order,
6390
+ contentType: row.content_type,
6391
+ contentConfig: row.content_config,
6392
+ enabled: row.enabled,
6393
+ createdAt: row.created_at,
6394
+ updatedAt: row.updated_at
6395
+ };
6396
+ }
6397
+ };
6398
+
5803
6399
  // src/createPgStoreConfig.ts
6400
+ import { PostgresSaver } from "@langchain/langgraph-checkpoint-postgres";
5804
6401
  function createPgStoreConfig(connectionString) {
5805
- const opts = { poolConfig: connectionString, autoMigrate: false };
5806
- const optsAuto = { poolConfig: connectionString, autoMigrate: true };
6402
+ const opts = { poolConfig: connectionString, autoMigrate: true };
6403
+ const checkpoint = PostgresSaver.fromConnString(connectionString);
6404
+ checkpoint.setup().catch((err) => {
6405
+ console.error("[pg-stores] Failed to setup checkpoint table:", err.message || err);
6406
+ });
5807
6407
  return {
5808
6408
  workspace: new PostgreSQLWorkspaceStore(opts),
5809
6409
  project: new PostgreSQLProjectStore(opts),
5810
- eval: new PostgreSQLEvalStore(optsAuto),
6410
+ eval: new PostgreSQLEvalStore(opts),
5811
6411
  user: new PostgreSQLUserStore(opts),
5812
6412
  tenant: new PostgreSQLTenantStore(opts),
5813
6413
  userTenantLink: new PostgreSQLUserTenantLinkStore(opts),
5814
- channelBinding: new ChannelBindingStore(optsAuto),
5815
- channelInstallation: new PostgreSQLChannelInstallationStore(optsAuto),
6414
+ channelBinding: new ChannelBindingStore(opts),
6415
+ channelInstallation: new PostgreSQLChannelInstallationStore(opts),
5816
6416
  thread: new PostgreSQLThreadStore(opts),
5817
6417
  database: new PostgreSQLDatabaseConfigStore(opts),
5818
6418
  metrics: new PostgreSQLMetricsServerConfigStore(opts),
5819
6419
  mcp: new PostgreSQLMcpServerConfigStore(opts),
5820
6420
  assistant: new PostgreSQLAssistantStore(opts),
5821
- workflowTracking: new PostgreSQLWorkflowTrackingStore(optsAuto),
5822
- threadMessageQueue: new ThreadMessageQueueStore(optsAuto),
5823
- a2aApiKey: new PostgreSQLA2AApiKeyStore(optsAuto),
5824
- schedule: new PostgreSQLScheduleStorage(opts)
6421
+ workflowTracking: new PostgreSQLWorkflowTrackingStore(opts),
6422
+ threadMessageQueue: new ThreadMessageQueueStore(opts),
6423
+ task: new PostgreSQLTaskStore(opts),
6424
+ a2aApiKey: new PostgreSQLA2AApiKeyStore(opts),
6425
+ schedule: new PostgreSQLScheduleStorage(opts),
6426
+ menu: new MenuStore(opts),
6427
+ checkpoint
5825
6428
  };
5826
6429
  }
5827
6430
 
5828
6431
  // src/stores/PostgreSQLSkillStore.ts
5829
- import { Pool as Pool18 } from "pg";
6432
+ import { Pool as Pool20 } from "pg";
5830
6433
 
5831
6434
  // src/migrations/skill_migrations.ts
5832
6435
  var createSkillsTable = {
@@ -5988,9 +6591,9 @@ var PostgreSQLSkillStore = class {
5988
6591
  this.ownsPool = true;
5989
6592
  this.initPromise = null;
5990
6593
  if (typeof options.poolConfig === "string") {
5991
- this.pool = new Pool18({ connectionString: options.poolConfig });
6594
+ this.pool = new Pool20({ connectionString: options.poolConfig });
5992
6595
  } else {
5993
- this.pool = new Pool18(options.poolConfig);
6596
+ this.pool = new Pool20(options.poolConfig);
5994
6597
  }
5995
6598
  this.migrationManager = new MigrationManager(this.pool);
5996
6599
  this.migrationManager.register(createSkillsTable);
@@ -6344,12 +6947,12 @@ var createChannelIdentityMappingTables = {
6344
6947
  };
6345
6948
 
6346
6949
  // src/stores/ChannelIdentityMappingStore.ts
6347
- import { Pool as Pool19 } from "pg";
6950
+ import { Pool as Pool21 } from "pg";
6348
6951
  var ChannelIdentityMappingStore = class {
6349
6952
  constructor(options) {
6350
6953
  this.initialized = false;
6351
6954
  this.initPromise = null;
6352
- this.pool = typeof options.poolConfig === "string" ? new Pool19({ connectionString: options.poolConfig }) : new Pool19(options.poolConfig);
6955
+ this.pool = typeof options.poolConfig === "string" ? new Pool21({ connectionString: options.poolConfig }) : new Pool21(options.poolConfig);
6353
6956
  this.migrationManager = new MigrationManager(this.pool);
6354
6957
  this.migrationManager.register(createChannelIdentityMappingTables);
6355
6958
  if (options.autoMigrate !== false) {
@@ -6563,8 +7166,9 @@ function mapRowToChannelIdentityMapping(row) {
6563
7166
  export {
6564
7167
  ChannelBindingStore,
6565
7168
  ChannelIdentityMappingStore,
7169
+ MenuStore,
6566
7170
  MigrationManager,
6567
- Pool20 as Pool,
7171
+ Pool22 as Pool,
6568
7172
  PostgreSQLA2AApiKeyStore,
6569
7173
  PostgreSQLAssistantStore,
6570
7174
  PostgreSQLChannelInstallationStore,
@@ -6586,6 +7190,7 @@ export {
6586
7190
  addProjectConfigColumn,
6587
7191
  addScheduleTenantId,
6588
7192
  addSkillTenantId,
7193
+ addStepThreadId,
6589
7194
  addThreadTenantId,
6590
7195
  alterChannelInstallationsTable,
6591
7196
  changeAssistantPrimaryKey,
@@ -6603,6 +7208,7 @@ export {
6603
7208
  createEvalRunsTable,
6604
7209
  createEvalSuitesTable,
6605
7210
  createMcpServerConfigsTable,
7211
+ createMenuItemsTable,
6606
7212
  createMetricsConfigsTable,
6607
7213
  createPgStoreConfig,
6608
7214
  createProjectsTable,