@empiricalrun/test-gen 0.76.0 → 0.77.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 (230) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/agent/base/index.d.ts +25 -21
  3. package/dist/agent/base/index.d.ts.map +1 -1
  4. package/dist/agent/base/index.js +48 -37
  5. package/dist/agent/browsing/run.d.ts +1 -2
  6. package/dist/agent/browsing/run.d.ts.map +1 -1
  7. package/dist/agent/browsing/run.js +3 -9
  8. package/dist/agent/browsing/utils.d.ts +2 -9
  9. package/dist/agent/browsing/utils.d.ts.map +1 -1
  10. package/dist/agent/browsing/utils.js +5 -109
  11. package/dist/agent/chat/agent-loop.d.ts +5 -5
  12. package/dist/agent/chat/agent-loop.d.ts.map +1 -1
  13. package/dist/agent/chat/agent-loop.js +3 -8
  14. package/dist/agent/chat/exports.d.ts +5 -4
  15. package/dist/agent/chat/exports.d.ts.map +1 -1
  16. package/dist/agent/chat/exports.js +4 -7
  17. package/dist/agent/chat/index.d.ts +2 -2
  18. package/dist/agent/chat/index.d.ts.map +1 -1
  19. package/dist/agent/chat/index.js +23 -35
  20. package/dist/agent/chat/models.d.ts +0 -2
  21. package/dist/agent/chat/models.d.ts.map +1 -1
  22. package/dist/agent/chat/models.js +12 -26
  23. package/dist/agent/chat/prompt/pw-utils-docs.d.ts +1 -1
  24. package/dist/agent/chat/prompt/pw-utils-docs.d.ts.map +1 -1
  25. package/dist/agent/chat/prompt/pw-utils-docs.js +52 -0
  26. package/dist/agent/chat/prompt/repo.d.ts.map +1 -1
  27. package/dist/agent/chat/prompt/repo.js +11 -22
  28. package/dist/agent/chat/prompt/test-case-def.d.ts +2 -0
  29. package/dist/agent/chat/prompt/test-case-def.d.ts.map +1 -0
  30. package/dist/agent/chat/prompt/test-case-def.js +44 -0
  31. package/dist/agent/chat/state.d.ts +7 -6
  32. package/dist/agent/chat/state.d.ts.map +1 -1
  33. package/dist/agent/chat/state.js +15 -45
  34. package/dist/agent/chat/utils.d.ts +2 -2
  35. package/dist/agent/chat/utils.d.ts.map +1 -1
  36. package/dist/agent/chat/utils.js +14 -7
  37. package/dist/agent/cli.d.ts.map +1 -1
  38. package/dist/agent/cli.js +62 -58
  39. package/dist/agent/code-review/executor/index.d.ts +5 -0
  40. package/dist/agent/code-review/executor/index.d.ts.map +1 -0
  41. package/dist/agent/code-review/executor/index.js +13 -0
  42. package/dist/agent/code-review/index.d.ts +8 -3
  43. package/dist/agent/code-review/index.d.ts.map +1 -1
  44. package/dist/agent/code-review/index.js +115 -21
  45. package/dist/agent/code-review/parser.d.ts +5 -0
  46. package/dist/agent/code-review/parser.d.ts.map +1 -0
  47. package/dist/agent/code-review/parser.js +70 -0
  48. package/dist/agent/code-review/types.d.ts +36 -0
  49. package/dist/agent/code-review/types.d.ts.map +1 -0
  50. package/dist/agent/code-review/types.js +13 -0
  51. package/dist/agent/cua/index.d.ts.map +1 -1
  52. package/dist/agent/cua/index.js +18 -2
  53. package/dist/agent/cua/model.d.ts.map +1 -1
  54. package/dist/agent/cua/model.js +4 -1
  55. package/dist/agent/cua/pw-codegen/pw-pause/index.d.ts.map +1 -1
  56. package/dist/agent/triage/index.d.ts +2 -2
  57. package/dist/agent/triage/index.d.ts.map +1 -1
  58. package/dist/agent/triage/index.js +8 -7
  59. package/dist/agent/video-analysis/executor/index.d.ts +5 -0
  60. package/dist/agent/video-analysis/executor/index.d.ts.map +1 -0
  61. package/dist/agent/video-analysis/executor/index.js +10 -0
  62. package/dist/agent/video-analysis/index.d.ts +2 -2
  63. package/dist/agent/video-analysis/index.d.ts.map +1 -1
  64. package/dist/agent/video-analysis/index.js +38 -13
  65. package/dist/artifacts/index.d.ts +1 -1
  66. package/dist/artifacts/index.d.ts.map +1 -1
  67. package/dist/artifacts/index.js +3 -1
  68. package/dist/artifacts/utils.d.ts.map +1 -1
  69. package/dist/bin/index.js +66 -21
  70. package/dist/constants/index.d.ts +14 -0
  71. package/dist/constants/index.d.ts.map +1 -1
  72. package/dist/constants/index.js +33 -1
  73. package/dist/file/server.d.ts +1 -3
  74. package/dist/file/server.d.ts.map +1 -1
  75. package/dist/file/server.js +0 -13
  76. package/dist/file-info/adapters/file-system/index.d.ts.map +1 -1
  77. package/dist/file-info/adapters/file-system/reader.d.ts.map +1 -1
  78. package/dist/file-info/adapters/file-system/reader.js +8 -1
  79. package/dist/file-info/adapters/github/index.d.ts.map +1 -1
  80. package/dist/file-info/adapters/github/reader.d.ts +1 -1
  81. package/dist/file-info/adapters/github/reader.d.ts.map +1 -1
  82. package/dist/file-info/adapters/github/reader.js +8 -5
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/tools/analyse-video/index.d.ts +5 -0
  85. package/dist/tools/analyse-video/index.d.ts.map +1 -0
  86. package/dist/tools/analyse-video/index.js +50 -0
  87. package/dist/tools/create-pull-request/index.js +4 -6
  88. package/dist/tools/create-pull-request/utils.d.ts +1 -1
  89. package/dist/tools/definitions/{fetch-video-analysis.d.ts → analyse-video.d.ts} +13 -8
  90. package/dist/tools/definitions/analyse-video.d.ts.map +1 -0
  91. package/dist/tools/definitions/analyse-video.js +60 -0
  92. package/dist/tools/definitions/review-pull-request.d.ts +3 -0
  93. package/dist/tools/definitions/review-pull-request.d.ts.map +1 -0
  94. package/dist/tools/definitions/review-pull-request.js +16 -0
  95. package/dist/tools/definitions/str_replace_editor.d.ts +1 -0
  96. package/dist/tools/definitions/str_replace_editor.d.ts.map +1 -1
  97. package/dist/tools/definitions/str_replace_editor.js +4 -1
  98. package/dist/tools/definitions/test-gen-browser.d.ts +0 -3
  99. package/dist/tools/definitions/test-gen-browser.d.ts.map +1 -1
  100. package/dist/tools/definitions/test-gen-browser.js +33 -8
  101. package/dist/tools/delete-file/index.d.ts.map +1 -1
  102. package/dist/tools/delete-file/index.js +1 -19
  103. package/dist/tools/executor/base.d.ts +32 -0
  104. package/dist/tools/executor/base.d.ts.map +1 -0
  105. package/dist/tools/executor/base.js +114 -0
  106. package/dist/tools/executor/index.d.ts +3 -22
  107. package/dist/tools/executor/index.d.ts.map +1 -1
  108. package/dist/tools/executor/index.js +7 -100
  109. package/dist/tools/executor/utils/checkpoint.d.ts +1 -1
  110. package/dist/tools/executor/utils/checkpoint.d.ts.map +1 -1
  111. package/dist/tools/executor/utils/checkpoint.js +6 -2
  112. package/dist/tools/executor/utils/git.d.ts +2 -2
  113. package/dist/tools/executor/utils/git.d.ts.map +1 -1
  114. package/dist/tools/executor/utils/git.js +7 -3
  115. package/dist/tools/executor/utils/index.d.ts.map +1 -1
  116. package/dist/tools/executor/utils/index.js +1 -1
  117. package/dist/tools/fetch-session-diff/index.js +2 -2
  118. package/dist/tools/file-operations/create.d.ts.map +1 -1
  119. package/dist/tools/file-operations/create.js +1 -4
  120. package/dist/tools/file-operations/index.d.ts +2 -1
  121. package/dist/tools/file-operations/index.d.ts.map +1 -1
  122. package/dist/tools/file-operations/index.js +4 -1
  123. package/dist/tools/file-operations/insert.d.ts +1 -2
  124. package/dist/tools/file-operations/insert.d.ts.map +1 -1
  125. package/dist/tools/file-operations/insert.js +1 -4
  126. package/dist/tools/file-operations/replace.d.ts.map +1 -1
  127. package/dist/tools/file-operations/replace.js +1 -4
  128. package/dist/tools/grep/index.d.ts.map +1 -1
  129. package/dist/tools/grep/index.js +18 -11
  130. package/dist/tools/index.d.ts +5 -5
  131. package/dist/tools/index.d.ts.map +1 -1
  132. package/dist/tools/index.js +17 -16
  133. package/dist/tools/merge-conflicts/index.d.ts.map +1 -1
  134. package/dist/tools/merge-conflicts/index.js +1 -1
  135. package/dist/tools/rename-file/index.js +1 -1
  136. package/dist/tools/review-pull-request/index.d.ts.map +1 -1
  137. package/dist/tools/review-pull-request/index.js +45 -59
  138. package/dist/tools/run-test.d.ts.map +1 -1
  139. package/dist/tools/run-test.js +25 -3
  140. package/dist/tools/test-gen-browser.d.ts.map +1 -1
  141. package/dist/tools/test-gen-browser.js +51 -47
  142. package/dist/utils/artifact-paths.d.ts +20 -0
  143. package/dist/utils/artifact-paths.d.ts.map +1 -0
  144. package/dist/utils/artifact-paths.js +16 -0
  145. package/dist/utils/dedup-image-fs.d.ts +2 -16
  146. package/dist/utils/dedup-image-fs.d.ts.map +1 -1
  147. package/dist/utils/dedup-image-fs.js +12 -16
  148. package/dist/utils/dedup-image.d.ts +1 -14
  149. package/dist/utils/dedup-image.d.ts.map +1 -1
  150. package/dist/utils/dedup-image.js +7 -62
  151. package/dist/utils/{local-ffmpeg-client.d.ts → ffmpeg/index.d.ts} +6 -7
  152. package/dist/utils/ffmpeg/index.d.ts.map +1 -0
  153. package/dist/utils/{local-ffmpeg-client.js → ffmpeg/index.js} +169 -53
  154. package/dist/utils/find-threshold.d.ts +8 -0
  155. package/dist/utils/find-threshold.d.ts.map +1 -0
  156. package/dist/utils/find-threshold.js +55 -0
  157. package/dist/utils/hash.d.ts +2 -0
  158. package/dist/utils/hash.d.ts.map +1 -0
  159. package/dist/utils/hash.js +24 -0
  160. package/dist/utils/model.d.ts +1 -1
  161. package/dist/utils/model.d.ts.map +1 -1
  162. package/dist/utils/model.js +7 -5
  163. package/dist/utils/repo-tree.d.ts +0 -1
  164. package/dist/utils/repo-tree.d.ts.map +1 -1
  165. package/dist/utils/repo-tree.js +2 -14
  166. package/dist/utils/slug.js +1 -1
  167. package/dist/video-core/agent-orchestrator.d.ts +14 -0
  168. package/dist/video-core/agent-orchestrator.d.ts.map +1 -0
  169. package/dist/video-core/agent-orchestrator.js +78 -0
  170. package/dist/video-core/analysis-server.d.ts +24 -0
  171. package/dist/video-core/analysis-server.d.ts.map +1 -0
  172. package/dist/video-core/analysis-server.js +398 -0
  173. package/dist/video-core/analysis-viewer.html +1374 -0
  174. package/dist/video-core/index.d.ts +44 -0
  175. package/dist/video-core/index.d.ts.map +1 -0
  176. package/dist/video-core/index.js +204 -0
  177. package/dist/video-core/model-limits.d.ts +4 -0
  178. package/dist/video-core/model-limits.d.ts.map +1 -0
  179. package/dist/video-core/model-limits.js +67 -0
  180. package/dist/video-core/storage-manager.d.ts +5 -0
  181. package/dist/video-core/storage-manager.d.ts.map +1 -0
  182. package/dist/video-core/storage-manager.js +55 -0
  183. package/dist/video-core/types.d.ts +13 -0
  184. package/dist/video-core/types.d.ts.map +1 -0
  185. package/dist/video-core/types.js +2 -0
  186. package/dist/video-core/utils.d.ts +25 -0
  187. package/dist/video-core/utils.d.ts.map +1 -0
  188. package/dist/video-core/utils.js +211 -0
  189. package/dist/video-core/xml-parser.d.ts +3 -0
  190. package/dist/video-core/xml-parser.d.ts.map +1 -0
  191. package/dist/video-core/xml-parser.js +27 -0
  192. package/package.json +5 -6
  193. package/tsconfig.tsbuildinfo +1 -1
  194. package/dist/agent/chat/prompt/index.d.ts +0 -6
  195. package/dist/agent/chat/prompt/index.d.ts.map +0 -1
  196. package/dist/agent/chat/prompt/index.js +0 -200
  197. package/dist/agent/code-review/prompt.d.ts +0 -2
  198. package/dist/agent/code-review/prompt.d.ts.map +0 -1
  199. package/dist/agent/code-review/prompt.js +0 -55
  200. package/dist/agent/diagnosis-agent/index.d.ts +0 -11
  201. package/dist/agent/diagnosis-agent/index.d.ts.map +0 -1
  202. package/dist/agent/diagnosis-agent/index.js +0 -88
  203. package/dist/agent/diagnosis-agent/strict-mode-violation.d.ts +0 -10
  204. package/dist/agent/diagnosis-agent/strict-mode-violation.d.ts.map +0 -1
  205. package/dist/agent/diagnosis-agent/strict-mode-violation.js +0 -30
  206. package/dist/tools/definitions/extract-frames-from-video.d.ts +0 -39
  207. package/dist/tools/definitions/extract-frames-from-video.d.ts.map +0 -1
  208. package/dist/tools/definitions/extract-frames-from-video.js +0 -60
  209. package/dist/tools/definitions/fetch-video-analysis.d.ts.map +0 -1
  210. package/dist/tools/definitions/fetch-video-analysis.js +0 -61
  211. package/dist/tools/extract-frames-from-video/index.d.ts +0 -7
  212. package/dist/tools/extract-frames-from-video/index.d.ts.map +0 -1
  213. package/dist/tools/extract-frames-from-video/index.js +0 -145
  214. package/dist/tools/fetch-video-analysis/index.d.ts +0 -5
  215. package/dist/tools/fetch-video-analysis/index.d.ts.map +0 -1
  216. package/dist/tools/fetch-video-analysis/index.js +0 -149
  217. package/dist/tools/fetch-video-analysis/open-ai.d.ts +0 -6
  218. package/dist/tools/fetch-video-analysis/open-ai.d.ts.map +0 -1
  219. package/dist/tools/fetch-video-analysis/open-ai.js +0 -37
  220. package/dist/tools/fetch-video-analysis/utils.d.ts +0 -16
  221. package/dist/tools/fetch-video-analysis/utils.d.ts.map +0 -1
  222. package/dist/tools/fetch-video-analysis/utils.js +0 -121
  223. package/dist/tools/fetch-video-analysis/video-analysis.d.ts +0 -7
  224. package/dist/tools/fetch-video-analysis/video-analysis.d.ts.map +0 -1
  225. package/dist/tools/fetch-video-analysis/video-analysis.js +0 -70
  226. package/dist/tools/file-operations/shared/git-helper.d.ts +0 -4
  227. package/dist/tools/file-operations/shared/git-helper.d.ts.map +0 -1
  228. package/dist/tools/file-operations/shared/git-helper.js +0 -29
  229. package/dist/utils/local-ffmpeg-client.d.ts.map +0 -1
  230. package/eslint.config.mjs +0 -43
