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
18 changes: 18 additions & 0 deletions src/core/eval.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ import type {
SessionSourceValue,
SessionTrace,
SpanRecord,
StartBatchInsightsInput,
StartBatchEvaluationInput,
UpdateConfigurationBundleInput,
UpdateOnlineEvalInput,
Expand Down Expand Up @@ -379,6 +380,23 @@ export class EvalClient implements CoreEvalClient {
);
}

async startBatchInsights(
input: StartBatchInsightsInput,
options: CoreOptions,
): Promise<StartBatchEvaluationResponse> {
const dataSourceConfig = await this.dataSourceConfigForSource(input.source, options);
return this.clients.data(toClientConfig(options)).send(
new StartBatchEvaluationCommand({
batchEvaluationName: input.name,
description: input.description,
insights: input.insightIds.map((insightId) => ({ insightId })),
evaluators: input.evaluatorIds?.map((evaluatorId) => ({ evaluatorId })),
dataSourceConfig,
kmsKeyArn: input.kmsKeyArn,
}),
);
}

// dataSourceConfigForSource maps a resolved SessionSourceValue to the data-plane
// dataSourceConfig union. The agent arm reuses the same runtime resolution +
// log-group derivation the control-plane agentDataSource uses, then attaches the
Expand Down
132 changes: 5 additions & 127 deletions src/handlers/eval/batch-evaluation/evaluate/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,16 @@ import { InputValidationError } from "../../../../errors";
import { JsonRendererKey } from "../../../../tui";
import { SourceResolver, type AppIO } from "../../../../io";
import type { Core } from "../../../types";
import type { SessionMetadataShape, DataSourceConfig } from "@aws-sdk/client-bedrock-agentcore";
import type { SessionMetadataShape } from "@aws-sdk/client-bedrock-agentcore";
import { coreOptsFromCtx, parseJsonFlag } from "../../../utils";
import type { SessionSourceValue, SessionWindow } from "../../types";
import { SessionSource } from "../../sessionSource";

export const createEvaluateBatchEvaluationHandler = (core: Core, io: AppIO) =>
createHandler({
name: "evaluate",
description: "evaluate existing sessions service-side (async; returns a job id)",
flags: [
flag(
"agent",
"source: harness id or runtime id whose sessions to evaluate",
z.string().optional(),
),
flag(
"endpoint",
"runtime endpoint qualifier (default DEFAULT; only with --agent)",
z.string().optional(),
),
flag(
"online-eval",

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.

Can you use online-eval as a data source for batch insight?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yea you can, the API accepts both online-evals and insights together. Current CLI exposes online-eval for insights as well

"source: evaluate sessions an online-eval config already sampled",
z.string().optional(),
),
flag(
"data-source-config",
"source: raw DataSourceConfig JSON (inline, file://<path>, or -); escape hatch",
z.string().optional(),
),
flag(
"start-time",
"time filter: window start (ISO-8601, with --end-time)",
z.string().optional(),
),
flag(
"end-time",
"time filter: window end (ISO-8601, with --start-time)",
z.string().optional(),
),
flag(
"session-ids",
"filter: specific session ids (only with --agent)",
z.array(z.string()).optional(),
),
...SessionSource.flags,
flag("evaluator", "evaluator id(s) to apply", z.array(z.string()).optional()),
flag(
"ground-truth",
Expand All @@ -68,13 +34,9 @@ export const createEvaluateBatchEvaluationHandler = (core: Core, io: AppIO) =>
);
}

const resolver = new SourceResolver({ stdin: io.stdin });
const rawDataSourceConfig = parseJsonFlag<DataSourceConfig>(
"data-source-config",
await resolver.resolveText("data-source-config", flags["data-source-config"]),
);
const source = resolveDataSource(flags, rawDataSourceConfig);
const source = await SessionSource.resolve(flags, io);

const resolver = new SourceResolver({ stdin: io.stdin });
const groundTruth = parseJsonFlag<SessionMetadataShape[]>(
"ground-truth",
await resolver.resolveText("ground-truth", flags["ground-truth"]),
Expand All @@ -94,87 +56,3 @@ export const createEvaluateBatchEvaluationHandler = (core: Core, io: AppIO) =>
ctx.require(JsonRendererKey).renderJson(response);
},
});

// DataSourceFlags is hand-listed and can drift from the flag declarations above.
// When insights lands as a second consumer, promote this type + resolveDataSource
// into a static SessionSource class instead of keeping them as loose siblings.
type DataSourceFlags = {
agent?: string;
endpoint?: string;
"online-eval"?: string;
"start-time"?: string;
"end-time"?: string;
"session-ids"?: string[];
};

