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
6 changes: 5 additions & 1 deletion src/core/project/manager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type {
ProjectResource,
RemoveResourceInput,
RemoveResourceResult,
RemoveResourcesResult,
} from "../../handlers/project/types";
import type { Logger } from "../../logging";
import {
Expand Down Expand Up @@ -531,6 +532,7 @@ export class FsProjectManager implements ProjectManager {

let removed = false;
let newSpec: unknown;
let removedResource = input;
if (input.resourceType === "policy") {
const candidates = existingProjectSpec.policyEngines.filter((engine) =>
engine.policies.some((policy) => policy.name === input.name),
Expand All @@ -546,6 +548,7 @@ export class FsProjectManager implements ProjectManager {
? candidates.find((engine) => engine.name === input.engineName)
: candidates[0];
removed = owner !== undefined;
if (owner) removedResource = { ...input, engineName: owner.name };
const engines = existingProjectSpec.policyEngines.map((engine) =>
engine === owner
? { ...engine, policies: engine.policies.filter((policy) => policy.name !== input.name) }
Expand Down Expand Up @@ -624,10 +627,11 @@ export class FsProjectManager implements ProjectManager {
return {
project: { ...project, spec: newProjectSpec },
removedEnvKeys,
removedResource,
};
}

public async removeAllResources(project: Project): Promise<RemoveResourceResult> {
public async removeAllResources(project: Project): Promise<RemoveResourcesResult> {
const agentCoreSpecPath = this.getProjectSpecPath(project);
const existingProjectSpec = await this.json.read(agentCoreSpecPath, ProjectSpecSchema);

Expand Down
31 changes: 17 additions & 14 deletions src/handlers/project/add/config-bundle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { KmsKeyArnSchema } from "../../../../projectSchemas/evaluator";
import { createHandler, flag, ProjectKey } from "../../../../router";
import { parseJsonFlagWithSchema } from "../../../utils";
import type { AddProjectResourceConfig } from "../types";
import { addProjectResource } from "../shared";

const ComponentsSchema = z
.record(z.string().min(1), ComponentConfigurationSchema.strict())
Expand Down Expand Up @@ -68,20 +69,22 @@ export const createAddConfigBundleHandler = (config: AddProjectResourceConfig) =
}

const project = ctx.require(ProjectKey);
for await (const event of config.projectManager.addResource(project, {
resourceType: "config-bundle",
resourceConfig: {
name: flags.name,
description: flags.description,
components,
branchName: flags["branch-name"],
commitMessage: flags["commit-message"],
kmsKeyArn: flags["kms-key-arn"],
await addProjectResource(
ctx,
config,
project,
{
resourceType: "config-bundle",
resourceConfig: {
name: flags.name,
description: flags.description,
components,
branchName: flags["branch-name"],
commitMessage: flags["commit-message"],
kmsKeyArn: flags["kms-key-arn"],
},
},
})) {
if (event.type === "step") config.io.stderr.write(`${event.message}\n`);
}

config.io.stderr.write(`added configuration bundle '${flags.name}' to '${project.name}'\n`);
`added configuration bundle '${flags.name}' to '${project.name}'`,
);
},
});
27 changes: 16 additions & 11 deletions src/handlers/project/add/credentials/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
credentialEnvVarName,
credentialNameFieldSuffix,
} from "../../../../projectSchemas/credential";
import { addProjectResource } from "../shared";

export { credentialEnvVarName };

Expand Down Expand Up @@ -68,15 +69,19 @@ export async function addCredentialToProject(
);
}

for await (const event of config.projectManager.addResource(project, {
resourceType: "credential",
...input,
})) {
if (event.type === "step") config.io.stderr.write(`${event.message}\n`);
}

config.io.stderr.write(`added credential '${input.resourceConfig.name}' to '${project.name}'\n`);
for (const entry of (input.envEntries ?? []).filter((e) => e.value === undefined)) {
config.io.stderr.write(`Set ${entry.key} in agentcore/.env.local before you deploy.\n`);
}
await addProjectResource(
ctx,
config,
project,
{
resourceType: "credential",
...input,
},
`added credential '${input.resourceConfig.name}' to '${project.name}'`,
{
notes: (input.envEntries ?? [])
.filter((entry) => entry.value === undefined)
.map((entry) => `Set ${entry.key} in agentcore/.env.local before you deploy.`),
},
);
}
19 changes: 19 additions & 0 deletions src/handlers/project/add/evaluator/code-based/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,25 @@ describe("project add evaluator code-based", () => {
expect(io.stderr()).toContain("returns Pass for every session");
});

test("--json reports the empty stub guidance as a structured note", async () => {
await inProject();
const { io } = await run([
"add",
"evaluator",
"code-based",
"--name",
"stub",
"--level",
"SESSION",
"--json",
]);

expect(JSON.parse(io.stdout()).notes).toEqual([
"note: this evaluator returns Pass for every session until you implement app/stub/lambda_function.py",
]);
expect(io.stderr()).not.toContain("returns Pass for every session");
});

test("external mode prints no stub note", async () => {
await inProject();
const { io } = await run([
Expand Down
49 changes: 29 additions & 20 deletions src/handlers/project/add/evaluator/code-based/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from "../../../types";
import { parseJsonFlagWithSchema } from "../../../../utils";
import type { AddProjectResourceConfig } from "../../types";
import { addProjectResource } from "../../shared";

export const createAddCodeBasedEvaluatorHandler = (config: AddProjectResourceConfig) =>
createHandler({
Expand Down Expand Up @@ -83,13 +84,16 @@ export const createAddCodeBasedEvaluatorHandler = (config: AddProjectResourceCon
config: { codeBased: { external: { lambdaArn: flags["lambda-arn"] } } },
});
if (!parsed.success) throw new InputValidationError(z.prettifyError(parsed.error));
for await (const event of config.projectManager.addResource(project, {
resourceType: "evaluator",
resourceConfig: parsed.data,
})) {
if (event.type === "step") config.io.stderr.write(`${event.message}\n`);
}
config.io.stderr.write(`added evaluator '${flags["name"]}' to '${project.name}'\n`);
await addProjectResource(
ctx,
config,
project,
{
resourceType: "evaluator",
resourceConfig: parsed.data,
},
`added evaluator '${flags["name"]}' to '${project.name}'`,
);
return;
}

Expand All @@ -102,19 +106,24 @@ export const createAddCodeBasedEvaluatorHandler = (config: AddProjectResourceCon
...(flags["timeout-seconds"] !== undefined && { timeoutSeconds: flags["timeout-seconds"] }),
};

for await (const event of config.projectManager.addResource(project, {
resourceType: "evaluator",
resourceConfig: { name: scaffold.name },
scaffold,
})) {
if (event.type === "step") config.io.stderr.write(`${event.message}\n`);
}

config.io.stderr.write(`added evaluator '${flags["name"]}' to '${project.name}'\n`);
if (!hasMetric)
config.io.stderr.write(
`note: this evaluator returns Pass for every session until you implement app/${flags["name"]}/lambda_function.py\n`,
);
await addProjectResource(
ctx,
config,
project,
{
resourceType: "evaluator",
resourceConfig: { name: scaffold.name },
scaffold,
},
`added evaluator '${flags["name"]}' to '${project.name}'`,
{
notes: hasMetric
? []
: [
`note: this evaluator returns Pass for every session until you implement app/${flags["name"]}/lambda_function.py`,
],
},
);
},
});

Expand Down
19 changes: 11 additions & 8 deletions src/handlers/project/add/evaluator/llm-as-a-judge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import { TagsSchema } from "../../../../../projectSchemas/tags";
import { parseJsonFlagWithSchema } from "../../../../utils";
import type { AddProjectResourceConfig } from "../../types";
import { addProjectResource } from "../../shared";
import {
isRatingScalePreset,
RATING_SCALE_PRESETS,
Expand Down Expand Up @@ -93,14 +94,16 @@ export const createAddLlmAsAJudgeEvaluatorHandler = (config: AddProjectResourceC
if (!parsed.success) throw new InputValidationError(z.prettifyError(parsed.error));

const project = ctx.require(ProjectKey);
for await (const event of config.projectManager.addResource(project, {
resourceType: "evaluator",
resourceConfig: parsed.data,
})) {
if (event.type === "step") config.io.stderr.write(`${event.message}\n`);
}

config.io.stderr.write(`added evaluator '${flags["name"]}' to '${project.name}'\n`);
await addProjectResource(
ctx,
config,
project,
{
resourceType: "evaluator",
resourceConfig: parsed.data,
},
`added evaluator '${flags["name"]}' to '${project.name}'`,
);
},
});

Expand Down
28 changes: 28 additions & 0 deletions src/handlers/project/add/gateway-connector/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,34 @@ const { addGateway, cleanup, inProject, projectSpec, run } =
afterEach(cleanup);

describe("project add gateway-connector", () => {
test("--json preserves the command resource type and parent Gateway", async () => {
const projectRoot = await inProject();
await addGateway();

const io = await run([
"add",
"gateway-connector",
"--gateway",
"tools",
"--name",
"web",
"--connector",
"web-search",
"--json",
]);

expect(JSON.parse(io.stdout())).toEqual({
operation: "add",
project: { name: "TestProject", path: projectRoot },
resource: {
type: "gateway-connector",
name: "web",
parent: { type: "gateway", name: "tools" },
},
});
expect(io.stderr()).not.toContain("added Connector Target");
});

test("adds Web Search and external Knowledge Base connectors", async () => {
const projectRoot = await inProject();
await addGateway();
Expand Down
21 changes: 12 additions & 9 deletions src/handlers/project/add/gateway-connector/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import { createHandler, flag, ProjectKey } from "../../../../router";
import { parseJsonFlagWithSchema } from "../../../utils";
import type { AddProjectResourceConfig } from "../types";
import { addProjectResource } from "../shared";

export const createAddGatewayConnectorHandler = (config: AddProjectResourceConfig) =>
createHandler({
Expand Down Expand Up @@ -85,15 +86,17 @@ export const createAddGatewayConnectorHandler = (config: AddProjectResourceConfi
);
}

for await (const event of config.projectManager.addResource(project, {
resourceType: "gateway-target",
gatewayName: flags.gateway,
resourceConfig: target,
})) {
if (event.type === "step") config.io.stderr.write(`${event.message}\n`);
}
config.io.stderr.write(
`added Connector Target '${target.name}' to Gateway '${flags.gateway}' in '${project.name}'\n`,
await addProjectResource(
ctx,
config,
project,
{
resourceType: "gateway-target",
gatewayName: flags.gateway,
resourceConfig: target,
},
`added Connector Target '${target.name}' to Gateway '${flags.gateway}' in '${project.name}'`,
{ resourceType: "gateway-connector" },
);
},
});
Expand Down
20 changes: 11 additions & 9 deletions src/handlers/project/add/gateway-target/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { createHandler, flag, ProjectKey } from "../../../../router";
import { parseJsonFlagWithSchema } from "../../../utils";
import type { Project } from "../../types";
import type { AddProjectResourceConfig } from "../types";
import { addProjectResource } from "../shared";

export const createAddGatewayTargetHandler = (config: AddProjectResourceConfig) =>
createHandler({
Expand Down Expand Up @@ -120,15 +121,16 @@ Use project add gateway-connector for curated Connector shortcuts.`,
};
}

for await (const event of config.projectManager.addResource(project, {
resourceType: "gateway-target",
gatewayName: flags.gateway,
resourceConfig: target,
})) {
if (event.type === "step") config.io.stderr.write(`${event.message}\n`);
}
config.io.stderr.write(
`added Target '${target.name}' to Gateway '${flags.gateway}' in '${project.name}'\n`,
await addProjectResource(
ctx,
config,
project,
{
resourceType: "gateway-target",
gatewayName: flags.gateway,
resourceConfig: target,
},
`added Target '${target.name}' to Gateway '${flags.gateway}' in '${project.name}'`,
);
},
});
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/project/add/gateway-test-support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function createGatewayProjectTestHarness(directoryPrefix: string) {
]);
const projectRoot = join(directory, name);
process.chdir(projectRoot);
return projectRoot;
return process.cwd();
}

async function addGateway(name = "tools"): Promise<void> {
Expand Down
18 changes: 11 additions & 7 deletions src/handlers/project/add/gateway/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { AgentCoreGateway } from "../../../../projectSchemas/gateway";
import { createHandler, flag, ProjectKey } from "../../../../router";
import { parseJsonFlagWithSchema, parseTags } from "../../../utils";
import type { AddProjectResourceConfig } from "../types";
import { addProjectResource } from "../shared";

const GatewayAuthorizerConfigurationInputSchema = GatewayAuthorizerConfigSchema.strict();

Expand Down Expand Up @@ -125,12 +126,15 @@ export const createAddGatewayHandler = (config: AddProjectResourceConfig) =>
tags: parseTags(flags.tags),
};

for await (const event of config.projectManager.addResource(project, {
resourceType: "gateway",
resourceConfig: gateway,
})) {
if (event.type === "step") config.io.stderr.write(`${event.message}\n`);
}
config.io.stderr.write(`added Gateway '${flags.name}' to '${project.name}'\n`);
await addProjectResource(
ctx,
config,
project,
{
resourceType: "gateway",
resourceConfig: gateway,
},
`added Gateway '${flags.name}' to '${project.name}'`,
);
},
});
Loading
Loading