Skip to content

Commit b8c9e3a

Browse files
authored
Merge pull request #5 from runloopai/wall-more
Improve the deploy agent action to support published agents
2 parents bcdf8c5 + d4cb33c commit b8c9e3a

5 files changed

Lines changed: 221 additions & 5 deletions

File tree

action.yml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ inputs:
1212
required: true
1313

1414
source-type:
15-
description: 'Agent source type: git, tar, or file'
15+
description: 'Agent source type: git, tar, file, npm, or pip'
1616
required: true
1717

1818
# Optional inputs
@@ -33,6 +33,24 @@ inputs:
3333
description: 'Git ref (branch/tag/commit SHA). Defaults to current commit or release tag'
3434
required: false
3535

36+
# NPM source inputs
37+
npm-package:
38+
description: 'NPM package name (required when source-type=npm, e.g., "@anthropic-ai/claude-code")'
39+
required: false
40+
41+
npm-registry-url:
42+
description: 'NPM registry URL (optional, defaults to public npm registry)'
43+
required: false
44+
45+
# Pip source inputs
46+
pip-package:
47+
description: 'PyPI package name (required when source-type=pip, e.g., "deepagents-cli")'
48+
required: false
49+
50+
pip-index-url:
51+
description: 'PyPI index URL (optional, defaults to public PyPI)'
52+
required: false
53+
3654
# File/tar source inputs
3755
path:
3856
description: 'Path to file or tar archive (required if source-type=tar/file)'

dist/index.js

Lines changed: 87 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/agent-deployer.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ export async function deployAgent(inputs: ActionInputs): Promise<DeploymentResul
4646
result = await deployFileAgent(client, agentName, inputs);
4747
break;
4848

49+
case 'npm':
50+
result = await deployNpmAgent(client, agentName, inputs);
51+
break;
52+
53+
case 'pip':
54+
result = await deployPipAgent(client, agentName, inputs);
55+
break;
56+
4957
default: {
5058
// Exhaustiveness check - this should never happen
5159
const exhaustiveCheck: never = inputs.sourceType;
@@ -186,3 +194,87 @@ async function deployFileAgent(
186194
objectId: uploadResult.objectId,
187195
};
188196
}
197+
198+
/**
199+
* Deploy an agent from an NPM package.
200+
*/
201+
async function deployNpmAgent(
202+
client: RunloopSDK,
203+
agentName: string,
204+
inputs: ActionInputs
205+
): Promise<DeploymentResult> {
206+
core.info('Deploying NPM agent...');
207+
208+
if (!inputs.npmPackage) {
209+
throw new Error('npm-package is required for npm agent deployment');
210+
}
211+
212+
const npmSource: Record<string, unknown> = {
213+
package_name: inputs.npmPackage,
214+
};
215+
if (inputs.npmRegistryUrl) {
216+
npmSource.registry_url = inputs.npmRegistryUrl;
217+
}
218+
if (inputs.setupCommands && inputs.setupCommands.length > 0) {
219+
npmSource.agent_setup = inputs.setupCommands;
220+
}
221+
222+
const agent = await client.api.post<unknown, AgentResponse>('/v1/agents', {
223+
body: {
224+
name: agentName,
225+
version: inputs.agentVersion,
226+
is_public: inputs.isPublic,
227+
source: {
228+
type: 'npm',
229+
npm: npmSource,
230+
},
231+
},
232+
});
233+
234+
return {
235+
agentId: agent.id,
236+
agentName: agent.name,
237+
};
238+
}
239+
240+
/**
241+
* Deploy an agent from a PyPI package.
242+
*/
243+
async function deployPipAgent(
244+
client: RunloopSDK,
245+
agentName: string,
246+
inputs: ActionInputs
247+
): Promise<DeploymentResult> {
248+
core.info('Deploying pip agent...');
249+
250+
if (!inputs.pipPackage) {
251+
throw new Error('pip-package is required for pip agent deployment');
252+
}
253+
254+
const pipSource: Record<string, unknown> = {
255+
package_name: inputs.pipPackage,
256+
};
257+
if (inputs.pipIndexUrl) {
258+
pipSource.index_url = inputs.pipIndexUrl;
259+
}
260+
if (inputs.setupCommands && inputs.setupCommands.length > 0) {
261+
pipSource.agent_setup = inputs.setupCommands;
262+
}
263+
264+
const agent = await client.api.post<unknown, AgentResponse>('/v1/agents', {
265+
body: {
266+
name: agentName,
267+
version: inputs.agentVersion,
268+
is_public: inputs.isPublic,
269+
source: {
270+
type: 'pip',
271+
pip: pipSource,
272+
},
273+
},
274+
});
275+
276+
return {
277+
agentId: agent.id,
278+
agentName: agent.name,
279+
};
280+
}

src/validators.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@ export interface ActionInputs {
1010
gitRepository?: string;
1111
gitRef?: string;
1212
path?: string;
13+
npmPackage?: string;
14+
npmRegistryUrl?: string;
15+
pipPackage?: string;
16+
pipIndexUrl?: string;
1317
setupCommands?: string[];
1418
isPublic: boolean;
1519
apiUrl: string;
1620
objectTtlDays?: number;
1721
}
1822

19-
export type SourceType = 'git' | 'tar' | 'file';
23+
export type SourceType = 'git' | 'tar' | 'file' | 'npm' | 'pip';
2024

2125
export function getInputs(): ActionInputs {
2226
// Get all inputs
@@ -33,6 +37,10 @@ export function getInputs(): ActionInputs {
3337
gitRepository: core.getInput('git-repository') || undefined,
3438
gitRef: core.getInput('git-ref') || undefined,
3539
path: core.getInput('path') || undefined,
40+
npmPackage: core.getInput('npm-package') || undefined,
41+
npmRegistryUrl: core.getInput('npm-registry-url') || undefined,
42+
pipPackage: core.getInput('pip-package') || undefined,
43+
pipIndexUrl: core.getInput('pip-index-url') || undefined,
3644
setupCommands: setupCommandsRaw
3745
? setupCommandsRaw
3846
.split('\n')
@@ -49,7 +57,7 @@ export function getInputs(): ActionInputs {
4957

5058
export function validateInputs(inputs: ActionInputs): void {
5159
// Validate source type
52-
const validSourceTypes: SourceType[] = ['git', 'tar', 'file'];
60+
const validSourceTypes: SourceType[] = ['git', 'tar', 'file', 'npm', 'pip'];
5361
if (!validSourceTypes.includes(inputs.sourceType)) {
5462
throw new Error(
5563
`Invalid source-type: ${inputs.sourceType}. Must be one of: ${validSourceTypes.join(', ')}`
@@ -71,6 +79,18 @@ export function validateInputs(inputs: ActionInputs): void {
7179
// Validation happens in git-utils.ts
7280
break;
7381

82+
case 'npm':
83+
if (!inputs.npmPackage) {
84+
throw new Error('npm-package is required when source-type is "npm"');
85+
}
86+
break;
87+
88+
case 'pip':
89+
if (!inputs.pipPackage) {
90+
throw new Error('pip-package is required when source-type is "pip"');
91+
}
92+
break;
93+
7494
default: {
7595
// Exhaustiveness check - this should never happen
7696
const exhaustiveCheck: never = inputs.sourceType;

0 commit comments

Comments
 (0)