@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.
- package/README.md +1 -0
- package/dist/index.js +181 -21
- 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 {
|
|
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/
|
|
403
|
-
function
|
|
403
|
+
//#region src/db/db9.ts
|
|
404
|
+
function createDb9PoolOptions(databaseUrl) {
|
|
404
405
|
return {
|
|
405
|
-
|
|
406
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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.
|
|
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",
|