@pantheon.ai/agents 0.3.2 → 0.3.3

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.
@@ -0,0 +1,5 @@
1
+ -- introduced_in: 0.3.2
2
+ -- Add optional env overrides for per-project agent config (db9/PostgreSQL).
3
+
4
+ ALTER TABLE agent_project_config
5
+ ADD COLUMN IF NOT EXISTS envs JSONB;
@@ -0,0 +1,5 @@
1
+ -- introduced_in: 0.3.2
2
+ -- Add optional env overrides for per-project agent config (TiDB/MySQL).
3
+
4
+ ALTER TABLE agent_project_config
5
+ ADD COLUMN IF NOT EXISTS envs JSON NULL;
package/dist/index.js CHANGED
@@ -399,7 +399,7 @@ var require_cli_options = /* @__PURE__ */ __commonJSMin(((exports, module) => {
399
399
 
400
400
  //#endregion
401
401
  //#region package.json
402
- var version = "0.3.1";
402
+ var version = "0.3.3";
403
403
 
404
404
  //#endregion
405
405
  //#region src/db/db9.ts
@@ -639,6 +639,7 @@ var TaskListDb9Provider = class extends TaskListProvider {
639
639
  "agent_project_config.retry_backoff_seconds",
640
640
  "agent_project_config.role",
641
641
  "agent_project_config.skills",
642
+ "agent_project_config.envs",
642
643
  "agent_project_config.prototype_url",
643
644
  "agent_project_config.execute_agent"
644
645
  ]).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();
@@ -657,26 +658,30 @@ var TaskListDb9Provider = class extends TaskListProvider {
657
658
  "agent_project_config.retry_backoff_seconds",
658
659
  "agent_project_config.role",
659
660
  "agent_project_config.skills",
661
+ "agent_project_config.envs",
660
662
  "agent_project_config.prototype_url",
661
663
  "agent_project_config.execute_agent"
662
664
  ]).select((eb) => eb.ref("task.status").$castTo().as("config_task_status")).where("agent_project_config.agent", "=", this.agentName).execute();
663
665
  }
