@agent-native/core 0.94.2 → 0.95.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +14 -0
  3. package/corpus/core/docs/content/pr-visual-recap.mdx +20 -12
  4. package/corpus/core/package.json +1 -1
  5. package/corpus/core/src/a2a/artifact-response.ts +154 -1
  6. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +3 -0
  7. package/corpus/core/src/agent/engine/registry.ts +6 -1
  8. package/corpus/core/src/agent/engine/types.ts +2 -0
  9. package/corpus/core/src/cli/code-agent-executor.ts +61 -1
  10. package/corpus/core/src/cli/pr-visual-recap-workflow.ts +1 -1
  11. package/corpus/core/src/cli/recap.ts +262 -25
  12. package/corpus/core/src/client/settings/UsageSection.tsx +26 -5
  13. package/corpus/core/src/index.ts +2 -0
  14. package/corpus/core/src/integrations/a2a-continuation-processor.ts +118 -31
  15. package/corpus/core/src/integrations/a2a-continuations-store.ts +165 -7
  16. package/corpus/core/src/integrations/adapters/slack.ts +77 -7
  17. package/corpus/core/src/integrations/types.ts +30 -0
  18. package/corpus/core/src/integrations/webhook-handler.ts +54 -18
  19. package/corpus/core/src/scripts/call-agent.ts +1 -0
  20. package/corpus/core/src/server/request-context.ts +2 -0
  21. package/corpus/core/src/usage/store.ts +82 -20
  22. package/corpus/templates/plan/actions/record-recap-usage-cost.ts +49 -0
  23. package/corpus/templates/plan/actions/record-recap-usage.ts +15 -22
  24. package/dist/a2a/artifact-response.d.ts.map +1 -1
  25. package/dist/a2a/artifact-response.js +127 -1
  26. package/dist/a2a/artifact-response.js.map +1 -1
  27. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  28. package/dist/agent/engine/ai-sdk-engine.js +3 -0
  29. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  30. package/dist/agent/engine/registry.d.ts +1 -1
  31. package/dist/agent/engine/registry.d.ts.map +1 -1
  32. package/dist/agent/engine/registry.js +2 -0
  33. package/dist/agent/engine/registry.js.map +1 -1
  34. package/dist/agent/engine/types.d.ts +2 -0
  35. package/dist/agent/engine/types.d.ts.map +1 -1
  36. package/dist/agent/engine/types.js.map +1 -1
  37. package/dist/cli/code-agent-executor.d.ts +2 -0
  38. package/dist/cli/code-agent-executor.d.ts.map +1 -1
  39. package/dist/cli/code-agent-executor.js +52 -3
  40. package/dist/cli/code-agent-executor.js.map +1 -1
  41. package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
  42. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  43. package/dist/cli/pr-visual-recap-workflow.js +1 -1
  44. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  45. package/dist/cli/recap.d.ts +22 -2
  46. package/dist/cli/recap.d.ts.map +1 -1
  47. package/dist/cli/recap.js +199 -22
  48. package/dist/cli/recap.js.map +1 -1
  49. package/dist/client/settings/UsageSection.d.ts.map +1 -1
  50. package/dist/client/settings/UsageSection.js +12 -3
  51. package/dist/client/settings/UsageSection.js.map +1 -1
  52. package/dist/collab/struct-routes.d.ts +1 -1
  53. package/dist/index.d.ts +1 -1
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js.map +1 -1
  56. package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -1
  57. package/dist/integrations/a2a-continuation-processor.js +76 -21
  58. package/dist/integrations/a2a-continuation-processor.js.map +1 -1
  59. package/dist/integrations/a2a-continuations-store.d.ts +4 -1
  60. package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
  61. package/dist/integrations/a2a-continuations-store.js +130 -6
  62. package/dist/integrations/a2a-continuations-store.js.map +1 -1
  63. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  64. package/dist/integrations/adapters/slack.js +56 -7
  65. package/dist/integrations/adapters/slack.js.map +1 -1
  66. package/dist/integrations/types.d.ts +25 -0
  67. package/dist/integrations/types.d.ts.map +1 -1
  68. package/dist/integrations/types.js.map +1 -1
  69. package/dist/integrations/webhook-handler.js +54 -16
  70. package/dist/integrations/webhook-handler.js.map +1 -1
  71. package/dist/resources/handlers.d.ts +2 -2
  72. package/dist/scripts/call-agent.d.ts.map +1 -1
  73. package/dist/scripts/call-agent.js +1 -0
  74. package/dist/scripts/call-agent.js.map +1 -1
  75. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  76. package/dist/server/request-context.d.ts +2 -0
  77. package/dist/server/request-context.d.ts.map +1 -1
  78. package/dist/server/request-context.js.map +1 -1
  79. package/dist/server/transcribe-voice.d.ts +1 -1
  80. package/dist/usage/store.d.ts +21 -0
  81. package/dist/usage/store.d.ts.map +1 -1
  82. package/dist/usage/store.js +54 -19
  83. package/dist/usage/store.js.map +1 -1
  84. package/docs/content/pr-visual-recap.mdx +20 -12
  85. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"call-agent.js","sourceRoot":"","sources":["../../src/scripts/call-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EACL,mBAAmB,EACnB,SAAS,EACT,2BAA2B,EAC3B,YAAY,GACb,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,+BAA+B,EAC/B,oBAAoB,GACrB,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EAAE,8BAA8B,EAAE,MAAM,4CAA4C,CAAC;AAC5F,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,8BAA8B,CAAC;AAEtC,MAAM,6CAA6C,GAAG,MAAM,CAAC;AAC7D,MAAM,kCAAkC,GAAG,KAAK,CAAC;AACjD,MAAM,yBAAyB,GAAG,KAAK,CAAC;AAExC,SAAS,cAAc,CAAC,KAAyB;IAC/C,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9D,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,gBAAgB;IACvB,2EAA2E;IAC3E,8EAA8E;IAC9E,qEAAqE;IACrE,OAAO,CACL,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO;QACrB,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB;QACtC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM;QACpB,UAAU,IAAI,UAAU,CACzB,CAAC;AACJ,CAAC;AAED,SAAS,2BAA2B;IAClC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,0BAA0B,EAAE;QAAE,OAAO,SAAS,CAAC;IAE3E,MAAM,UAAU,GAAG,cAAc,CAC/B,OAAO,CAAC,GAAG,CAAC,uCAAuC,CACpD,CAAC;IACF,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,UAAU,CAAC;IAEhD,uEAAuE;IACvE,wEAAwE;IACxE,6EAA6E;IAC7E,yDAAyD;IACzD,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO;QAAE,OAAO,kCAAkC,CAAC;IAEnE,OAAO,6CAA6C,CAAC;AACvD,CAAC;AAED,SAAS,4BAA4B;IACnC,MAAM,WAAW,GAAG,4BAA4B,EAAE,CAAC;IACnD,MAAM,QAAQ,GAAG,WAAW,EAAE,QAAQ,CAAC;IACvC,IAAI,QAAQ,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS;QAAE,OAAO,EAAE,CAAC;IAErE,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC9C,MAAM,WAAW,GACf,SAAS,CAAC,QAAQ,KAAK,WAAW;YAClC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC5C,IAAI,SAAS,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,WAAW;YAAE,OAAO,EAAE,CAAC;QAC/D,OAAO,CACL,6BAA6B,SAAS,CAAC,QAAQ,EAAE,GAAG;YACpD,kGAAkG,CACnG,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,oCAAoC,CAC3C,SAAiB,EACjB,KAAc;IAEd,OAAO,oBAAoB,CAAC,KAAK,CAAC;QAChC,CAAC,CAAC,+BAA+B,CAAC,EAAE,SAAS,EAAE,CAAC;QAChD,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,MAAM,CAAC,MAAM,IAAI,GAAe;IAC9B,WAAW,EACT,+WAA+W;QAC/W,wSAAwS;QACxS,qCAAqC;QACrC,qMAAqM;QACrM,+QAA+Q;QAC/Q,qPAAqP;IACvP,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,+HAA+H;aAClI;YACD,OAAO,EAAE;gBACP,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,iDAAiD;aAC/D;SACF;QACD,QAAQ,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC;KAC/B;CACF,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,IAA4B,EAC5B,OAA0B,EAC1B,SAAkB;IAElB,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAE/C,IAAI,CAAC,aAAa;QAAE,OAAO,4BAA4B,CAAC;IACxD,IAAI,CAAC,OAAO;QAAE,OAAO,8BAA8B,CAAC;IAEpD,2EAA2E;IAC3E,IAAI,SAAS,IAAI,aAAa,CAAC,WAAW,EAAE,KAAK,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;QACzE,OAAO,sDAAsD,SAAS,6HAA6H,CAAC;IACtM,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IACxD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,SAAS,GAAG,CAAC,MAAM,cAAc,CAAC,SAAS,CAAC,CAAC;aAChD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;aAClB,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,OAAO,iBAAiB,aAAa,kCAAkC,SAAS,IAAI,QAAQ,EAAE,CAAC;IACjG,CAAC;IAED,yEAAyE;IACzE,wEAAwE;IACxE,sEAAsE;IACtE,uEAAuE;IACvE,oCAAoC;IACpC,MAAM,eAAe,GACnB,GAAG,OAAO,GAAG,4BAA4B,EAAE,MAAM;QACjD,mKAAmK;QACnK,sGAAsG,KAAK,CAAC,GAAG,kDAAkD;QACjK,0GAA0G,CAAC;IAE7G,IAAI,CAAC;QACH,4EAA4E;QAC5E,IAAI,OAAO,EAAE,IAAI,EAAE,CAAC;YAClB,MAAM,WAAW,GAAG,mBAAmB,EAAE,CAAC;YAE1C,+BAA+B;YAC/B,MAAM,WAAW,GAA4B,EAAE,CAAC;YAChD,IAAI,WAAW;gBAAE,WAAW,CAAC,SAAS,GAAG,WAAW,CAAC;YAErD,kDAAkD;YAClD,IAAI,eAAmC,CAAC;YACxC,IAAI,eAAmC,CAAC;YACxC,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;YAChC,IAAI,KAAK,EAAE,CAAC;gBACV,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,CAAC;oBACzC,IAAI,MAAM,EAAE,CAAC;wBACX,eAAe,GAAG,MAAM,CAAC;wBACzB,WAAW,CAAC,SAAS,GAAG,MAAM,CAAC;oBACjC,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC,CAAA,CAAC;gBACV,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,CAAC;oBAC5C,IAAI,MAAM;wBAAE,eAAe,GAAG,MAAM,CAAC;gBACvC,CAAC;gBAAC,MAAM,CAAC,CAAA,CAAC;YACZ,CAAC;YAED,+DAA+D;YAC/D,IAAI,MAA0B,CAAC;YAC/B,IAAI,WAAW,IAAI,CAAC,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/D,IAAI,CAAC;oBACH,MAAM,GAAG,MAAM,YAAY,CACzB,WAAW,EACX,eAAe,EACf,eAAe,EACf;wBACE,SAAS,EAAE,yBAAyB;wBACpC,kBAAkB,EAAE,2BAA2B,CAAC,eAAe,CAAC;qBACjE,CACF,CAAC;gBACJ,CAAC;gBAAC,MAAM,CAAC,CAAA,CAAC;YACZ,CAAC;YAED,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,IAAI,WAAW,EAAE,CAAC;gBACzD,IAAI,CAAC;oBACH,MAAM,EAAE,wBAAwB,EAAE,GAChC,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;oBAC3C,MAAM,QAAQ,GAAG,MAAM,wBAAwB,CAC7C,QAAQ,EACR,WAAW,CACZ,CAAC;oBACF,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;oBACnC,IAAI,MAAM,EAAE,YAAY,EAAE,CAAC;wBACzB,WAAW,CAAC,WAAW,GAAG,MAAM,CAAC,YAAY,CAAC;oBAChD,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC,CAAA,CAAC;YACZ,CAAC;YAED,IAAI,YAAY,GAAG,EAAE,CAAC;YACtB,IAAI,cAAc,GAAG,CAAC,CAAC;YACvB,MAAM,wBAAwB,GAC5B,MAAM,4CAA4C,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACrE,IAAI,wBAAwB;gBAAE,OAAO,wBAAwB,CAAC;YAE9D,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,YAAY;gBAClB,KAAK,EAAE,KAAK,CAAC,IAAI;gBACjB,MAAM,EAAE,OAAO;aAChB,CAAC,CAAC;YAEH,MAAM,WAAW,GAAG,CAAC,OAAe,EAAE,EAAE;gBACtC,IAAI,OAAO,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;oBACpC,OAAO,CAAC,IAAK,CAAC;wBACZ,IAAI,EAAE,iBAAiB;wBACvB,KAAK,EAAE,KAAK,CAAC,IAAI;wBACjB,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC;qBACpC,CAAC,CAAC;oBACH,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;gBAClC,CAAC;gBACD,YAAY,GAAG,OAAO,CAAC;YACzB,CAAC,CAAC;YAEF,kEAAkE;YAClE,kEAAkE;YAClE,sEAAsE;YACtE,qEAAqE;YACrE,sEAAsE;YACtE,qEAAqE;YACrE,wEAAwE;YACxE,qEAAqE;YACrE,iEAAiE;YACjE,sEAAsE;YACtE,wEAAwE;YACxE,+BAA+B;YAC/B,EAAE;YACF,kEAAkE;YAClE,mEAAmE;YACnE,uEAAuE;YACvE,kEAAkE;YAClE,qDAAqD;YACrD,kEAAkE;YAClE,qDAAqD;YACrD,0CAA0C;YAC1C,sEAAsE;YACtE,+DAA+D;YAC/D,oEAAoE;YACpE,wEAAwE;YACxE,gBAAgB;YAChB,EAAE;YACF,sEAAsE;YACtE,qEAAqE;YACrE,wEAAwE;YACxE,wEAAwE;YACxE,uEAAuE;YACvE,uEAAuE;YACvE,kEAAkE;YAClE,uEAAuE;YACvE,wEAAwE;YACxE,yDAAyD;YACzD,EAAE;YACF,uEAAuE;YACvE,yEAAyE;YACzE,uEAAuE;YACvE,oEAAoE;YACpE,EAAE;YACF,2DAA2D;YAC3D,kEAAkE;YAClE,oEAAoE;YACpE,wEAAwE;YACxE,mEAAmE;YACnE,wEAAwE;YACxE,uEAAuE;YACvE,yEAAyE;YACzE,wEAAwE;YACxE,wCAAwC;YACxC,MAAM,wBAAwB,GAAG,MAAM,CAAC;YACxC,yEAAyE;YACzE,oEAAoE;YACpE,4CAA4C;YAC5C,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;YAClE,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACjC,IAAI,kBAAkB,GAAG,aAAa,CAAC;YACvC,MAAM,kBAAkB,GAAG,CAAC,IAAU,EAAE,EAAE;gBACxC,MAAM,KAAK,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC;gBAClC,IAAI,CAAC,KAAK,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,KAAK,CAAC;oBAAE,OAAO;gBAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACvB,IAAI,GAAG,GAAG,kBAAkB,GAAG,wBAAwB;oBAAE,OAAO;gBAChE,kBAAkB,GAAG,GAAG,CAAC;gBACzB,MAAM,MAAM,GAAG,2BAA2B,CAAC,IAAI,CAAC,CAAC;gBACjD,OAAO,CAAC,IAAK,CAAC;oBACZ,IAAI,EAAE,qBAAqB;oBAC3B,KAAK,EAAE,KAAK,CAAC,IAAI;oBACjB,KAAK;oBACL,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,aAAa,CAAC,GAAG,IAAI,CAAC;oBACxD,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC9B,CAAC,CAAC;YACL,CAAC,CAAC;YAEF,IAAI,CAAC;gBACH,+DAA+D;gBAC/D,mEAAmE;gBACnE,qEAAqE;gBACrE,qEAAqE;gBACrE,MAAM,aAAa,GAAG,2BAA2B,EAAE,CAAC;gBACpD,YAAY,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,eAAe,EAAE;oBACzD,MAAM;oBACN,SAAS,EAAE,WAAW;oBACtB,SAAS,EAAE,eAAe;oBAC1B,SAAS,EAAE,eAAe;oBAC1B,QAAQ,EAAE,kBAAkB;oBAC5B,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACvD,CAAC,CAAC;gBACH,YAAY;oBACV,oCAAoC,CAAC,KAAK,CAAC,IAAI,EAAE,YAAY,CAAC;wBAC9D,YAAY,CAAC;gBACf,2DAA2D;gBAC3D,iEAAiE;gBACjE,uEAAuE;gBACvE,uEAAuE;gBACvE,YAAY,GAAG,kBAAkB,CAAC,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC3D,iEAAiE;gBACjE,IAAI,YAAY;oBAAE,WAAW,CAAC,YAAY,CAAC,CAAC;YAC9C,CAAC;YAAC,OAAO,OAAY,EAAE,CAAC;gBACtB,MAAM,aAAa,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;gBACvD,IAAI,aAAa,EAAE,CAAC;oBAClB,MAAM,MAAM,GAAG,MAAM,wCAAwC,CAC3D,aAAa,EACb,KAAK,EACL,OAAO,EACP,WAAW,CACZ,CAAC;oBACF,IAAI,MAAM,EAAE,CAAC;wBACX,YAAY;4BACV,GAAG,8BAA8B,IAAI;gCACrC,OAAO,KAAK,CAAC,IAAI,iIAAiI;gCAClJ,eAAe,KAAK,CAAC,IAAI,6IAA6I,KAAK,CAAC,IAAI,oCAAoC,CAAC;oBACzN,CAAC;yBAAM,CAAC;wBACN,MAAM,MAAM,GAAG,OAAO,EAAE,OAAO,IAAI,eAAe,CAAC;wBACnD,YAAY,GAAG,OAAO,KAAK,CAAC,IAAI,oEAAoE,MAAM,GAAG,CAAC;oBAChH,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,MAAM,MAAM,GAAG,OAAO,EAAE,OAAO,IAAI,eAAe,CAAC;oBACnD,YAAY;wBACV,oCAAoC,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC;4BACzD,OAAO,KAAK,CAAC,IAAI,oEAAoE,MAAM,GAAG,CAAC;gBACnG,CAAC;YACH,CAAC;YAED,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,YAAY;gBAClB,KAAK,EAAE,KAAK,CAAC,IAAI;gBACjB,MAAM,EAAE,MAAM;aACf,CAAC,CAAC;YAEH,OAAO,YAAY,IAAI,kBAAkB,CAAC;QAC5C,CAAC;QAED,wEAAwE;QACxE,uEAAuE;QACvE,MAAM,KAAK,GAAG,mBAAmB,EAAE,CAAC;QACpC,IAAI,MAA0B,CAAC;QAC/B,IAAI,SAA6B,CAAC;QAClC,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;QACvC,IAAI,YAAY,EAAE,CAAC;YACjB,IAAI,CAAC;gBACH,MAAM,GAAG,CAAC,MAAM,YAAY,CAAC,YAAY,CAAC,CAAC,IAAI,SAAS,CAAC;YAC3D,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;YACV,IAAI,CAAC;gBACH,SAAS,GAAG,CAAC,MAAM,eAAe,CAAC,YAAY,CAAC,CAAC,IAAI,SAAS,CAAC;YACjE,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,eAAe,EAAE;YAC3D,SAAS,EAAE,KAAK;YAChB,SAAS,EAAE,MAAM;YACjB,SAAS;SACV,CAAC,CAAC;QACH,MAAM,SAAS,GACb,oCAAoC,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,QAAQ,CAAC;QACzE,OAAO,kBAAkB,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,kBAAkB,CAAC;IACxE,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,GAAG,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,iBAAiB,GAAG,oCAAoC,CAC5D,KAAK,CAAC,IAAI,EACV,GAAG,CACJ,CAAC;QACF,IAAI,iBAAiB;YAAE,OAAO,iBAAiB,CAAC;QAChD,0EAA0E;QAC1E,sCAAsC;QACtC,IAAI,0CAA0C,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACzD,OAAO,OAAO,KAAK,CAAC,IAAI,gGAAgG,KAAK,CAAC,IAAI,gBAAgB,CAAC;QACrJ,CAAC;QACD,OAAO,iBAAiB,KAAK,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;IAC/C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,wCAAwC,CACrD,MAAc,EACd,KAAoC,EACpC,OAAe,EACf,UAA8B;IAE9B,MAAM,WAAW,GAAG,4BAA4B,EAAE,CAAC;IACnD,IAAI,CAAC,WAAW,IAAI,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IAE9C,IAAI,CAAC;QACH,MAAM,CAAC,EAAE,qBAAqB,EAAE,EAAE,EAAE,uBAAuB,EAAE,CAAC,GAC5D,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,MAAM,CAAC,4CAA4C,CAAC;YACpD,MAAM,CAAC,+CAA+C,CAAC;SACxD,CAAC,CAAC;QACL,MAAM,YAAY,GAAG,MAAM,qBAAqB,CAAC;YAC/C,iBAAiB,EAAE,WAAW,CAAC,MAAM;YACrC,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAAC,QAAQ;YACvC,gBAAgB,EAAE,WAAW,CAAC,QAAQ,CAAC,gBAAgB;YACvD,QAAQ,EAAE,WAAW,CAAC,QAAQ;YAC9B,cAAc,EAAE,WAAW,CAAC,cAAc;YAC1C,UAAU;YACV,KAAK,EAAE,eAAe,EAAE,IAAI,IAAI;YAChC,SAAS,EAAE,KAAK,CAAC,IAAI;YACrB,QAAQ,EAAE,KAAK,CAAC,GAAG;YACnB,SAAS,EAAE,mCAAmC,CAAC,OAAO,CAAC;YACvD,SAAS,EAAE,MAAM;YACjB,oEAAoE;YACpE,+DAA+D;YAC/D,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;QACH,MAAM,uBAAuB,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YAC3D,OAAO,CAAC,KAAK,CACX,oDAAoD,YAAY,CAAC,EAAE,GAAG,EACtE,GAAG,CACJ,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,kDAAkD,EAAE,GAAG,CAAC,CAAC;QACvE,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,yEAAyE;AACzE,4EAA4E;AAC5E,2EAA2E;AAC3E,MAAM,yBAAyB,GAAG,GAAG,CAAC;AACtC,SAAS,2BAA2B,CAAC,IAAU;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC;IAC1C,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,IAAI,GAAG,KAAK;SACf,MAAM,CAAC,CAAC,CAAC,EAAuC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;SACrE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SAClB,IAAI,CAAC,GAAG,CAAC;SACT,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;IACV,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,OAAO,IAAI,CAAC,MAAM,GAAG,yBAAyB;QAC5C,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,yBAAyB,GAAG,CAAC,CAAC,GAAG;QACpD,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,SAAS,uBAAuB,CAAC,GAAY;IAC3C,IAAI,GAAG,YAAY,mBAAmB;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC;IAE1D,MAAM,SAAS,GAAG,GAGL,CAAC;IACd,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;IACjD,IACE,SAAS,EAAE,IAAI,KAAK,qBAAqB;QACzC,OAAO,SAAS,CAAC,MAAM,KAAK,QAAQ,EACpC,CAAC;QACD,OAAO,SAAS,CAAC,MAAM,CAAC;IAC1B,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IACrE,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC5B,CAAC;AAED,KAAK,UAAU,4CAA4C,CACzD,KAGC,EACD,OAAe;IAEf,MAAM,WAAW,GAAG,4BAA4B,EAAE,CAAC;IACnD,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAElE,IAAI,CAAC;QACH,MAAM,EAAE,0CAA0C,EAAE,GAClD,MAAM,MAAM,CAAC,4CAA4C,CAAC,CAAC;QAC7D,MAAM,aAAa,GAAG,MAAM,0CAA0C,CACpE,WAAW,CAAC,MAAM,EAClB,KAAK,CAAC,GAAG,EACT,mCAAmC,CAAC,OAAO,CAAC,CAC7C,CAAC;QACF,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE,CACjD,CAAC,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC,QAAQ,CAC3D,YAAY,CAAC,MAAM,CACpB,CACF,CAAC;QACF,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAEzB,MAAM,KAAK,GACT,MAAM,CAAC,MAAM,KAAK,WAAW;YAC3B,CAAC,CAAC,sGAAsG;YACxG,CAAC,CAAC,2GAA2G,CAAC;QAClH,OAAO,CACL,GAAG,8BAA8B,IAAI;YACrC,OAAO,KAAK,CAAC,IAAI,UAAU,KAAK,iBAAiB,KAAK,CAAC,IAAI,6IAA6I,KAAK,CAAC,IAAI,kDAAkD,CACrQ,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,uDAAuD,EAAE,GAAG,CAAC,CAAC;QAC5E,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,mCAAmC,CAAC,OAAe;IAC1D,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACvD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC/D,CAAC;AAED,+EAA+E;AAC/E,8EAA8E;AAC9E,6EAA6E;AAC7E,2EAA2E;AAC3E,4EAA4E;AAC5E,4CAA4C;AAC5C,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,QAAgB;IAC/D,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACzC,4EAA4E;IAC5E,8EAA8E;IAC9E,OAAO,IAAI,CAAC,OAAO,CACjB,oDAAoD,EACpD,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE,CAChD,CAAC;AACJ,CAAC","sourcesContent":["import { createHash } from \"node:crypto\";\n\nimport {\n A2ATaskTimeoutError,\n callAgent,\n shouldPreferGlobalA2ASecret,\n signA2AToken,\n} from \"../a2a/client.js\";\nimport type { Task } from \"../a2a/types.js\";\nimport {\n formatLlmCredentialErrorMessage,\n isLlmCredentialError,\n} from \"../agent/engine/credential-errors.js\";\nimport type { ActionRunContext } from \"../agent/production-agent.js\";\nimport type { ActionTool } from \"../agent/types.js\";\nimport { A2A_CONTINUATION_QUEUED_MARKER } from \"../integrations/a2a-continuation-marker.js\";\nimport { getOrgDomain, getOrgA2ASecret } from \"../org/context.js\";\nimport { findAgent, discoverAgents } from \"../server/agent-discovery.js\";\nimport {\n getRequestUserEmail,\n getRequestOrgId,\n isIntegrationCallerRequest,\n getIntegrationRequestContext,\n} from \"../server/request-context.js\";\n\nconst DEFAULT_SERVERLESS_INTEGRATION_A2A_TIMEOUT_MS = 18_000;\nconst NETLIFY_INTEGRATION_A2A_TIMEOUT_MS = 2_000;\nconst INTEGRATION_A2A_TOKEN_TTL = \"30m\";\n\nfunction parseTimeoutMs(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed <= 0) return undefined;\n return Math.floor(parsed);\n}\n\nfunction isServerlessHost(): boolean {\n // Detection mirrors db/migrations.ts:297-301. On Cloudflare Workers/Pages,\n // `process.env` is shimmed and CF_PAGES isn't reliably populated at runtime —\n // the canonical signal is the `__cf_env` global injected by workerd.\n return (\n !!process.env.NETLIFY ||\n !!process.env.AWS_LAMBDA_FUNCTION_NAME ||\n !!process.env.VERCEL ||\n \"__cf_env\" in globalThis\n );\n}\n\nfunction getIntegrationCallTimeoutMs(): number | undefined {\n if (!isServerlessHost() || !isIntegrationCallerRequest()) return undefined;\n\n const configured = parseTimeoutMs(\n process.env.AGENT_NATIVE_INTEGRATION_A2A_TIMEOUT_MS,\n );\n if (configured !== undefined) return configured;\n\n // Netlify's current synchronous function budget is 60s. Keep delegated\n // calls very short so multi-agent integration requests queue downstream\n // continuations quickly instead of spending the parent Slack/email processor\n // budget waiting on separately deployed apps one-by-one.\n if (process.env.NETLIFY) return NETLIFY_INTEGRATION_A2A_TIMEOUT_MS;\n\n return DEFAULT_SERVERLESS_INTEGRATION_A2A_TIMEOUT_MS;\n}\n\nfunction integrationSourceContextHint(): string {\n const integration = getIntegrationRequestContext();\n const incoming = integration?.incoming;\n if (incoming?.platform !== \"slack\" || !incoming.sourceUrl) return \"\";\n\n try {\n const sourceUrl = new URL(incoming.sourceUrl);\n const isSlackHost =\n sourceUrl.hostname === \"slack.com\" ||\n sourceUrl.hostname.endsWith(\".slack.com\");\n if (sourceUrl.protocol !== \"https:\" || !isSlackHost) return \"\";\n return (\n `\\n\\n[Source Slack thread: ${sourceUrl.toString()} ` +\n \"Preserve this exact URL as request provenance when creating an intake record or other artifact.]\"\n );\n } catch {\n return \"\";\n }\n}\n\nfunction formatDownstreamLlmCredentialFailure(\n agentName: string,\n value: unknown,\n): string | null {\n return isLlmCredentialError(value)\n ? formatLlmCredentialErrorMessage({ agentName })\n : null;\n}\n\nexport const tool: ActionTool = {\n description:\n \"Call a DIFFERENT, separately-deployed agent app to ask a question or delegate a task. This is strictly for cross-app A2A communication — for example, asking the mail agent to send an email while you are the calendar agent. NEVER use this to call your own app or perform actions you can do with your own tools. Using call-agent on yourself will fail and waste time. \" +\n 'For brand-consistent generated media, the first-party Assets agent is available as agent=\"assets\"; use it when another app needs generated heroes, diagrams, product shots, thumbnails, videos, or design imagery, unless the current app has its own generation action that already delegates there. ' +\n \"IMPORTANT — handling the response: \" +\n \"(a) If it contains a URL or ID, copy it VERBATIM into your reply. Do not 'correct' or pluralize the path (e.g. /deck/ → /decks/), normalize casing, or change the slug — any edit breaks the link. \" +\n '(b) If it does NOT contain a URL/ID and the user asked for one, say so explicitly (e.g. \"the agent created the deck/image but didn\\'t return a link — open the app directly to view it\"). NEVER invent a URL, slug, or path — guessing produces broken links that look real. ' +\n \"(c) If the downstream response reports missing credentials, never repeat raw env var names, Vault key names, token names, secret names, or other credential identifiers. Tell the user the target app needs its LLM/provider connection configured.\",\n parameters: {\n type: \"object\",\n properties: {\n agent: {\n type: \"string\",\n description:\n \"Name or URL of a DIFFERENT deployed agent app (e.g. 'mail', 'calendar', 'analytics'). Must not be the current app's own name.\",\n },\n message: {\n type: \"string\",\n description: \"The message/question to send to the other agent\",\n },\n },\n required: [\"agent\", \"message\"],\n },\n};\n\nexport async function run(\n args: Record<string, string>,\n context?: ActionRunContext,\n selfAppId?: string,\n): Promise<string> {\n const { agent: agentIdOrName, message } = args;\n\n if (!agentIdOrName) return \"Error: --agent is required\";\n if (!message) return \"Error: --message is required\";\n\n // Prevent self-calls — the agent must use its own registered tools instead\n if (selfAppId && agentIdOrName.toLowerCase() === selfAppId.toLowerCase()) {\n return `Error: You cannot use call-agent to call yourself (${selfAppId}). Use your own registered actions/tools instead. call-agent is only for communicating with OTHER separately-deployed apps.`;\n }\n\n const agent = await findAgent(agentIdOrName, selfAppId);\n if (!agent) {\n const available = (await discoverAgents(selfAppId))\n .map((a) => a.name)\n .join(\", \");\n return `Error: Agent \"${agentIdOrName}\" not found. Available agents: ${available || \"(none)\"}`;\n }\n\n // Append a small cross-app hint to the outgoing message so the receiving\n // agent (which may be on an older deploy without the receiver-side hint\n // in handlers.ts) still emits fully-qualified URLs. This is belt-and-\n // suspenders with the receiver hint — but it works against any current\n // deployment, no redeploy required.\n const messageWithHint =\n `${message}${integrationSourceContextHint()}\\n\\n` +\n `[Note: this request comes from another app via A2A. The caller cannot see your local UI, deck list, or navigation — only the literal text you put in your reply. ` +\n `If you create or reference a deck/document/design/dashboard, include its FULLY-QUALIFIED URL (e.g. ${agent.url}/deck/<id>) in your reply, not a relative path. ` +\n `Use only artifact IDs and URL paths returned by successful actions — never invent slugs, IDs, or hosts.]`;\n\n try {\n // If we have a send context, use streaming so the UI shows progressive text\n if (context?.send) {\n const callerEmail = getRequestUserEmail();\n\n // Build metadata with identity\n const a2aMetadata: Record<string, unknown> = {};\n if (callerEmail) a2aMetadata.userEmail = callerEmail;\n\n // Include org domain for cross-app org resolution\n let callerOrgDomain: string | undefined;\n let callerOrgSecret: string | undefined;\n const orgId = getRequestOrgId();\n if (orgId) {\n try {\n const domain = await getOrgDomain(orgId);\n if (domain) {\n callerOrgDomain = domain;\n a2aMetadata.orgDomain = domain;\n }\n } catch {}\n try {\n const secret = await getOrgA2ASecret(orgId);\n if (secret) callerOrgSecret = secret;\n } catch {}\n }\n\n // Sign JWT with identity + org domain for the streaming client\n let apiKey: string | undefined;\n if (callerEmail && (callerOrgSecret || process.env.A2A_SECRET)) {\n try {\n apiKey = await signA2AToken(\n callerEmail,\n callerOrgDomain,\n callerOrgSecret,\n {\n expiresIn: INTEGRATION_A2A_TOKEN_TTL,\n preferGlobalSecret: shouldPreferGlobalA2ASecret(callerOrgSecret),\n },\n );\n } catch {}\n }\n\n if (process.env.NODE_ENV === \"production\" && callerEmail) {\n try {\n const { listOAuthAccountsByOwner } =\n await import(\"../oauth-tokens/store.js\");\n const accounts = await listOAuthAccountsByOwner(\n \"google\",\n callerEmail,\n );\n const tokens = accounts[0]?.tokens;\n if (tokens?.access_token) {\n a2aMetadata.googleToken = tokens.access_token;\n }\n } catch {}\n }\n\n let responseText = \"\";\n let lastSentLength = 0;\n const existingContinuationText =\n await formatExistingIntegrationContinuationIfRetry(agent, message);\n if (existingContinuationText) return existingContinuationText;\n\n context.send({\n type: \"agent_call\",\n agent: agent.name,\n status: \"start\",\n });\n\n const emitNewText = (newText: string) => {\n if (newText.length > lastSentLength) {\n context.send!({\n type: \"agent_call_text\",\n agent: agent.name,\n text: newText.slice(lastSentLength),\n });\n lastSentLength = newText.length;\n }\n responseText = newText;\n };\n\n // Skip the SSE streaming attempt and go straight to async + poll.\n // Why: on Netlify (Lambda), the receiving server has no streaming\n // response support, so message/stream returns a single JSON-RPC error\n // body in a 200 response that our SSE parser silently consumes — the\n // `for await` loop yields nothing AND keeps the connection open until\n // the function timeout, eating the current serverless budget. By the\n // time we get to the sync fallback, Lambda is dead and the second fetch\n // errors out as \"fetch failed\". Async+poll has its own short fetches\n // with their own budgets, so it works reliably across hosts. The\n // trade-off is we lose progressive in-UI text streaming for cross-app\n // A2A calls, but the receiving agent's full response still surfaces via\n // the tool_result event below.\n //\n // That trade-off has a second-order cost: callAgent()'s poll (see\n // A2AClient.sendAndWait in a2a/client.ts) can legitimately run for\n // minutes with nothing emitted to the parent between the \"start\" event\n // above and \"done\" below. On the parent run, that silence freezes\n // `last_progress_at` — shouldBumpProgressForEvent in\n // agent/run-manager.ts treats a stream of literally nothing as no\n // progress — which trips the client's stuck-detector\n // (DEFAULT_STUCK_THRESHOLD_MS = 90_000 in\n // client/use-run-stuck-detection.ts) and the server's stale-run sweep\n // (BACKGROUND_RUN_STALE_MS = 90_000 in agent/run-store.ts). In\n // production this handed users a \"still working, no progress\" Retry\n // button that aborted a perfectly healthy call and re-ran the sub-agent\n // from scratch.\n //\n // Fix: surface the REAL remote liveness the poll already gathers. The\n // A2A poll round-trips to the remote agent every ~2s and gets back a\n // task with `status.state` (see A2AClient.sendAndWait / `onUpdate`). We\n // emit an `agent_call_progress` event ONLY from that callback, and ONLY\n // when a poll actually succeeds AND reports an actively-working state.\n // Crucially this is NOT a timer: if the remote hangs or dies, the poll\n // fetch throws, `onUpdate` stops firing, we emit nothing, and the\n // stuck-detector correctly surfaces its banner. A wall-clock heartbeat\n // would instead keep a dead sub-agent looking alive forever — trading a\n // false stuck-positive for a worse false stuck-negative.\n //\n // Throttle: the poll runs every ~2s but both thresholds above are 90s,\n // so emitting per-poll would be ~45 events per stuck-window. We coalesce\n // to at most one emission per 30s — a 3x margin under 90s, so at least\n // two land inside either window even with jitter, without flooding.\n //\n // Shape: a dedicated `agent_call_progress` event type (see\n // agent/types.ts), not an extra `agent_call` status. `agent_call`\n // consumers (production-agent.ts's step summarizer, slack.ts's task\n // cards) render any status that isn't \"start\"/\"done\" as a failure, so a\n // \"progress\" status would surface an in-flight tick as an error. A\n // distinct type is instead ignored gracefully everywhere: the run-event\n // switches fall to their `default`, the client if-chains fall through,\n // and sse-event-processor returns `{action:\"continue\"}`. It still counts\n // as real progress in shouldBumpProgressForEvent (any non-special event\n // type does), which is the whole point.\n const PROGRESS_MIN_INTERVAL_MS = 30_000;\n // Terminal states resolve the poll; \"input-required\" means the remote is\n // blocked waiting on us, not making progress. Only actively-working\n // states count as liveness worth surfacing.\n const ACTIVELY_WORKING_STATES = new Set([\"working\", \"submitted\"]);\n const callStartedAt = Date.now();\n let lastProgressEmitAt = callStartedAt;\n const onRemotePollUpdate = (task: Task) => {\n const state = task?.status?.state;\n if (!state || !ACTIVELY_WORKING_STATES.has(state)) return;\n const now = Date.now();\n if (now - lastProgressEmitAt < PROGRESS_MIN_INTERVAL_MS) return;\n lastProgressEmitAt = now;\n const detail = extractRemoteProgressDetail(task);\n context.send!({\n type: \"agent_call_progress\",\n agent: agent.name,\n state,\n elapsedSeconds: Math.round((now - callStartedAt) / 1000),\n ...(detail ? { detail } : {}),\n });\n };\n\n try {\n // Apply a polling cap ONLY for integration-platform callers on\n // serverless hosts. Normal chat, local Node, self-hosted Node, and\n // Docker can wait for slow-but-valid answers; integration processors\n // still need to finish before their current function execution dies.\n const callTimeoutMs = getIntegrationCallTimeoutMs();\n responseText = await callAgent(agent.url, messageWithHint, {\n apiKey,\n userEmail: callerEmail,\n orgDomain: callerOrgDomain,\n orgSecret: callerOrgSecret,\n onUpdate: onRemotePollUpdate,\n ...(callTimeoutMs ? { timeoutMs: callTimeoutMs } : {}),\n });\n responseText =\n formatDownstreamLlmCredentialFailure(agent.name, responseText) ??\n responseText;\n // Some agents reply with relative paths (e.g. slides emits\n // \"/deck/abc\"). Those resolve against the caller's host, not the\n // receiver's, so they're broken for the user. Expand any leading-slash\n // URL into a fully-qualified one rooted at the receiving agent's host.\n responseText = expandRelativeUrls(responseText, agent.url);\n // Mirror the response into the streaming UI so the user sees it.\n if (responseText) emitNewText(responseText);\n } catch (pollErr: any) {\n const timeoutTaskId = getA2ATaskTimeoutTaskId(pollErr);\n if (timeoutTaskId) {\n const queued = await enqueueIntegrationContinuationIfPossible(\n timeoutTaskId,\n agent,\n message,\n callerEmail,\n );\n if (queued) {\n responseText =\n `${A2A_CONTINUATION_QUEUED_MARKER}\\n` +\n `The ${agent.name} agent accepted this delegated subtask and will post its own final result to the originating integration thread automatically. ` +\n `Do not call ${agent.name} again for this same subtask. Continue any other requested work, then answer with the completed results you have; if needed, mention that ${agent.name} is posting its result separately.`;\n } else {\n const reason = pollErr?.message ?? \"unknown error\";\n responseText = `The ${agent.name} agent is taking longer than expected and didn't reply in time. (${reason})`;\n }\n } else {\n const reason = pollErr?.message ?? \"unknown error\";\n responseText =\n formatDownstreamLlmCredentialFailure(agent.name, pollErr) ??\n `The ${agent.name} agent is taking longer than expected and didn't reply in time. (${reason})`;\n }\n }\n\n context.send({\n type: \"agent_call\",\n agent: agent.name,\n status: \"done\",\n });\n\n return responseText || \"(empty response)\";\n }\n\n // No context — use the async + poll call so we don't get cut off at the\n // serverless gateway's ~30s timeout. callAgent defaults to async:true.\n const email = getRequestUserEmail();\n let domain: string | undefined;\n let orgSecret: string | undefined;\n const currentOrgId = getRequestOrgId();\n if (currentOrgId) {\n try {\n domain = (await getOrgDomain(currentOrgId)) ?? undefined;\n } catch {}\n try {\n orgSecret = (await getOrgA2ASecret(currentOrgId)) ?? undefined;\n } catch {}\n }\n const response = await callAgent(agent.url, messageWithHint, {\n userEmail: email,\n orgDomain: domain,\n orgSecret,\n });\n const sanitized =\n formatDownstreamLlmCredentialFailure(agent.name, response) ?? response;\n return expandRelativeUrls(sanitized, agent.url) || \"(empty response)\";\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n const credentialMessage = formatDownstreamLlmCredentialFailure(\n agent.name,\n err,\n );\n if (credentialMessage) return credentialMessage;\n // Friendlier message for the common timeout case so the calling agent can\n // decide whether to give up or retry.\n if (/timeout|did not complete|Inactivity|504/i.test(msg)) {\n return `The ${agent.name} agent is taking longer than expected. Please try again, ask a simpler question, or open the ${agent.name} app directly.`;\n }\n return `Error calling ${agent.name}: ${msg}`;\n }\n}\n\nasync function enqueueIntegrationContinuationIfPossible(\n taskId: string,\n agent: { name: string; url: string },\n message: string,\n ownerEmail: string | undefined,\n): Promise<boolean> {\n const integration = getIntegrationRequestContext();\n if (!integration || !ownerEmail) return false;\n\n try {\n const [{ insertA2AContinuation }, { dispatchA2AContinuation }] =\n await Promise.all([\n import(\"../integrations/a2a-continuations-store.js\"),\n import(\"../integrations/a2a-continuation-processor.js\"),\n ]);\n const continuation = await insertA2AContinuation({\n integrationTaskId: integration.taskId,\n platform: integration.incoming.platform,\n externalThreadId: integration.incoming.externalThreadId,\n incoming: integration.incoming,\n placeholderRef: integration.placeholderRef,\n ownerEmail,\n orgId: getRequestOrgId() ?? null,\n agentName: agent.name,\n agentUrl: agent.url,\n dedupeKey: getIntegrationContinuationDedupeKey(message),\n a2aTaskId: taskId,\n // Do not persist the short-lived JWT used for the initial send. The\n // continuation processor can mint a fresh token for each poll.\n a2aAuthToken: null,\n });\n await dispatchA2AContinuation(continuation.id).catch((err) => {\n console.error(\n `[call-agent] Failed to dispatch A2A continuation ${continuation.id}:`,\n err,\n );\n });\n return true;\n } catch (err) {\n console.error(\"[call-agent] Failed to enqueue A2A continuation:\", err);\n return false;\n }\n}\n\n// Pull a short human-readable detail from a polled A2A task's status message,\n// when the remote includes one, so the progress event can surface a real\n// signal (e.g. \"Generating hero image…\") instead of a bare elapsed counter.\n// Bounded so a chatty remote can't push a large payload through the event.\nconst MAX_PROGRESS_DETAIL_CHARS = 200;\nfunction extractRemoteProgressDetail(task: Task): string | undefined {\n const parts = task.status?.message?.parts;\n if (!parts) return undefined;\n const text = parts\n .filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n .map((p) => p.text)\n .join(\" \")\n .replace(/\\s+/g, \" \")\n .trim();\n if (!text) return undefined;\n return text.length > MAX_PROGRESS_DETAIL_CHARS\n ? `${text.slice(0, MAX_PROGRESS_DETAIL_CHARS - 1)}…`\n : text;\n}\n\nfunction getA2ATaskTimeoutTaskId(err: unknown): string | null {\n if (err instanceof A2ATaskTimeoutError) return err.taskId;\n\n const candidate = err as\n | { name?: unknown; taskId?: unknown; message?: unknown }\n | null\n | undefined;\n const message = String(candidate?.message ?? \"\");\n if (\n candidate?.name === \"A2ATaskTimeoutError\" &&\n typeof candidate.taskId === \"string\"\n ) {\n return candidate.taskId;\n }\n\n const match = message.match(/^A2A task ([^\\s]+) did not complete\\b/);\n return match?.[1] ?? null;\n}\n\nasync function formatExistingIntegrationContinuationIfRetry(\n agent: {\n name: string;\n url: string;\n },\n message: string,\n): Promise<string | null> {\n const integration = getIntegrationRequestContext();\n if (!integration || (integration.attempts ?? 1) <= 1) return null;\n\n try {\n const { getA2AContinuationsForIntegrationTaskAgent } =\n await import(\"../integrations/a2a-continuations-store.js\");\n const continuations = await getA2AContinuationsForIntegrationTaskAgent(\n integration.taskId,\n agent.url,\n getIntegrationContinuationDedupeKey(message),\n );\n const active = continuations.find((continuation) =>\n [\"pending\", \"processing\", \"delivering\", \"completed\"].includes(\n continuation.status,\n ),\n );\n if (!active) return null;\n\n const state =\n active.status === \"completed\"\n ? \"already completed this delegated subtask and posted its result to the originating integration thread\"\n : \"already accepted this delegated subtask and is still working on it for the originating integration thread\";\n return (\n `${A2A_CONTINUATION_QUEUED_MARKER}\\n` +\n `The ${agent.name} agent ${state}. Do not call ${agent.name} again for this same subtask. Continue any other requested work, then answer with the completed results you have; if needed, mention that ${agent.name} is posting or has posted its result separately.`\n );\n } catch (err) {\n console.error(\"[call-agent] Failed to inspect existing continuation:\", err);\n return null;\n }\n}\n\nfunction getIntegrationContinuationDedupeKey(message: string): string {\n const normalized = message.trim().replace(/\\s+/g, \" \");\n return createHash(\"sha256\").update(normalized).digest(\"hex\");\n}\n\n// Expand bare leading-slash paths (e.g. \"/deck/abc\") into fully-qualified URLs\n// rooted at the receiving agent's host. The receiver doesn't always know it's\n// being called cross-app, so it may emit relative paths that resolve against\n// the caller's host (broken). Match a path that starts at a word boundary,\n// begins with `/`, and has at least one path segment after that. Skip if it\n// already looks like a fully-qualified URL.\nexport function expandRelativeUrls(text: string, agentUrl: string): string {\n if (!text || !agentUrl) return text;\n const base = agentUrl.replace(/\\/$/, \"\");\n // Path must start at boundary (start, whitespace, or punctuation that isn't\n // ':' — to avoid mangling `https://example.com/foo` or markdown link bodies).\n return text.replace(\n /(^|[\\s([<\"'`])(\\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi,\n (_match, lead, path) => `${lead}${base}${path}`,\n );\n}\n"]}
