@pantheon.ai/agents 0.2.2 → 0.3.0

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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +181 -21
  3. package/package.json +4 -2
package/README.md CHANGED
@@ -13,6 +13,7 @@
13
13
  Create/update `.env`:
14
14
 
15
15
  ```bash
16
+ # Use mysql://... for TiDB, or postgresql://... for db9.
16
17
  DATABASE_URL=mysql://root@127.0.0.1:4000/pantheon_agents
17
18
  PANTHEON_API_KEY=<your_pantheon_api_key>
18
19
  DEFAULT_PANTHEON_PROJECT_ID=<optional_default_project_id>
package/dist/index.js CHANGED
@@ -5,9 +5,10 @@ import process$1 from "node:process";
5
5
  import * as fs from "node:fs";
6
6
  import path from "node:path";
7
7
  import { multistream, pino, transport } from "pino";
8
- import { Kysely, MysqlDialect } from "kysely";
9
- import { createPool } from "mysql2";
8
+ import { Kysely, MysqlDialect, PostgresDialect } from "kysely";
9
+ import { Pool } from "pg";
10
10
  import z$1, { z } from "zod";
11
+ import { createPool } from "mysql2";
11
12
  import readline from "node:readline/promises";
12
13
  import expandTilde from "expand-tilde";
13
14
  import blessed from "reblessed";
@@ -399,18 +400,16 @@ var require_cli_options = /* @__PURE__ */ __commonJSMin(((exports, module) => {
399
400
  var version = "0.2.2";
400
401
 
401
402
  //#endregion
402
- //#region src/db/tidb.ts
403
- function createTidbPoolOptions(databaseUrl) {
403
+ //#region src/db/db9.ts
404
+ function createDb9PoolOptions(databaseUrl) {
404
405
  return {
405
- uri: databaseUrl,
406
- supportBigNumbers: true,
407
- bigNumberStrings: true,
408
- timezone: "Z"
406
+ connectionString: databaseUrl,
407
+ ssl: process.env.DB9_INSECURE === "true" ? { rejectUnauthorized: false } : true
409
408
  };
410
409
  }
411
- function createTidbDb(databaseUrl = process.env.DATABASE_URL) {
410
+ function createDb9Db(databaseUrl = process.env.DATABASE_URL) {
412
411
  if (!databaseUrl) throw new Error("DATABASE_URL environment variable is not set.");
413
- return new Kysely({ dialect: new MysqlDialect({ pool: createPool(createTidbPoolOptions(databaseUrl)) }) });
412
+ return new Kysely({ dialect: new PostgresDialect({ pool: new Pool(createDb9PoolOptions(databaseUrl)) }) });
414
413
  }
415
414
 
416
415
  //#endregion
@@ -602,6 +601,140 @@ var TaskListProvider = class {
602
601
  }
603
602
  };
604
603
 
604
+ //#endregion
605
+ //#region src/providers/task-list-db9-provider.ts
606
+ var TaskListDb9Provider = class extends TaskListProvider {
607
+ db;
608
+ ownsDb;
609
+ constructor(agentName, logger, options = {}) {
610
+ super(agentName, logger);
611
+ if (options.db) {
612
+ this.db = options.db;
613
+ this.ownsDb = false;
614
+ } else {
615
+ this.db = createDb9Db();
616
+ this.ownsDb = true;
617
+ }
618
+ }
619
+ async close() {
620
+ if (this.ownsDb) await this.db.destroy();
621
+ }
622
+ selectTask() {
623
+ return this.db.selectFrom("task").selectAll().where("agent", "=", this.agentName);
624
+ }
625
+ async getAgentConfig(projectId) {
626
+ const config = await this.db.selectFrom("agent_project_config").innerJoin("task", "task.id", "agent_project_config.config_task_id").select([
627
+ "agent_project_config.agent",
628
+ "agent_project_config.project_id",
629
+ "agent_project_config.base_branch_id",
630
+ "agent_project_config.config_version",
631
+ "agent_project_config.config_task_id",
632
+ "agent_project_config.concurrency",
633
+ "agent_project_config.role",
634
+ "agent_project_config.skills",
635
+ "agent_project_config.prototype_url",
636
+ "agent_project_config.execute_agent"
637
+ ]).select((eb) => eb.ref("task.status").$castTo().as("config_task_status")).where("agent_project_config.project_id", "=", projectId).where("agent_project_config.agent", "=", this.agentName).executeTakeFirst();
638
+ if (config == null) return null;
639
+ return config;
640
+ }
641
+ async getAgentConfigs() {
642
+ return await this.db.selectFrom("agent_project_config").innerJoin("task", "task.id", "agent_project_config.config_task_id").select([
643
+ "agent_project_config.agent",
644
+ "agent_project_config.project_id",
645
+ "agent_project_config.base_branch_id",
646
+ "agent_project_config.config_version",
647
+ "agent_project_config.config_task_id",
648
+ "agent_project_config.concurrency",
649
+ "agent_project_config.role",
650
+ "agent_project_config.skills",
651
+ "agent_project_config.prototype_url",
652
+ "agent_project_config.execute_agent"
653
+ ]).select((eb) => eb.ref("task.status").$castTo().as("config_task_status")).where("agent_project_config.agent", "=", this.agentName).execute();
654
+ }
655
+ async setAgentConfig({ skills, ...config }) {
656
+ await this.db.insertInto("agent_project_config").values({
657
+ agent: this.agentName,
658
+ skills: JSON.stringify(skills),
659
+ ...config
660
+ }).execute();
661
+ }
662
+ async updateAgentConfig({ skills, ...config }) {
663
+ const result = await this.db.updateTable("agent_project_config").set({
664
+ skills: JSON.stringify(skills),
665
+ ...config
666
+ }).where("agent", "=", this.agentName).where("project_id", "=", config.project_id).executeTakeFirst();
667
+ if (Number(result.numUpdatedRows ?? 0) === 0) throw new Error(`No config found to update for agent ${this.agentName} and project ${config.project_id}.`);
668
+ }
669
+ async getTask(taskId) {
670
+ const taskItem = await this.selectTask().where("id", "=", taskId).executeTakeFirst();
671
+ if (taskItem == null) return null;
672
+ return taskItemSchema.parse(taskItem);
673
+ }
674
+ async getTasks({ status, order_by, order_direction = "asc", from, limit, type, min_config_version, max_config_version, parent_task_id, project_id } = {}) {
675
+ let builder = this.selectTask();
676
+ if (status && status.length > 0) builder = builder.where("status", "in", status);
677
+ if (from) builder = builder.where("queued_at", ">=", from);
678
+ if (type) builder = builder.where("type", "=", type);
679
+ if (min_config_version != null) builder = builder.where("config_version", ">=", min_config_version);
680
+ if (max_config_version != null) builder = builder.where("config_version", "<=", max_config_version);
681
+ if (parent_task_id === null) builder = builder.where("parent_task_id", "is", null);
682
+ else if (parent_task_id) builder = builder.where("parent_task_id", "=", parent_task_id);
683
+ if (project_id != null) builder = builder.where("project_id", "=", project_id);
684
+ if (order_by) builder = builder.orderBy(order_by, order_direction);
685
+ if (limit != null) builder = builder.limit(limit);
686
+ return (await builder.execute()).map((item) => taskItemSchema.parse(item));
687
+ }
688
+ async listAgentNames() {
689
+ const [taskAgents, configAgents] = await Promise.all([this.db.selectFrom("task").select("agent").distinct().execute(), this.db.selectFrom("agent_project_config").select("agent").distinct().execute()]);
690
+ const agents = /* @__PURE__ */ new Set();
691
+ for (const item of taskAgents) agents.add(item.agent);
692
+ for (const item of configAgents) agents.add(item.agent);
693
+ return Array.from(agents).sort();
694
+ }
695
+ async updateTask(taskItem) {
696
+ const { id, started_at, ended_at, queued_at, cancelled_at, ...rest } = taskItem;
697
+ await this.db.updateTable("task").set({
698
+ started_at,
699
+ ended_at,
700
+ queued_at,
701
+ cancelled_at,
702
+ ...rest
703
+ }).where("id", "=", id).where("agent", "=", this.agentName).execute();
704
+ }
705
+ async insertTask(taskItem) {
706
+ const { started_at, ended_at, queued_at, cancelled_at, ...rest } = taskItem;
707
+ const inserted = await this.db.insertInto("task").values({
708
+ agent: this.agentName,
709
+ started_at,
710
+ ended_at,
711
+ queued_at,
712
+ cancelled_at,
713
+ ...rest
714
+ }).returningAll().executeTakeFirstOrThrow();
715
+ return taskItemSchema.parse(inserted);
716
+ }
717
+ async deleteTask(taskId) {
718
+ const result = await this.db.deleteFrom("task").where("id", "=", taskId).where("agent", "=", this.agentName).executeTakeFirst();
719
+ return Number(result.numDeletedRows ?? 0) > 0;
720
+ }
721
+ };
722
+
723
+ //#endregion
724
+ //#region src/db/tidb.ts
725
+ function createTidbPoolOptions(databaseUrl) {
726
+ return {
727
+ uri: databaseUrl,
728
+ supportBigNumbers: true,
729
+ bigNumberStrings: true,
730
+ timezone: "Z"
731
+ };
732
+ }
733
+ function createTidbDb(databaseUrl = process.env.DATABASE_URL) {
734
+ if (!databaseUrl) throw new Error("DATABASE_URL environment variable is not set.");
735
+ return new Kysely({ dialect: new MysqlDialect({ pool: createPool(createTidbPoolOptions(databaseUrl)) }) });
736
+ }
737
+
605
738
  //#endregion
606
739
  //#region src/providers/task-list-tidb-provider.ts
607
740
  var TaskListTidbProvider = class extends TaskListProvider {
@@ -702,6 +835,28 @@ var TaskListTidbProvider = class extends TaskListProvider {
702
835
  }
703
836
  };
704
837
 
838
+ //#endregion
839
+ //#region src/providers/task-list-provider-factory.ts
840
+ function getDatabaseProtocol(databaseUrl) {
841
+ try {
842
+ return new URL(databaseUrl).protocol.toLowerCase();
843
+ } catch {
844
+ throw new Error("Invalid DATABASE_URL. Expected a URL starting with mysql:// or postgresql://.");
845
+ }
846
+ }
847
+ function resolveTaskListProviderKind(databaseUrl) {
848
+ const protocol = getDatabaseProtocol(databaseUrl);
849
+ if (protocol === "mysql:") return "tidb";
850
+ if (protocol === "postgresql:") return "db9";
851
+ throw new Error(`Unsupported DATABASE_URL protocol '${protocol}'. Use mysql:// for TiDB or postgresql:// for db9.`);
852
+ }
853
+ function createTaskListProvider(agentName, logger) {
854
+ const databaseUrl = process.env.DATABASE_URL?.trim();
855
+ if (!databaseUrl) throw new Error("DATABASE_URL environment variable is not set.");
856
+ if (resolveTaskListProviderKind(databaseUrl) === "db9") return new TaskListDb9Provider(agentName, logger);
857
+ return new TaskListTidbProvider(agentName, logger);
858
+ }
859
+
705
860
  //#endregion
