scorer-online.ts 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. /**
  2. * Entry point for `braintrust push` to deploy scorers to Braintrust.
  3. *
  4. * Excluded scorers:
  5. * - sqlSyntaxScorer, sqlIdentifierQuotingScorer: use libpg-query (WASM),
  6. * which esbuild cannot bundle for Braintrust's remote infra.
  7. * - toolUsageScorer: requires expected.requiredTools, offline-eval-only.
  8. * - correctnessScorer: requires ground truth (expected output), offline-eval-only.
  9. */
  10. import braintrust, { type EvalScorer } from 'braintrust'
  11. import {
  12. completenessScorer,
  13. concisenessScorer,
  14. docsFaithfulnessScorer,
  15. goalCompletionScorer,
  16. safetyScorer,
  17. urlValidityScorer,
  18. type AssistantEvalInput,
  19. type AssistantEvalOutput,
  20. type Expected,
  21. } from './scorer'
  22. import manifest from './scorer-online-manifest.json'
  23. const projectId = process.env.BRAINTRUST_PROJECT_ID
  24. if (!projectId && process.env.IS_BRAINTRUST_PUSH)
  25. throw new Error('BRAINTRUST_PROJECT_ID is not set')
  26. // When running in CI, prefix scorers with the branch name to avoid collisions between PRs
  27. // in the staging project. GITHUB_HEAD_REF is only set on PR events, not push events (e.g. master).
  28. const branch = process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME
  29. const prNumber = process.env.GITHUB_PR_NUMBER ? Number(process.env.GITHUB_PR_NUMBER) : undefined
  30. const prefix = process.env.GITHUB_HEAD_REF
  31. ? `${process.env.GITHUB_HEAD_REF.replace(/[^a-z0-9-]/gi, '-').toLowerCase()}-`
  32. : ''
  33. const metadata = branch ? { gitBranch: branch, ...(prNumber && { prNumber }) } : undefined
  34. const description = prNumber && branch ? `#${prNumber} · ${branch}` : branch
  35. const handlers = {
  36. 'goal-completion': goalCompletionScorer,
  37. conciseness: concisenessScorer,
  38. completeness: completenessScorer,
  39. 'docs-faithfulness': docsFaithfulnessScorer,
  40. 'url-validity': urlValidityScorer,
  41. // safetyScorer guards on requiresSafetyCheck (an offline-eval concept).
  42. // Online traces have no expected, so we wrap it to always run.
  43. safety: (args) =>
  44. safetyScorer({ ...args, expected: { ...args.expected, requiresSafetyCheck: true } }),
  45. } satisfies Record<string, EvalScorer<AssistantEvalInput, AssistantEvalOutput, Expected>>
  46. // @ts-expect-error - Project ID is only required at build-time
  47. const project = braintrust.projects.create({ id: projectId })
  48. for (const { slug, name } of manifest) {
  49. project.scorers.create({
  50. slug: `${prefix}${slug}`,
  51. name,
  52. description,
  53. handler: handlers[slug as keyof typeof handlers],
  54. ifExists: 'replace',
  55. metadata,
  56. })
  57. }