1
+ {"version":3,"file":"call-agent.js","sourceRoot":"","sources":["../../src/scripts/call-agent.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\n\nimport {\n A2ATaskTimeoutError,\n callAgent,\n shouldPreferGlobalA2ASecret,\n signA2AToken,\n} from \"../a2a/client.js\";\nimport type { Task } from \"../a2a/types.js\";\nimport {\n formatLlmCredentialErrorMessage,\n isLlmCredentialError,\n} from \"../agent/engine/credential-errors.js\";\nimport type { ActionRunContext } from \"../agent/production-agent.js\";\nimport type { ActionTool } from \"../agent/types.js\";\nimport { A2A_CONTINUATION_QUEUED_MARKER } from \"../integrations/a2a-continuation-marker.js\";\nimport { getOrgDomain, getOrgA2ASecret } from \"../org/context.js\";\nimport { findAgent, discoverAgents } from \"../server/agent-discovery.js\";\nimport {\n getRequestUserEmail,\n getRequestOrgId,\n isIntegrationCallerRequest,\n getIntegrationRequestContext,\n} from \"../server/request-context.js\";\n\nconst DEFAULT_SERVERLESS_INTEGRATION_A2A_TIMEOUT_MS = 18_000;\nconst NETLIFY_INTEGRATION_A2A_TIMEOUT_MS = 2_000;\nconst INTEGRATION_A2A_TOKEN_TTL = \"30m\";\n\nfunction parseTimeoutMs(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed <= 0) return undefined;\n return Math.floor(parsed);\n}\n\nfunction isServerlessHost(): boolean {\n // Detection mirrors db/migrations.ts:297-301. On Cloudflare Workers/Pages,\n // `process.env` is shimmed and CF_PAGES isn't reliably populated at runtime —\n // the canonical signal is the `__cf_env` global injected by workerd.\n return (\n !!process.env.NETLIFY ||\n !!process.env.AWS_LAMBDA_FUNCTION_NAME ||\n !!process.env.VERCEL ||\n \"__cf_env\" in globalThis\n );\n}\n\nfunction getIntegrationCallTimeoutMs(): number | undefined {\n if (!isServerlessHost() || !isIntegrationCallerRequest()) return undefined;\n\n const configured = parseTimeoutMs(\n process.env.AGENT_NATIVE_INTEGRATION_A2A_TIMEOUT_MS,\n );\n if (configured !== undefined) return configured;\n\n // Netlify's current synchronous function budget is 60s. Keep delegated\n // calls very short so multi-agent integration requests queue downstream\n // continuations quickly instead of spending the parent Slack/email processor\n // budget waiting on separately deployed apps one-by-one.\n if (process.env.NETLIFY) return NETLIFY_INTEGRATION_A2A_TIMEOUT_MS;\n\n return DEFAULT_SERVERLESS_INTEGRATION_A2A_TIMEOUT_MS;\n}\n\nfunction integrationSourceContextHint(): string {\n const integration = getIntegrationRequestContext();\n const incoming = integration?.incoming;\n if (incoming?.platform !== \"slack\" || !incoming.sourceUrl) return \"\";\n\n try {\n const sourceUrl = new URL(incoming.sourceUrl);\n const isSlackHost =\n sourceUrl.hostname === \"slack.com\" ||\n sourceUrl.hostname.endsWith(\".slack.com\");\n if (sourceUrl.protocol !== \"https:\" || !isSlackHost) return \"\";\n return (\n `\\n\\n[Source Slack thread: ${sourceUrl.toString()} ` +\n \"Preserve this exact URL as request provenance when creating an intake record or other artifact.]\"\n );\n } catch {\n return \"\";\n }\n}\n\nfunction formatDownstreamLlmCredentialFailure(\n agentName: string,\n value: unknown,\n): string | null {\n return isLlmCredentialError(value)\n ? formatLlmCredentialErrorMessage({ agentName })\n : null;\n}\n\nexport const tool: ActionTool = {\n description:\n \"Call a DIFFERENT, separately-deployed agent app to ask a question or delegate a task. This is strictly for cross-app A2A communication — for example, asking the mail agent to send an email while you are the calendar agent. NEVER use this to call your own app or perform actions you can do with your own tools. Using call-agent on yourself will fail and waste time. \" +\n 'For brand-consistent generated media, the first-party Assets agent is available as agent=\"assets\"; use it when another app needs generated heroes, diagrams, product shots, thumbnails, videos, or design imagery, unless the current app has its own generation action that already delegates there. ' +\n \"IMPORTANT — handling the response: \" +\n \"(a) If it contains a URL or ID, copy it VERBATIM into your reply. Do not 'correct' or pluralize the path (e.g. /deck/ → /decks/), normalize casing, or change the slug — any edit breaks the link. \" +\n '(b) If it does NOT contain a URL/ID and the user asked for one, say so explicitly (e.g. \"the agent created the deck/image but didn\\'t return a link — open the app directly to view it\"). NEVER invent a URL, slug, or path — guessing produces broken links that look real. ' +\n \"(c) If the downstream response reports missing credentials, never repeat raw env var names, Vault key names, token names, secret names, or other credential identifiers. Tell the user the target app needs its LLM/provider connection configured.\",\n parameters: {\n type: \"object\",\n properties: {\n agent: {\n type: \"string\",\n description:\n \"Name or URL of a DIFFERENT deployed agent app (e.g. 'mail', 'calendar', 'analytics'). Must not be the current app's own name.\",\n },\n message: {\n type: \"string\",\n description: \"The message/question to send to the other agent\",\n },\n },\n required: [\"agent\", \"message\"],\n },\n};\n\nexport async function run(\n args: Record<string, string>,\n context?: ActionRunContext,\n selfAppId?: string,\n): Promise<string> {\n const { agent: agentIdOrName, message } = args;\n\n if (!agentIdOrName) return \"Error: --agent is required\";\n if (!message) return \"Error: --message is required\";\n\n // Prevent self-calls — the agent must use its own registered tools instead\n if (selfAppId && agentIdOrName.toLowerCase() === selfAppId.toLowerCase()) {\n return `Error: You cannot use call-agent to call yourself (${selfAppId}). Use your own registered actions/tools instead. call-agent is only for communicating with OTHER separately-deployed apps.`;\n }\n\n const agent = await findAgent(agentIdOrName, selfAppId);\n if (!agent) {\n const available = (await discoverAgents(selfAppId))\n .map((a) => a.name)\n .join(\", \");\n return `Error: Agent \"${agentIdOrName}\" not found. Available agents: ${available || \"(none)\"}`;\n }\n\n // Append a small cross-app hint to the outgoing message so the receiving\n // agent (which may be on an older deploy without the receiver-side hint\n // in handlers.ts) still emits fully-qualified URLs. This is belt-and-\n // suspenders with the receiver hint — but it works against any current\n // deployment, no redeploy required.\n const messageWithHint =\n `${message}${integrationSourceContextHint()}\\n\\n` +\n `[Note: this request comes from another app via A2A. The caller cannot see your local UI, deck list, or navigation — only the literal text you put in your reply. ` +\n `If you create or reference a deck/document/design/dashboard, include its FULLY-QUALIFIED URL (e.g. ${agent.url}/deck/<id>) in your reply, not a relative path. ` +\n `Use only artifact IDs and URL paths returned by successful actions — never invent slugs, IDs, or hosts.]`;\n\n try {\n // If we have a send context, use streaming so the UI shows progressive text\n if (context?.send) {\n const callerEmail = getRequestUserEmail();\n\n // Build metadata with identity\n const a2aMetadata: Record<string, unknown> = {};\n if (callerEmail) a2aMetadata.userEmail = callerEmail;\n\n // Include org domain for cross-app org resolution\n let callerOrgDomain: string | undefined;\n let callerOrgSecret: string | undefined;\n const orgId = getRequestOrgId();\n if (orgId) {\n try {\n const domain = await getOrgDomain(orgId);\n if (domain) {\n callerOrgDomain = domain;\n a2aMetadata.orgDomain = domain;\n }\n } catch {}\n try {\n const secret = await getOrgA2ASecret(orgId);\n if (secret) callerOrgSecret = secret;\n } catch {}\n }\n\n // Sign JWT with identity + org domain for the streaming client\n let apiKey: string | undefined;\n if (callerEmail && (callerOrgSecret || process.env.A2A_SECRET)) {\n try {\n apiKey = await signA2AToken(\n callerEmail,\n callerOrgDomain,\n callerOrgSecret,\n {\n expiresIn: INTEGRATION_A2A_TOKEN_TTL,\n preferGlobalSecret: shouldPreferGlobalA2ASecret(callerOrgSecret),\n },\n );\n } catch {}\n }\n\n if (process.env.NODE_ENV === \"production\" && callerEmail) {\n try {\n const { listOAuthAccountsByOwner } =\n await import(\"../oauth-tokens/store.js\");\n const accounts = await listOAuthAccountsByOwner(\n \"google\",\n callerEmail,\n );\n const tokens = accounts[0]?.tokens;\n if (tokens?.access_token) {\n a2aMetadata.googleToken = tokens.access_token;\n }\n } catch {}\n }\n\n let responseText = \"\";\n let lastSentLength = 0;\n const existingContinuationText =\n await formatExistingIntegrationContinuationIfRetry(agent, message);\n if (existingContinuationText) return existingContinuationText;\n\n context.send({\n type: \"agent_call\",\n agent: agent.name,\n status: \"start\",\n });\n\n const emitNewText = (newText: string) => {\n if (newText.length > lastSentLength) {\n context.send!({\n type: \"agent_call_text\",\n agent: agent.name,\n text: newText.slice(lastSentLength),\n });\n lastSentLength = newText.length;\n }\n responseText = newText;\n };\n\n // Skip the SSE streaming attempt and go straight to async + poll.\n // Why: on Netlify (Lambda), the receiving server has no streaming\n // response support, so message/stream returns a single JSON-RPC error\n // body in a 200 response that our SSE parser silently consumes — the\n // `for await` loop yields nothing AND keeps the connection open until\n // the function timeout, eating the current serverless budget. By the\n // time we get to the sync fallback, Lambda is dead and the second fetch\n // errors out as \"fetch failed\". Async+poll has its own short fetches\n // with their own budgets, so it works reliably across hosts. The\n // trade-off is we lose progressive in-UI text streaming for cross-app\n // A2A calls, but the receiving agent's full response still surfaces via\n // the tool_result event below.\n //\n // That trade-off has a second-order cost: callAgent()'s poll (see\n // A2AClient.sendAndWait in a2a/client.ts) can legitimately run for\n // minutes with nothing emitted to the parent between the \"start\" event\n // above and \"done\" below. On the parent run, that silence freezes\n // `last_progress_at` — shouldBumpProgressForEvent in\n // agent/run-manager.ts treats a stream of literally nothing as no\n // progress — which trips the client's stuck-detector\n // (DEFAULT_STUCK_THRESHOLD_MS = 90_000 in\n // client/use-run-stuck-detection.ts) and the server's stale-run sweep\n // (BACKGROUND_RUN_STALE_MS = 90_000 in agent/run-store.ts). In\n // production this handed users a \"still working, no progress\" Retry\n // button that aborted a perfectly healthy call and re-ran the sub-agent\n // from scratch.\n //\n // Fix: surface the REAL remote liveness the poll already gathers. The\n // A2A poll round-trips to the remote agent every ~2s and gets back a\n // task with `status.state` (see A2AClient.sendAndWait / `onUpdate`). We\n // emit an `agent_call_progress` event ONLY from that callback, and ONLY\n // when a poll actually succeeds AND reports an actively-working state.\n // Crucially this is NOT a timer: if the remote hangs or dies, the poll\n // fetch throws, `onUpdate` stops firing, we emit nothing, and the\n // stuck-detector correctly surfaces its banner. A wall-clock heartbeat\n // would instead keep a dead sub-agent looking alive forever — trading a\n // false stuck-positive for a worse false stuck-negative.\n //\n // Throttle: the poll runs every ~2s but both thresholds above are 90s,\n // so emitting per-poll would be ~45 events per stuck-window. We coalesce\n // to at most one emission per 30s — a 3x margin under 90s, so at least\n // two land inside either window even with jitter, without flooding.\n //\n // Shape: a dedicated `agent_call_progress` event type (see\n // agent/types.ts), not an extra `agent_call` status. `agent_call`\n // consumers (production-agent.ts's step summarizer, slack.ts's task\n // cards) render any status that isn't \"start\"/\"done\" as a failure, so a\n // \"progress\" status would surface an in-flight tick as an error. A\n // distinct type is instead ignored gracefully everywhere: the run-event\n // switches fall to their `default`, the client if-chains fall through,\n // and sse-event-processor returns `{action:\"continue\"}`. It still counts\n // as real progress in shouldBumpProgressForEvent (any non-special event\n // type does), which is the whole point.\n const PROGRESS_MIN_INTERVAL_MS = 30_000;\n // Terminal states resolve the poll; \"input-required\" means the remote is\n // blocked waiting on us, not making progress. Only actively-working\n // states count as liveness worth surfacing.\n const ACTIVELY_WORKING_STATES = new Set([\"working\", \"submitted\"]);\n const callStartedAt = Date.now();\n let lastProgressEmitAt = callStartedAt;\n const onRemotePollUpdate = (task: Task) => {\n const state = task?.status?.state;\n if (!state || !ACTIVELY_WORKING_STATES.has(state)) return;\n const now = Date.now();\n if (now - lastProgressEmitAt < PROGRESS_MIN_INTERVAL_MS) return;\n lastProgressEmitAt = now;\n const detail = extractRemoteProgressDetail(task);\n context.send!({\n type: \"agent_call_progress\",\n agent: agent.name,\n state,\n elapsedSeconds: Math.round((now - callStartedAt) / 1000),\n ...(detail ? { detail } : {}),\n });\n };\n\n try {\n // Apply a polling cap ONLY for integration-platform callers on\n // serverless hosts. Normal chat, local Node, self-hosted Node, and\n // Docker can wait for slow-but-valid answers; integration processors\n // still need to finish before their current function execution dies.\n const callTimeoutMs = getIntegrationCallTimeoutMs();\n responseText = await callAgent(agent.url, messageWithHint, {\n apiKey,\n userEmail: callerEmail,\n orgDomain: callerOrgDomain,\n orgSecret: callerOrgSecret,\n onUpdate: onRemotePollUpdate,\n ...(callTimeoutMs ? { timeoutMs: callTimeoutMs } : {}),\n });\n responseText =\n formatDownstreamLlmCredentialFailure(agent.name, responseText) ??\n responseText;\n // Some agents reply with relative paths (e.g. slides emits\n // \"/deck/abc\"). Those resolve against the caller's host, not the\n // receiver's, so they're broken for the user. Expand any leading-slash\n // URL into a fully-qualified one rooted at the receiving agent's host.\n responseText = expandRelativeUrls(responseText, agent.url);\n // Mirror the response into the streaming UI so the user sees it.\n if (responseText) emitNewText(responseText);\n } catch (pollErr: any) {\n const timeoutTaskId = getA2ATaskTimeoutTaskId(pollErr);\n if (timeoutTaskId) {\n const queued = await enqueueIntegrationContinuationIfPossible(\n timeoutTaskId,\n agent,\n message,\n callerEmail,\n );\n if (queued) {\n responseText =\n `${A2A_CONTINUATION_QUEUED_MARKER}\\n` +\n `The ${agent.name} agent accepted this delegated subtask and will post its own final result to the originating integration thread automatically. ` +\n `Do not call ${agent.name} again for this same subtask. Continue any other requested work, then answer with the completed results you have; if needed, mention that ${agent.name} is posting its result separately.`;\n } else {\n const reason = pollErr?.message ?? \"unknown error\";\n responseText = `The ${agent.name} agent is taking longer than expected and didn't reply in time. (${reason})`;\n }\n } else {\n const reason = pollErr?.message ?? \"unknown error\";\n responseText =\n formatDownstreamLlmCredentialFailure(agent.name, pollErr) ??\n `The ${agent.name} agent is taking longer than expected and didn't reply in time. (${reason})`;\n }\n }\n\n context.send({\n type: \"agent_call\",\n agent: agent.name,\n status: \"done\",\n });\n\n return responseText || \"(empty response)\";\n }\n\n // No context — use the async + poll call so we don't get cut off at the\n // serverless gateway's ~30s timeout. callAgent defaults to async:true.\n const email = getRequestUserEmail();\n let domain: string | undefined;\n let orgSecret: string | undefined;\n const currentOrgId = getRequestOrgId();\n if (currentOrgId) {\n try {\n domain = (await getOrgDomain(currentOrgId)) ?? undefined;\n } catch {}\n try {\n orgSecret = (await getOrgA2ASecret(currentOrgId)) ?? undefined;\n } catch {}\n }\n const response = await callAgent(agent.url, messageWithHint, {\n userEmail: email,\n orgDomain: domain,\n orgSecret,\n });\n const sanitized =\n formatDownstreamLlmCredentialFailure(agent.name, response) ?? response;\n return expandRelativeUrls(sanitized, agent.url) || \"(empty response)\";\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n const credentialMessage = formatDownstreamLlmCredentialFailure(\n agent.name,\n err,\n );\n if (credentialMessage) return credentialMessage;\n // Friendlier message for the common timeout case so the calling agent can\n // decide whether to give up or retry.\n if (/timeout|did not complete|Inactivity|504/i.test(msg)) {\n return `The ${agent.name} agent is taking longer than expected. Please try again, ask a simpler question, or open the ${agent.name} app directly.`;\n }\n return `Error calling ${agent.name}: ${msg}`;\n }\n}\n\nasync function enqueueIntegrationContinuationIfPossible(\n taskId: string,\n agent: { name: string; url: string },\n message: string,\n ownerEmail: string | undefined,\n): Promise<boolean> {\n const integration = getIntegrationRequestContext();\n if (!integration || !ownerEmail) return false;\n\n try {\n const [{ insertA2AContinuation }, { dispatchA2AContinuation }] =\n await Promise.all([\n import(\"../integrations/a2a-continuations-store.js\"),\n import(\"../integrations/a2a-continuation-processor.js\"),\n ]);\n const continuation = await insertA2AContinuation({\n integrationTaskId: integration.taskId,\n platform: integration.incoming.platform,\n externalThreadId: integration.incoming.externalThreadId,\n incoming: integration.incoming,\n placeholderRef: integration.placeholderRef,\n progressRef: integration.progressRef,\n ownerEmail,\n orgId: getRequestOrgId() ?? null,\n agentName: agent.name,\n agentUrl: agent.url,\n dedupeKey: getIntegrationContinuationDedupeKey(message),\n a2aTaskId: taskId,\n // Do not persist the short-lived JWT used for the initial send. The\n // continuation processor can mint a fresh token for each poll.\n a2aAuthToken: null,\n });\n await dispatchA2AContinuation(continuation.id).catch((err) => {\n console.error(\n `[call-agent] Failed to dispatch A2A continuation ${continuation.id}:`,\n err,\n );\n });\n return true;\n } catch (err) {\n console.error(\"[call-agent] Failed to enqueue A2A continuation:\", err);\n return false;\n }\n}\n\n// Pull a short human-readable detail from a polled A2A task's status message,\n// when the remote includes one, so the progress event can surface a real\n// signal (e.g. \"Generating hero image…\") instead of a bare elapsed counter.\n// Bounded so a chatty remote can't push a large payload through the event.\nconst MAX_PROGRESS_DETAIL_CHARS = 200;\nfunction extractRemoteProgressDetail(task: Task): string | undefined {\n const parts = task.status?.message?.parts;\n if (!parts) return undefined;\n const text = parts\n .filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n .map((p) => p.text)\n .join(\" \")\n .replace(/\\s+/g, \" \")\n .trim();\n if (!text) return undefined;\n return text.length > MAX_PROGRESS_DETAIL_CHARS\n ? `${text.slice(0, MAX_PROGRESS_DETAIL_CHARS - 1)}…`\n : text;\n}\n\nfunction getA2ATaskTimeoutTaskId(err: unknown): string | null {\n if (err instanceof A2ATaskTimeoutError) return err.taskId;\n\n const candidate = err as\n | { name?: unknown; taskId?: unknown; message?: unknown }\n | null\n | undefined;\n const message = String(candidate?.message ?? \"\");\n if (\n candidate?.name === \"A2ATaskTimeoutError\" &&\n typeof candidate.taskId === \"string\"\n ) {\n return candidate.taskId;\n }\n\n const match = message.match(/^A2A task ([^\\s]+) did not complete\\b/);\n return match?.[1] ?? null;\n}\n\nasync function formatExistingIntegrationContinuationIfRetry(\n agent: {\n name: string;\n url: string;\n },\n message: string,\n): Promise<string | null> {\n const integration = getIntegrationRequestContext();\n if (!integration || (integration.attempts ?? 1) <= 1) return null;\n\n try {\n const { getA2AContinuationsForIntegrationTaskAgent } =\n await import(\"../integrations/a2a-continuations-store.js\");\n const continuations = await getA2AContinuationsForIntegrationTaskAgent(\n integration.taskId,\n agent.url,\n getIntegrationContinuationDedupeKey(message),\n );\n const active = continuations.find((continuation) =>\n [\"pending\", \"processing\", \"delivering\", \"completed\"].includes(\n continuation.status,\n ),\n );\n if (!active) return null;\n\n const state =\n active.status === \"completed\"\n ? \"already completed this delegated subtask and posted its result to the originating integration thread\"\n : \"already accepted this delegated subtask and is still working on it for the originating integration thread\";\n return (\n `${A2A_CONTINUATION_QUEUED_MARKER}\\n` +\n `The ${agent.name} agent ${state}. Do not call ${agent.name} again for this same subtask. Continue any other requested work, then answer with the completed results you have; if needed, mention that ${agent.name} is posting or has posted its result separately.`\n );\n } catch (err) {\n console.error(\"[call-agent] Failed to inspect existing continuation:\", err);\n return null;\n }\n}\n\nfunction getIntegrationContinuationDedupeKey(message: string): string {\n const normalized = message.trim().replace(/\\s+/g, \" \");\n return createHash(\"sha256\").update(normalized).digest(\"hex\");\n}\n\n// Expand bare leading-slash paths (e.g. \"/deck/abc\") into fully-qualified URLs\n// rooted at the receiving agent's host. The receiver doesn't always know it's\n// being called cross-app, so it may emit relative paths that resolve against\n// the caller's host (broken). Match a path that starts at a word boundary,\n// begins with `/`, and has at least one path segment after that. Skip if it\n// already looks like a fully-qualified URL.\nexport function expandRelativeUrls(text: string, agentUrl: string): string {\n if (!text || !agentUrl) return text;\n const base = agentUrl.replace(/\\/$/, \"\");\n // Path must start at boundary (start, whitespace, or punctuation that isn't\n // ':' — to avoid mangling `https://example.com/foo` or markdown link bodies).\n return text.replace(\n /(^|[\\s([<\"'`])(\\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi,\n (_match, lead, path) => `${lead}${base}${path}`,\n );\n}\n"]}
@@ -27,11 +27,11 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
27
27
  export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
