@axiom-lattice/pg-stores 1.0.71 → 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,
@@ -3195,7 +3264,15 @@ var PostgreSQLWorkflowTrackingStore = class {
3195
3264
  [request.runId, request.stepType, request.stepName]
3196
3265
  );
3197
3266
  if (result.rows.length > 0) {
3198
- return this.mapRowToRunStep(result.rows[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;
3199
3276
  }
3200
3277
  return this.createRunStep(request);
3201
3278
  }
@@ -3283,6 +3360,7 @@ var PostgreSQLWorkflowTrackingStore = class {
3283
3360
  tenantId: row.tenant_id,
3284
3361
  stepType: row.step_type,
3285
3362
  stepName: row.step_name,
3363
+ threadId: row.thread_id,
3286
3364
  edgeFrom: row.edge_from,
3287
3365
  edgeTo: row.edge_to,
3288
3366
  edgePurpose: row.edge_purpose,
@@ -4335,6 +4413,30 @@ var alterMessageQueueIdColumn = {
4335
4413
  }
4336
4414
  };
4337
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
+
4338
4440
  // src/stores/ThreadMessageQueueStore.ts
4339
4441
  var ThreadMessageQueueStore = class {
4340
4442
  constructor(options) {
@@ -4351,6 +4453,7 @@ var ThreadMessageQueueStore = class {
4351
4453
  this.migrationManager.register(addPriorityAndCommandColumns);
4352
4454
  this.migrationManager.register(addCustomRunConfigColumn);
4353
4455
  this.migrationManager.register(alterMessageQueueIdColumn);
4456
+ this.migrationManager.register(addWorkspaceProjectToQueue);
4354
4457
  if (options.autoMigrate !== false) {
4355
4458
  this.initialize().catch((error) => {
4356
4459
  console.error("Failed to initialize ThreadMessageQueueStore:", error);
@@ -4380,7 +4483,7 @@ var ThreadMessageQueueStore = class {
4380
4483
  * Add message to queue
4381
4484
  */
4382
4485
  async addMessage(params) {
4383
- 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;
4384
4487
  const seqResult = await this.pool.query(
4385
4488
  `SELECT COALESCE(MAX(sequence_order), 0) + 1 as next_seq
4386
4489
  FROM lattice_thread_message_queue
@@ -4390,10 +4493,10 @@ var ThreadMessageQueueStore = class {
4390
4493
  const nextSeq = seqResult.rows[0].next_seq;
4391
4494
  const result = await this.pool.query(
4392
4495
  `INSERT INTO lattice_thread_message_queue
4393
- (id, thread_id, tenant_id, assistant_id, message_content, message_type, sequence_order, priority, command, custom_run_config)
4394
- 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)
4395
4498
  RETURNING *`,
4396
- [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]
4397
4500
  );
4398
4501
  return this.rowToMessage(result.rows[0]);
4399
4502
  }
@@ -4402,7 +4505,7 @@ var ThreadMessageQueueStore = class {
4402
4505
  * Uses priority=100 to ensure message is processed first
4403
4506
  */
4404
4507
  async addMessageAtHead(params) {
4405
- 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;
4406
4509
  const resolvedTenantId = tenantId;
4407
4510
  const resolvedAssistantId = assistantId;
4408
4511
  const seqResult = await this.pool.query(
@@ -4414,10 +4517,10 @@ var ThreadMessageQueueStore = class {
4414
4517
  const nextSeq = seqResult.rows[0].next_seq;
4415
4518
  const result = await this.pool.query(
4416
4519
  `INSERT INTO lattice_thread_message_queue
4417
- (id, thread_id, tenant_id, assistant_id, message_content, message_type, sequence_order, priority, command, custom_run_config)
4418
- 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)
4419
4522
  RETURNING *`,
4420
- [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]
4421
4524
  );
4422
4525
  return this.rowToMessage(result.rows[0]);
4423
4526
  }
@@ -4461,7 +4564,7 @@ var ThreadMessageQueueStore = class {
4461
4564
  */
4462
4565
  async getThreadsWithPendingMessages() {
4463
4566
  const result = await this.pool.query(
4464
- `SELECT DISTINCT tenant_id, assistant_id, thread_id
4567
+ `SELECT DISTINCT ON (thread_id) tenant_id, assistant_id, thread_id, workspace_id, project_id
4465
4568
  FROM lattice_thread_message_queue
4466
4569
  WHERE status IN ('pending', 'processing')
4467
4570
  ORDER BY thread_id`
@@ -4469,7 +4572,9 @@ var ThreadMessageQueueStore = class {
4469
4572
  return result.rows.map((row) => ({
4470
4573
  tenantId: row.tenant_id,
4471
4574
  assistantId: row.assistant_id,
4472
- threadId: row.thread_id
4575
+ threadId: row.thread_id,
4576
+ workspaceId: row.workspace_id || void 0,
4577
+ projectId: row.project_id || void 0
4473
4578
  }));
4474
4579
  }
4475
4580
  /**
@@ -4896,6 +5001,25 @@ var PostgreSQLChannelInstallationStore = class {
4896
5001
  );
4897
5002
  return result.rows.map((row) => this.mapRowToInstallation(row));
4898
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
+ }
4899
5023
  async createInstallation(tenantId, installationId, data) {
4900
5024
  await this.ensureInitialized();
4901
5025
  const now = /* @__PURE__ */ new Date();
@@ -5811,33 +5935,501 @@ var PostgreSQLScheduleStorage = class {
5811
5935
  }
5812
5936
  };
5813
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
+
5814
6399
  // src/createPgStoreConfig.ts
6400
+ import { PostgresSaver } from "@langchain/langgraph-checkpoint-postgres";
5815
6401
  function createPgStoreConfig(connectionString) {
5816
- const opts = { poolConfig: connectionString, autoMigrate: false };
5817
- 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
+ });
5818
6407
  return {
5819
6408
  workspace: new PostgreSQLWorkspaceStore(opts),
5820
6409
  project: new PostgreSQLProjectStore(opts),
5821
- eval: new PostgreSQLEvalStore(optsAuto),
6410
+ eval: new PostgreSQLEvalStore(opts),
5822
6411
  user: new PostgreSQLUserStore(opts),
5823
6412
  tenant: new PostgreSQLTenantStore(opts),
5824
6413
  userTenantLink: new PostgreSQLUserTenantLinkStore(opts),
5825
- channelBinding: new ChannelBindingStore(optsAuto),
5826
- channelInstallation: new PostgreSQLChannelInstallationStore(optsAuto),
6414
+ channelBinding: new ChannelBindingStore(opts),
6415
+ channelInstallation: new PostgreSQLChannelInstallationStore(opts),
5827
6416
  thread: new PostgreSQLThreadStore(opts),
5828
6417
  database: new PostgreSQLDatabaseConfigStore(opts),
5829
6418
  metrics: new PostgreSQLMetricsServerConfigStore(opts),
5830
6419
  mcp: new PostgreSQLMcpServerConfigStore(opts),
5831
6420
  assistant: new PostgreSQLAssistantStore(opts),
5832
- workflowTracking: new PostgreSQLWorkflowTrackingStore(optsAuto),
5833
- threadMessageQueue: new ThreadMessageQueueStore(optsAuto),
5834
- a2aApiKey: new PostgreSQLA2AApiKeyStore(optsAuto),
5835
- 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
5836
6428
  };
5837
6429
  }
5838
6430
 
5839
6431
  // src/stores/PostgreSQLSkillStore.ts
5840
- import { Pool as Pool18 } from "pg";
6432
+ import { Pool as Pool20 } from "pg";
5841
6433
 
5842
6434
  // src/migrations/skill_migrations.ts
5843
6435
  var createSkillsTable = {
@@ -5999,9 +6591,9 @@ var PostgreSQLSkillStore = class {
5999
6591
  this.ownsPool = true;
6000
6592
  this.initPromise = null;
6001
6593
  if (typeof options.poolConfig === "string") {
6002
- this.pool = new Pool18({ connectionString: options.poolConfig });
6594
+ this.pool = new Pool20({ connectionString: options.poolConfig });
6003
6595
  } else {
6004
- this.pool = new Pool18(options.poolConfig);
6596
+ this.pool = new Pool20(options.poolConfig);
6005
6597
  }
6006
6598
  this.migrationManager = new MigrationManager(this.pool);
6007
6599
  this.migrationManager.register(createSkillsTable);
@@ -6355,12 +6947,12 @@ var createChannelIdentityMappingTables = {
6355
6947
  };
6356
6948
 
6357
6949
  // src/stores/ChannelIdentityMappingStore.ts
6358
- import { Pool as Pool19 } from "pg";
6950
+ import { Pool as Pool21 } from "pg";
6359
6951
  var ChannelIdentityMappingStore = class {
6360
6952
  constructor(options) {
6361
6953
  this.initialized = false;
6362
6954
  this.initPromise = null;
6363
- 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);
6364
6956
  this.migrationManager = new MigrationManager(this.pool);
6365
6957
  this.migrationManager.register(createChannelIdentityMappingTables);
6366
6958
  if (options.autoMigrate !== false) {
@@ -6574,8 +7166,9 @@ function mapRowToChannelIdentityMapping(row) {
6574
7166
  export {
6575
7167
  ChannelBindingStore,
6576
7168
  ChannelIdentityMappingStore,
7169
+ MenuStore,
6577
7170
  MigrationManager,
6578
- Pool20 as Pool,
7171
+ Pool22 as Pool,
6579
7172
  PostgreSQLA2AApiKeyStore,
6580
7173
  PostgreSQLAssistantStore,
6581
7174
  PostgreSQLChannelInstallationStore,
@@ -6597,6 +7190,7 @@ export {
6597
7190
  addProjectConfigColumn,
6598
7191
  addScheduleTenantId,
6599
7192
  addSkillTenantId,
7193
+ addStepThreadId,
6600
7194
  addThreadTenantId,
6601
7195
  alterChannelInstallationsTable,
6602
7196
  changeAssistantPrimaryKey,
@@ -6614,6 +7208,7 @@ export {
6614
7208
  createEvalRunsTable,
6615
7209
  createEvalSuitesTable,
6616
7210
  createMcpServerConfigsTable,
7211
+ createMenuItemsTable,
6617
7212
  createMetricsConfigsTable,
6618
7213
  createPgStoreConfig,
6619
7214
  createProjectsTable,