706
861
  //#region src/core/agent-config-utils.ts
707
862
  function normalizeRepoUrl(value) {
@@ -1929,7 +2084,7 @@ async function startTaskListLoop(agentName, { loopInterval = 5 }, logger) {
1929
2084
  abortController.abort(signal);
1930
2085
  process.exit(1);
1931
2086
  });
1932
- const provider = new TaskListTidbProvider(agentName, logger);
2087
+ const provider = createTaskListProvider(agentName, logger);
1933
2088
  while (!abortController.signal.aborted) {
1934
2089
  const loopIndex = i++;
1935
2090
  await loopOnce(provider, logger.child({ name: `loop:${loopIndex}` }));
@@ -2575,7 +2730,7 @@ function resolveConfigRole(options) {
2575
2730
  return { error: "--role is required for first-time config in a project." };
2576
2731
  }
2577
2732
  async function configAgent(name, options) {
2578
- const provider = new TaskListTidbProvider(name, pino());
2733
+ const provider = createTaskListProvider(name, pino());
2579
2734
  try {
2580
2735
  const previousConfig = await provider.getAgentConfig(options.projectId);
2581
2736
  const resolvedRoleResult = resolveConfigRole({
@@ -2735,7 +2890,7 @@ async function resolveInitialBaseBranchId(projectId, rootBranchId) {
2735
2890
  return project.root_branch_id;
2736
2891
  }
2737
2892
  async function addTask(name, options) {
2738
- const provider = new TaskListTidbProvider(name, pino());
2893
+ const provider = createTaskListProvider(name, pino());
2739
2894
  try {
2740
2895
  const config = await provider.getAgentConfig(options.projectId);
2741
2896
  if (!config) throw new Error(`Agent ${name} not configured for project ${options.projectId}`);
@@ -2751,7 +2906,7 @@ async function addTask(name, options) {
2751
2906
  }
2752
2907
  }
2753
2908
  async function deleteTask(agentName, taskId) {
2754
- const provider = new TaskListTidbProvider(agentName, pino());
2909
+ const provider = createTaskListProvider(agentName, pino());
2755
2910
  try {
2756
2911
  const task = await provider.getTask(taskId);
2757
2912
  if (!task) return null;
@@ -2762,7 +2917,7 @@ async function deleteTask(agentName, taskId) {
2762
2917
  }
2763
2918
  }
2764
2919
  async function getTask(agentName, taskId) {
2765
- const provider = new TaskListTidbProvider(agentName, pino());
2920
+ const provider = createTaskListProvider(agentName, pino());
2766
2921
  try {
2767
2922
  return await provider.getTask(taskId);
2768
2923
  } finally {
@@ -2770,7 +2925,7 @@ async function getTask(agentName, taskId) {
2770
2925
  }
2771
2926
  }
2772
2927
  async function cancelTask(agentName, taskId, reason) {
2773
- const provider = new TaskListTidbProvider(agentName, pino());
2928
+ const provider = createTaskListProvider(agentName, pino());
2774
2929
  try {
2775
2930
  const task = await provider.getTask(taskId);
2776
2931
  if (!task) return null;
@@ -2782,7 +2937,7 @@ async function cancelTask(agentName, taskId, reason) {
2782
2937
  }
2783
2938
  }
2784
2939
  async function showAgentConfig(agentName, projectId) {
2785
- const provider = new TaskListTidbProvider(agentName, pino());
2940
+ const provider = createTaskListProvider(agentName, pino());
2786
2941
  try {
2787
2942
  return await provider.getAgentConfig(projectId);
2788
2943
  } finally {
@@ -2790,7 +2945,7 @@ async function showAgentConfig(agentName, projectId) {
2790
2945
  }
2791
2946
  }
2792
2947
  async function showAgentConfigs(agentName) {
2793
- const provider = new TaskListTidbProvider(agentName, pino());
2948
+ const provider = createTaskListProvider(agentName, pino());
2794
2949
  try {
2795
2950
  return await provider.getAgentConfigs();
2796
2951
  } finally {
@@ -2798,7 +2953,7 @@ async function showAgentConfigs(agentName) {
2798
2953
  }
2799
2954
  }
2800
2955
  async function showTasks(name, options) {
2801
- const provider = new TaskListTidbProvider(name, pino());
2956
+ const provider = createTaskListProvider(name, pino());
2802
2957
  try {
2803
2958
  return await provider.getTasks({
2804
2959
  status: options.status,
@@ -2811,7 +2966,7 @@ async function showTasks(name, options) {
2811
2966
  }
2812
2967
  }
2813
2968
  async function listAgentNames() {
2814
- const provider = new TaskListTidbProvider("list-agents", pino());
2969
+ const provider = createTaskListProvider("list-agents", pino());
2815
2970
  try {
2816
2971
  return await provider.listAgentNames();
2817
2972
  } finally {
@@ -5068,6 +5223,11 @@ async function resolveWatchTargets(options) {
5068
5223
  warnings
5069
5224
  };
5070
5225
  }
5226
+ function createWatchDb() {
5227
+ const databaseUrl = process.env.DATABASE_URL?.trim();
5228
+ if (!databaseUrl) throw new Error("DATABASE_URL environment variable is not set.");
5229
+ return resolveTaskListProviderKind(databaseUrl) === "db9" ? createDb9Db() : createTidbDb();
5230
+ }
5071
5231
  const ANSI = {
5072
5232
  reset: "\x1B[0m",
5073
5233
  bold: "\x1B[1m",
@@ -5153,7 +5313,7 @@ function createWatchCommand(version) {
5153
5313
  console.error("Use either --tasks or --agents, not both.");
5154
5314
  process.exit(1);
5155
5315
  }
5156
- const db = createTidbDb();
5316
+ const db = createWatchDb();
5157
5317
  try {
5158
5318
  const { targets, warnings } = await resolveWatchTargets({
5159
5319
  db,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pantheon.ai/agents",
3
3
  "type": "module",
4
- "version": "0.2.2",
4
+ "version": "0.3.0",
5
5
  "bin": {
6
6
  "pantheon-agents": "dist/index.js"
7
7
  },
@@ -17,15 +17,17 @@
17
17
  "test": "bun test",
18
18
  "test:coverage": "bun test --coverage",
19
19
  "dev:db:start": "tiup playground --without-monitor --tag pantheon-agents",
20
- "dev:db:gen": "kysely-codegen "
20
+ "dev:db:gen": "kysely-codegen --no-domains"
21
21
  },
22
22
  "dependencies": {
23
+ "@types/pg": "^8.18.0",
23
24
  "@types/shell-quote": "^1.7.5",
24
25
  "commander": "^14.0.3",
25
26
  "dotenv": "^17.2.4",
26
27
  "expand-tilde": "^2.0.2",
27
28
  "kysely": "^0.28.11",
28
29
  "mysql2": "^3.16.3",
30
+ "pg": "^8.19.0",
29
31
  "pino": "^10.3.0",
30
32
  "pino-pretty": "^13.1.3",
31
33
  "pino-roll": "^4.0.0",