28
28
  error: any;
29
29
  } | {
30
+ error?: undefined;
30
31
  ok: boolean;
31
32
  key: string;
32
33
  baseUrlKey?: string;
33
34
  scope: AgentEngineApiKeyScope;
34
- error?: undefined;
35
35
  }>>;
36
36
  export {};
37
37
  //# sourceMappingURL=agent-engine-api-key-route.d.ts.map
@@ -113,6 +113,8 @@ export interface RequestContext {
113
113
  attempts?: number;
114
114
  incoming: import("../integrations/types.js").IncomingMessage;
115
115
  placeholderRef?: string;
116
+ /** Opaque provider-native progress surface for a durable continuation. */
117
+ progressRef?: import("../integrations/types.js").PlatformRunProgressRef;
116
118
  installationId?: string;
117
119
  scopeId?: string;
118
120
  principalType?: "user" | "service";
@@ -1 +1 @@
1
- {"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"request-context.js","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Per-request context using AsyncLocalStorage.\n *\n * Replaces the unsafe pattern of mutating `process.env.AGENT_USER_EMAIL` /\n * `process.env.AGENT_ORG_ID` on every request. On Node.js (Netlify, self-hosted)\n * concurrent requests would overwrite each other's env vars. AsyncLocalStorage\n * gives each async call-chain its own isolated context.\n *\n * Supported on all deployment targets:\n * - Node.js (native)\n * - Cloudflare Workers (via nodejs_compat flag)\n * - Deno Deploy (via node:async_hooks compat)\n *\n * For CLI scripts that run outside a request context, the getters fall back to\n * process.env so existing `AGENT_USER_EMAIL=x pnpm action foo` invocations\n * continue to work.\n */\n\ntype AsyncLocalStorageLike<T> = {\n getStore(): T | undefined;\n run<R>(store: T, callback: () => R): R;\n};\n\ntype AsyncLocalStorageCtor = new <T>() => AsyncLocalStorageLike<T>;\n\nclass StackAsyncLocalStorage<T> implements AsyncLocalStorageLike<T> {\n private readonly stack: T[] = [];\n\n getStore(): T | undefined {\n return this.stack.at(-1);\n }\n\n run<R>(store: T, callback: () => R): R {\n this.stack.push(store);\n try {\n const result = callback();\n const maybePromise = result as unknown as\n | { finally?: (callback: () => void) => unknown }\n | undefined;\n if (maybePromise && typeof maybePromise.finally === \"function\") {\n return maybePromise.finally(() => {\n this.stack.pop();\n }) as R;\n }\n this.stack.pop();\n return result;\n } catch (error) {\n this.stack.pop();\n throw error;\n }\n }\n}\n\nfunction getAsyncLocalStorageCtor(): AsyncLocalStorageCtor | undefined {\n if (\n typeof window !== \"undefined\" ||\n typeof process === \"undefined\" ||\n !process.versions?.node ||\n typeof process.getBuiltinModule !== \"function\"\n ) {\n return undefined;\n }\n return process.getBuiltinModule(\"node:async_hooks\")?.AsyncLocalStorage as\n | AsyncLocalStorageCtor\n | undefined;\n}\n\nconst AsyncLocalStorageCtor = getAsyncLocalStorageCtor();\n\nfunction processEnv(name: string): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n return process.env?.[name];\n}\n\n/**\n * Per-request agent-run state. Lives on `RequestContext.run` so the\n * agent-chat plugin can populate fields as the run progresses (owner,\n * resolved API key, system prompt, engine, model, threadId) without\n * mutating module-scope `let` bindings — those leak across concurrent\n * requests on a single Node.js process.\n *\n * Mutated in-place by `prepareRun`, `onEngineResolved`, `onRunStart` so\n * tool factory closures (automation, fetch, team, builder-browser) read\n * the live per-request value via `getRequestRunContext()`.\n */\nexport interface RequestRunContext {\n /** Origin of the current request (used by the builder-browser tool). */\n requestOrigin?: string;\n /** Stable browser tab id for tab-scoped app-state reads/writes. */\n browserTabId?: string;\n /** Resource scope for the current chat thread, e.g. the active deck. */\n chatScope?: {\n type: string;\n id: string;\n label?: string;\n } | null;\n /** Resolved owner email (set by prepareRun). */\n owner?: string;\n /** Owner's active Anthropic API key (set by prepareRun). */\n userApiKey?: string;\n /** Thread ID for the current run (set by onRunStart). */\n threadId?: string;\n /** System prompt actually sent to the model for this run. */\n systemPrompt?: string;\n /** Engine instance for this run (set by onEngineResolved). */\n engine?: import(\"../agent/engine/types.js\").AgentEngine;\n /** Model name for this run (set by onEngineResolved). */\n model?: string;\n /**\n * True when this run is executing inside the durable background-function\n * worker (the `_process-run` self-dispatch), not the synchronous foreground\n * request. Template `extraContext` / system-prompt builders can read this to\n * skip heavy, hang-prone enrichment (large data-dictionary DB reads, etc.)\n * in the worker so it reliably claims its run within the setup budget.\n */\n isBackgroundWorker?: boolean;\n /** Tool calls made so far in the current agent loop. */\n toolCalls?: Array<{ name: string; input: unknown }>;\n /** Tool results returned so far in the current agent loop. */\n toolResults?: Array<{ name: string; content: string; isError: boolean }>;\n /** Per-run fingerprints for large extension bodies already sent to the LLM. */\n extensionContentReads?: Record<string, string>;\n /** Per-run fingerprints for repeated tool-search calls already sent to the LLM. */\n toolSearchReads?: Record<\n string,\n { totalTools: number; resultNames: string[] }\n >;\n}\n\nexport interface RequestContext {\n userEmail?: string;\n userName?: string;\n orgId?: string;\n timezone?: string;\n /**\n * Set when code reads authenticated request context. Public SSR shell/data\n * should not depend on this value; user/org-specific reads belong behind\n * client-side actions/API after hydration.\n */\n authContextAccessed?: boolean;\n /**\n * Origin of the inbound request (e.g. `http://127.0.0.1:8100`). Set by the\n * MCP mount from the request headers so actions that build externally\n * fetchable URLs (e.g. design `export-coding-handoff`'s signed raw-code URL)\n * resolve the real local-workspace origin instead of a prod/localhost\n * fallback. Optional — absent on paths that don't populate it.\n */\n requestOrigin?: string;\n /**\n * True when this request is being processed by an integration-platform\n * webhook (Slack, Telegram, etc.) where the function timeout is the\n * binding constraint. Code that calls slow remote APIs can use this to apply\n * tighter budgets on this path while leaving normal agent-chat callers\n * (5+ min budget) unaffected.\n */\n isIntegrationCaller?: boolean;\n /**\n * Metadata for the currently-processing integration task. This lets tools\n * that start long-running remote work persist a continuation that can update\n * the originating platform thread after the current function budget ends.\n */\n integration?: {\n taskId: string;\n attempts?: number;\n incoming: import(\"../integrations/types.js\").IncomingMessage;\n placeholderRef?: string;\n installationId?: string;\n scopeId?: string;\n principalType?: \"user\" | \"service\";\n lineage?: {\n runId?: string;\n parentTaskId?: string;\n source?: {\n kind: string;\n platform?: string;\n id: string;\n url?: string;\n };\n network?: {\n protocol: \"a2a\" | \"mcp\" | \"provider-api\";\n id: string;\n peer?: string;\n };\n };\n };\n /**\n * Mutable per-request agent-run state. Populated by the agent-chat plugin\n * during a run; tool closures dereference it on each invocation.\n */\n run?: RequestRunContext;\n}\n\nconst GLOBAL_KEY = \"__agentNativeRequestContextAls\" as const;\nconst OBSERVERS_KEY = \"__agentNativeRequestContextObservers\" as const;\ntype RequestContextObserver = (ctx: RequestContext) => void;\ntype GlobalWithRequestContext = typeof globalThis & {\n [GLOBAL_KEY]?: AsyncLocalStorageLike<RequestContext>;\n [OBSERVERS_KEY]?: RequestContextObserver[];\n};\nconst globalRef = globalThis as GlobalWithRequestContext;\nif (!globalRef[GLOBAL_KEY]) {\n globalRef[GLOBAL_KEY] = AsyncLocalStorageCtor\n ? new AsyncLocalStorageCtor<RequestContext>()\n : new StackAsyncLocalStorage<RequestContext>();\n}\nif (!globalRef[OBSERVERS_KEY]) {\n globalRef[OBSERVERS_KEY] = [];\n}\nconst als = globalRef[GLOBAL_KEY]!;\nconst observers = globalRef[OBSERVERS_KEY]!;\n\n/**\n * Register a callback fired every time `runWithRequestContext` enters a new\n * scope. The hook runs INSIDE the AsyncLocalStorage scope, so observability\n * helpers that read the current isolation scope (e.g. Sentry) attach to the\n * right per-request context.\n *\n * Returned function unregisters the observer. Observers must never throw —\n * any error is swallowed so a misbehaving observer can't break the request\n * path.\n */\nexport function addRequestContextObserver(\n observer: RequestContextObserver,\n): () => void {\n observers.push(observer);\n return () => {\n const i = observers.indexOf(observer);\n if (i !== -1) observers.splice(i, 1);\n };\n}\n\n/**\n * Run a callback within a per-request context. The context is available to all\n * async operations spawned from `fn` via `getRequestUserEmail()` / `getRequestOrgId()`.\n *\n * Any registered `addRequestContextObserver` callbacks fire inside the new\n * scope before `fn` runs, so observability code can pin user/org info onto\n * isolation-scoped backends (Sentry, OpenTelemetry, etc.).\n */\nexport function runWithRequestContext<T>(\n ctx: RequestContext,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n return als.run(ctx, () => {\n if (observers.length > 0) {\n for (const obs of observers) {\n try {\n obs(ctx);\n } catch {\n // Observers must never break the request path.\n }\n }\n }\n return fn();\n });\n}\n\n/**\n * Return the active request context, if this call chain is running under one.\n *\n * This is intentionally distinct from `getRequestUserEmail()`: callers that\n * have an active context with no authenticated user must not fall through to\n * process-wide CLI fallbacks such as `AGENT_USER_EMAIL` or \"latest session\".\n */\nexport function getRequestContext(): RequestContext | undefined {\n const store = als.getStore();\n markAuthContextAccess(store);\n return store;\n}\n\n/**\n * True when AsyncLocalStorage has an active context for this call chain.\n * Useful for helpers that support both HTTP requests and standalone CLI runs.\n */\nexport function hasRequestContext(): boolean {\n return als.getStore() !== undefined;\n}\n\n/**\n * Get the current request's user email.\n *\n * - If a request context exists (HTTP/A2A path), returns its `userEmail` —\n * even when that value is `undefined`. The env fallback MUST NOT fire here:\n * a stale process-wide `AGENT_USER_EMAIL` from a CLI run or previous bug\n * would leak into an unauthenticated A2A/API call (e.g. unsigned or API-key\n * modes where `runWithRequestContext({ userEmail: undefined })` is used).\n * - Only when there is NO request context (CLI scripts) do we fall back to\n * `process.env.AGENT_USER_EMAIL`.\n */\nexport function getRequestUserEmail(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) {\n if (store.userEmail) markAuthContextAccess(store);\n return store.userEmail;\n }\n return processEnv(\"AGENT_USER_EMAIL\");\n}\n\n/**\n * Get the current request's display name, when the auth provider supplied one.\n *\n * The same request-context fallback rules as `getRequestUserEmail()` apply:\n * HTTP/A2A calls only read AsyncLocalStorage, while CLI scripts may opt in via\n * `AGENT_USER_NAME`.\n */\nexport function getRequestUserName(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) {\n if (store.userName) markAuthContextAccess(store);\n return store.userName;\n }\n return processEnv(\"AGENT_USER_NAME\");\n}\n\n/**\n * Get the current request's org ID.\n *\n * Same store-aware semantics as `getRequestUserEmail()` — env fallback is\n * CLI-only, so a request that explicitly has no org doesn't inherit a stale\n * `process.env.AGENT_ORG_ID` from a prior request on the same Lambda instance.\n */\nexport function getRequestOrgId(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) {\n if (store.orgId) markAuthContextAccess(store);\n return store.orgId;\n }\n return processEnv(\"AGENT_ORG_ID\");\n}\n\nfunction markAuthContextAccess(ctx: RequestContext | undefined) {\n if (!ctx) return;\n if (ctx.userEmail || ctx.userName || ctx.orgId) {\n ctx.authContextAccessed = true;\n }\n}\n\nexport function hasAuthContextAccess(ctx: RequestContext | undefined): boolean {\n return Boolean(ctx?.authContextAccessed);\n}\n\n/**\n * Get the current request's IANA timezone (e.g. \"America/Los_Angeles\").\n * The UI sends this via the `x-user-timezone` header on every action call, and\n * the agent chat plugin propagates it into the request context so that\n * agent-initiated tool calls also see the user's timezone. Falls back to\n * `process.env.AGENT_USER_TIMEZONE` only for CLI scripts (no request context).\n */\nexport function getRequestTimezone(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) return store.timezone;\n return processEnv(\"AGENT_USER_TIMEZONE\");\n}\n\n/**\n * Returns true when this request is on an integration-platform path (Slack,\n * Telegram, etc.) — i.e. we're inside the integration plugin's processor\n * function and the platform's deliver-by deadline plus the host's function\n * timeout are the binding budget. Non-integration callers (CLI, normal\n * agent chat) should treat this as `false`.\n */\nexport function isIntegrationCallerRequest(): boolean {\n return als.getStore()?.isIntegrationCaller === true;\n}\n\nexport function getIntegrationRequestContext():\n | NonNullable<RequestContext[\"integration\"]>\n | undefined {\n return als.getStore()?.integration;\n}\n\n/**\n * Convenience: returns `{ userEmail, orgId }` from the active request context,\n * suitable for passing to `resolveCredential(key, ctx)`. Returns `null` when\n * no user is associated with the call (e.g. an unauthenticated public route).\n *\n * For framework actions auto-mounted at `/_agent-native/actions/...` this is\n * always populated because action-routes wraps every invocation in\n * `runWithRequestContext`. For hand-written `/api/*` routes the calling code\n * is responsible for setting up the context (see `runWithRequestContext`).\n */\nexport function getCredentialContext(): {\n userEmail: string;\n orgId: string | null;\n} | null {\n const userEmail = getRequestUserEmail();\n if (!userEmail) return null;\n return { userEmail, orgId: getRequestOrgId() ?? null };\n}\n\n/**\n * Get the active request's mutable agent-run state. Returns `undefined` when\n * called outside an agent run (e.g. before `prepareRun` or in a non-agent\n * code path). Callers must tolerate the field absence; use the helper\n * `requireRequestRunContext()` if missing context is a programming error.\n */\nexport function getRequestRunContext(): RequestRunContext | undefined {\n const store = als.getStore();\n if (!store) return undefined;\n return store.run;\n}\n\n/**\n * Ensure a `RequestRunContext` exists on the active request store and\n * return it. Used by the agent-chat handler to attach run state once it\n * starts processing a chat request. Returns `undefined` if there is no\n * active request store (caller should not be invoking this outside ALS).\n */\nexport function ensureRequestRunContext(): RequestRunContext | undefined {\n const store = als.getStore();\n if (!store) return undefined;\n if (!store.run) store.run = {};\n return store.run;\n}\n"]}
1
+ {"version":3,"file":"request-context.js","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Per-request context using AsyncLocalStorage.\n *\n * Replaces the unsafe pattern of mutating `process.env.AGENT_USER_EMAIL` /\n * `process.env.AGENT_ORG_ID` on every request. On Node.js (Netlify, self-hosted)\n * concurrent requests would overwrite each other's env vars. AsyncLocalStorage\n * gives each async call-chain its own isolated context.\n *\n * Supported on all deployment targets:\n * - Node.js (native)\n * - Cloudflare Workers (via nodejs_compat flag)\n * - Deno Deploy (via node:async_hooks compat)\n *\n * For CLI scripts that run outside a request context, the getters fall back to\n * process.env so existing `AGENT_USER_EMAIL=x pnpm action foo` invocations\n * continue to work.\n */\n\ntype AsyncLocalStorageLike<T> = {\n getStore(): T | undefined;\n run<R>(store: T, callback: () => R): R;\n};\n\ntype AsyncLocalStorageCtor = new <T>() => AsyncLocalStorageLike<T>;\n\nclass StackAsyncLocalStorage<T> implements AsyncLocalStorageLike<T> {\n private readonly stack: T[] = [];\n\n getStore(): T | undefined {\n return this.stack.at(-1);\n }\n\n run<R>(store: T, callback: () => R): R {\n this.stack.push(store);\n try {\n const result = callback();\n const maybePromise = result as unknown as\n | { finally?: (callback: () => void) => unknown }\n | undefined;\n if (maybePromise && typeof maybePromise.finally === \"function\") {\n return maybePromise.finally(() => {\n this.stack.pop();\n }) as R;\n }\n this.stack.pop();\n return result;\n } catch (error) {\n this.stack.pop();\n throw error;\n }\n }\n}\n\nfunction getAsyncLocalStorageCtor(): AsyncLocalStorageCtor | undefined {\n if (\n typeof window !== \"undefined\" ||\n typeof process === \"undefined\" ||\n !process.versions?.node ||\n typeof process.getBuiltinModule !== \"function\"\n ) {\n return undefined;\n }\n return process.getBuiltinModule(\"node:async_hooks\")?.AsyncLocalStorage as\n | AsyncLocalStorageCtor\n | undefined;\n}\n\nconst AsyncLocalStorageCtor = getAsyncLocalStorageCtor();\n\nfunction processEnv(name: string): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n return process.env?.[name];\n}\n\n/**\n * Per-request agent-run state. Lives on `RequestContext.run` so the\n * agent-chat plugin can populate fields as the run progresses (owner,\n * resolved API key, system prompt, engine, model, threadId) without\n * mutating module-scope `let` bindings — those leak across concurrent\n * requests on a single Node.js process.\n *\n * Mutated in-place by `prepareRun`, `onEngineResolved`, `onRunStart` so\n * tool factory closures (automation, fetch, team, builder-browser) read\n * the live per-request value via `getRequestRunContext()`.\n */\nexport interface RequestRunContext {\n /** Origin of the current request (used by the builder-browser tool). */\n requestOrigin?: string;\n /** Stable browser tab id for tab-scoped app-state reads/writes. */\n browserTabId?: string;\n /** Resource scope for the current chat thread, e.g. the active deck. */\n chatScope?: {\n type: string;\n id: string;\n label?: string;\n } | null;\n /** Resolved owner email (set by prepareRun). */\n owner?: string;\n /** Owner's active Anthropic API key (set by prepareRun). */\n userApiKey?: string;\n /** Thread ID for the current run (set by onRunStart). */\n threadId?: string;\n /** System prompt actually sent to the model for this run. */\n systemPrompt?: string;\n /** Engine instance for this run (set by onEngineResolved). */\n engine?: import(\"../agent/engine/types.js\").AgentEngine;\n /** Model name for this run (set by onEngineResolved). */\n model?: string;\n /**\n * True when this run is executing inside the durable background-function\n * worker (the `_process-run` self-dispatch), not the synchronous foreground\n * request. Template `extraContext` / system-prompt builders can read this to\n * skip heavy, hang-prone enrichment (large data-dictionary DB reads, etc.)\n * in the worker so it reliably claims its run within the setup budget.\n */\n isBackgroundWorker?: boolean;\n /** Tool calls made so far in the current agent loop. */\n toolCalls?: Array<{ name: string; input: unknown }>;\n /** Tool results returned so far in the current agent loop. */\n toolResults?: Array<{ name: string; content: string; isError: boolean }>;\n /** Per-run fingerprints for large extension bodies already sent to the LLM. */\n extensionContentReads?: Record<string, string>;\n /** Per-run fingerprints for repeated tool-search calls already sent to the LLM. */\n toolSearchReads?: Record<\n string,\n { totalTools: number; resultNames: string[] }\n >;\n}\n\nexport interface RequestContext {\n userEmail?: string;\n userName?: string;\n orgId?: string;\n timezone?: string;\n /**\n * Set when code reads authenticated request context. Public SSR shell/data\n * should not depend on this value; user/org-specific reads belong behind\n * client-side actions/API after hydration.\n */\n authContextAccessed?: boolean;\n /**\n * Origin of the inbound request (e.g. `http://127.0.0.1:8100`). Set by the\n * MCP mount from the request headers so actions that build externally\n * fetchable URLs (e.g. design `export-coding-handoff`'s signed raw-code URL)\n * resolve the real local-workspace origin instead of a prod/localhost\n * fallback. Optional — absent on paths that don't populate it.\n */\n requestOrigin?: string;\n /**\n * True when this request is being processed by an integration-platform\n * webhook (Slack, Telegram, etc.) where the function timeout is the\n * binding constraint. Code that calls slow remote APIs can use this to apply\n * tighter budgets on this path while leaving normal agent-chat callers\n * (5+ min budget) unaffected.\n */\n isIntegrationCaller?: boolean;\n /**\n * Metadata for the currently-processing integration task. This lets tools\n * that start long-running remote work persist a continuation that can update\n * the originating platform thread after the current function budget ends.\n */\n integration?: {\n taskId: string;\n attempts?: number;\n incoming: import(\"../integrations/types.js\").IncomingMessage;\n placeholderRef?: string;\n /** Opaque provider-native progress surface for a durable continuation. */\n progressRef?: import(\"../integrations/types.js\").PlatformRunProgressRef;\n installationId?: string;\n scopeId?: string;\n principalType?: \"user\" | \"service\";\n lineage?: {\n runId?: string;\n parentTaskId?: string;\n source?: {\n kind: string;\n platform?: string;\n id: string;\n url?: string;\n };\n network?: {\n protocol: \"a2a\" | \"mcp\" | \"provider-api\";\n id: string;\n peer?: string;\n };\n };\n };\n /**\n * Mutable per-request agent-run state. Populated by the agent-chat plugin\n * during a run; tool closures dereference it on each invocation.\n */\n run?: RequestRunContext;\n}\n\nconst GLOBAL_KEY = \"__agentNativeRequestContextAls\" as const;\nconst OBSERVERS_KEY = \"__agentNativeRequestContextObservers\" as const;\ntype RequestContextObserver = (ctx: RequestContext) => void;\ntype GlobalWithRequestContext = typeof globalThis & {\n [GLOBAL_KEY]?: AsyncLocalStorageLike<RequestContext>;\n [OBSERVERS_KEY]?: RequestContextObserver[];\n};\nconst globalRef = globalThis as GlobalWithRequestContext;\nif (!globalRef[GLOBAL_KEY]) {\n globalRef[GLOBAL_KEY] = AsyncLocalStorageCtor\n ? new AsyncLocalStorageCtor<RequestContext>()\n : new StackAsyncLocalStorage<RequestContext>();\n}\nif (!globalRef[OBSERVERS_KEY]) {\n globalRef[OBSERVERS_KEY] = [];\n}\nconst als = globalRef[GLOBAL_KEY]!;\nconst observers = globalRef[OBSERVERS_KEY]!;\n\n/**\n * Register a callback fired every time `runWithRequestContext` enters a new\n * scope. The hook runs INSIDE the AsyncLocalStorage scope, so observability\n * helpers that read the current isolation scope (e.g. Sentry) attach to the\n * right per-request context.\n *\n * Returned function unregisters the observer. Observers must never throw —\n * any error is swallowed so a misbehaving observer can't break the request\n * path.\n */\nexport function addRequestContextObserver(\n observer: RequestContextObserver,\n): () => void {\n observers.push(observer);\n return () => {\n const i = observers.indexOf(observer);\n if (i !== -1) observers.splice(i, 1);\n };\n}\n\n/**\n * Run a callback within a per-request context. The context is available to all\n * async operations spawned from `fn` via `getRequestUserEmail()` / `getRequestOrgId()`.\n *\n * Any registered `addRequestContextObserver` callbacks fire inside the new\n * scope before `fn` runs, so observability code can pin user/org info onto\n * isolation-scoped backends (Sentry, OpenTelemetry, etc.).\n */\nexport function runWithRequestContext<T>(\n ctx: RequestContext,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n return als.run(ctx, () => {\n if (observers.length > 0) {\n for (const obs of observers) {\n try {\n obs(ctx);\n } catch {\n // Observers must never break the request path.\n }\n }\n }\n return fn();\n });\n}\n\n/**\n * Return the active request context, if this call chain is running under one.\n *\n * This is intentionally distinct from `getRequestUserEmail()`: callers that\n * have an active context with no authenticated user must not fall through to\n * process-wide CLI fallbacks such as `AGENT_USER_EMAIL` or \"latest session\".\n */\nexport function getRequestContext(): RequestContext | undefined {\n const store = als.getStore();\n markAuthContextAccess(store);\n return store;\n}\n\n/**\n * True when AsyncLocalStorage has an active context for this call chain.\n * Useful for helpers that support both HTTP requests and standalone CLI runs.\n */\nexport function hasRequestContext(): boolean {\n return als.getStore() !== undefined;\n}\n\n/**\n * Get the current request's user email.\n *\n * - If a request context exists (HTTP/A2A path), returns its `userEmail` —\n * even when that value is `undefined`. The env fallback MUST NOT fire here:\n * a stale process-wide `AGENT_USER_EMAIL` from a CLI run or previous bug\n * would leak into an unauthenticated A2A/API call (e.g. unsigned or API-key\n * modes where `runWithRequestContext({ userEmail: undefined })` is used).\n * - Only when there is NO request context (CLI scripts) do we fall back to\n * `process.env.AGENT_USER_EMAIL`.\n */\nexport function getRequestUserEmail(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) {\n if (store.userEmail) markAuthContextAccess(store);\n return store.userEmail;\n }\n return processEnv(\"AGENT_USER_EMAIL\");\n}\n\n/**\n * Get the current request's display name, when the auth provider supplied one.\n *\n * The same request-context fallback rules as `getRequestUserEmail()` apply:\n * HTTP/A2A calls only read AsyncLocalStorage, while CLI scripts may opt in via\n * `AGENT_USER_NAME`.\n */\nexport function getRequestUserName(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) {\n if (store.userName) markAuthContextAccess(store);\n return store.userName;\n }\n return processEnv(\"AGENT_USER_NAME\");\n}\n\n/**\n * Get the current request's org ID.\n *\n * Same store-aware semantics as `getRequestUserEmail()` — env fallback is\n * CLI-only, so a request that explicitly has no org doesn't inherit a stale\n * `process.env.AGENT_ORG_ID` from a prior request on the same Lambda instance.\n */\nexport function getRequestOrgId(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) {\n if (store.orgId) markAuthContextAccess(store);\n return store.orgId;\n }\n return processEnv(\"AGENT_ORG_ID\");\n}\n\nfunction markAuthContextAccess(ctx: RequestContext | undefined) {\n if (!ctx) return;\n if (ctx.userEmail || ctx.userName || ctx.orgId) {\n ctx.authContextAccessed = true;\n }\n}\n\nexport function hasAuthContextAccess(ctx: RequestContext | undefined): boolean {\n return Boolean(ctx?.authContextAccessed);\n}\n\n/**\n * Get the current request's IANA timezone (e.g. \"America/Los_Angeles\").\n * The UI sends this via the `x-user-timezone` header on every action call, and\n * the agent chat plugin propagates it into the request context so that\n * agent-initiated tool calls also see the user's timezone. Falls back to\n * `process.env.AGENT_USER_TIMEZONE` only for CLI scripts (no request context).\n */\nexport function getRequestTimezone(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) return store.timezone;\n return processEnv(\"AGENT_USER_TIMEZONE\");\n}\n\n/**\n * Returns true when this request is on an integration-platform path (Slack,\n * Telegram, etc.) — i.e. we're inside the integration plugin's processor\n * function and the platform's deliver-by deadline plus the host's function\n * timeout are the binding budget. Non-integration callers (CLI, normal\n * agent chat) should treat this as `false`.\n */\nexport function isIntegrationCallerRequest(): boolean {\n return als.getStore()?.isIntegrationCaller === true;\n}\n\nexport function getIntegrationRequestContext():\n | NonNullable<RequestContext[\"integration\"]>\n | undefined {\n return als.getStore()?.integration;\n}\n\n/**\n * Convenience: returns `{ userEmail, orgId }` from the active request context,\n * suitable for passing to `resolveCredential(key, ctx)`. Returns `null` when\n * no user is associated with the call (e.g. an unauthenticated public route).\n *\n * For framework actions auto-mounted at `/_agent-native/actions/...` this is\n * always populated because action-routes wraps every invocation in\n * `runWithRequestContext`. For hand-written `/api/*` routes the calling code\n * is responsible for setting up the context (see `runWithRequestContext`).\n */\nexport function getCredentialContext(): {\n userEmail: string;\n orgId: string | null;\n} | null {\n const userEmail = getRequestUserEmail();\n if (!userEmail) return null;\n return { userEmail, orgId: getRequestOrgId() ?? null };\n}\n\n/**\n * Get the active request's mutable agent-run state. Returns `undefined` when\n * called outside an agent run (e.g. before `prepareRun` or in a non-agent\n * code path). Callers must tolerate the field absence; use the helper\n * `requireRequestRunContext()` if missing context is a programming error.\n */\nexport function getRequestRunContext(): RequestRunContext | undefined {\n const store = als.getStore();\n if (!store) return undefined;\n return store.run;\n}\n\n/**\n * Ensure a `RequestRunContext` exists on the active request store and\n * return it. Used by the agent-chat handler to attach run state once it\n * starts processing a chat request. Returns `undefined` if there is no\n * active request store (caller should not be invoking this outside ALS).\n */\nexport function ensureRequestRunContext(): RequestRunContext | undefined {\n const store = als.getStore();\n if (!store) return undefined;\n if (!store.run) store.run = {};\n return store.run;\n}\n"]}
@@ -20,7 +20,7 @@ export declare function createTranscribeVoiceHandler(): import("h3").EventHandle
20
20
  error: string;