@@ -1,75 +1,20 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.deduplicateImages = deduplicateImages;
7
- const pixelmatch_1 = __importDefault(require("pixelmatch"));
8
- const sharp_1 = __importDefault(require("sharp"));
9
- /**
10
- * Processes an array of base64 image objects and returns only unique images.
11
- * Two images are considered "similar" if the fraction of differing pixels (when resized)
12
- * is below the provided threshold.
13
- *
14
- * @param options - Configuration options
15
- * @param options.base64Images - An array of objects, each with a metadata field and a base64-encoded image string.
16
- * @param options.threshold - The maximum fraction of pixels allowed to differ to consider two images similar.
17
- * For example, 0.01 means that if less than 1% of the pixels differ, the images are considered duplicates.
18
- * Default is 0.001 (0.1%).
19
- * @param options.logPrefix - The ID of the test run, used for logging purposes.
20
- * @returns A promise that resolves to an array of unique image objects.
21
- */
22
- async function deduplicateImages({ base64Images, threshold = 0.001, logPrefix = "dedup-image", }) {
4
+ const find_threshold_1 = require("./find-threshold");
5
+ async function deduplicateImages({ base64Images, threshold, logPrefix = "dedup-image", }) {
23
6
  const uniqueImages = [];
24
- // We'll store the raw pixel data (RGBA) and dimensions for the previous unique image.
25
- let previousImageData = null;
26
- let previousWidth = null;
27
- let previousHeight = null;
7
+ let previousImageBuffer = null;
28
8
  for (const imgData of base64Images) {
29
9
  try {
30
- // Convert the base64 string to a Buffer.
31
- const buffer = Buffer.from(imgData.image, "base64");
32
- const imgMetadata = await (0, sharp_1.default)(buffer).metadata();
33
- const height = imgMetadata.height || 0;
34
- const width = imgMetadata.width || 0;
35
- // Resize the image to fixed dimensions and extract its raw RGBA pixel data.
36
- const { data } = await (0, sharp_1.default)(buffer)
37
- .ensureAlpha()
38
- .raw()
39
- .toBuffer({ resolveWithObject: true });
10
+ const currentBuffer = Buffer.from(imgData.image, "base64");
40
11
  let isDuplicate = false;
41
- // If there's a previously processed unique image, compare the current image with it.
42
- if (previousImageData &&
43
- previousWidth === width &&
44
- previousHeight === height) {
45
- // Only compare images if they have the same dimensions
46
- try {
47
- const diffPixels = (0, pixelmatch_1.default)(data, // current image pixel data
48
- previousImageData, // previous image pixel data
49
- null, // no diff image output is needed
50
- width, height, { threshold: 0.1 });
51
- // console.log("diffPixels", diffPixels);
52
- const totalPixels = height * width;
53
- const diffFraction = diffPixels / totalPixels;
54
- // console.log("diffFraction", diffFraction);
55
- // If the fraction of differing pixels is below (or equal to) the threshold,
56
- // consider the current image a duplicate.
57
- if (diffFraction <= threshold) {
58
- isDuplicate = true;
59
- }
60
- }
61
- catch (error) {
62
- console.error(`[${logPrefix}] Error comparing images:`, error);
63
- // If comparison fails, treat as non-duplicate
64
- isDuplicate = false;
65
- }
12
+ if (previousImageBuffer) {
13
+ isDuplicate = await (0, find_threshold_1.areImagesDuplicate)(currentBuffer, previousImageBuffer, threshold);
66
14
  }
67
- // If the image is not a duplicate, add it to the list and update the previous image data.
68
15
  if (!isDuplicate) {
69
16
  uniqueImages.push(imgData);
70
- previousImageData = data;
71
- previousWidth = width;
72
- previousHeight = height;
17
+ previousImageBuffer = currentBuffer;
73
18
  }
74
19
  }
75
20
  catch (error) {
@@ -1,4 +1,4 @@
1
- import { UniqueFrameWithMetadata } from "@empiricalrun/shared-types";
1
+ import { UniqueFrameInfos } from "@empiricalrun/shared-types";
2
2
  export declare class LocalFFmpegClient {
3
3
  private static readonly MAX_VIDEO_DURATION_SECONDS;
4
4
  private static readonly CHUNK_DURATION_SECONDS;
@@ -6,22 +6,21 @@ export declare class LocalFFmpegClient {
6
6
  private checkFFmpegAvailability;
7
7
  private getVideoDuration;
8
8
  private validateVideoChunk;
9
- private downloadVideo;
10
9
  private ensureEmptyDir;
11
10
  private runFFmpegCommand;
12
11
  private createVideoChunks;
13
- private extractFramesToFiles;
12
+ private extractFramesWithFPS;
14
13
  private processVideoChunks;
15
- storeUniqueFrames(uniqueFrames: UniqueFrameWithMetadata[], workingDir: string): Promise<string>;
16
- extractVideoFrames(videoUrl: string, outputDir: string, options?: {
14
+ storeUniqueFrames(uniqueFrameInfos: UniqueFrameInfos[], workingDir: string): Promise<string>;
15
+ extractVideoFrames(videoUrl: string, videoUrlHash: string, absoluteWorkingDir: string, options?: {
17
16
  fps?: number;
18
17
  threshold?: number;
19
18
  startTime?: number;
20
19
  duration?: number;
21
20
  }): Promise<{
22
21
  totalFramesCount: number;
23
- uniqueFrames: UniqueFrameWithMetadata[];
22
+ uniqueFrameInfos: UniqueFrameInfos[];
24
23
  videoDurationSeconds: number;
25
24
  }>;
26
25
  }
27
- //# sourceMappingURL=local-ffmpeg-client.d.ts.map
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/ffmpeg/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAa9D,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,0BAA0B,CAAW;IAC7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAU;;IAMxD,OAAO,CAAC,uBAAuB;YAWjB,gBAAgB;YAiBhB,kBAAkB;YAgClB,cAAc;YASd,gBAAgB;YAoBhB,iBAAiB;YAsEjB,oBAAoB;YAkEpB,kBAAkB;IA8G1B,iBAAiB,CACrB,gBAAgB,EAAE,gBAAgB,EAAE,EACpC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC;IAgFZ,kBAAkB,CACtB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,kBAAkB,EAAE,MAAM,EAC1B,OAAO,CAAC,EAAE;QACR,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GACA,OAAO,CAAC;QACT,gBAAgB,EAAE,MAAM,CAAC;QACzB,gBAAgB,EAAE,gBAAgB,EAAE,CAAC;QACrC,oBAAoB,EAAE,MAAM,CAAC;KAC9B,CAAC;CA0IH"}
@@ -4,12 +4,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.LocalFFmpegClient = void 0;
7
+ const node_crypto_1 = __importDefault(require("node:crypto"));
7
8
  const child_process_1 = require("child_process");
8
9
  const fs_1 = require("fs");
9
10
  const path_1 = __importDefault(require("path"));
10
11
  const util_1 = require("util");
11
- const dedup_image_fs_1 = require("./dedup-image-fs");
12
+ const constants_1 = require("../../constants");
13
+ const utils_1 = require("../../video-core/utils");
14
+ const dedup_image_fs_1 = require("../dedup-image-fs");
12
15
  const execAsync = (0, util_1.promisify)(child_process_1.exec);
16
+ const FRAME_DIMENSION = "1280:720";
13
17
  class LocalFFmpegClient {
14
18
  static MAX_VIDEO_DURATION_SECONDS = 15 * 60; // 15 minutes
15
19
  static CHUNK_DURATION_SECONDS = 2 * 60; // 2 minutes
@@ -66,15 +70,6 @@ class LocalFFmpegClient {
66
70
  return false;
67
71
  }
68
72
  }
69
- async downloadVideo(videoUrl, outputPath) {
70
- console.log(`Downloading video from: ${videoUrl}`);
71
- const response = await fetch(videoUrl);
72
- if (!response.ok) {
73
- throw new Error(`Failed to download video: ${response.statusText}`);
74
- }
75
- const buffer = await response.arrayBuffer();
76
- await fs_1.promises.writeFile(outputPath, Buffer.from(buffer));
77
- }
78
73
  async ensureEmptyDir(dir) {
79
74
  try {
80
75
  await fs_1.promises.rm(dir, { recursive: true, force: true });
@@ -146,96 +141,198 @@ class LocalFFmpegClient {
146
141
  }
147
142
  return chunkPaths;
148
143
  }
149
- async extractFramesToFiles(videoPath, outputDir, chunkIndex, fps) {
150
- await this.ensureEmptyDir(outputDir);
151
- const framePrefix = chunkIndex !== undefined ? `chunk${chunkIndex}_frame` : "frame";
152
- const framePattern = path_1.default.join(outputDir, `${framePrefix}_%04d.png`);
153
- console.log(`Extracting frames with command: ffmpeg -i "${videoPath}" -vf "fps=${fps}" "${framePattern}"`);
144
+ async extractFramesWithFPS({ videoPath, outputDir, fps, globalStartTime, duration, }) {
145
+ // Create directory but don't clear it - multiple calls may be appending
146
+ await fs_1.promises.mkdir(outputDir, { recursive: true });
147
+ console.log(`Extracting frames at ${fps} fps using single ffmpeg command (${duration ? duration + "s duration" : "full length"}) starting at global time ${globalStartTime}s`);
148
+ const outputPattern = path_1.default.join(outputDir, "frame_%06d.png");
149
+ const args = [];
150
+ if (duration) {
151
+ args.push("-t", duration.toString());
152
+ }
153
+ const vf = `fps=${fps},scale=${FRAME_DIMENSION}:force_original_aspect_ratio=decrease,pad=${FRAME_DIMENSION}:(ow-iw)/2:(oh-ih)/2`;
154
+ args.push("-vf", `"${vf}"`, "-q:v", "2", "-y");
154
155
  try {
155
156
  await this.runFFmpegCommand({
156
157
  inputPath: videoPath,
157
- args: ["-vf", `fps=${fps}`],
158
- outputPath: framePattern,
158
+ args: args,
159
+ outputPath: outputPattern,
159
160
  });
161
+ const files = await fs_1.promises.readdir(outputDir);
162
+ const frameFiles = files
163
+ .filter((f) => f.startsWith("frame_") && f.endsWith(".png"))
164
+ .sort();
165
+ const renamedFiles = [];
166
+ for (let i = 0; i < frameFiles.length; i++) {
167
+ const originalPath = path_1.default.join(outputDir, frameFiles[i]);
168
+ const globalFrameNumber = Math.floor(globalStartTime * fps) + i;
169
+ const newFileName = `chunk0_frame_${globalFrameNumber.toString().padStart(6, "0")}.png`;
170
+ const newPath = path_1.default.join(outputDir, newFileName);
171
+ await fs_1.promises.rename(originalPath, newPath);
172
+ renamedFiles.push(newPath);
173
+ }
174
+ console.log(`Successfully extracted ${renamedFiles.length} frames using single ffmpeg command with global frame numbering starting from ${Math.floor(globalStartTime * fps)}`);
175
+ return renamedFiles;
160
176
  }
161
177
  catch (error) {
162
- throw new Error(`Frame extraction failed: ${error}`);
178
+ console.warn(`Failed to extract frames with fps filter:`, error);
179
+ return [];
163
180
  }
164
- const files = await fs_1.promises.readdir(outputDir);
165
- const frameFiles = files
166
- .filter((file) => file.startsWith(framePrefix) && file.endsWith(".png"))
167
- .sort()
168
- .map((file) => path_1.default.join(outputDir, file));
169
- console.log(`Extracted ${frameFiles.length} frames from ${chunkIndex !== undefined ? `chunk ${chunkIndex}` : "video"}`);
170
- return frameFiles;
171
181
  }
172
- async processVideoChunks(chunkPaths, workingDir, fps) {
182
+ async processVideoChunks(chunkPaths, workingDir, fps, effectiveDuration, globalStartTime = 0) {
173
183
  const allFramePaths = [];
174
184
  const consolidatedFramesDir = path_1.default.join(workingDir, "consolidated_frames");
175
- await this.ensureEmptyDir(consolidatedFramesDir);
176
- let globalFrameIndex = 0;
185
+ // Check if consolidated_frames directory exists and has frames - if so, append mode
186
+ const dirExists = await fs_1.promises
187
+ .access(consolidatedFramesDir)
188
+ .then(() => true)
189
+ .catch(() => false);
190
+ let hasExistingFrames = false;
191
+ if (dirExists) {
192
+ try {
193
+ const existingFiles = await fs_1.promises.readdir(consolidatedFramesDir);
194
+ hasExistingFrames = existingFiles.some((file) => file.endsWith(".png"));
195
+ }
196
+ catch {
197
+ hasExistingFrames = false;
198
+ }
199
+ }
200
+ if (hasExistingFrames) {
201
+ // Append mode: directory has frames, don't clear it
202
+ console.log(`Appending to existing consolidated_frames directory`);
203
+ }
204
+ else {
205
+ // Fresh mode: clear and recreate directory
206
+ await this.ensureEmptyDir(consolidatedFramesDir);
207
+ console.log(`Creating fresh consolidated_frames directory`);
208
+ }
177
209
  for (let i = 0; i < chunkPaths.length; i++) {
178
210
  const chunkPath = chunkPaths[i];
179
211
  const chunkFramesDir = path_1.default.join(workingDir, `chunk_${i}_frames`);
180
- console.log(`Processing chunk ${i + 1}/${chunkPaths.length}`);
212
+ console.log(`Processing chunk ${i + 1}/${chunkPaths.length} with precise frame extraction`);
181
213
  if (chunkPath === undefined) {
182
214
  throw new Error(`Chunk path is undefined for chunk ${i + 1}`);
183
215
  }
184
216
  try {
185
- const chunkFramePaths = await this.extractFramesToFiles(chunkPath, chunkFramesDir, i, fps);
217
+ const chunkStartTime = i * LocalFFmpegClient.CHUNK_DURATION_SECONDS;
218
+ const chunkDuration = Math.min(LocalFFmpegClient.CHUNK_DURATION_SECONDS, effectiveDuration - chunkStartTime);
219
+ const actualGlobalStartTime = globalStartTime + chunkStartTime;
220
+ const chunkFramePaths = await this.extractFramesWithFPS({
221
+ videoPath: chunkPath,
222
+ outputDir: chunkFramesDir,
223
+ fps,
224
+ globalStartTime: actualGlobalStartTime,
225
+ duration: chunkDuration,
226
+ });
186
227
  for (const framePath of chunkFramePaths) {
187
- const newFramePath = path_1.default.join(consolidatedFramesDir, `frame_${globalFrameIndex.toString().padStart(6, "0")}.png`);
228
+ const basename = path_1.default.basename(framePath);
229
+ const frameNumberMatch = basename.match(/frame_(\d+)\.png$/);
230
+ const localFrameNumber = frameNumberMatch && frameNumberMatch[1]
231
+ ? parseInt(frameNumberMatch[1], 10)
232
+ : 0;
233
+ const globalFrameNumber = Math.floor(chunkStartTime * fps) + localFrameNumber;
234
+ const newFramePath = path_1.default.join(consolidatedFramesDir, `frame_${globalFrameNumber.toString().padStart(6, "0")}.png`);
235
+ // In append mode, check if frame already exists
236
+ if (hasExistingFrames) {
237
+ const frameExists = await fs_1.promises
238
+ .access(newFramePath)
239
+ .then(() => true)
240
+ .catch(() => false);
241
+ if (frameExists) {
242
+ console.log(`Frame ${newFramePath} already exists, skipping`);
243
+ allFramePaths.push(newFramePath);
244
+ continue;
245
+ }
246
+ }
188
247
  await fs_1.promises.rename(framePath, newFramePath);
189
248
  allFramePaths.push(newFramePath);
190
- globalFrameIndex++;
191
249
  }
192
250
  }
193
251
  catch (error) {
194
252
  console.warn(`Failed to process chunk ${i + 1}: ${error}. Skipping this chunk.`);
195
253
  // Continue with other chunks instead of failing completely
196
254
  }
197
- try {
198
- await fs_1.promises.rm(chunkFramesDir, { recursive: true });
199
- }
200
- catch (error) {
201
- console.warn(`Failed to clean up chunk frames directory: ${error}`);
202
- }
203
255
  if (global.gc) {
204
256
  global.gc();
205
257
  }
206
258
  }
207
259
  return allFramePaths;
208
260
  }
209
- async storeUniqueFrames(uniqueFrames, workingDir) {
261
+ async storeUniqueFrames(uniqueFrameInfos, workingDir) {
210
262
  const uniqueFramesDir = path_1.default.join(workingDir, "unique_frames");
211
- await this.ensureEmptyDir(uniqueFramesDir);
212
- console.log(`Storing ${uniqueFrames.length} unique frames in ${uniqueFramesDir}`);
213
- for (let i = 0; i < uniqueFrames.length; i++) {
214
- const frame = uniqueFrames[i];
263
+ // Check if directory exists and has frames - if so, append mode
264
+ const dirExists = await fs_1.promises
265
+ .access(uniqueFramesDir)
266
+ .then(() => true)
267
+ .catch(() => false);
268
+ let hasExistingFrames = false;
269
+ if (dirExists) {
270
+ try {
271
+ const existingFiles = await fs_1.promises.readdir(uniqueFramesDir);
272
+ hasExistingFrames = existingFiles.some((file) => file.endsWith(".png"));
273
+ }
274
+ catch {
275
+ hasExistingFrames = false;
276
+ }
277
+ }
278
+ if (hasExistingFrames) {
279
+ // Append mode: directory has frames, don't clear it
280
+ console.log(`Appending ${uniqueFrameInfos.length} frames to existing ${uniqueFramesDir}`);
281
+ }
282
+ else {
283
+ // Fresh mode: clear and recreate directory
284
+ await this.ensureEmptyDir(uniqueFramesDir);
285
+ console.log(`Creating fresh ${uniqueFramesDir} with ${uniqueFrameInfos.length} frames`);
286
+ }
287
+ console.log(`Storing ${uniqueFrameInfos.length} unique frames in ${uniqueFramesDir}`);
288
+ for (let i = 0; i < uniqueFrameInfos.length; i++) {
289
+ const frame = uniqueFrameInfos[i];
215
290
  if (!frame)
216
291
  continue;
217
- const originalPath = frame.metadata.path;
218
- const uniqueFramePath = path_1.default.join(uniqueFramesDir, `unique_frame_${i.toString().padStart(4, "0")}.png`);
292
+ const originalPath = frame.path;
293
+ const originalBasename = path_1.default.basename(originalPath);
294
+ const frameNumberMatch = originalBasename.match(/frame_(\d+)\.png$/);
295
+ const frameNumber = frameNumberMatch
296
+ ? frameNumberMatch[1]
297
+ : i.toString().padStart(6, "0");
298
+ const uniqueFramePath = path_1.default.join(uniqueFramesDir, `frame_${frameNumber}.png`);
219
299
  try {
300
+ // In append mode, check if frame already exists to avoid overwriting
301
+ if (hasExistingFrames) {
302
+ const frameExists = await fs_1.promises
303
+ .access(uniqueFramePath)
304
+ .then(() => true)
305
+ .catch(() => false);
306
+ if (frameExists) {
307
+ console.log(`Frame ${uniqueFramePath} already exists, skipping`);
308
+ continue;
309
+ }
310
+ }
220
311
  await fs_1.promises.copyFile(originalPath, uniqueFramePath);
221
312
  }
222
313
  catch (error) {
223
314
  console.warn(`Failed to copy frame ${originalPath} to ${uniqueFramePath}:`, error);
224
315
  }
225
316
  }
226
- console.log(`Stored ${uniqueFrames.length} unique frames in: ${uniqueFramesDir}`);
317
+ console.log(`Stored ${uniqueFrameInfos.length} unique frames in: ${uniqueFramesDir}`);
227
318
  return uniqueFramesDir;
228
319
  }
229
- async extractVideoFrames(videoUrl, outputDir, options) {
230
- const workingDir = path_1.default.join(process.cwd(), outputDir);
231
- const videoPath = path_1.default.join(workingDir, `video_${Date.now()}.webm`);
320
+ async extractVideoFrames(videoUrl, videoUrlHash, absoluteWorkingDir, options) {
321
+ console.log("🚀 ~ LocalFFmpegClient ~ using absolute workingDir:", absoluteWorkingDir);
322
+ const workingDir = absoluteWorkingDir;
323
+ const urlHash = node_crypto_1.default
324
+ .createHash("sha256")
325
+ .update(videoUrl)
326
+ .digest("hex")
327
+ .substring(0, 16);
328
+ const videoPath = path_1.default.join(workingDir, `video_${urlHash}.webm`);
232
329
  const fps = options?.fps ?? 30;
233
330
  const threshold = options?.threshold ?? 0.001;
234
331
  const startTime = options?.startTime;
235
332
  const duration = options?.duration;
236
333
  try {
237
334
  await fs_1.promises.mkdir(workingDir, { recursive: true });
238
- await this.downloadVideo(videoUrl, videoPath);
335
+ await (0, utils_1.downloadVideo)(videoUrl, videoPath);
239
336
  const videoDuration = await this.getVideoDuration(videoPath);
240
337
  console.log(`Video duration: ${Math.round(videoDuration)} seconds`);
241
338
  if (videoDuration > LocalFFmpegClient.MAX_VIDEO_DURATION_SECONDS) {
@@ -269,7 +366,8 @@ class LocalFFmpegClient {
269
366
  }
270
367
  console.log(`Effective extraction range: ${effectiveStartTime}s to ${effectiveStartTime + effectiveDuration}s`);
271
368
  const chunkPaths = await this.createVideoChunks(videoPath, workingDir, effectiveDuration, effectiveStartTime);
272
- const allFramePaths = await this.processVideoChunks(chunkPaths, workingDir, fps);
369
+ const allFramePaths = await this.processVideoChunks(chunkPaths, workingDir, fps, effectiveDuration, // Pass duration for precise calculations
370
+ effectiveStartTime);
273
371
  const allFramesCount = allFramePaths.length;
274
372
  const uniqueImages = await (0, dedup_image_fs_1.deduplicateImageFiles)({
275
373
  imagePaths: allFramePaths,
@@ -284,10 +382,28 @@ class LocalFFmpegClient {
284
382
  }
285
383
  throw new Error("No frames were extracted from the video");
286
384
  }
287
- await this.storeUniqueFrames(uniqueImages, workingDir);
385
+ const uniqueFrameInfos = uniqueImages.map((f) => {
386
+ const normalizedIndex = f.metadata.index
387
+ .toString()
388
+ .padStart(constants_1.VIDEO_ANALYSIS.FRAME_INDEX_PADDING, "0");
389
+ const timeInSeconds = f.metadata.index / fps;
390
+ const minutes = Math.floor(timeInSeconds / 60);
391
+ const seconds = Math.floor(timeInSeconds % 60);
392
+ const timestamp = `${minutes}m${seconds.toString().padStart(2, "0")}s`;
393
+ const fileName = `frame_${normalizedIndex}.png`;
394
+ return {
395
+ index: f.metadata.index,
396
+ path: f.metadata.path,
397
+ fileName: fileName,
398
+ base64: f.image,
399
+ url: `${(0, utils_1.getR2BaseUrlByHash)(videoUrlHash)}${fileName}`,
400
+ timestamp: timestamp,
401
+ };
402
+ });
403
+ await this.storeUniqueFrames(uniqueFrameInfos, workingDir);
288
404
  return {
289
405
  totalFramesCount: allFramesCount,
290
- uniqueFrames: uniqueImages,
406
+ uniqueFrameInfos,
291
407
  videoDurationSeconds: videoDuration,
292
408
  };
293
409
  }
@@ -0,0 +1,8 @@
1
+ export declare function compareImageBuffers(buffer1: Buffer, buffer2: Buffer, pixelmatchThreshold: number): Promise<{
2
+ diffPixels: number;
3
+ totalPixels: number;
4
+ diffFraction: number;
5
+ }>;
6
+ export declare function findSimilarityPercentage(base64Image1: string, base64Image2: string): Promise<number>;
7
+ export declare function areImagesDuplicate(buffer1: Buffer, buffer2: Buffer, threshold: number): Promise<boolean>;
8
+ //# sourceMappingURL=find-threshold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-threshold.d.ts","sourceRoot":"","sources":["../../src/utils/find-threshold.ts"],"names":[],"mappings":"AAKA,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CA6B5E;AAED,wBAAsB,wBAAwB,CAC5C,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CASjB;AAED,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAYlB"}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.compareImageBuffers = compareImageBuffers;
7
+ exports.findSimilarityPercentage = findSimilarityPercentage;
8
+ exports.areImagesDuplicate = areImagesDuplicate;
9
+ const pixelmatch_1 = __importDefault(require("pixelmatch"));
10
+ const sharp_1 = __importDefault(require("sharp"));
11
+ const PIXELMATCH_THRESHOLD = 0.1;
12
+ async function compareImageBuffers(buffer1, buffer2, pixelmatchThreshold) {
13
+ const metadata1 = await (0, sharp_1.default)(buffer1).metadata();
14
+ const metadata2 = await (0, sharp_1.default)(buffer2).metadata();
15
+ const width = metadata1.width || 0;
16
+ const height = metadata1.height || 0;
17
+ if (width !== (metadata2.width || 0) || height !== (metadata2.height || 0)) {
18
+ throw new Error("Images must have the same dimensions for comparison");
19
+ }
20
+ const { data: data1 } = await (0, sharp_1.default)(buffer1)
21
+ .ensureAlpha()
22
+ .raw()
23
+ .toBuffer({ resolveWithObject: true });
24
+ const { data: data2 } = await (0, sharp_1.default)(buffer2)
25
+ .ensureAlpha()
26
+ .raw()
27
+ .toBuffer({ resolveWithObject: true });
28
+ const diffPixels = (0, pixelmatch_1.default)(data1, data2, null, width, height, {
29
+ threshold: pixelmatchThreshold,
30
+ });
31
+ const totalPixels = width * height;
32
+ const diffFraction = diffPixels / totalPixels;
33
+ return { diffPixels, totalPixels, diffFraction };
34
+ }
35
+ async function findSimilarityPercentage(base64Image1, base64Image2) {
36
+ try {
37
+ const buffer1 = Buffer.from(base64Image1, "base64");
38
+ const buffer2 = Buffer.from(base64Image2, "base64");
39
+ const { diffFraction } = await compareImageBuffers(buffer1, buffer2, 0.1);
40
+ return diffFraction;
41
+ }
42
+ catch (error) {
43
+ throw new Error(`Error calculating similarity: ${error}`);
44
+ }
45
+ }
46
+ async function areImagesDuplicate(buffer1, buffer2, threshold) {
47
+ try {
48
+ const { diffFraction } = await compareImageBuffers(buffer1, buffer2, PIXELMATCH_THRESHOLD);
49
+ return diffFraction <= threshold;
50
+ }
51
+ catch (error) {
52
+ console.error("Error comparing images for duplication:", error);
53
+ return false;
54
+ }
55
+ }
@@ -0,0 +1,2 @@
1
+ export declare function createHashBasedOnParams(mainStringToHash: string, additionalParams: Record<string, any>): string;
2
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAEA,wBAAgB,uBAAuB,CACrC,gBAAgB,EAAE,MAAM,EACxB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACpC,MAAM,CAmBR"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createHashBasedOnParams = createHashBasedOnParams;
7
+ const node_crypto_1 = __importDefault(require("node:crypto"));
8
+ function createHashBasedOnParams(mainStringToHash, additionalParams) {
9
+ const sortedParams = Object.keys(additionalParams)
10
+ .sort()
11
+ .reduce((acc, key) => {
12
+ acc[key] = additionalParams[key];
13
+ return acc;
14
+ }, {});
15
+ const json = JSON.stringify({
16
+ mainStringTohash: mainStringToHash,
17
+ ...sortedParams,
18
+ });
19
+ return node_crypto_1.default
20
+ .createHash("sha256")
21
+ .update(json)
22
+ .digest("hex")
23
+ .substring(0, 16);
24
+ }
@@ -1,3 +1,3 @@
1
1
  import { SupportedChatModels } from "@empiricalrun/shared-types";
2
- export declare const ARGS_TO_MODEL_MAP: Record<string, SupportedChatModels>;
2
+ export declare const CLI_ARGS_TO_MODEL_MAP: Record<string, SupportedChatModels>;
3
3
  //# sourceMappingURL=model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/utils/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAkBjE,CAAC"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/utils/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAoBrE,CAAC"}
@@ -1,12 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ARGS_TO_MODEL_MAP = void 0;
4
- exports.ARGS_TO_MODEL_MAP = {
5
- "claude-3-5": "claude-3-5-sonnet-20241022",
6
- "claude-3-7": "claude-3-7-sonnet-20250219",
3
+ exports.CLI_ARGS_TO_MODEL_MAP = void 0;
4
+ exports.CLI_ARGS_TO_MODEL_MAP = {
7
5
  "claude-4": "claude-sonnet-4-20250514",
8
- "claude-sonnet-4": "claude-sonnet-4-20250514",
6
+ "claude-4-5": "claude-sonnet-4-5-20250929",
9
7
  "claude-opus-4": "claude-opus-4-20250514",
8
+ "claude-sonnet-4": "claude-sonnet-4-20250514",
9
+ "claude-sonnet-4-5": "claude-sonnet-4-5-20250929",
10
+ "claude-haiku": "claude-3-5-haiku-20241022",
11
+ "claude-haiku-3-5": "claude-3-5-haiku-20241022",
10
12
  gemini: "gemini-2.5-pro",
11
13
  "gemini-2.5": "gemini-2.5-pro",
12
14
  "gemini-2.5-pro": "gemini-2.5-pro",
@@ -1,4 +1,3 @@
1
1
  import { FileInfo } from "@empiricalrun/shared-types";
2
- export declare const DEFAULT_EXCLUDE: (string | RegExp)[];
3
2
  export declare function generateAsciiTree(root: FileInfo, options?: {}): string;
4
3
  //# sourceMappingURL=repo-tree.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"repo-tree.d.ts","sourceRoot":"","sources":["../../src/utils/repo-tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAEtD,eAAO,MAAM,eAAe,qBAW3B,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,KAAK,UAqF7D"}
1
+ {"version":3,"file":"repo-tree.d.ts","sourceRoot":"","sources":["../../src/utils/repo-tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAGtD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,KAAK,UAqF7D"}
@@ -1,23 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_EXCLUDE = void 0;
4
3
  exports.generateAsciiTree = generateAsciiTree;
5
- exports.DEFAULT_EXCLUDE = [
6
- "node_modules",
7
- "dist",
8
- "build",
9
- /\.git/,
10
- ".DS_Store",
11
- "playwright-report",
12
- "test-results",
13
- ".empiricalrun",
14
- "auth",
15
- "package-lock.json",
16
- ];
4
+ const constants_1 = require("../constants");
17
5
  function generateAsciiTree(root, options = {}) {
18
6
  const defaultOptions = {
19
7
  showHidden: false,
20
- exclude: exports.DEFAULT_EXCLUDE,
8
+ exclude: constants_1.DEFAULT_EXCLUDE,
21
9
  maxDepth: 10,
22
10
  };
23
11
  const opts = { ...defaultOptions, ...options };
@@ -44,7 +44,7 @@ const slugify = (str) => {
44
44
  exports.slugify = slugify;
45
45
  const extractSlugFromDiagnosisUrl = (diagnosisUrl) => {
46
46
  const slug = diagnosisUrl.split("--").pop();
47
- if (!slug) {
47
+ if (!diagnosisUrl.includes("--") || !slug) {
48
48
  throw new Error("Invalid diagnosis URL - could not extract slug");
49
49
  }
50
50
  return slug;
@@ -0,0 +1,14 @@
1
+ import type { Attachment, CanonicalMessage, ChatState, SupportedChatModels } from "@empiricalrun/shared-types";
2
+ import { ProcessedAnalysis } from "./types";
3
+ export declare function extractTextPartFromLastMessage(messages: CanonicalMessage[]): string | null;
4
+ export declare function getChatStateWithFrameIdAttachmentParts(attachments: Attachment[], selectedModel: SupportedChatModels): ChatState;
5
+ export declare function orchestrateVideoAnalysis({ selectedModel, featureFlags, workingDirectory, frameBatch, }: {
6
+ selectedModel: SupportedChatModels;
7
+ featureFlags: string[];
8
+ workingDirectory: string;
9
+ frameBatch: Attachment[];
10
+ }): Promise<{
11
+ analysis: string;
12
+ allMessages: CanonicalMessage[];
13
+ } & ProcessedAnalysis>;
14
+ //# sourceMappingURL=agent-orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-orchestrator.d.ts","sourceRoot":"","sources":["../../src/video-core/agent-orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAChB,SAAS,EACT,mBAAmB,EAEpB,MAAM,4BAA4B,CAAC;AAIpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAG5C,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,gBAAgB,EAAE,GAC3B,MAAM,GAAG,IAAI,CAgBf;AAED,wBAAgB,sCAAsC,CACpD,WAAW,EAAE,UAAU,EAAE,EACzB,aAAa,EAAE,mBAAmB,GACjC,SAAS,CAqBX;AAED,wBAAsB,wBAAwB,CAAC,EAC7C,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,UAAU,GACX,EAAE;IACD,aAAa,EAAE,mBAAmB,CAAC;IACnC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,UAAU,EAAE,CAAC;CAC1B,GAAG,OAAO,CACT;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,gBAAgB,EAAE,CAAA;CAAE,GAAG,iBAAiB,CAC1E,CAoDA"}