function resolveDataSource(
flags: DataSourceFlags,
rawDataSourceConfig: DataSourceConfig | undefined,
): SessionSourceValue {
const hasAgent = flags["agent"] !== undefined;
const hasOnlineEval = flags["online-eval"] !== undefined;
const hasRaw = rawDataSourceConfig !== undefined;

const armCount = [hasAgent, hasOnlineEval, hasRaw].filter(Boolean).length;
if (armCount !== 1) {
throw new InputValidationError(
"specify exactly one source: '--agent', '--online-eval', or '--data-source-config'",
);
}

const hasIds = !!flags["session-ids"]?.length;

if (hasRaw) {
// The raw config is self-contained; the ergonomic filter flags don't apply.
if (
flags["start-time"] !== undefined ||
flags["end-time"] !== undefined ||
hasIds ||
flags["endpoint"] !== undefined
) {
throw new InputValidationError(
"filter flags cannot be combined with '--data-source-config' (put them in the JSON)",
);
}
return { origin: "raw", dataSourceConfig: rawDataSourceConfig! };
}

const window = resolveWindow(flags);

if (hasOnlineEval) {
// The online-eval arm has no sessionIds filter and no endpoint.
if (hasIds)
throw new InputValidationError("'--session-ids' cannot be used with '--online-eval'");
if (flags["endpoint"])
throw new InputValidationError("'--endpoint' can only be used with '--agent'");
return { origin: "online-eval", onlineEvaluationConfigId: flags["online-eval"]!, window };
}

return {
origin: "agent",
agent: flags["agent"]!,
endpoint: flags["endpoint"],
window,
sessionIds: hasIds ? flags["session-ids"] : undefined,
};
}

