Skip to content

Commit 0b6ad93

Browse files
steveworleyclaude
andcommitted
feat: match agents by name instead of requiring agent_id
List existing agents via the SDK on each run and match by name. If an agent with the same name exists, update it. Otherwise create. Removes the need for agent_id in agent.json and the write-back step. Output changed from flat ID array to directory name → agent ID map for easy lookup in workflows. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent bb86f6b commit 0b6ad93

3 files changed

Lines changed: 70 additions & 36 deletions

File tree

action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ inputs:
1919
required: false
2020
outputs:
2121
deployed_agents:
22-
description: 'JSON array of deployed agent IDs'
22+
description: 'JSON map of directory name to agent ID'
2323
runs:
2424
using: 'node20'
2525
main: 'dist/index.js'

dist/index.js

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47370,6 +47370,23 @@ async function run() {
4737047370
core.setFailed(`Agents directory not found: ${resolvedDir}`);
4737147371
return;
4737247372
}
47373+
// Fetch existing agents once for name-based matching.
47374+
core.info('Fetching existing agents...');
47375+
const existingAgents = new Map();
47376+
try {
47377+
const listResponse = await agentsApi.listAIAgents(organization);
47378+
for (const agent of listResponse.data.agents || []) {
47379+
if (agent.name && agent.agentId) {
47380+
existingAgents.set(agent.name, agent.agentId);
47381+
}
47382+
}
47383+
core.info(` Found ${existingAgents.size} existing agent(s)`);
47384+
}
47385+
catch (err) {
47386+
const message = err.response?.data?.error || err.message || String(err);
47387+
core.setFailed(`Failed to list existing agents: ${message}`);
47388+
return;
47389+
}
4737347390
const deployedAgents = [];
4737447391
const entries = fs.readdirSync(resolvedDir, { withFileTypes: true });
4737547392
for (const entry of entries) {
@@ -47396,11 +47413,13 @@ async function run() {
4739647413
core.setFailed(`Agent ${entry.name}: no systemPrompt or prompt_file provided`);
4739747414
return;
4739847415
}
47399-
let agentId = agentConfig.agent_id;
47416+
// Match by name to determine create vs update.
47417+
const existingId = existingAgents.get(agentConfig.name);
47418+
let agentId;
4740047419
let created = false;
47401-
if (agentId) {
47402-
// Update existing agent.
47403-
core.info(`Updating agent: ${agentConfig.name} (${agentId})`);
47420+
if (existingId) {
47421+
// Update existing agent matched by name.
47422+
core.info(`Updating agent: ${agentConfig.name} (${existingId})`);
4740447423
const updateRequest = {
4740547424
name: agentConfig.name,
4740647425
description: agentConfig.description,
@@ -47413,17 +47432,18 @@ async function run() {
4741347432
group: agentConfig.group,
4741447433
};
4741547434
try {
47416-
await agentsApi.updateAIAgent(organization, agentId, updateRequest);
47435+
await agentsApi.updateAIAgent(organization, existingId, updateRequest);
47436+
agentId = existingId;
4741747437
core.info(` Agent updated successfully`);
4741847438
}
4741947439
catch (err) {
4742047440
const message = err.response?.data?.error || err.message || String(err);
47421-
core.setFailed(`Failed to update agent ${agentId}: ${message}`);
47441+
core.setFailed(`Failed to update agent ${existingId}: ${message}`);
4742247442
return;
4742347443
}
4742447444
}
4742547445
else {
47426-
// Create new agent.
47446+
// Create new agent — no existing agent with this name.
4742747447
core.info(`Creating agent: ${agentConfig.name}`);
4742847448
const createRequest = {
4742947449
name: agentConfig.name,
@@ -47446,20 +47466,21 @@ async function run() {
4744647466
}
4744747467
core.info(` Agent created with ID: ${agentId}`);
4744847468
created = true;
47449-
// Write the agent_id back to agent.json so subsequent runs update instead of create.
47450-
agentConfig.agent_id = agentId;
47451-
fs.writeFileSync(configPath, JSON.stringify(agentConfig, null, 2) + '\n');
47452-
core.info(` Updated agent.json with agent_id`);
4745347469
}
4745447470
catch (err) {
4745547471
const message = err.response?.data?.error || err.message || String(err);
4745647472
core.setFailed(`Failed to create agent ${agentConfig.name}: ${message}`);
4745747473
return;
4745847474
}
4745947475
}
47460-
deployedAgents.push({ agent_id: agentId, name: agentConfig.name, created });
47476+
deployedAgents.push({ agent_id: agentId, dir_name: entry.name, name: agentConfig.name, created });
47477+
}
47478+
// Output a map of directory name → agent ID for easy lookup in workflows.
47479+
const agentMap = {};
47480+
for (const agent of deployedAgents) {
47481+
agentMap[agent.dir_name] = agent.agent_id;
4746147482
}
47462-
core.setOutput('deployed_agents', JSON.stringify(deployedAgents.map(a => a.agent_id)));
47483+
core.setOutput('deployed_agents', JSON.stringify(agentMap));
4746347484
core.info('');
4746447485
core.info('=== Deploy Summary ===');
4746547486
for (const agent of deployedAgents) {

src/index.ts

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,11 @@ import { Configuration, AIAgentsApi, CreateAIAgentRequest, UpdateAIAgentRequest
66
const DEFAULT_BASE_URL = 'https://dashboard.quantcdn.io';
77

88
interface AgentConfig {
9-
// If set, update an existing agent. If omitted, create a new one.
10-
agent_id?: string;
11-
12-
// Required fields for agent creation.
139
name: string;
1410
description: string;
1511
modelId: string;
16-
17-
// System prompt — inline or loaded from a file.
1812
systemPrompt?: string;
1913
prompt_file?: string;
20-
21-
// Optional agent configuration.
2214
temperature?: number;
2315
maxTokens?: number;
2416
allowedTools?: string[];
@@ -28,6 +20,7 @@ interface AgentConfig {
2820

2921
interface DeployedAgent {
3022
agent_id: string;
23+
dir_name: string;
3124
name: string;
3225
created: boolean;
3326
}
@@ -54,6 +47,23 @@ async function run(): Promise<void> {
5447
return;
5548
}
5649

50+
// Fetch existing agents once for name-based matching.
51+
core.info('Fetching existing agents...');
52+
const existingAgents = new Map<string, string>();
53+
try {
54+
const listResponse = await agentsApi.listAIAgents(organization);
55+
for (const agent of listResponse.data.agents || []) {
56+
if (agent.name && agent.agentId) {
57+
existingAgents.set(agent.name, agent.agentId);
58+
}
59+
}
60+
core.info(` Found ${existingAgents.size} existing agent(s)`);
61+
} catch (err: any) {
62+
const message = err.response?.data?.error || err.message || String(err);
63+
core.setFailed(`Failed to list existing agents: ${message}`);
64+
return;
65+
}
66+
5767
const deployedAgents: DeployedAgent[] = [];
5868

5969
const entries = fs.readdirSync(resolvedDir, { withFileTypes: true });
@@ -86,12 +96,14 @@ async function run(): Promise<void> {
8696
return;
8797
}
8898

89-
let agentId = agentConfig.agent_id;
99+
// Match by name to determine create vs update.
100+
const existingId = existingAgents.get(agentConfig.name);
101+
let agentId: string | undefined;
90102
let created = false;
91103

92-
if (agentId) {
93-
// Update existing agent.
94-
core.info(`Updating agent: ${agentConfig.name} (${agentId})`);
104+
if (existingId) {
105+
// Update existing agent matched by name.
106+
core.info(`Updating agent: ${agentConfig.name} (${existingId})`);
95107

96108
const updateRequest: UpdateAIAgentRequest = {
97109
name: agentConfig.name,
@@ -106,15 +118,16 @@ async function run(): Promise<void> {
106118
};
107119

108120
try {
109-
await agentsApi.updateAIAgent(organization, agentId, updateRequest);
121+
await agentsApi.updateAIAgent(organization, existingId, updateRequest);
122+
agentId = existingId;
110123
core.info(` Agent updated successfully`);
111124
} catch (err: any) {
112125
const message = err.response?.data?.error || err.message || String(err);
113-
core.setFailed(`Failed to update agent ${agentId}: ${message}`);
126+
core.setFailed(`Failed to update agent ${existingId}: ${message}`);
114127
return;
115128
}
116129
} else {
117-
// Create new agent.
130+
// Create new agent — no existing agent with this name.
118131
core.info(`Creating agent: ${agentConfig.name}`);
119132

120133
const createRequest: CreateAIAgentRequest = {
@@ -141,22 +154,22 @@ async function run(): Promise<void> {
141154

142155
core.info(` Agent created with ID: ${agentId}`);
143156
created = true;
144-
145-
// Write the agent_id back to agent.json so subsequent runs update instead of create.
146-
agentConfig.agent_id = agentId;
147-
fs.writeFileSync(configPath, JSON.stringify(agentConfig, null, 2) + '\n');
148-
core.info(` Updated agent.json with agent_id`);
149157
} catch (err: any) {
150158
const message = err.response?.data?.error || err.message || String(err);
151159
core.setFailed(`Failed to create agent ${agentConfig.name}: ${message}`);
152160
return;
153161
}
154162
}
155163

156-
deployedAgents.push({ agent_id: agentId!, name: agentConfig.name, created });
164+
deployedAgents.push({ agent_id: agentId!, dir_name: entry.name, name: agentConfig.name, created });
157165
}
158166

159-
core.setOutput('deployed_agents', JSON.stringify(deployedAgents.map(a => a.agent_id)));
167+
// Output a map of directory name → agent ID for easy lookup in workflows.
168+
const agentMap: Record<string, string> = {};
169+
for (const agent of deployedAgents) {
170+
agentMap[agent.dir_name] = agent.agent_id;
171+
}
172+
core.setOutput('deployed_agents', JSON.stringify(agentMap));
160173

161174
core.info('');
162175
core.info('=== Deploy Summary ===');

0 commit comments

Comments
 (0)