21
21
  text?: undefined;
22
22
  } | {
23
- text: string;
24
23
  error?: undefined;
24
+ text: string;
25
25
  }>>;
26
26
  //# sourceMappingURL=transcribe-voice.d.ts.map
@@ -36,6 +36,8 @@ export interface UsageRecord {
36
36
  * provider-reported dollar cost so two surfaces agree exactly.
37
37
  */
38
38
  costCentsX100?: number;
39
+ /** Whether cost is provider-reported, estimated, or unavailable. */
40
+ costSource?: UsageCostSource;
39
41
  orgId?: string;
40
42
  runId?: string;
41
43
  threadId?: string;
@@ -44,6 +46,7 @@ export interface UsageRecord {
44
46
  sourcePlatform?: string;
45
47
  sourceId?: string;
46
48
  }
49
+ export type UsageCostSource = "reported" | "estimated" | "unavailable";
47
50
  /**
48
51
  * Calculate cost in centicents (1/100th of a cent).
49
52
  * Accepts cache tokens so callers that use prompt caching are priced
@@ -72,14 +75,29 @@ export interface UsageBucket {
72
75
  cacheReadTokens: number;
73
76
  cacheWriteTokens: number;
74
77
  cents: number;
78
+ cost: UsageCostAggregate;
75
79
  calls: number;
76
80
  }
77
81
  export interface DailyBucket {
78
82
  /** YYYY-MM-DD (UTC) */
79
83
  date: string;
80
84
  cents: number;
85
+ cost: UsageCostAggregate;
81
86
  calls: number;
82
87
  }