664
- async setAgentConfig({ skills, ...config }) {
666
+ async setAgentConfig({ skills, envs, ...config }) {
665
667
  const maxRetryAttempts = config.max_retry_attempts ?? 3;
666
668
  const retryBackoffSeconds = config.retry_backoff_seconds ?? 30;
667
669
  await this.db.insertInto("agent_project_config").values({
668
670
  agent: this.agentName,
669
671
  skills: JSON.stringify(skills),
672
+ envs: JSON.stringify(envs ?? {}),
670
673
  ...config,
671
674
  max_retry_attempts: maxRetryAttempts,
672
675
  retry_backoff_seconds: retryBackoffSeconds
673
676
  }).execute();
674
677
  }
675
- async updateAgentConfig({ skills, ...config }) {
678
+ async updateAgentConfig({ skills, envs, ...config }) {
676
679
  const maxRetryAttempts = config.max_retry_attempts;
677
680
  const retryBackoffSeconds = config.retry_backoff_seconds;
681
+ const resolvedEnvs = envs == null ? void 0 : JSON.stringify(envs);
678
682
  const result = await this.db.updateTable("agent_project_config").set({
679
683
  skills: JSON.stringify(skills),
684
+ ...resolvedEnvs == null ? {} : { envs: resolvedEnvs },
680
685
  ...config,
681
686
  ...maxRetryAttempts == null ? {} : { max_retry_attempts: maxRetryAttempts },
682
687
  ...retryBackoffSeconds == null ? {} : { retry_backoff_seconds: retryBackoffSeconds }
@@ -783,22 +788,25 @@ var TaskListTidbProvider = class extends TaskListProvider {
783
788
  async getAgentConfigs() {
784
789
  return await this.db.selectFrom("agent_project_config").innerJoin("task", "task.id", "agent_project_config.config_task_id").selectAll("agent_project_config").select((eb) => eb.ref("task.status").$castTo().as("config_task_status")).where("agent_project_config.agent", "=", this.agentName).execute();
785
790
  }
786
- async setAgentConfig({ skills, ...config }) {
791
+ async setAgentConfig({ skills, envs, ...config }) {
787
792
  const maxRetryAttempts = config.max_retry_attempts ?? 3;
788
793
  const retryBackoffSeconds = config.retry_backoff_seconds ?? 30;
789
794
  await this.db.insertInto("agent_project_config").values({
790
795
  agent: this.agentName,
791
796
  skills: JSON.stringify(skills),
797
+ envs: JSON.stringify(envs ?? {}),
792
798
  ...config,
793
799
  max_retry_attempts: maxRetryAttempts,
794
800
  retry_backoff_seconds: retryBackoffSeconds
795
801
  }).execute();
796
802
  }
797
- async updateAgentConfig({ skills, ...config }) {
803
+ async updateAgentConfig({ skills, envs, ...config }) {
798
804
  const maxRetryAttempts = config.max_retry_attempts;
799
805
  const retryBackoffSeconds = config.retry_backoff_seconds;
806
+ const resolvedEnvs = envs == null ? void 0 : JSON.stringify(envs);
800
807
  const result = await this.db.updateTable("agent_project_config").set({
801
808
  skills: JSON.stringify(skills),
809
+ ...resolvedEnvs == null ? {} : { envs: resolvedEnvs },
802
810
  ...config,
803
811
  ...maxRetryAttempts == null ? {} : { max_retry_attempts: maxRetryAttempts },
804
812
  ...retryBackoffSeconds == null ? {} : { retry_backoff_seconds: retryBackoffSeconds }
@@ -902,6 +910,20 @@ function normalizeSkills(value) {
902
910
  }
903
911
  return [];
904
912
  }
913
+ function normalizeEnvs(value) {
914
+ const parseRecord = (input) => {
915
+ if (!input || typeof input !== "object" || Array.isArray(input)) return {};
916
+ const result = {};
917
+ for (const [key, item] of Object.entries(input)) if (typeof item === "string") result[key] = item;
918
+ return result;
919
+ };
920
+ if (typeof value === "string") try {
921
+ return parseRecord(JSON.parse(value));
922
+ } catch {
923
+ return {};
924
+ }
925
+ return parseRecord(value);
926
+ }
905
927
  function buildConfigSetupStep(options) {
906
928
  const prototypeRepoUrl = normalizeRepoUrl(options.prototypeRepoUrl);
907
929
  const skillsArg = JSON.stringify(options.skills.join(","));
@@ -1787,6 +1809,7 @@ const listProjectBackgroundTasks = defineApi(get`/api/v1/projects/${"projectId"}
1787
1809
  const createProjectExploration = defineApi(post`/api/v1/projects/${"projectId"}/explorations`, typeOf(), createExplorationResultSchema);
1788
1810
  const listProjectExplorations = defineApi(get`/api/v1/projects/${"projectId"}/explorations`, null, explorationSchema.array());
1789
1811
  const getProjectExplorationResult = defineApi(get`/api/v1/projects/${"projectId"}/explorations/${"explorationId"}/result`, null, explorationResultSchema);
1812
+ const killProjectBranch = defineApi(post`/api/v1/projects/${"projectId"}/branches/${"branchId"}/kill`, typeOf(), snapSchema.nullable());
1790
1813
  const getProjectBranchFs = defineApi(get`/api/v1/projects/${"projectId"}/branches/${"branchId"}/fs/${"path*"}`, null, FSResponseValidator);
1791
1814
  const getProjectBranchFsPreview = defineApi(get`/api/v1/projects/${"projectId"}/branches/${"branchId"}/preview/${"path*"}`, null, FSResponseValidator);
1792
1815
 
@@ -2027,7 +2050,6 @@ const executor = createApiExecutor({
2027
2050
  headers: { Authorization: `Bearer ${process.env.PANTHEON_API_KEY}` },
2028
2051
  validateResponse
2029
2052
  });
2030
- const killProjectBranchExecutionApi = defineApi(post`/api/v1/projects/${"projectId"}/branches/${"branchId"}/kill`, typeOf(), "raw");
2031
2053
  async function getPantheonProjectInfo({ projectId }) {
2032
2054
  return await executor.execute(getProject, { projectId }, null);
2033
2055
  }
@@ -2076,13 +2098,14 @@ async function getPantheonBranchInfo({ projectId, branchId }) {
2076
2098
  branchId
2077
2099
  }, null);
2078
2100
  }
2079
- async function executeOnPantheon({ projectId, branchId, prompt, agent }) {
2101
+ async function executeOnPantheon({ projectId, branchId, prompt, agent, envs }) {
2080
2102
  const promptSequence = Array.isArray(prompt) ? prompt : [prompt];
2081
2103
  return (await executor.execute(createProjectExploration, { projectId }, {
2082
2104
  shared_prompt_sequence: promptSequence,
2083
2105
  num_branches: 1,
2084
2106
  agent,
2085
- parent_branch_id: branchId
2107
+ parent_branch_id: branchId,
2108
+ envs
2086
2109
  })).branches[0];
2087
2110
  }
2088
2111
  function isNotFoundError(error) {
@@ -2092,7 +2115,7 @@ function isNotFoundError(error) {
2092
2115
  }
2093
2116
  async function killPantheonBranchExecution({ projectId, branchId }) {
2094
2117
  try {
2095
- await executor.execute(killProjectBranchExecutionApi, {
2118
+ await executor.execute(killProjectBranch, {
2096
2119
  projectId,
2097
2120
  branchId
2098
2121
  }, {});
@@ -2246,6 +2269,7 @@ async function pollRunningTaskState(provider, state, logger) {
2246
2269
  execute_agent: config.execute_agent,
2247
2270
  role: config.role,
2248
2271
  skills: normalizeSkills(config.skills),
2272
+ envs: normalizeEnvs(config.envs),
2249
2273
  prototype_url: config.prototype_url
2250
2274
  });
2251
2275
  } else if (newStatus.state === "failed") {
@@ -2350,7 +2374,8 @@ async function startPendingTask(provider, task, config, logger) {
2350
2374
  projectId: taskToStart.project_id,
2351
2375
  branchId: taskToStart.base_branch_id,
2352
2376
  prompt: promptSequence,
2353
- agent: config.execute_agent
2377
+ agent: config.execute_agent,
2378
+ envs: normalizeEnvs(config.envs)
2354
2379
  });
2355
2380
  });
2356
2381
  logger.info(`Task ${taskToStart.id} started successfully on branch [id = ${taskBranch.branch_id}, snap_id = ${taskBranch.latest_snap_id}]`);
@@ -2877,6 +2902,7 @@ async function configAgent(name, options) {
2877
2902
  return;
2878
2903
  }
2879
2904
  const resolvedSkills = options.skills ?? normalizeSkills(previousConfig?.skills);
2905
+ const resolvedEnvs = options.envs ?? normalizeEnvs(previousConfig?.envs);
2880
2906
  const resolvedExecuteAgent = options.executeAgent.trim() || previousConfig?.execute_agent || "codex";
2881
2907
  const resolvedPrototypeUrl = options.prototypeUrl.trim() || previousConfig?.prototype_url || "https://github.com/pingcap-inc/pantheon-agents";
2882
2908
  const baseBranchId = previousConfig ? previousConfig.base_branch_id : await resolveInitialBaseBranchId(options.projectId, options.rootBranchId);
@@ -2911,6 +2937,7 @@ async function configAgent(name, options) {
2911
2937
  execute_agent: resolvedExecuteAgent,
2912
2938
  role: resolvedRole ?? previousConfig.role,
2913
2939
  skills: resolvedSkills,
2940
+ envs: resolvedEnvs,
2914
2941
  prototype_url: resolvedPrototypeUrl
2915
2942
  });
2916
2943
  if (!options.prompt) await provider.updateTask({
@@ -2980,6 +3007,7 @@ async function configAgent(name, options) {
2980
3007
  execute_agent: resolvedExecuteAgent,
2981
3008
  role: resolvedRole,
2982
3009
  skills: resolvedSkills,
3010
+ envs: resolvedEnvs,
2983
3011
  prototype_url: resolvedPrototypeUrl
2984
3012
  });
2985
3013
  else await provider.updateAgentConfig({
@@ -2993,6 +3021,7 @@ async function configAgent(name, options) {
2993
3021
  execute_agent: resolvedExecuteAgent,
2994
3022
  role: resolvedRole ?? previousConfig.role,
2995
3023
  skills: resolvedSkills,
3024
+ envs: resolvedEnvs,
2996
3025
  prototype_url: resolvedPrototypeUrl
2997
3026
  });
2998
3027
  for (const pendingTask of pendingTasks) {
@@ -3549,8 +3578,25 @@ function parsePositiveInteger(value, fieldName) {
3549
3578
  if (!Number.isInteger(parsed) || parsed <= 0) throw new InvalidArgumentError(`${fieldName} must be a positive integer.`);
3550
3579
  return parsed;
3551
3580
  }
3581
+ function parseEnvs(value) {
3582
+ const trimmed = value.trim();
3583
+ if (!trimmed) throw new InvalidArgumentError("envs must be a JSON object of string values.");
3584
+ let parsed;
3585
+ try {
3586
+ parsed = JSON.parse(trimmed);
3587
+ } catch {
3588
+ throw new InvalidArgumentError("envs must be valid JSON.");
3589
+ }
3590
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new InvalidArgumentError("envs must be a JSON object.");
3591
+ const out = {};
3592
+ for (const [key, item] of Object.entries(parsed)) {
3593
+ if (typeof item !== "string") throw new InvalidArgumentError(`envs.${key} must be a string value.`);
3594
+ out[key] = item;
3595
+ }
3596
+ return out;
3597
+ }
3552
3598
  function createConfigAgentCommand(version, deps = {}) {
3553
- return createCommand("config").version(version).description("Queue a configuration task for an agent/project").argument("<name>", "The name of the agent.").argument("[prompt]", "The configuration task prompt.").option("--project-id <project-id>", "The project id of the agent. Defaults to DEFAULT_PANTHEON_PROJECT_ID.").option("--task-id <task-id>", "Optional parent task id.").option("--role <role>", "Role metadata. Required for first-time project config; optional override later.").option("--skills <skills>", "The skills of the agent. Multiple values are separated by comma.", parseUniqueCommaList).option("--execute-agent <agent>", "The execute agent of the agent.", "codex").option("--concurrency <number>", "Max number of parallel running tasks for this project.", parseConcurrency).option("--max-retry-attempts <number>", "Max automatic retry attempts per task after failures.", (value) => parseNonNegativeInteger(value, "max-retry-attempts")).option("--retry-backoff-seconds <seconds>", "Base delay (seconds) for exponential retry backoff.", (value) => parsePositiveInteger(value, "retry-backoff-seconds")).option("--root-branch-id <branchId>", "The root branch id of the agent. Defaults to DEFAULT_PANTHEON_ROOT_BRANCH_ID, then project root branch id.").option("--prototype-url <url>", "Role and skill definitions repo.", "https://github.com/pingcap-inc/pantheon-agents").action(async function() {
3599
+ return createCommand("config").version(version).description("Queue a configuration task for an agent/project").argument("<name>", "The name of the agent.").argument("[prompt]", "The configuration task prompt.").option("--project-id <project-id>", "The project id of the agent. Defaults to DEFAULT_PANTHEON_PROJECT_ID.").option("--task-id <task-id>", "Optional parent task id.").option("--role <role>", "Role metadata. Required for first-time project config; optional override later.").option("--skills <skills>", "The skills of the agent. Multiple values are separated by comma.", parseUniqueCommaList).option("--execute-agent <agent>", "The execute agent of the agent.", "codex").option("--concurrency <number>", "Max number of parallel running tasks for this project.", parseConcurrency).option("--max-retry-attempts <number>", "Max automatic retry attempts per task after failures.", (value) => parseNonNegativeInteger(value, "max-retry-attempts")).option("--retry-backoff-seconds <seconds>", "Base delay (seconds) for exponential retry backoff.", (value) => parsePositiveInteger(value, "retry-backoff-seconds")).option("--root-branch-id <branchId>", "The root branch id of the agent. Defaults to DEFAULT_PANTHEON_ROOT_BRANCH_ID, then project root branch id.").option("--prototype-url <url>", "Role and skill definitions repo.", "https://github.com/pingcap-inc/pantheon-agents").option("--envs <json>", "Pantheon branch envs in JSON object format, e.g. '{\"ANTHROPIC_MODEL\":\"claude-opus-4-5\"}'.", parseEnvs).action(async function() {
3554
3600
  const [name, prompt] = this.args;
3555
3601
  const options = this.opts();
3556
3602
  const resolvedProjectId = resolvePantheonProjectId(options.projectId);
@@ -3571,6 +3617,7 @@ function createConfigAgentCommand(version, deps = {}) {
3571
3617
  maxRetryAttempts: options.maxRetryAttempts,
3572
3618
  retryBackoffSeconds: options.retryBackoffSeconds,
3573
3619
  skills: options.skills,
3620
+ envs: options.envs,
3574
3621
  prototypeUrl: options.prototypeUrl,
3575
3622
  rootBranchId: resolvedRootBranchId
3576
3623
  });
@@ -3774,7 +3821,8 @@ function createShowConfigCommand(version) {
3774
3821
  role: config.role,
3775
3822
  execute_agent: config.execute_agent,
3776
3823
  prototype_url: config.prototype_url,
3777
- skills: Array.isArray(config.skills) ? config.skills.join(", ") : String(config.skills)
3824
+ skills: Array.isArray(config.skills) ? config.skills.join(", ") : String(config.skills),
3825
+ envs: config.envs && typeof config.envs === "object" ? JSON.stringify(config.envs) : String(config.envs ?? "{}")
3778
3826
  }]);
3779
3827
  return;
3780
3828
  }
@@ -3800,7 +3848,8 @@ function createShowConfigCommand(version) {
3800
3848
  role: config.role,
3801
3849
  execute_agent: config.execute_agent,
3802
3850
  prototype_url: config.prototype_url,
3803
- skills: Array.isArray(config.skills) ? config.skills.join(", ") : String(config.skills)
3851
+ skills: Array.isArray(config.skills) ? config.skills.join(", ") : String(config.skills),
3852
+ envs: config.envs && typeof config.envs === "object" ? JSON.stringify(config.envs) : String(config.envs ?? "{}")
3804
3853
  })));
3805
3854
  });
3806
3855
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pantheon.ai/agents",
3
3
  "type": "module",
4
- "version": "0.3.2",
4
+ "version": "0.3.3",
5
5
  "bin": {
6
6
  "pantheon-agents": "dist/index.js"
7
7
  },