tokenBudget.ts 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import { getBudgetContinuationMessage } from '../utils/tokenBudget.js'
  2. const COMPLETION_THRESHOLD = 0.9
  3. const DIMINISHING_THRESHOLD = 500
  4. export type BudgetTracker = {
  5. continuationCount: number
  6. lastDeltaTokens: number
  7. lastGlobalTurnTokens: number
  8. startedAt: number
  9. }
  10. export function createBudgetTracker(): BudgetTracker {
  11. return {
  12. continuationCount: 0,
  13. lastDeltaTokens: 0,
  14. lastGlobalTurnTokens: 0,
  15. startedAt: Date.now(),
  16. }
  17. }
  18. type ContinueDecision = {
  19. action: 'continue'
  20. nudgeMessage: string
  21. continuationCount: number
  22. pct: number
  23. turnTokens: number
  24. budget: number
  25. }
  26. type StopDecision = {
  27. action: 'stop'
  28. completionEvent: {
  29. continuationCount: number
  30. pct: number
  31. turnTokens: number
  32. budget: number
  33. diminishingReturns: boolean
  34. durationMs: number
  35. } | null
  36. }
  37. export type TokenBudgetDecision = ContinueDecision | StopDecision
  38. export function checkTokenBudget(
  39. tracker: BudgetTracker,
  40. agentId: string | undefined,
  41. budget: number | null,
  42. globalTurnTokens: number,
  43. ): TokenBudgetDecision {
  44. if (agentId || budget === null || budget <= 0) {
  45. return { action: 'stop', completionEvent: null }
  46. }
  47. const turnTokens = globalTurnTokens
  48. const pct = Math.round((turnTokens / budget) * 100)
  49. const deltaSinceLastCheck = globalTurnTokens - tracker.lastGlobalTurnTokens
  50. const isDiminishing =
  51. tracker.continuationCount >= 3 &&
  52. deltaSinceLastCheck < DIMINISHING_THRESHOLD &&
  53. tracker.lastDeltaTokens < DIMINISHING_THRESHOLD
  54. if (!isDiminishing && turnTokens < budget * COMPLETION_THRESHOLD) {
  55. tracker.continuationCount++
  56. tracker.lastDeltaTokens = deltaSinceLastCheck
  57. tracker.lastGlobalTurnTokens = globalTurnTokens
  58. return {
  59. action: 'continue',
  60. nudgeMessage: getBudgetContinuationMessage(pct, turnTokens, budget),
  61. continuationCount: tracker.continuationCount,
  62. pct,
  63. turnTokens,
  64. budget,
  65. }
  66. }
  67. if (isDiminishing || tracker.continuationCount > 0) {
  68. return {
  69. action: 'stop',
  70. completionEvent: {
  71. continuationCount: tracker.continuationCount,
  72. pct,
  73. turnTokens,
  74. budget,
  75. diminishingReturns: isDiminishing,
  76. durationMs: Date.now() - tracker.startedAt,
  77. },
  78. }
  79. }
  80. return { action: 'stop', completionEvent: null }
  81. }