Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions src/core/project/manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const AGENT_PYTHON_STRANDS_CONTAINER = resolveRuntimeTemplateShortcut(
const AGENT_TYPESCRIPT_STRANDS = resolveRuntimeTemplateShortcut("agent-typescript-strands");
const A2A_PYTHON_STRANDS = resolveRuntimeTemplateShortcut("a2a-python-strands");
const AGENT_PYTHON_LANGCHAIN = resolveRuntimeTemplateShortcut("agent-python-langchain");
const BEDROCK_MANAGED_AGENTS = resolveRuntimeTemplateShortcut("bedrock-managed-agents");
const BEDROCK_MANAGED_AGENTS = resolveRuntimeTemplateShortcut("environment-python-bma");

function withTemplateProfile(
input: ScaffoldRuntimeInput,
Expand Down Expand Up @@ -301,14 +301,14 @@ describe("FsProjectManager.create", () => {
});

const projectRoot = join(directory, "example");
const appDir = join(projectRoot, "app", "bedrock_managed_agents");
const appDir = join(projectRoot, "app", "environment_python_bma");
const spec = await Bun.file(join(projectRoot, "agentcore", "agentcore.json")).json();
expect(spec.runtimes).toEqual([
{
name: "bedrock_managed_agents",
name: "environment_python_bma",
build: "Container",
entrypoint: "lifecycle/server.py",
codeLocation: "app/bedrock_managed_agents",
codeLocation: "app/environment_python_bma",
dockerfile: "Dockerfile",
additionalPolicies: ["bma-acr-policy.json"],
protocol: "HTTP",
Expand All @@ -328,7 +328,7 @@ describe("FsProjectManager.create", () => {
).exists(),
).toBe(true);
expect(await Bun.file(join(appDir, "pyproject.toml")).text()).toContain(
'name = "bedrock_managed_agents"',
'name = "environment_python_bma"',
);
expect(setup.commands).toEqual([
{
Expand Down Expand Up @@ -950,7 +950,7 @@ describe("FsProjectManager.addResource", () => {

const { error } = await deployOutcome(subject, project);
expect(error).toBeInstanceOf(RegionUnsupportedFeatureError);
expect(String(error)).toContain("runtime 'bedrock_managed_agents'");
expect(String(error)).toContain("runtime 'environment_python_bma'");
expect(String(error)).toContain(BMA_CN_MESSAGE);
expect(deployCalls).toEqual([]);
});
Expand Down
15 changes: 3 additions & 12 deletions src/core/project/manager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,7 @@ import type { CreateCloudFormationClient } from "../types";
import type { CoreIdentityClient } from "../../handlers/identity/types";
import { templateManagesDependencies } from "../../handlers/project/templateProfile";
import { resolveRuntimeTemplateProfile } from "../../handlers/project/runtimeTemplateProfile";
import {
BMA_POLICY_FILE,
BMA_TEMPLATE_NAME,
BMA_TEMPLATE_TAG_KEY,
BMA_TEMPLATE_TAG_VALUE,
} from "../../handlers/project/bmaProfile";
import { isBmaRuntime } from "../../handlers/project/bma";

const TARGETS_EXAMPLE = '[{ "name": "default", "account": "111122223333", "region": "us-east-1" }]';

Expand Down Expand Up @@ -469,7 +464,7 @@ export class FsProjectManager implements ProjectManager {
if (input.resourceType === "runtime") {
const { framework, modelProvider, modelId, memory } =
input.resourceConfig.scaffoldRuntimeInput;
if (framework === BMA_TEMPLATE_NAME) {
if (framework === "bma") {
throw new RegionUnsupportedFeatureError(BMA_CN_MESSAGE);
}
if (framework !== "none") {
Expand Down Expand Up @@ -1167,11 +1162,7 @@ export class FsProjectManager implements ProjectManager {
// modelProvider (BYO, provider-free, hand-edited, or scaffolded by an
// older CLI) cannot be classified and only get an informational note.
if (isChinaRegion(target.region)) {
const bmaRuntimes = project.spec.runtimes.filter(
(runtime) =>
runtime.tags?.[BMA_TEMPLATE_TAG_KEY] === BMA_TEMPLATE_TAG_VALUE ||
runtime.additionalPolicies?.includes(BMA_POLICY_FILE),
);
const bmaRuntimes = project.spec.runtimes.filter(isBmaRuntime);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice this is simple

if (bmaRuntimes.length > 0) {
throw new RegionUnsupportedFeatureError(
`Cannot deploy to China region ${target.region}: ` +
Expand Down
4 changes: 1 addition & 3 deletions src/core/project/templates/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,9 +331,7 @@ const getTemplateResolvers = (assetSource: AssetSource, templateRenderer: Templa
spec: { runtimes: [{ ...buildRuntimeSpec(input), protocol: "HTTP" as const }] },
};
},
[buildResolverKey("bedrock-managed-agents", "Python", "HTTP")]: async (
input: RuntimeResourceConfig,
) => {
[buildResolverKey("bma", "Python", "HTTP")]: async (input: RuntimeResourceConfig) => {
const tree = await FsTreeNode.fromAssetSource(
{ assetSource },
{ assetDir: "templates/bedrock-managed-agents" },
Expand Down
4 changes: 2 additions & 2 deletions src/errors/errors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ export class ResourceNotFoundError extends AgentCoreCLIError {

/** Error raised when a command or operation has not been implemented yet. */
export class NotImplementedError extends AgentCoreCLIError {
constructor(message?: string, options?: Omit<AgentCoreCLIErrorOptions, "source">) {
super(message ?? "not implemented yet", { ...options, source: ERROR_SOURCE.INTERNAL });
constructor(message?: string, options?: AgentCoreCLIErrorOptions) {
super(message ?? "not implemented yet", { source: ERROR_SOURCE.INTERNAL, ...options });
}
}

Expand Down
45 changes: 27 additions & 18 deletions src/handlers/project/add/runtime/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ describe("project add runtime", () => {
build: "CodeZip",
protocol: "AGUI",
},
"bedrock-managed-agents template preset": {
"environment-python-bma template preset": {
build: "Container",
entrypoint: "lifecycle/server.py",
dockerfile: "Dockerfile",
Expand Down Expand Up @@ -176,8 +176,8 @@ describe("project add runtime", () => {
["--name", "my_agui", "--template", "agui-python-strands"],
],
[
"bedrock-managed-agents template preset",
["--name", "my_bma", "--template", "bedrock-managed-agents"],
"environment-python-bma template preset",
["--name", "my_bma", "--template", "environment-python-bma"],
],
[
"agent-python-strands with session, EFS, and S3 mounts",
Expand Down Expand Up @@ -286,14 +286,14 @@ describe("project add runtime", () => {
const spec = await Bun.file(join(projectRoot, "agentcore", "agentcore.json")).json();
const runtime = spec.runtimes.find((candidate: { name: string }) => candidate.name === name);
expect(runtime).toMatchObject({ entrypoint: "main.py", ...expectedSpecByLabel[label] });
const isBma = flags.includes("bedrock-managed-agents");
const isBma = flags.includes("environment-python-bma");
expect(
await Bun.file(
join(projectRoot, "app", name, isBma ? "lifecycle/server.py" : "main.py"),
).exists(),
).toBe(true);
const isContainer = flags.some(
(flag) => flag.endsWith("-container") || flag === "bedrock-managed-agents",
(flag) => flag.endsWith("-container") || flag === "environment-python-bma",
);
expect(runtime.runtimeVersion).toBe(isContainer ? undefined : "PYTHON_3_14");
expect(await Bun.file(join(projectRoot, "app", name, "Dockerfile")).exists()).toBe(isContainer);
Expand All @@ -311,7 +311,7 @@ describe("project add runtime", () => {
"--name",
"my_bma",
"--template",
"bedrock-managed-agents",
"environment-python-bma",
]);

expect(core.projectCommands).toEqual([]);
Expand All @@ -329,7 +329,7 @@ describe("project add runtime", () => {
"--name",
"my_bma",
"--template",
"bedrock-managed-agents",
"environment-python-bma",
"--lifecycle-configuration",
'{"idleRuntimeSessionTimeout":300,"maxLifetime":3600}',
"--additional-policies",
Expand Down Expand Up @@ -363,7 +363,7 @@ describe("project add runtime", () => {
"--name",
"my_bma",
"--template",
"bedrock-managed-agents",
"environment-python-bma",
"--role-arn",
roleArn,
"--json",
Expand Down Expand Up @@ -391,7 +391,7 @@ describe("project add runtime", () => {
["agent-typescript-vercel", []],
["mcp-python-fastmcp", []],
["agui-python-strands", ["SEMANTIC", "USER_PREFERENCE", "SUMMARIZATION", "EPISODIC"]],
["bedrock-managed-agents", []],
["environment-python-bma", []],
])("%s ships with its pre-configured memory", async (templateName, expectedStrategies) => {
const { projectRoot, cleanup } = await initProject();
cleanups.push(cleanup);
Expand Down Expand Up @@ -526,8 +526,9 @@ describe("project add runtime", () => {
],
],
[
"--model-provider is not valid with the bedrock-managed-agents template",
["--name", "my_bma", "--template", "bedrock-managed-agents", "--model-provider", "Anthropic"],
"--model-provider is not valid with the environment-python-bma template",
["--name", "my_bma", "--template", "environment-python-bma", "--model-provider", "Anthropic"],
"--model-provider, --model-id, and --api-key are not valid with the environment-python-bma template",
],
[
"--model-provider without a template requires agent-python-strands",
Expand All @@ -545,13 +546,21 @@ describe("project add runtime", () => {
await expectError(promise, requiredMessage ?? /./, InputValidationError);
});

test("rejects an unknown --template value", async () => {
const { cleanup } = await initProject();
cleanups.push(cleanup);
await expect(
run(["add", "runtime", "--name", "my_agent", "--template", "nonsense"]),
).rejects.toThrow();
});
test.each(["nonsense", "bedrock-managed-agents"])(
"rejects the unknown --template value %s",
async (template) => {
const { projectRoot, cleanup } = await initProject();
cleanups.push(cleanup);
await expect(
run(["add", "runtime", "--name", "my_agent", "--template", template]),
).rejects.toThrow();
const spec = await Bun.file(join(projectRoot, "agentcore", "agentcore.json")).json();
expect(spec.runtimes).toEqual([]);
expect(
await Bun.file(join(projectRoot, "app", "my_agent", "lifecycle", "server.py")).exists(),
).toBe(false);
},
);
});

describe("project add runtime --type import", () => {
Expand Down
4 changes: 2 additions & 2 deletions src/handlers/project/add/runtime/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
} from "../../importBedrockAgent";
import { RegionKey } from "../../../keys";
import { addProjectResource, requireDeployedNameFits } from "../shared";
import { BMA_CUSTOM_EXECUTION_ROLE_WARNING, BMA_TEMPLATE_NAME } from "../../bmaProfile";
import { BMA_CUSTOM_EXECUTION_ROLE_WARNING } from "../../bma";

const CONFIGURATION = "Configuration:";
const ENVIRONMENT = "Environment:";
Expand Down Expand Up @@ -275,7 +275,7 @@ export const createAddRuntimeHandler = (config: AddProjectResourceConfig) =>
})
: resolveRuntimeTemplateShortcut("agent-python-minimal", { runtimeName: flags.name });

if (scaffoldRuntimeInput.framework === BMA_TEMPLATE_NAME && flags["role-arn"] !== undefined) {
if (scaffoldRuntimeInput.framework === "bma" && flags["role-arn"] !== undefined) {
notes.push(BMA_CUSTOM_EXECUTION_ROLE_WARNING);
}

Expand Down
4 changes: 3 additions & 1 deletion src/handlers/project/add/runtime/runtime.screen.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,17 +142,19 @@ describe("project add runtime wizard", () => {
await r.press("return");

await waitForText(r.lastFrame, "choose a template");
await selectTemplate(r, "bedrock-managed-agents");
await selectTemplate(r, "environment-python-bma");
await r.press("return");

await waitForFlatText(r.lastFrame, "build Container");
expect(flatFrame(r.lastFrame)).toContain("template environment-python-bma");
await r.press("return");
await waitForText(r.lastFrame, "added runtime 'bma_environment' to 'TestProject'");

expect(await runtimeInSpec(projectRoot, "bma_environment")).toMatchObject({
build: "Container",
entrypoint: "lifecycle/server.py",
additionalPolicies: ["bma-acr-policy.json"],
tags: { "agentcore:template": "BedrockManagedAgents" },
});
expect(
await Bun.file(
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/project/add/runtime/screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ function AddRuntimeWizard({ project, core }: { project: Project; core: ScreenPro
</Step>

<Step stepKey="template" prompt="choose a template">
<ChoiceField
<ChoiceField<RuntimeTemplateShortcutName>
help="the agent code scaffolded into app/"
choices={TEMPLATE_CHOICES}
value={values.template}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import type { RuntimeTemplateProfile } from "./templateProfile";
import type { ProjectRuntime } from "../../projectSchemas/runtime";

export const BMA_TEMPLATE_NAME = "bedrock-managed-agents";
export const BMA_TEMPLATE_NAME = "environment-python-bma";
export const BMA_POLICY_FILE = "bma-acr-policy.json";
export const BMA_TEMPLATE_TAG_KEY = "agentcore:template";
export const BMA_TEMPLATE_TAG_VALUE = "BedrockManagedAgents";

export function isBmaRuntime(
runtime: Pick<ProjectRuntime, "tags" | "additionalPolicies">,
): boolean {
return (
runtime.tags?.[BMA_TEMPLATE_TAG_KEY] === BMA_TEMPLATE_TAG_VALUE ||
runtime.additionalPolicies?.includes(BMA_POLICY_FILE) === true
);
}

export const BMA_CUSTOM_EXECUTION_ROLE_WARNING =
`Warning: --role-arn uses an existing execution role, so AgentCore CDK cannot attach ` +
`${BMA_POLICY_FILE}. Ensure the role grants bedrock-mantle:RegisterEnvironment and ` +
Expand Down
8 changes: 4 additions & 4 deletions src/handlers/project/create/create.screen.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ describe("project create wizard", () => {
expect(r.lastFrame()).toContain("● agent-python-strands");
expect(r.lastFrame()).not.toContain("agent-python-strands (recommended)");
expect(r.lastFrame()).toContain("agent-python-strands-container");
expect(r.lastFrame()).toContain("bedrock-managed-agents");
expect(r.lastFrame()).toContain("environment-python-bma");
await r.press("return");

// No memory step: memory is no longer a choice, so review follows directly.
Expand Down Expand Up @@ -438,8 +438,8 @@ describe("project create wizard", () => {
await waitForText(r.lastFrame, "choose a template");
await r.press("down"); // agent-python-strands-container
await r.press("down"); // agent-python-langchain
await r.press("down"); // bedrock-managed-agents
await waitForText(r.lastFrame, "● bedrock-managed-agents");
await r.press("down"); // environment-python-bma
await waitForText(r.lastFrame, "● environment-python-bma");
await r.press("return");
await waitForText(r.lastFrame, "this project will be created");
await r.press("return");
Expand All @@ -465,7 +465,7 @@ describe("project create wizard", () => {
await waitForText(r.lastFrame, "choose a template");
await r.press("down"); // agent-python-strands-container
await r.press("down"); // agent-python-langchain
await r.press("down"); // bedrock-managed-agents
await r.press("down"); // environment-python-bma
await r.press("down"); // agent-python-minimal
await waitForText(r.lastFrame, "● agent-python-minimal ");
await r.press("return");
Expand Down
3 changes: 1 addition & 2 deletions src/handlers/project/create/region.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
MODEL_PROVIDER_RUNTIMES_CN_MESSAGE,
} from "../../../core/project/manager";
import { RegionUnsupportedFeatureError } from "../../../errors";
import { BMA_TEMPLATE_NAME } from "../bmaProfile";
import type { CreateProjectInput } from "../types";

/** Applies the hard create-time restrictions shared by the CLI and interactive wizard. */
Expand All @@ -20,7 +19,7 @@ export function validateCreateRegionSupport(input: CreateProjectInput, region: s

const runtime = input.scaffoldRuntimeInput;
if (runtime === undefined || runtime.framework === "none") return;
if (runtime.framework === BMA_TEMPLATE_NAME) {
if (runtime.framework === "bma") {
throw new RegionUnsupportedFeatureError(BMA_CN_MESSAGE);
}
if ((runtime.modelProvider ?? "Bedrock") !== "LiteLLM") {
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/project/create/screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export function ProjectCreateScreen({ ctx, core }: ScreenProps) {

{values.kind === "agent" && (
<Step stepKey="template" prompt="choose a template">
<ChoiceField
<ChoiceField<TemplateName>
choices={TEMPLATE_CHOICES}
value={values.template}
onChange={(template) => patch({ template })}
Expand Down
Loading
Loading