88
+ export type UsageCostAggregate = {
89
+ status: "known";
90
+ knownCents: number;
91
+ unavailableCalls: 0;
92
+ } | {
93
+ status: "partial";
94
+ knownCents: number;
95
+ unavailableCalls: number;
96
+ } | {
97
+ status: "unavailable";
98
+ knownCents: 0;
99
+ unavailableCalls: number;
100
+ };
83
101
  export interface UsageRecentEntry {
84
102
  id: number;
85
103
  createdAt: number;
@@ -91,10 +109,13 @@ export interface UsageRecentEntry {
91
109
  cacheReadTokens: number;
92
110
  cacheWriteTokens: number;
93
111
  cents: number;
112
+ costSource: UsageCostSource;
94
113
  }
95
114
  export interface UsageSummary {
96
115
  billing?: UsageBillingMode;
116
+ /** Legacy known-cost subtotal. Use totalCost to preserve unavailable spend. */
97
117
  totalCents: number;
118
+ totalCost: UsageCostAggregate;
98
119
  totalCalls: number;
99
120
  totalInputTokens: number;
100
121
  totalOutputTokens: number;
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/usage/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/usage/store.ts"],"names":[],"mappings":"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"}
@@ -152,6 +152,7 @@ async function ensureUsageTable() {
152
152
  cache_read_tokens ${intType()} NOT NULL DEFAULT 0,
153
153
  cache_write_tokens ${intType()} NOT NULL DEFAULT 0,
154
154
  cost_cents_x100 ${intType()} NOT NULL DEFAULT 0,
155
+ cost_source TEXT NOT NULL DEFAULT 'estimated',
155
156
  model TEXT NOT NULL DEFAULT '',
156
157
  label TEXT NOT NULL DEFAULT 'chat',
157
158
  app TEXT NOT NULL DEFAULT '',
@@ -170,6 +171,7 @@ async function ensureUsageTable() {
170
171
  const additions = [
171
172
  ["cache_read_tokens", `${intType()} NOT NULL DEFAULT 0`],
172
173
  ["cache_write_tokens", `${intType()} NOT NULL DEFAULT 0`],
174
+ ["cost_source", `TEXT NOT NULL DEFAULT 'estimated'`],
173
175
  ["label", `TEXT NOT NULL DEFAULT 'chat'`],
174
176
  ["app", `TEXT NOT NULL DEFAULT ''`],
175
177
  ["ref_id", `TEXT NOT NULL DEFAULT ''`],
@@ -258,7 +260,7 @@ export async function recordUsage(recordOrOwner, inputTokens, outputTokens, mode
258
260
  model: model ?? "",
259
261
  }
260
262
  : recordOrOwner;
261
- const { ownerEmail, inputTokens: inTok, outputTokens: outTok, cacheReadTokens = 0, cacheWriteTokens = 0, model: modelName, label, app, refId, costCentsX100, orgId, runId, threadId, taskId, integrationScopeId, sourcePlatform, sourceId, } = record;
263
+ const { ownerEmail, inputTokens: inTok, outputTokens: outTok, cacheReadTokens = 0, cacheWriteTokens = 0, model: modelName, label, app, refId, costCentsX100, costSource, orgId, runId, threadId, taskId, integrationScopeId, sourcePlatform, sourceId, } = record;
262
264
  // Skip no-op writes (e.g. a stream aborted before any tokens flowed)
263
265
  if (!inTok && !outTok && !cacheReadTokens && !cacheWriteTokens)
264
266
  return;
@@ -278,13 +280,16 @@ export async function recordUsage(recordOrOwner, inputTokens, outputTokens, mode
278
280
  }
279
281
  // Prefer an explicit precomputed cost (e.g. a provider-reported dollar cost);
280
282
  // otherwise derive it from tokens via the pricing table.
281
- const costX100 = costCentsX100 ??
282
- calculateCost(inTok, outTok, modelName, cacheReadTokens, cacheWriteTokens);
283
+ const resolvedCostSource = costSource ?? (costCentsX100 == null ? "estimated" : "reported");
284
+ const costX100 = resolvedCostSource === "unavailable"
285
+ ? 0
286
+ : (costCentsX100 ??
287
+ calculateCost(inTok, outTok, modelName, cacheReadTokens, cacheWriteTokens));
283
288
  const id = Date.now() * 1000 + Math.floor(Math.random() * 1000);
284
289
  await client.execute({
285
290
  sql: `INSERT INTO token_usage
286
- (id, owner_email, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, cost_cents_x100, model, label, app, ref_id, org_id, run_id, thread_id, task_id, integration_scope_id, source_platform, source_id, created_at)
287
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
291
+ (id, owner_email, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, cost_cents_x100, cost_source, model, label, app, ref_id, org_id, run_id, thread_id, task_id, integration_scope_id, source_platform, source_id, created_at)
292
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
288
293
  args: [
289
294
  id,
290
295
  ownerEmail,
@@ -293,6 +298,7 @@ export async function recordUsage(recordOrOwner, inputTokens, outputTokens, mode
293
298
  cacheReadTokens,
294
299
  cacheWriteTokens,
295
300
  costX100,
301
+ resolvedCostSource,
296
302
  modelName,
297
303
  resolvedLabel,
298
304
  resolvedApp,
@@ -330,7 +336,8 @@ export async function getUsageSummary(options) {
330
336
  const sinceMs = options.sinceMs ?? Date.now() - 30 * DAY_MS;
331
337
  const totalRow = await client.execute({
332
338
  sql: `SELECT
333
- COALESCE(SUM(cost_cents_x100), 0) AS cents,
339
+ COALESCE(SUM(CASE WHEN cost_source = 'unavailable' THEN 0 ELSE cost_cents_x100 END), 0) AS known_cents,
340
+ COALESCE(SUM(CASE WHEN cost_source = 'unavailable' THEN 1 ELSE 0 END), 0) AS unavailable_calls,
334
341
  COUNT(*) AS calls,
335
342
  COALESCE(SUM(input_tokens), 0) AS in_tok,
336
343
  COALESCE(SUM(output_tokens), 0) AS out_tok,
@@ -342,7 +349,8 @@ export async function getUsageSummary(options) {
342
349
  const t = (totalRow.rows[0] ?? {});
343
350
  const bucketSql = (col) => ({
344
351
  sql: `SELECT ${col} AS k,
345
- COALESCE(SUM(cost_cents_x100), 0) AS cents,
352
+ COALESCE(SUM(CASE WHEN cost_source = 'unavailable' THEN 0 ELSE cost_cents_x100 END), 0) AS known_cents,
353
+ COALESCE(SUM(CASE WHEN cost_source = 'unavailable' THEN 1 ELSE 0 END), 0) AS unavailable_calls,
346
354
  COUNT(*) AS calls,
347
355
  COALESCE(SUM(input_tokens), 0) AS in_tok,
348
356
  COALESCE(SUM(output_tokens), 0) AS out_tok,
@@ -351,14 +359,17 @@ export async function getUsageSummary(options) {
351
359
  FROM token_usage
352
360
  WHERE owner_email = ? AND created_at >= ?
353
361
  GROUP BY ${col}
354
- ORDER BY cents DESC`,
362
+ ORDER BY known_cents DESC`,
355
363
  args: [options.ownerEmail, sinceMs],
356
364
  });
357
365
  const mapBuckets = (rows) => rows.map((r) => {
358
366
  const row = r;
367
+ const knownCents = Number(row.known_cents ?? 0) / 100;
368
+ const unavailableCalls = Number(row.unavailable_calls ?? 0);
359
369
  return {
360
370
  key: String(row.k ?? ""),
361
- cents: Number(row.cents ?? 0) / 100,
371
+ cents: knownCents,
372
+ cost: buildUsageCostAggregate(knownCents, unavailableCalls),
362
373
  calls: Number(row.calls ?? 0),
363
374
  inputTokens: Number(row.in_tok ?? 0),
364
375
  outputTokens: Number(row.out_tok ?? 0),
@@ -375,29 +386,40 @@ export async function getUsageSummary(options) {
375
386
  // date functions (SQLite `strftime`, Postgres `to_char`). Cheap enough
376
387
  // for a 30-day window; if this grows, swap for a dialect-aware query.
377
388
  const dayRows = await client.execute({
378
- sql: `SELECT created_at, cost_cents_x100 FROM token_usage
389
+ sql: `SELECT created_at, cost_cents_x100, cost_source FROM token_usage
379
390
  WHERE owner_email = ? AND created_at >= ?`,
380
391
  args: [options.ownerEmail, sinceMs],
381
392
  });
382
393
  const dayMap = new Map();
383
394
  for (const row of dayRows.rows) {
384
395
  const date = new Date(Number(row.created_at)).toISOString().slice(0, 10);
385
- const prev = dayMap.get(date) ?? { cents: 0, calls: 0 };
386
- prev.cents += Number(row.cost_cents_x100 ?? 0);
396
+ const prev = dayMap.get(date) ?? {
397
+ knownCentsX100: 0,
398
+ unavailableCalls: 0,
399
+ calls: 0,
400
+ };
401
+ if (row.cost_source === "unavailable")
402
+ prev.unavailableCalls += 1;
403
+ else
404
+ prev.knownCentsX100 += Number(row.cost_cents_x100 ?? 0);
387
405
  prev.calls += 1;
388
406
  dayMap.set(date, prev);
389
407
  }
390
408
  const byDay = [...dayMap.entries()]
391
- .map(([date, v]) => ({
392
- date,
393
- cents: v.cents / 100,
394
- calls: v.calls,
395
- }))
409
+ .map(([date, v]) => {
410
+ const knownCents = v.knownCentsX100 / 100;
411
+ return {
412
+ date,
413
+ cents: knownCents,
414
+ cost: buildUsageCostAggregate(knownCents, v.unavailableCalls),
415
+ calls: v.calls,
416
+ };
417
+ })
396
418
  .sort((a, b) => a.date.localeCompare(b.date));
397
419
  const recentRows = await client.execute({
398
420
  sql: `SELECT id, created_at, label, app, model,
399
421
  input_tokens, output_tokens, cache_read_tokens, cache_write_tokens,
400
- cost_cents_x100
422
+ cost_cents_x100, cost_source
401
423
  FROM token_usage
402
424
  WHERE owner_email = ?
403
425
  ORDER BY created_at DESC
@@ -415,10 +437,14 @@ export async function getUsageSummary(options) {
415
437
  cacheReadTokens: Number(row.cache_read_tokens ?? 0),
416
438
  cacheWriteTokens: Number(row.cache_write_tokens ?? 0),
417
439
  cents: Number(row.cost_cents_x100 ?? 0) / 100,
440
+ costSource: String(row.cost_source ?? "estimated"),
418
441
  }));
442
+ const knownCents = Number(t.known_cents ?? 0) / 100;
443
+ const unavailableCalls = Number(t.unavailable_calls ?? 0);
419
444
  return {
420
445
  billing: USD_USAGE_BILLING,
421
- totalCents: Number(t.cents ?? 0) / 100,
446
+ totalCents: knownCents,
447
+ totalCost: buildUsageCostAggregate(knownCents, unavailableCalls),
422
448
  totalCalls: Number(t.calls ?? 0),
423
449
  totalInputTokens: Number(t.in_tok ?? 0),
424
450
  totalOutputTokens: Number(t.out_tok ?? 0),
@@ -432,4 +458,13 @@ export async function getUsageSummary(options) {
432
458
  recent,
433
459
  };
434
460
  }
461
+ function buildUsageCostAggregate(knownCents, unavailableCalls) {
462
+ if (unavailableCalls === 0) {
463
+ return { status: "known", knownCents, unavailableCalls: 0 };
464
+ }
465
+ if (knownCents === 0) {
466
+ return { status: "unavailable", knownCents: 0, unavailableCalls };
467
+ }
468
+ return { status: "partial", knownCents, unavailableCalls };
469
+ }
435
470
  //# sourceMappingURL=store.js.map