Skip to content

feat(eval): add datasets CLI commands - #1911

Open
nborges-aws wants to merge 4 commits into
refactorfrom
datasets-cli
Open

feat(eval): add datasets CLI commands #1911
nborges-aws wants to merge 4 commits into
refactorfrom
datasets-cli

Conversation

@nborges-aws

@nborges-aws nborges-aws commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Description

Adds command-line CRUDL plus versioning for AgentCore evaluation datasets:

  • eval dataset create
  • eval dataset get
  • eval dataset list
  • eval dataset delete
  • eval dataset publish

eval dataset update will land in follow up PR

  • DataSourceType union on CreateDataset allowing users to pass in s3 uri or file path for data set creation.
  • source.tsx - Responsible for translating file path in dataSourceType union to the service API expected inlineExample format. inlineExamples is a dict, with list of JSONL items inside. For user convenience and ability to pass their JSONL draft file as a whole -- we accept filepath, and parse the file into inlineExamples list before call to service
  • --file-path flag conditional logic on delete: eval datasets get without file path flag will fetch metadata and print to command line (getDataset API). When file path flag is included, CLI will pull content from pre-signed downloadUrl provided in metadata, and writes content to provided file location (streamed into temp file and renamed into place)
  • New error types in src/errors: DatasetDownloadError (SERVICE, covers a missing or unfetchable presigned URL) and DatasetWriteError (USER, covers local write issues)
  • EvalClient now receives the injected CoreFetch from CoreClient, since dataset content is served from S3
  • create, publish, delete are all async operation which return CREATING / UPDATING / DELETING

Related Issue

Closes #

Documentation PR

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Other (please describe):

Testing

Manually tested commands using bun run ... against personal account, happy path and negative validation.

Full suite against latest HEAD after rebasing onto refactor:

  • bun test (729 pass, 0 fail)
  • bun run typecheck clean
  • bun run lint:check clean
  • bun run format:check clean
  • bun run build clean

How have you tested the change?

  • I ran npm run test:unit and npm run test:integ
  • I ran npm run typecheck
  • I ran npm run lint
  • If I modified src/assets/, I ran npm run test:update-snapshots and committed the updated snapshots

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

Stack created with GitHub Stacks CLIGive Feedback 💬

@github-actions github-actions Bot added the agentcore-harness-reviewing AgentCore Harness review in progress label Aug 4, 2026
@codecov-commenter

codecov-commenter commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.46809% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.37%. Comparing base (ae6e810) to head (f3fe5d7).

Files with missing lines Patch % Lines
src/io/atomicWrite.ts 92.30% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           refactor    #1911      +/-   ##
============================================
+ Coverage     96.28%   96.37%   +0.09%     
============================================
  Files           245      253       +8     
  Lines         12105    12471     +366     
============================================
+ Hits          11655    12019     +364     
- Misses          450      452       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot removed the agentcore-harness-reviewing AgentCore Harness review in progress label Aug 4, 2026
handle: async (ctx, flags) => {
if (!flags["id"]) throw new InputValidationError("required option '--id <id>' not specified");

// Publishing an unmodified DRAFT creates a version identical to the last

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.

current implementation will allow user to publish a version that is unmodified from the last. If silently publishing unmodified version feels wrong here, we can check draftStatus for UNMODIFIED and use that to prompt/warn/reject publishing.

Comment thread src/core/eval.tsx Outdated
// renamed into place once the transfer completes. Streams so a large dataset
// is never held in memory. A failed or aborted transfer removes the temp file and
// leaves any existing file at `filePath` untouched.
async function streamToFile(

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.

This seems like it should be in the io package.

Comment thread src/errors/errors.tsx Outdated
* A downloaded dataset could not be written to its destination.
* Local and user-fixable: a missing directory, a permission denial, etc.
*/
export class DatasetWriteError extends AgentCoreCLIError {

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 these exceptions be made more general? Maybe NetworkingError and FileWriteError?

@jariy17 jariy17 left a comment

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.

Pretty Good! Just look at the error handling for the handlers

Comment thread src/core/eval.tsx Outdated
// ingesting has no URL to offer yet. Report the status, which is what tells
// the caller whether to retry.
if (!dataset.downloadUrl) {
throw new DatasetDownloadError(

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.

This isn't really a user fault, more of service issue. Should we add a retry mechanism here?

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.

I've classified this as a SERVICE error. I considered adding a retry mechanism, but it was plausible that after a short-polling loop it still wouldn't be active. I lead towards classifying this as a service-side retryable exception, and informing the user to retry once ACTIVE as the right call. Updated code does exactly that

Comment thread src/core/eval.tsx Outdated
try {
const response = await this.fetch(dataset.downloadUrl, { signal });
if (!response.ok) {
throw new DatasetDownloadError(

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.

Again this could be a service issue or an Internal issue.

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.

I think for this case we're good to leave as service. If we hit !response.ok then we successfully made the http call and got a non-2xx

Comment thread src/core/eval.tsx
});
}
body = response.body;
} catch (error) {

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.

Concern about the catch-all wrap here. Blanket-tagging every unknown fetch failure as SERVICE is a guess, and it can mislabel things:
1. A bug in our own request construction is really INTERNAL, not SERVICE.
2. A runtime or polyfill issue is also INTERNAL.

'd only wrap the cases we can positively attribute to the service, like the non-ok HTTP status above. Let anything unrecognized fall through to fromError so it categorizes based on what it actually observes.

Comment thread src/core/eval.tsx Outdated
// renamed into place once the transfer completes. Streams so a large dataset
// is never held in memory. A failed or aborted transfer removes the temp file and
// leaves any existing file at `filePath` untouched.
async function streamToFile(

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.

There should be a library package for this

const interrupt = () => controller.abort();
process.once("SIGINT", interrupt);
try {
const response = await core.eval.downloadDataset(

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.

We should add filePath to the response here. Right now the output is just metadata, so nothing in it confirms where the file was written. Returning { ...dataset, filePath } gives the customer clear confirmation of the download and its location.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants