Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Add prompt id patch + eval pull#444

Merged
potofpie merged 3 commits intofeature-evalfrom
add-prompt-id-patch
Sep 15, 2025
Merged

Add prompt id patch + eval pull#444
potofpie merged 3 commits intofeature-evalfrom
add-prompt-id-patch

Conversation

@potofpie
Copy link
Copy Markdown
Member

@potofpie potofpie commented Sep 15, 2025

Summary by CodeRabbit

  • New Features

    • Added an eval CLI with create and pull subcommands to manage evaluations.
    • Interactive flow for choosing evaluation type and providing name/description; supports non-interactive use with --force.
    • Outputs generated evaluation code to stdout and saves it to a chosen directory (via -d).
  • Chores

    • Enhanced AI integration telemetry with prompt-linked metadata and standardized prompt handling across generation and embedding operations; no user action required.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Sep 15, 2025

Walkthrough

Adds a new Cobra-based eval CLI with create and pull subcommands, associated API helpers and types, interactive/TTY-aware prompts, file output to src/evals/*.ts, and flags. Updates Vercel AI bundler to inject telemetry setup with prompt metadata and prompt stringification for multiple AI functions.

Changes

Cohort / File(s) Summary
CLI Eval feature
cmd/eval.go
Adds eval parent command with create and pull subcommands; introduces EvalObject/EvalPullObject types and response aliases; implements CreateGenerativeEvaluation, CreateTemplateEvaluation, PullEvaluation; interactive prompts and --force handling; writes TS code to src/evals/.ts; dir flag (-d) support.
Vercel AI telemetry patch
internal/bundler/vercel_ai.go
Replaces simple telemetry enable patch with a composite Before patch: clones args, builds metadata from prompt.id, sets experimental_telemetry with metadata, stringifies prompt, writes back to _args[0]; applied to generateText/streamText/generateObject/streamObject/embed/embedMany.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI as eval CLI
  participant API as Cloud API
  participant FS as Filesystem

  rect rgb(235,245,255)
    note over User,CLI: eval create (TTY-aware)
    User->>CLI: eval create [--force] [-d DIR] [name desc]
    CLI->>CLI: Determine type (template/generative)
    alt template
      CLI->>CLI: Gather name/description (args or prompts)
    else generative
      CLI->>CLI: Use generative path
    end
    CLI->>User: Confirm (skip if --force)
    alt confirmed
      alt template
        CLI->>API: CreateTemplateEvaluation(projectId, name, desc)
      else generative
        CLI->>API: CreateGenerativeEvaluation(projectId)
      end
      API-->>CLI: evalId
      CLI->>API: PullEvaluation(evalId)
      API-->>CLI: { code, id, name, description }
      CLI->>FS: Write src/evals/<Name>.ts
      CLI-->>User: Output code and success info
    else canceled
      CLI-->>User: Abort
    end
  end
Loading
sequenceDiagram
  participant User
  participant CLI as eval CLI
  participant API as Cloud API
  participant FS as Filesystem

  note over User,CLI: eval pull
  User->>CLI: eval pull --id <evalId> [-d DIR]
  CLI->>API: PullEvaluation(evalId)
  API-->>CLI: { code, id, name, description }
  CLI->>FS: Write src/evals/<Name>.ts
  CLI-->>User: Output code
Loading
sequenceDiagram
  participant Caller
  participant Patch as Before Patch
  participant AI as Vercel AI fn

  Caller->>Patch: call generateText(...) with _args[0]=opts
  Patch->>Patch: opts = { ..._args[0] }
  Patch->>Patch: metadata = { promptId: opts.prompt.id }
  Patch->>Patch: opts.experimental_telemetry = { isEnabled: true, metadata }
  Patch->>Patch: opts.prompt = opts.prompt.toString()
  Patch->>AI: proceed with _args[0] = opts
  AI-->>Caller: result/stream
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I tap my paws on the terminal ground,
“eval create!”—a new warren found.
Pull down code, to burrow I sprint,
TS twinkles with telemetry’s hint.
Prompts get strings, IDs take flight—
Carrots compiled, the build’s just right.
Hop, ship, delight! 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Add prompt id patch + eval pull" accurately and concisely reflects the two main changes in the diff: adding a prompt-id telemetry patch in the bundler (vercel_ai.go) and introducing eval pull/create functionality in the CLI (cmd/eval.go). It is directly related to the raw summary and specific enough for a reviewer to understand the primary intent without listing files or extraneous details. The use of "+" is informal but does not obscure the meaning.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add-prompt-id-patch

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Comment @coderabbitai help to get the list of available commands and usage tips.

@potofpie potofpie marked this pull request as draft September 15, 2025 14:39
@potofpie potofpie changed the base branch from main to feature-eval September 15, 2025 14:41
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

This PR is being reviewed by Cursor Bugbot

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

opts.experimental_telemetry = { isEnabled: true , metadata: metadata };
opts.prompt = opts.prompt.toString();
_args[0] = opts;
`)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: Telemetry Patch Fails Without Prompt Validation

The telemetry patch accesses opts.prompt.id and calls opts.prompt.toString() without checking if opts.prompt exists or has the expected structure. This can lead to runtime errors, especially for Vercel AI functions like embed that may not include a prompt object in their arguments.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
cmd/eval.go (4)

221-224: Protect against accidental overwrite (create).

Currently overwrites without warning. Prompt on TTY unless --force is set.

- filePath := filepath.Join(evalsDir, filename)
- if err := os.WriteFile(filePath, []byte(evalObj.Code), 0644); err != nil {
+ filePath := filepath.Join(evalsDir, filename)
+ if _, err := os.Stat(filePath); err == nil && tui.HasTTY && !force {
+   if !tui.Ask(logger, fmt.Sprintf("File %s exists. Overwrite?", filePath), false) {
+     tui.ShowWarning("cancelled")
+     return
+   }
+ }
+ if err := os.WriteFile(filePath, []byte(evalObj.Code), 0644); err != nil {
   errsystem.New(errsystem.ErrOpenFile, err, errsystem.WithUserMessage("Failed to write evaluation code to file")).ShowErrorAndExit()
 }

273-276: Protect against accidental overwrite (pull).

Prompt before overwriting, mirroring create behavior.

- filename := evalObj.Name + ".ts"
+ safeName := filepath.Base(evalObj.Name)
+ safeName = strings.TrimSpace(safeName)
+ if safeName == "" { safeName = "evaluation" }
+ safeName = strings.Map(func(r rune) rune {
+   switch r {
+   case '/', '\\', ':', '*', '?', '"', '<', '>', '|':
+     return '_'
+   default:
+     return r
+   }
+ }, safeName)
+ filename := safeName + ".ts"
   evalsDir := filepath.Join(dir, "src", "evals")
@@
- filePath := filepath.Join(evalsDir, filename)
- if err := os.WriteFile(filePath, []byte(evalObj.Code), 0644); err != nil {
+ filePath := filepath.Join(evalsDir, filename)
+ if _, err := os.Stat(filePath); err == nil && tui.HasTTY {
+   if !tui.Ask(logger, fmt.Sprintf("File %s exists. Overwrite?", filePath), false) {
+     tui.ShowWarning("cancelled")
+     return
+   }
+ }
+ if err := os.WriteFile(filePath, []byte(evalObj.Code), 0644); err != nil {
   errsystem.New(errsystem.ErrOpenFile, err, errsystem.WithUserMessage("Failed to write evaluation code to file")).ShowErrorAndExit()
 }

Note: Ensure "strings" is imported (see earlier import diff).

Also applies to: 282-285


122-127: Avoid shadowing the context import.

context := project.EnsureProject(...) shadows the context package and harms readability.

Consider renaming to projCtx or pctx and updating subsequent uses.


210-215: Nil-guard evalObj after spinner.

If an unexpected error path returns without exiting, evalObj could be nil.

 spinner.New().Title("Creating evaluation...").Action(action).Run()

 // Write code to file
- filename := evalObj.Name + ".ts"
+ if evalObj == nil {
+   errsystem.New(errsystem.ErrApiRequest, nil, errsystem.WithUserMessage("Evaluation payload was empty")).ShowErrorAndExit()
+ }
+ filename := evalObj.Name + ".ts"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b0a6104 and 50bfdf9.

📒 Files selected for processing (2)
  • cmd/eval.go (1 hunks)
  • internal/bundler/vercel_ai.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/eval.go (4)
internal/util/api.go (1)
  • NewAPIClient (70-78)
internal/project/project.go (1)
  • EnsureProject (586-610)
internal/errsystem/errorcodes.go (3)
  • ErrApiRequest (21-24)
  • ErrCreateDirectory (61-64)
  • ErrOpenFile (73-76)
internal/errsystem/errsystem.go (1)
  • WithUserMessage (70-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: Build and Test (macos-latest)
  • GitHub Check: Test CLI Upgrade Path (windows-latest)
  • GitHub Check: Analyze (go)
🔇 Additional comments (1)
internal/bundler/vercel_ai.go (1)

34-40: experimental_telemetry is correct — no changes required.
Docs confirm per-call experimental_telemetry with isEnabled and metadata (plus optional functionId/recordInputs/recordOutputs) is the supported shape for generateText/streamText.

Comment thread cmd/eval.go
Comment on lines +212 to +215
// Write code to file
filename := evalObj.Name + ".ts"
evalsDir := filepath.Join(dir, "src", "evals")

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.

⚠️ Potential issue

Sanitize file name to prevent path traversal and invalid chars.

evalObj.Name + ".ts" can escape src/evals or include illegal characters.

Apply this diff (imports added below):

- filename := evalObj.Name + ".ts"
- evalsDir := filepath.Join(dir, "src", "evals")
+ safeName := filepath.Base(evalObj.Name)
+ safeName = strings.TrimSpace(safeName)
+ if safeName == "" {
+   safeName = "evaluation"
+ }
+ // replace path separators and disallowed chars
+ safeName = strings.Map(func(r rune) rune {
+   switch r {
+   case '/', '\\', ':', '*', '?', '"', '<', '>', '|':
+     return '_'
+   default:
+     return r
+   }
+ }, safeName)
+ filename := safeName + ".ts"
+ evalsDir := filepath.Join(dir, "src", "evals")

Add import:

 import (
   "context"
   "fmt"
   "os"
   "os/signal"
   "path/filepath"
   "syscall"
+  "strings"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Write code to file
filename := evalObj.Name + ".ts"
evalsDir := filepath.Join(dir, "src", "evals")
import (
"context"
"fmt"
"os"
"os/signal"
"path/filepath"
"syscall"
"strings"
)
Suggested change
// Write code to file
filename := evalObj.Name + ".ts"
evalsDir := filepath.Join(dir, "src", "evals")
// Write code to file
safeName := filepath.Base(evalObj.Name)
safeName = strings.TrimSpace(safeName)
if safeName == "" {
safeName = "evaluation"
}
// replace path separators and disallowed chars
safeName = strings.Map(func(r rune) rune {
switch r {
case '/', '\\', ':', '*', '?', '"', '<', '>', '|':
return '_'
default:
return r
}
}, safeName)
filename := safeName + ".ts"
evalsDir := filepath.Join(dir, "src", "evals")

Comment thread cmd/eval.go
func init() {
rootCmd.AddCommand(evalCmd)

evalCreateCmd.Flags().Bool("force", !hasTTY, "Don't prompt for confirmation")
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.

⚠️ Potential issue

Fix compile error: undefined hasTTY.

Use the exported tui.HasTTY.

- evalCreateCmd.Flags().Bool("force", !hasTTY, "Don't prompt for confirmation")
+ evalCreateCmd.Flags().Bool("force", !tui.HasTTY, "Don't prompt for confirmation")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
evalCreateCmd.Flags().Bool("force", !hasTTY, "Don't prompt for confirmation")
evalCreateCmd.Flags().Bool("force", !tui.HasTTY, "Don't prompt for confirmation")
🤖 Prompt for AI Agents
In cmd/eval.go around line 297 the code references an undefined identifier
`hasTTY`; replace it with the exported `tui.HasTTY` (i.e., use tui.HasTTY when
setting the default for the "force" flag) and ensure the package `tui` is
imported at the top of the file if not already present. Ensure the flag line
becomes evalCreateCmd.Flags().Bool("force", !tui.HasTTY, "Don't prompt for
confirmation") and run `go build` to confirm compilation.

Comment on lines +34 to +40
var vercelTelemetryPatch = generateJSArgsPatch(0, ``) + fmt.Sprintf(`
const opts = {...(_args[0] ?? {}) };
const metadata = { promptId: opts.prompt.id };
opts.experimental_telemetry = { isEnabled: true , metadata: metadata };
opts.prompt = opts.prompt.toString();
_args[0] = opts;
`)
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.

⚠️ Potential issue

Guard against undefined opts.prompt and avoid breaking non-text APIs (embed/embedMany).

Directly accessing opts.prompt.id and calling .toString() will throw when prompt is absent (not provided for embed/embedMany) or not an object. Also, don’t clobber existing experimental_telemetry.

Apply this diff:

- var vercelTelemetryPatch = generateJSArgsPatch(0, ``) + fmt.Sprintf(`
- const opts = {...(_args[0] ?? {}) };
- const metadata = { promptId: opts.prompt.id };
- opts.experimental_telemetry = { isEnabled: true , metadata: metadata };
- opts.prompt = opts.prompt.toString();
- _args[0] = opts;
- `)
+ var vercelTelemetryPatch = generateJSArgsPatch(0, ``) + fmt.Sprintf(`
+ const opts = { ...(_args[0] ?? {}) };
+ const p = opts.prompt;
+ const metadata = {};
+ if (p && typeof p === 'object' && 'id' in p) {
+   metadata.promptId = p.id;
+ }
+ opts.experimental_telemetry = { ...(opts.experimental_telemetry ?? {}), isEnabled: true, metadata };
+ if (typeof p === 'string') {
+   // keep as-is
+ } else if (p && typeof p.toString === 'function') {
+   opts.prompt = p.toString();
+ }
+ _args[0] = opts;
+ `)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var vercelTelemetryPatch = generateJSArgsPatch(0, ``) + fmt.Sprintf(`
const opts = {...(_args[0] ?? {}) };
const metadata = { promptId: opts.prompt.id };
opts.experimental_telemetry = { isEnabled: true , metadata: metadata };
opts.prompt = opts.prompt.toString();
_args[0] = opts;
`)
var vercelTelemetryPatch = generateJSArgsPatch(0, ``) + fmt.Sprintf(`
const opts = { ...(_args[0] ?? {}) };
const p = opts.prompt;
const metadata = {};
if (p && typeof p === 'object' && 'id' in p) {
metadata.promptId = p.id;
}
opts.experimental_telemetry = { ...(opts.experimental_telemetry ?? {}), isEnabled: true, metadata };
if (typeof p === 'string') {
// keep as-is
} else if (p && typeof p.toString === 'function') {
opts.prompt = p.toString();
}
_args[0] = opts;
`)
🤖 Prompt for AI Agents
In internal/bundler/vercel_ai.go around lines 34 to 40, the injected JS assumes
opts.prompt exists and is an object and unconditionally overwrites
opts.experimental_telemetry, which breaks embed/embedMany and non-object
prompts; fix by guarding access: check that opts.prompt is defined and typeof
opts.prompt === 'object' before reading prompt.id and calling toString(), only
set metadata when an id exists, and if prompt is a primitive use
String(opts.prompt) instead of .toString() on undefined; also merge into any
existing opts.experimental_telemetry (e.g., opts.experimental_telemetry = {
...(opts.experimental_telemetry||{}), isEnabled: true, metadata }) rather than
clobbering it so existing telemetry fields are preserved.

@potofpie potofpie marked this pull request as ready for review September 15, 2025 16:38
@potofpie potofpie merged commit 8c6744e into feature-eval Sep 15, 2025
15 checks passed
@potofpie potofpie deleted the add-prompt-id-patch branch September 15, 2025 16:38
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant