Skip to content

Commit 3d3fc04

Browse files
committed
agentapi module
1 parent bd5ad3b commit 3d3fc04

File tree

10 files changed

+730
-0
lines changed

10 files changed

+730
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
display_name: AgentAPI
3+
description: Building block for modules that need to run an agentapi server
4+
icon: ../../../../.icons/coder.svg
5+
maintainer_github: coder
6+
verified: true
7+
tags: [internal]
8+
---
9+
10+
# AgentAPI
11+
12+
The AgentAPI module is a building block for modules that need to run an agentapi server. It is intended primarily for internal use by Coder to create modules compatible with Tasks.
13+
14+
We do not recommend using this module directly. Instead, please consider using one of our [Tasks-compatible AI agent modules](https://registry.coder.com/modules?search=tag%3Atasks).
15+
16+
```tf
17+
module "agentapi" {
18+
source = "registry.coder.com/coder/agentapi/coder"
19+
version = "1.0.0"
20+
21+
agent_id = var.agent_id
22+
web_app_slug = local.app_slug
23+
web_app_order = var.order
24+
web_app_group = var.group
25+
web_app_icon = var.icon
26+
web_app_display_name = "Goose"
27+
cli_app_slug = "goose-cli"
28+
cli_app_display_name = "Goose CLI"
29+
module_dir_name = local.module_dir_name
30+
install_agentapi = var.install_agentapi
31+
pre_install_script = var.pre_install_script
32+
post_install_script = var.post_install_script
33+
start_script = local.start_script
34+
install_script = <<-EOT
35+
#!/bin/bash
36+
set -o errexit
37+
set -o pipefail
38+
39+
echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh
40+
chmod +x /tmp/install.sh
41+
42+
ARG_PROVIDER='${var.goose_provider}' \
43+
ARG_MODEL='${var.goose_model}' \
44+
ARG_GOOSE_CONFIG="$(echo -n '${base64encode(local.combined_extensions)}' | base64 -d)" \
45+
ARG_INSTALL='${var.install_goose}' \
46+
ARG_GOOSE_VERSION='${var.goose_version}' \
47+
/tmp/install.sh
48+
EOT
49+
}
50+
```
51+
52+
## For module developers
53+
54+
For a complete example of how to use this module, see the [goose module](https://github.com/coder/registry/blob/main/registry/coder/modules/goose/main.tf).
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import {
2+
test,
3+
afterEach,
4+
expect,
5+
describe,
6+
setDefaultTimeout,
7+
beforeAll,
8+
} from "bun:test";
9+
import { execContainer, readFileContainer, runTerraformInit } from "~test";
10+
import {
11+
loadTestFile,
12+
writeExecutable,
13+
setup as setupUtil,
14+
execModuleScript,
15+
expectAgentAPIStarted,
16+
} from "./test-util";
17+
18+
let cleanupFunctions: (() => Promise<void>)[] = [];
19+
20+
const registerCleanup = (cleanup: () => Promise<void>) => {
21+
cleanupFunctions.push(cleanup);
22+
};
23+
24+
// Cleanup logic depends on the fact that bun's built-in test runner
25+
// runs tests sequentially.
26+
// https://bun.sh/docs/test/discovery#execution-order
27+
// Weird things would happen if tried to run tests in parallel.
28+
// One test could clean up resources that another test was still using.
29+
afterEach(async () => {
30+
// reverse the cleanup functions so that they are run in the correct order
31+
const cleanupFnsCopy = cleanupFunctions.slice().reverse();
32+
cleanupFunctions = [];
33+
for (const cleanup of cleanupFnsCopy) {
34+
try {
35+
await cleanup();
36+
} catch (error) {
37+
console.error("Error during cleanup:", error);
38+
}
39+
}
40+
});
41+
42+
interface SetupProps {
43+
skipAgentAPIMock?: boolean;
44+
moduleVariables?: Record<string, string>;
45+
}
46+
47+
const moduleDirName = ".agentapi-module";
48+
49+
const setup = async (props?: SetupProps): Promise<{ id: string }> => {
50+
const projectDir = "/home/coder/project";
51+
const { id } = await setupUtil({
52+
moduleVariables: {
53+
experiment_report_tasks: "true",
54+
install_agentapi: props?.skipAgentAPIMock ? "true" : "false",
55+
web_app_display_name: "AgentAPI Web",
56+
web_app_slug: "agentapi-web",
57+
web_app_icon: "/icon/coder.svg",
58+
cli_app_display_name: "AgentAPI CLI",
59+
cli_app_slug: "agentapi-cli",
60+
agentapi_version: "latest",
61+
module_dir_name: moduleDirName,
62+
start_script: await loadTestFile(import.meta.dir, "agentapi-start.sh"),
63+
folder: projectDir,
64+
...props?.moduleVariables,
65+
},
66+
registerCleanup,
67+
projectDir,
68+
skipAgentAPIMock: props?.skipAgentAPIMock,
69+
moduleDir: import.meta.dir,
70+
});
71+
await writeExecutable({
72+
containerId: id,
73+
filePath: "/usr/bin/aiagent",
74+
content: await loadTestFile(import.meta.dir, "ai-agent-mock.js"),
75+
});
76+
return { id };
77+
};
78+
79+
// increase the default timeout to 60 seconds
80+
setDefaultTimeout(60 * 1000);
81+
82+
// we don't run these tests in CI because they take too long and make network
83+
// calls. they are dedicated for local development.
84+
describe("agentapi", async () => {
85+
beforeAll(async () => {
86+
await runTerraformInit(import.meta.dir);
87+
});
88+
89+
test("happy-path", async () => {
90+
const { id } = await setup();
91+
92+
await execModuleScript(id);
93+
94+
await expectAgentAPIStarted(id);
95+
});
96+
97+
test("custom-port", async () => {
98+
const { id } = await setup({
99+
moduleVariables: {
100+
agentapi_port: "3827",
101+
},
102+
});
103+
await execModuleScript(id);
104+
await expectAgentAPIStarted(id, 3827);
105+
});
106+
107+
test("pre-post-install-scripts", async () => {
108+
const { id } = await setup({
109+
moduleVariables: {
110+
pre_install_script: `#!/bin/bash\necho "pre-install"`,
111+
install_script: `#!/bin/bash\necho "install"`,
112+
post_install_script: `#!/bin/bash\necho "post-install"`,
113+
},
114+
});
115+
116+
await execModuleScript(id);
117+
await expectAgentAPIStarted(id);
118+
119+
const preInstallLog = await readFileContainer(
120+
id,
121+
`/home/coder/${moduleDirName}/pre_install.log`,
122+
);
123+
const installLog = await readFileContainer(
124+
id,
125+
`/home/coder/${moduleDirName}/install.log`,
126+
);
127+
const postInstallLog = await readFileContainer(
128+
id,
129+
`/home/coder/${moduleDirName}/post_install.log`,
130+
);
131+
132+
expect(preInstallLog).toContain("pre-install");
133+
expect(installLog).toContain("install");
134+
expect(postInstallLog).toContain("post-install");
135+
});
136+
137+
test("install-agentapi", async () => {
138+
const { id } = await setup({ skipAgentAPIMock: true });
139+
140+
const respModuleScript = await execModuleScript(id);
141+
expect(respModuleScript.exitCode).toBe(0);
142+
143+
await expectAgentAPIStarted(id);
144+
const respAgentAPI = await execContainer(id, [
145+
"bash",
146+
"-c",
147+
"agentapi --version",
148+
]);
149+
expect(respAgentAPI.exitCode).toBe(0);
150+
});
151+
});

0 commit comments

Comments
 (0)