// resolveWindow validates the explicit time window: both halves must come
// together and start must precede end.
function resolveWindow(flags: DataSourceFlags): SessionWindow | undefined {
const hasStart = flags["start-time"] !== undefined;
const hasEnd = flags["end-time"] !== undefined;
if (!hasStart && !hasEnd) return undefined; // no time filter — all available sessions
if (!hasStart || !hasEnd) {
throw new InputValidationError("--start-time and --end-time must be provided together");
}
const startTime = new Date(flags["start-time"]!);
const endTime = new Date(flags["end-time"]!);
if (Number.isNaN(+startTime) || Number.isNaN(+endTime)) {
throw new InputValidationError("--start-time and --end-time must be ISO-8601 timestamps");
}
if (+startTime >= +endTime) {
throw new InputValidationError("--start-time must be before --end-time");
}
return { startTime, endTime };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/asdf_MyAgent-3s5axvBC6Q",
"agentRuntimeName": "asdf_MyAgent",
"agentRuntimeId": "asdf_MyAgent-3s5axvBC6Q",
"agentRuntimeVersion": "1",
"createdAt": {
"$date": "2026-04-23T21:17:21.895Z"
},
"lastUpdatedAt": {
"$date": "2026-04-23T21:17:35.159Z"
},
"roleArn": "arn:aws:iam::685197708687:role/AgentCore-asdf-default-ApplicationAgentMyAgentRunti-KdyUbgImzDRK",
"networkConfiguration": {
"networkMode": "PUBLIC"
},
"status": "READY",
"lifecycleConfiguration": {
"idleRuntimeSessionTimeout": 900,
"maxLifetime": 28800
},
"description": "AgentCore Runtime: asdf_MyAgent",
"workloadIdentityDetails": {
"workloadIdentityArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:workload-identity-directory/default/workload-identity/asdf_MyAgent-3s5axvBC6Q"
},
"agentRuntimeArtifact": {
"codeConfiguration": {
"code": {
"s3": {
"bucket": "cdk-hnb659fds-assets-685197708687-us-west-2",
"prefix": "a07977786dda1e2e5be304cb7485237a19ed24d5e05b02e73ca91a43fd2e7280.zip"
}
},
"runtime": "PYTHON_3_13",
"entryPoint": [
"opentelemetry-instrument",
"main.py"
]
}
},
"environmentVariables": {
"AGENTCORE_GATEWAY_BUGBASHGW1776978672_AUTH_TYPE": "NONE",
"AGENTCORE_GATEWAY_BUGBASHGW1776978672_URL": "https://bugbashgw1776978672-zsy8cbqwts.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp"
},
"metadataConfiguration": {
"requireMMDSV2": true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"batchEvaluationId": "golden_batch_insights_fixture-cd634815b4",
"batchEvaluationArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:batch-evaluate/golden_batch_insights_fixture-cd634815b4",
"batchEvaluationName": "golden_batch_insights_fixture",
"status": "COMPLETED",
"createdAt": {
"$date": "2026-08-21T19:27:51.136Z"
},
"insights": [
{
"insightId": "Builtin.Insight.FailureAnalysis"
}
],
"dataSourceConfig": {
"cloudWatchLogs": {
"serviceNames": [
"asdf_MyAgent.DEFAULT"
],
"logGroupNames": [
"/aws/bedrock-agentcore/runtimes/asdf_MyAgent-3s5axvBC6Q-DEFAULT"
]
}
},
"evaluationResults": {
"numberOfSessionsCompleted": 2,
"numberOfSessionsInProgress": 0,
"numberOfSessionsFailed": 0,
"totalNumberOfSessions": 2,
"numberOfSessionsIgnored": 0,
"evaluatorSummaries": []
},
"description": "Golden batch insights fixture",
"updatedAt": {
"$date": "2026-08-21T19:28:56.756Z"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
{
"batchEvaluations": [
{
"batchEvaluationId": "golden_batch_evaluate-b957bb900a",
"batchEvaluationArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:batch-evaluate/golden_batch_evaluate-b957bb900a",
"batchEvaluationName": "golden_batch_evaluate",
"status": "COMPLETED",
"createdAt": {
"$date": "2026-08-11T21:18:32.724Z"
},
"evaluators": [
{
"evaluatorId": "Builtin.Helpfulness"
}
],
"updatedAt": {
"$date": "2026-08-11T21:18:35.488Z"
}
},
{
"batchEvaluationId": "golden_batch_evaluate_fixture685-d2967f9a21",
"batchEvaluationArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:batch-evaluate/golden_batch_evaluate_fixture685-d2967f9a21",
"batchEvaluationName": "golden_batch_evaluate_fixture685",
"status": "COMPLETED",
"createdAt": {
"$date": "2026-08-11T21:19:58.199Z"
},
"evaluators": [
{
"evaluatorId": "Builtin.Helpfulness"
}
],
"updatedAt": {
"$date": "2026-08-11T21:20:01.334Z"
}
},
{
"batchEvaluationId": "golden_batch_insights_fixture-cd634815b4",
"batchEvaluationArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:batch-evaluate/golden_batch_insights_fixture-cd634815b4",
"batchEvaluationName": "golden_batch_insights_fixture",
"status": "COMPLETED",
"createdAt": {
"$date": "2026-08-21T19:27:51.136Z"
},
"description": "Golden batch insights fixture",
"insights": [
{
"insightId": "Builtin.Insight.FailureAnalysis"
}
],
"updatedAt": {
"$date": "2026-08-21T19:28:56.756Z"
}
},
{
"batchEvaluationId": "sim_live_1f9e-cbcc074b38",
"batchEvaluationArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:batch-evaluate/sim_live_1f9e-cbcc074b38",
"batchEvaluationName": "sim_live_1f9e",
"status": "COMPLETED",
"createdAt": {
"$date": "2026-08-13T22:26:21.948Z"
},
"evaluators": [
{
"evaluatorId": "Builtin.Helpfulness"
}
],
"updatedAt": {
"$date": "2026-08-13T22:27:25.296Z"
}
},
{
"batchEvaluationId": "sim_live_6275-c9338a9ec5",
"batchEvaluationArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:batch-evaluate/sim_live_6275-c9338a9ec5",
"batchEvaluationName": "sim_live_6275",
"status": "FAILED",
"createdAt": {
"$date": "2026-08-13T22:18:02.147Z"
},
"evaluators": [
{
"evaluatorId": "Builtin.Helpfulness"
}
],
"errorDetails": [
"All 2 sessions failed during batch evaluation."
],
"updatedAt": {
"$date": "2026-08-13T22:19:05.784Z"
}
},
{
"batchEvaluationId": "sim_mt_2755-7517683065",
"batchEvaluationArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:batch-evaluate/sim_mt_2755-7517683065",
"batchEvaluationName": "sim_mt_2755",
"status": "COMPLETED",
"createdAt": {
"$date": "2026-08-14T19:49:59.317Z"
},
"evaluators": [
{
"evaluatorId": "Builtin.Helpfulness"
}
],
"updatedAt": {
"$date": "2026-08-14T19:51:02.750Z"
}
}
]
}
Loading
Loading