@empiricalrun/test-gen 0.75.0 → 0.76.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 (102) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/agent/base/index.d.ts +26 -19
  3. package/dist/agent/base/index.d.ts.map +1 -1
  4. package/dist/agent/base/index.js +88 -56
  5. package/dist/agent/chat/agent-loop.d.ts +4 -3
  6. package/dist/agent/chat/agent-loop.d.ts.map +1 -1
  7. package/dist/agent/chat/agent-loop.js +4 -10
  8. package/dist/agent/chat/exports.d.ts +4 -2
  9. package/dist/agent/chat/exports.d.ts.map +1 -1
  10. package/dist/agent/chat/exports.js +8 -7
  11. package/dist/agent/chat/index.d.ts +6 -10
  12. package/dist/agent/chat/index.d.ts.map +1 -1
  13. package/dist/agent/chat/index.js +129 -196
  14. package/dist/agent/chat/prompt/index.d.ts +5 -4
  15. package/dist/agent/chat/prompt/index.d.ts.map +1 -1
  16. package/dist/agent/chat/prompt/index.js +79 -68
  17. package/dist/agent/chat/state.d.ts +1 -2
  18. package/dist/agent/chat/state.d.ts.map +1 -1
  19. package/dist/agent/chat/state.js +2 -2
  20. package/dist/agent/chat/utils.d.ts +2 -3
  21. package/dist/agent/chat/utils.d.ts.map +1 -1
  22. package/dist/agent/chat/utils.js +1 -2
  23. package/dist/agent/cli.d.ts +11 -0
  24. package/dist/agent/cli.d.ts.map +1 -0
  25. package/dist/agent/cli.js +209 -0
  26. package/dist/agent/code-review/index.d.ts +7 -0
  27. package/dist/agent/code-review/index.d.ts.map +1 -0
  28. package/dist/agent/code-review/index.js +65 -0
  29. package/dist/agent/code-review/prompt.d.ts +1 -1
  30. package/dist/agent/code-review/prompt.d.ts.map +1 -1
  31. package/dist/agent/code-review/prompt.js +52 -16
  32. package/dist/agent/index.d.ts +10 -0
  33. package/dist/agent/index.d.ts.map +1 -0
  34. package/dist/agent/index.js +19 -0
  35. package/dist/agent/triage/index.d.ts +7 -0
  36. package/dist/agent/triage/index.d.ts.map +1 -0
  37. package/dist/agent/triage/index.js +102 -0
  38. package/dist/agent/video-analysis/index.d.ts +7 -0
  39. package/dist/agent/video-analysis/index.d.ts.map +1 -0
  40. package/dist/agent/video-analysis/index.js +35 -0
  41. package/dist/bin/index.js +6 -6
  42. package/dist/file-info/adapters/github/index.d.ts.map +1 -1
  43. package/dist/file-info/adapters/github/index.js +1 -2
  44. package/dist/file-info/adapters/github/reader.d.ts +4 -9
  45. package/dist/file-info/adapters/github/reader.d.ts.map +1 -1
  46. package/dist/file-info/adapters/github/reader.js +163 -134
  47. package/dist/tools/create-pull-request/index.d.ts.map +1 -0
  48. package/dist/tools/{definitions/commit-and-create-pr.js → create-pull-request/index.js} +30 -1
  49. package/dist/tools/create-pull-request/utils.d.ts +21 -0
  50. package/dist/tools/create-pull-request/utils.d.ts.map +1 -0
  51. package/dist/tools/create-pull-request/utils.js +83 -0
  52. package/dist/tools/definitions/extract-frames-from-video.d.ts +39 -0
  53. package/dist/tools/definitions/extract-frames-from-video.d.ts.map +1 -0
  54. package/dist/tools/definitions/extract-frames-from-video.js +60 -0
  55. package/dist/tools/definitions/fetch-video-analysis.d.ts +4 -4
  56. package/dist/tools/executor/index.d.ts +1 -1
  57. package/dist/tools/executor/index.d.ts.map +1 -1
  58. package/dist/tools/executor/index.js +18 -4
  59. package/dist/tools/extract-frames-from-video/index.d.ts +7 -0
  60. package/dist/tools/extract-frames-from-video/index.d.ts.map +1 -0
  61. package/dist/tools/extract-frames-from-video/index.js +145 -0
  62. package/dist/tools/fetch-session-diff/index.d.ts +3 -0
  63. package/dist/tools/fetch-session-diff/index.d.ts.map +1 -0
  64. package/dist/tools/fetch-session-diff/index.js +46 -0
  65. package/dist/tools/fetch-video-analysis/index.d.ts.map +1 -1
  66. package/dist/tools/fetch-video-analysis/index.js +18 -7
  67. package/dist/tools/fetch-video-analysis/utils.d.ts +5 -2
  68. package/dist/tools/fetch-video-analysis/utils.d.ts.map +1 -1
  69. package/dist/tools/fetch-video-analysis/utils.js +34 -11
  70. package/dist/tools/fetch-video-analysis/video-analysis.d.ts +2 -2
  71. package/dist/tools/fetch-video-analysis/video-analysis.d.ts.map +1 -1
  72. package/dist/tools/fetch-video-analysis/video-analysis.js +24 -8
  73. package/dist/tools/index.d.ts +28 -2
  74. package/dist/tools/index.d.ts.map +1 -1
  75. package/dist/tools/index.js +46 -28
  76. package/dist/tools/review-pull-request/index.d.ts +3 -0
  77. package/dist/tools/review-pull-request/index.d.ts.map +1 -0
  78. package/dist/tools/review-pull-request/index.js +103 -0
  79. package/dist/tools/test-run-fetcher/index.d.ts.map +1 -1
  80. package/dist/tools/test-run-fetcher/index.js +4 -14
  81. package/dist/tools/utils/urls.d.ts +5 -0
  82. package/dist/tools/utils/urls.d.ts.map +1 -0
  83. package/dist/tools/utils/urls.js +19 -0
  84. package/dist/tools/view-failed-test-run-report/index.d.ts.map +1 -1
  85. package/dist/tools/view-failed-test-run-report/index.js +3 -15
  86. package/dist/utils/file.d.ts +1 -0
  87. package/dist/utils/file.d.ts.map +1 -1
  88. package/dist/utils/file.js +45 -1
  89. package/dist/{tools/fetch-video-analysis → utils}/local-ffmpeg-client.d.ts +4 -0
  90. package/dist/utils/local-ffmpeg-client.d.ts.map +1 -0
  91. package/dist/{tools/fetch-video-analysis → utils}/local-ffmpeg-client.js +63 -11
  92. package/package.json +2 -2
  93. package/tsconfig.tsbuildinfo +1 -1
  94. package/dist/agent/chat/utils/tool-calls.d.ts +0 -21
  95. package/dist/agent/chat/utils/tool-calls.d.ts.map +0 -1
  96. package/dist/agent/chat/utils/tool-calls.js +0 -64
  97. package/dist/tools/commit-and-create-pr/index.d.ts.map +0 -1
  98. package/dist/tools/commit-and-create-pr/index.js +0 -83
  99. package/dist/tools/definitions/commit-and-create-pr.d.ts +0 -3
  100. package/dist/tools/definitions/commit-and-create-pr.d.ts.map +0 -1
  101. package/dist/tools/fetch-video-analysis/local-ffmpeg-client.d.ts.map +0 -1
  102. /package/dist/tools/{commit-and-create-pr → create-pull-request}/index.d.ts +0 -0
@@ -2,15 +2,10 @@ import { FileInfo, FileReadResult, IDashboardAPIClient } from "@empiricalrun/sha
2
2
  export declare class GitHubFileReader {
3
3
  private repoName;
4
4
  private apiClient;
5
- private repoOwner;
6
- constructor(repoName: string, apiClient: IDashboardAPIClient, repoOwner: string);
7
- private fetchFileFromGitHub;
8
- private fetchTreeFromGitHub;
9
- private resolveBranchName;
5
+ constructor(repoName: string, apiClient: IDashboardAPIClient);
6
+ resolveBranchName(branchName: string | undefined, baseBranch?: string): Promise<string>;
10
7
  readFile(filePath: string, branchName: string, baseBranch: string): Promise<FileReadResult | null>;
11
- private getFileContent;
12
- private getContentsForDirectory;
13
- getFileInfo(branchName: string, baseBranch: string): Promise<FileInfo>;
8
+ private readDirectory;
14
9
  }
15
- export declare function getFileInfoFromGitHub(repoName: string, apiClient: IDashboardAPIClient, branchName: string, baseBranch: string): Promise<FileInfo>;
10
+ export declare function getFileInfoFromGitHub(repoName: string, apiClient: IDashboardAPIClient, branchName: string, baseBranchName: string): Promise<FileInfo>;
16
11
  //# sourceMappingURL=reader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../../../src/file-info/adapters/github/reader.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,cAAc,EACd,mBAAmB,EACpB,MAAM,4BAA4B,CAAC;AA4CpC,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,SAAS;gBAFT,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,mBAAmB,EAC9B,SAAS,EAAE,MAAM;YAGb,mBAAmB;YAUnB,mBAAmB;YASnB,iBAAiB;IAqBzB,QAAQ,CACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;YAmCnB,cAAc;YAkBd,uBAAuB;IAwB/B,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;CAoF7E;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,mBAAmB,EAC9B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,QAAQ,CAAC,CAGnB"}
1
+ {"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../../../src/file-info/adapters/github/reader.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,cAAc,EACd,mBAAmB,EACpB,MAAM,4BAA4B,CAAC;AAcpC,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,SAAS;gBADT,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,mBAAmB;IAGlC,iBAAiB,CACrB,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,UAAU,GAAE,MAAe,GAC1B,OAAO,CAAC,MAAM,CAAC;IAsBZ,QAAQ,CACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;YA4CnB,aAAa;CA8C5B;AAyED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,mBAAmB,EAC9B,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,QAAQ,CAAC,CAyFnB"}
@@ -6,181 +6,210 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.GitHubFileReader = void 0;
7
7
  exports.getFileInfoFromGitHub = getFileInfoFromGitHub;
8
8
  const path_1 = __importDefault(require("path"));
9
- const dashboard_1 = require("../../../dashboard");
10
- const REPO_OWNER = "empirical-run";
11
9
  class GitHubFileReader {
12
10
  repoName;
13
11
  apiClient;
14
- repoOwner;
15
- constructor(repoName, apiClient, repoOwner) {
12
+ constructor(repoName, apiClient) {
16
13
  this.repoName = repoName;
17
14
  this.apiClient = apiClient;
18
- this.repoOwner = repoOwner;
19
15
  }
20
- async fetchFileFromGitHub(filePath, branch) {
21
- return (await this.apiClient.callGitHubProxy({
22
- method: "GET",
23
- url: `/repos/${this.repoOwner}/${this.repoName}/contents/${filePath}?ref=${branch}`,
24
- }));
25
- }
26
- async fetchTreeFromGitHub(branch) {
27
- return (await this.apiClient.callGitHubProxy({
28
- method: "GET",
29
- url: `/repos/${this.repoOwner}/${this.repoName}/git/trees/${branch}?recursive=1`,
30
- }));
31
- }
32
- async resolveBranchName(branchName, baseBranch) {
16
+ async resolveBranchName(branchName, baseBranch = "main") {
33
17
  if (!branchName || branchName === baseBranch) {
34
18
  return baseBranch;
35
19
  }
36
20
  try {
37
- // Try to fetch the branch to see if it exists
21
+ // Try to fetch the branch to see if it exists via GitHub proxy
38
22
  await this.apiClient.callGitHubProxy({
39
23
  method: "GET",
40
- url: `/repos/${this.repoOwner}/${this.repoName}/branches/${branchName}`,
24
+ url: `/repos/empirical-run/${this.repoName}/branches/${branchName}`,
41
25
  });
26
+ console.log(`[GitHubFileReader] Branch ${branchName} exists`);
42
27
  return branchName;
43
28
  }
44
29
  catch {
45
30
  // Branch doesn't exist, fallback to base branch
31
+ console.log(`[GitHubFileReader] Branch ${branchName} not found, falling back to ${baseBranch}`);
46
32
  return baseBranch;
47
33
  }
48
34
  }
49
35
  async readFile(filePath, branchName, baseBranch) {
50
- const branch = await this.resolveBranchName(branchName, baseBranch);
51
- const normalizedPath = filePath === "" ? "." : filePath;
36
+ const resolvedBranch = await this.resolveBranchName(branchName, baseBranch);
37
+ // Check if path has file extension - if not, treat as directory
38
+ const hasFileExtension = path_1.default.extname(filePath) !== "";
39
+ if (!hasFileExtension) {
40
+ console.log(`[GitHubFileReader] Reading as directory: ${filePath}`);
41
+ return this.readDirectory(filePath, resolvedBranch);
42
+ }
52
43
  try {
53
- const response = await this.fetchFileFromGitHub(normalizedPath, branch);
54
- const isDirectory = Array.isArray(response);
55
- if (!isDirectory) {
56
- if (response.type === "file" && response.content) {
57
- const content = Buffer.from(response.content, "base64").toString("utf-8");
58
- return {
59
- content,
60
- isDirectory: false,
61
- };
62
- }
63
- }
64
- else {
44
+ console.log(`[GitHubFileReader] Reading as file: ${filePath}, resolved branch: ${resolvedBranch}`);
45
+ const params = {
46
+ repo: this.repoName,
47
+ path: filePath,
48
+ ref: resolvedBranch,
49
+ };
50
+ const response = await this.apiClient.request(`/api/github/files`, {
51
+ method: "GET",
52
+ params,
53
+ });
54
+ if (response.data?.fileContents.available) {
65
55
  return {
66
- content: response.map((item) => item.name).join("\n"),
67
- isDirectory: true,
56
+ content: response.data.fileContents.content,
57
+ isDirectory: false,
68
58
  };
69
59
  }
60
+ console.log(`[GitHubFileReader] File not available: ${filePath}`);
61
+ // For file paths (with extensions), don't fall back to directory reading
62
+ return null;
70
63
  }
71
64
  catch (error) {
72
- if (error instanceof dashboard_1.NonRetryableHTTPError && error.status === 404) {
73
- return null; // File or directory not found
74
- }
75
- throw error; // Re-throw other errors
65
+ console.log(`[GitHubFileReader] Error reading file ${filePath}:`, error);
66
+ // For file paths, return null (file not found)
67
+ return null;
76
68
  }
77
- return null;
78
69
  }
79
- async getFileContent(path, branchName, baseBranch) {
80
- const branch = await this.resolveBranchName(branchName, baseBranch);
81
- const response = await this.fetchFileFromGitHub(path, branch);
82
- const isDirectory = Array.isArray(response);
83
- if (isDirectory) {
84
- throw new Error(`${path} is a directory, not a file`);
70
+ async readDirectory(filePath, resolvedBranch) {
71
+ try {
72
+ console.log(`[GitHubFileReader] Reading directory: ${filePath}, resolved branch: ${resolvedBranch}`);
73
+ const params = {
74
+ repo: this.repoName,
75
+ path: filePath || ".", // Handle empty path
76
+ ref: resolvedBranch,
77
+ };
78
+ const treeResponse = await this.apiClient.request(`/api/github/tree`, {
79
+ method: "GET",
80
+ params,
81
+ });
82
+ if (treeResponse.data?.tree) {
83
+ const targetPath = filePath === "." || filePath === "" ? "" : filePath;
84
+ const files = treeResponse.data.tree.tree
85
+ .map((item) => item.path)
86
+ .filter((itemPath) => {
87
+ if (!itemPath)
88
+ return false;
89
+ // Check if item is a direct child of the target directory
90
+ const itemDir = path_1.default.dirname(itemPath);
91
+ // Normalize "." to "" for root directory comparison
92
+ const normalizedItemDir = itemDir === "." ? "" : itemDir;
93
+ return normalizedItemDir === targetPath;
94
+ })
95
+ .map((itemPath) => path_1.default.basename(itemPath))
96
+ .sort()
97
+ .join("\n");
98
+ return { content: files, isDirectory: true };
99
+ }
85
100
  }
86
- if (response.type === "file" && response.content) {
87
- return Buffer.from(response.content, "base64").toString("utf-8");
101
+ catch (error) {
102
+ console.log(`[GitHubFileReader] Error reading directory ${filePath}:`, error);
88
103
  }
89
- throw new Error(`Unable to fetch file content for ${path}`);
104
+ return null;
90
105
  }
91
- async getContentsForDirectory(path, branchName, baseBranch) {
92
- const branch = await this.resolveBranchName(branchName, baseBranch);
93
- const response = await this.fetchTreeFromGitHub(branch);
94
- if (response.tree) {
95
- // Convert to expected RepoTree format
96
- return {
97
- sha: response.sha,
98
- truncated: false,
99
- tree: response.tree.map((item) => ({
100
- path: item.path || "",
101
- mode: item.mode || "",
102
- type: item.type === "blob" ? "blob" : "tree",
103
- sha: item.sha,
104
- })),
105
- };
106
- }
107
- throw new Error(`Unable to fetch directory contents for ${path}`);
106
+ }
107
+ exports.GitHubFileReader = GitHubFileReader;
108
+ async function getFileContent(repoName, path, apiClient, branchName) {
109
+ const params = {
110
+ repo: repoName,
111
+ path: path,
112
+ };
113
+ if (branchName) {
114
+ params.ref = branchName;
115
+ }
116
+ const response = await apiClient.request(`/api/github/files`, {
117
+ method: "GET",
118
+ params,
119
+ });
120
+ if (!response.data) {
121
+ throw new Error(`Unable to fetch file for FileInfo`);
122
+ }
123
+ return response.data.fileContents.content;
124
+ }
125
+ async function getContentsForDirectory({ repo, path, }, apiClient, branchName) {
126
+ const params = {
127
+ repo: repo,
128
+ path: path,
129
+ };
130
+ if (branchName) {
131
+ params.ref = branchName;
132
+ }
133
+ const response = await apiClient.request(`/api/github/tree`, {
134
+ method: "GET",
135
+ params,
136
+ });
137
+ if (!response.data) {
138
+ throw new Error(`Unable to fetch file for FileInfo`);
139
+ }
140
+ return response.data.tree;
141
+ }
142
+ async function getFileInfoFromGitHub(repoName, apiClient, branchName, baseBranchName) {
143
+ // Use GitHubFileReader to resolve the branch
144
+ const fileReader = new GitHubFileReader(repoName, apiClient);
145
+ const resolvedBranch = await fileReader.resolveBranchName(branchName, baseBranchName);
146
+ const files = await getContentsForDirectory({ repo: repoName, path: "" }, apiClient, resolvedBranch);
147
+ const root = [];
148
+ const nodeMap = {};
149
+ if (!files) {
150
+ return {
151
+ type: "directory",
152
+ path: repoName,
153
+ name: repoName,
154
+ children: [],
155
+ };
108
156
  }
109
- async getFileInfo(branchName, baseBranch) {
110
- const rootPath = "";
111
- const files = await this.getContentsForDirectory(rootPath, branchName, baseBranch);
112
- const root = [];
113
- const nodeMap = {};
114
- if (!files) {
115
- return {
157
+ files.tree.forEach((file) => {
158
+ if (!file.path) {
159
+ return;
160
+ }
161
+ const pathParts = file.path.split("/");
162
+ const fileName = path_1.default.basename(file.path);
163
+ const isFile = file.type === "blob";
164
+ const currentPath = file.path;
165
+ const currentNode = isFile
166
+ ? {
167
+ type: "file",
168
+ path: currentPath,
169
+ name: fileName,
170
+ getContent: async () => getFileContent(repoName, currentPath, apiClient, resolvedBranch),
171
+ }
172
+ : {
116
173
  type: "directory",
117
- path: this.repoName,
118
- name: this.repoName,
174
+ path: currentPath,
175
+ name: fileName,
119
176
  children: [],
120
177
  };
178
+ nodeMap[currentPath] = currentNode;
179
+ if (pathParts.length === 1) {
180
+ root.push(currentNode);
121
181
  }
122
- files.tree.forEach((file) => {
123
- if (!file.path) {
124
- return;
125
- }
126
- const pathParts = file.path.split("/");
127
- const fileName = path_1.default.basename(file.path);
128
- const isFile = file.type === "blob";
129
- const currentPath = file.path;
130
- const currentNode = isFile
131
- ? {
132
- type: "file",
133
- path: currentPath,
134
- name: fileName,
135
- getContent: async () => this.getFileContent(currentPath, branchName, baseBranch),
136
- }
137
- : {
182
+ else {
183
+ const parentPath = path_1.default.dirname(currentPath);
184
+ if (!nodeMap[parentPath]) {
185
+ const parentNode = {
138
186
  type: "directory",
139
- path: currentPath,
140
- name: fileName,
187
+ path: parentPath,
188
+ name: parentPath.split("/").pop() || "",
141
189
  children: [],
142
190
  };
143
- nodeMap[currentPath] = currentNode;
144
- if (pathParts.length === 1) {
145
- root.push(currentNode);
146
- }
147
- else {
148
- const parentPath = path_1.default.dirname(currentPath);
149
- if (!nodeMap[parentPath]) {
150
- const parentNode = {
151
- type: "directory",
152
- path: parentPath,
153
- name: parentPath.split("/").pop() || "",
154
- children: [],
155
- };
156
- nodeMap[parentPath] = parentNode;
157
- const parentPathParts = parentPath.split("/");
158
- if (parentPathParts.length === 1) {
159
- root.push(parentNode);
160
- }
161
- else {
162
- const grandparentPath = path_1.default.dirname(parentPath);
163
- if (nodeMap[grandparentPath] &&
164
- nodeMap[grandparentPath].type === "directory") {
165
- nodeMap[grandparentPath].children.push(parentNode);
166
- }
167
- }
191
+ nodeMap[parentPath] = parentNode;
192
+ const parentPathParts = parentPath.split("/");
193
+ if (parentPathParts.length === 1) {
194
+ root.push(parentNode);
168
195
  }
169
- if (nodeMap[parentPath].type === "directory") {
170
- nodeMap[parentPath].children.push(currentNode);
196
+ else {
197
+ const grandparentPath = path_1.default.dirname(parentPath);
198
+ if (nodeMap[grandparentPath] &&
199
+ nodeMap[grandparentPath].type === "directory") {
200
+ nodeMap[grandparentPath].children.push(parentNode);
201
+ }
171
202
  }
172
203
  }
173
- });
174
- return {
175
- type: "directory",
176
- path: this.repoName,
177
- name: this.repoName,
178
- children: root,
179
- };
180
- }
181
- }
182
- exports.GitHubFileReader = GitHubFileReader;
183
- async function getFileInfoFromGitHub(repoName, apiClient, branchName, baseBranch) {
184
- const fileReader = new GitHubFileReader(repoName, apiClient, REPO_OWNER);
185
- return fileReader.getFileInfo(branchName, baseBranch);
204
+ if (nodeMap[parentPath].type === "directory") {
205
+ nodeMap[parentPath].children.push(currentNode);
206
+ }
207
+ }
208
+ });
209
+ return {
210
+ type: "directory",
211
+ path: repoName,
212
+ name: repoName,
213
+ children: root,
214
+ };
186
215
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/create-pull-request/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAC;AA6BvD,eAAO,MAAM,qBAAqB,EAAE,IAwDnC,CAAC"}
@@ -2,6 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createPullRequestTool = void 0;
4
4
  const zod_1 = require("zod");
5
+ const utils_1 = require("../executor/utils");
6
+ const utils_2 = require("./utils");
7
+ const REPO_OWNER = "empirical-run";
5
8
  const createPullRequestSchema = zod_1.z.object({
6
9
  pullRequestTitle: zod_1.z
7
10
  .string()
@@ -27,5 +30,31 @@ Don't ask the user for this information, just come up with it yourself.
27
30
  parameters: createPullRequestSchema,
28
31
  },
29
32
  needsBrowser: false,
30
- isInlineTool: false,
33
+ isInlineTool: true,
34
+ execute: async ({ input, apiClient, chatSession }) => {
35
+ const owner = REPO_OWNER;
36
+ try {
37
+ const valids = await (0, utils_2.validateInputs)({ input, apiClient, chatSession });
38
+ const { pullRequestTitle, pullRequestDescription, branchName } = valids;
39
+ const repo = await (0, utils_2.getRepoName)(chatSession, apiClient);
40
+ const existingPR = await (0, utils_1.getExistingPR)({
41
+ owner,
42
+ repo,
43
+ branchName,
44
+ apiClient: apiClient,
45
+ });
46
+ if (existingPR) {
47
+ return await (0, utils_2.handleExistingPullRequest)(existingPR, owner, repo, pullRequestDescription, chatSession, apiClient);
48
+ }
49
+ else {
50
+ return await (0, utils_2.handleNewPullRequest)(owner, repo, pullRequestTitle, branchName, chatSession, pullRequestDescription, apiClient);
51
+ }
52
+ }
53
+ catch (error) {
54
+ return {
55
+ isError: true,
56
+ result: `Failed to commit and push changes: ${error instanceof Error ? error.message : String(error)}`,
57
+ };
58
+ }
59
+ },
31
60
  };
@@ -0,0 +1,21 @@
1
+ import { ChatSessionInfo, IDashboardAPIClient } from "@empiricalrun/shared-types";
2
+ export interface ValidatedInputs {
3
+ pullRequestTitle: string;
4
+ pullRequestDescription: string;
5
+ branchName: string;
6
+ }
7
+ export declare function validateInputs({ input, apiClient, chatSession, }: any): Promise<ValidatedInputs>;
8
+ export declare function getRepoName(chatSession: ChatSessionInfo | null | undefined, apiClient: IDashboardAPIClient): Promise<string>;
9
+ export declare function getMergeableStateInfo(owner: string, repo: string, pullRequest: any, apiClient: any): Promise<{
10
+ mergeableState: "unknown" | "clean" | "dirty" | "unstable";
11
+ stateDescription: string;
12
+ }>;
13
+ export declare function handleExistingPullRequest(pullRequest: any, owner: string, repo: string, pullRequestDescription: string, chatSession: any, apiClient: any): Promise<{
14
+ isError: boolean;
15
+ result: string;
16
+ }>;
17
+ export declare function handleNewPullRequest(owner: string, repo: string, pullRequestTitle: string, branchName: string, chatSession: any, pullRequestDescription: string, apiClient: any): Promise<{
18
+ isError: boolean;
19
+ result: string;
20
+ }>;
21
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/tools/create-pull-request/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,mBAAmB,EAEpB,MAAM,4BAA4B,CAAC;AAUpC,MAAM,WAAW,eAAe;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,cAAc,CAAC,EACnC,KAAK,EACL,SAAS,EACT,WAAW,GACZ,EAAE,GAAG,GAAG,OAAO,CAAC,eAAe,CAAC,CAehC;AAED,wBAAsB,WAAW,CAC/B,WAAW,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,EAC/C,SAAS,EAAE,mBAAmB,GAC7B,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,GAAG,EAChB,SAAS,EAAE,GAAG;;;GAUf;AAED,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,GAAG,EAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,sBAAsB,EAAE,MAAM,EAC9B,WAAW,EAAE,GAAG,EAChB,SAAS,EAAE,GAAG;;;GAqBf;AAED,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,MAAM,EACxB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,GAAG,EAChB,sBAAsB,EAAE,MAAM,EAC9B,SAAS,EAAE,GAAG;;;GAuBf"}
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateInputs = validateInputs;
4
+ exports.getRepoName = getRepoName;
5
+ exports.getMergeableStateInfo = getMergeableStateInfo;
6
+ exports.handleExistingPullRequest = handleExistingPullRequest;
7
+ exports.handleNewPullRequest = handleNewPullRequest;
8
+ const utils_1 = require("../executor/utils");
9
+ const pr_description_1 = require("../executor/utils/pr-description");
10
+ async function validateInputs({ input, apiClient, chatSession, }) {
11
+ const { pullRequestTitle, pullRequestDescription } = input;
12
+ const branchName = chatSession?.branchName;
13
+ if (!apiClient) {
14
+ throw new Error("Dashboard API client is not available.");
15
+ }
16
+ if (!branchName) {
17
+ throw new Error("Branch name is not available in the chat session.");
18
+ }
19
+ return {
20
+ pullRequestTitle,
21
+ pullRequestDescription,
22
+ branchName,
23
+ };
24
+ }
25
+ async function getRepoName(chatSession, apiClient) {
26
+ if (!chatSession?.id) {
27
+ throw new Error("Cannot create pull request without repo name or chat session ID.");
28
+ }
29
+ try {
30
+ const url = `/api/chat-sessions/${chatSession.id}/details`;
31
+ const sessionDetails = await apiClient.request(url, { method: "GET" });
32
+ if ("error" in sessionDetails) {
33
+ throw new Error(`Failed to fetch session details: ${sessionDetails.error}`);
34
+ }
35
+ if (!sessionDetails.gitPayload?.repoName) {
36
+ throw new Error("Repository name not found in session details.");
37
+ }
38
+ return sessionDetails.gitPayload.repoName;
39
+ }
40
+ catch (error) {
41
+ throw new Error(`Failed to fetch repository name: ${error instanceof Error ? error.message : String(error)}`);
42
+ }
43
+ }
44
+ async function getMergeableStateInfo(owner, repo, pullRequest, apiClient) {
45
+ const mergeableState = await (0, utils_1.getMergeableState)({
46
+ owner,
47
+ repo,
48
+ pullRequest,
49
+ apiClient,
50
+ });
51
+ const stateDescription = (0, utils_1.getMergeableStateDescription)(mergeableState);
52
+ return { mergeableState, stateDescription };
53
+ }
54
+ async function handleExistingPullRequest(pullRequest, owner, repo, pullRequestDescription, chatSession, apiClient) {
55
+ const updatedPR = await (0, utils_1.updatePullRequest)({
56
+ owner,
57
+ repo,
58
+ prNumber: pullRequest.number,
59
+ body: (0, pr_description_1.addMetadataToPRDescription)(pullRequestDescription, chatSession),
60
+ apiClient,
61
+ });
62
+ const { mergeableState, stateDescription } = await getMergeableStateInfo(owner, repo, updatedPR, apiClient);
63
+ return {
64
+ isError: false,
65
+ result: `Updated existing PR: ${updatedPR.html_url}\n\nMergeable state: ${mergeableState} - ${stateDescription}`,
66
+ };
67
+ }
68
+ async function handleNewPullRequest(owner, repo, pullRequestTitle, branchName, chatSession, pullRequestDescription, apiClient) {
69
+ const newPR = await (0, utils_1.createPullRequest)({
70
+ owner,
71
+ repo,
72
+ title: pullRequestTitle,
73
+ head: branchName,
74
+ base: chatSession?.baseBranchName || "main",
75
+ body: (0, pr_description_1.addMetadataToPRDescription)(pullRequestDescription, chatSession),
76
+ apiClient,
77
+ });
78
+ const { mergeableState, stateDescription } = await getMergeableStateInfo(owner, repo, newPR, apiClient);
79
+ return {
80
+ isError: false,
81
+ result: `Created a new PR: ${newPR.html_url}\n\nMergeable state: ${mergeableState} - ${stateDescription}`,
82
+ };
83
+ }
@@ -0,0 +1,39 @@
1
+ import { ToolDefinition } from "@empiricalrun/shared-types";
2
+ import z from "zod";
3
+ export declare const extractFramesFromVideoSchema: z.ZodObject<{
4
+ videoUrl: z.ZodString;
5
+ params: z.ZodOptional<z.ZodObject<{
6
+ fps: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
7
+ threshold: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
8
+ startTime: z.ZodOptional<z.ZodString>;
9
+ duration: z.ZodOptional<z.ZodString>;
10
+ }, "strip", z.ZodTypeAny, {
11
+ startTime?: string | undefined;
12
+ threshold?: number | undefined;
13
+ fps?: number | undefined;
14
+ duration?: string | undefined;
15
+ }, {
16
+ startTime?: string | undefined;
17
+ threshold?: number | undefined;
18
+ fps?: number | undefined;
19
+ duration?: string | undefined;
20
+ }>>;
21
+ }, "strip", z.ZodTypeAny, {
22
+ videoUrl: string;
23
+ params?: {
24
+ startTime?: string | undefined;
25
+ threshold?: number | undefined;
26
+ fps?: number | undefined;
27
+ duration?: string | undefined;
28
+ } | undefined;
29
+ }, {
30
+ videoUrl: string;
31
+ params?: {
32
+ startTime?: string | undefined;
33
+ threshold?: number | undefined;
34
+ fps?: number | undefined;
35
+ duration?: string | undefined;
36
+ } | undefined;
37
+ }>;
38
+ export declare const extractFramesFromVideo: ToolDefinition<z.infer<typeof extractFramesFromVideoSchema>>;
39
+ //# sourceMappingURL=extract-frames-from-video.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-frames-from-video.d.ts","sourceRoot":"","sources":["../../../src/tools/definitions/extract-frames-from-video.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,CAAC,MAAM,KAAK,CAAC;AAEpB,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCvC,CAAC;AAEH,eAAO,MAAM,sBAAsB,EAAE,cAAc,CACjD,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAoB7C,CAAC"}
@@ -0,0 +1,60 @@
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.extractFramesFromVideo = exports.extractFramesFromVideoSchema = void 0;
7
+ const zod_1 = __importDefault(require("zod"));
8
+ exports.extractFramesFromVideoSchema = zod_1.default.object({
9
+ videoUrl: zod_1.default
10
+ .string()
11
+ .url("Must be a valid URL")
12
+ .describe("The URL of the video to extract frames from."),
13
+ params: zod_1.default
14
+ .object({
15
+ fps: zod_1.default
16
+ .number()
17
+ .int()
18
+ .min(1)
19
+ .max(120)
20
+ .default(30)
21
+ .optional()
22
+ .describe("Frames per second to extract from the video (default: 30)"),
23
+ threshold: zod_1.default
24
+ .number()
25
+ .min(0)
26
+ .max(0.5)
27
+ .default(0.001)
28
+ .optional()
29
+ .describe("Deduplication threshold (fraction of pixels that may differ to consider frames identical). Lower = stricter. Default: 0.001"),
30
+ startTime: zod_1.default
31
+ .string()
32
+ .optional()
33
+ .describe("Start time in format MM:SS, example 1 min 32 sec -> 01:32"),
34
+ duration: zod_1.default
35
+ .string()
36
+ .optional()
37
+ .describe("Duration time in format MM:SS, example 1 min 32 sec -> 01:32"),
38
+ })
39
+ .optional(),
40
+ });
41
+ exports.extractFramesFromVideo = {
42
+ schema: {
43
+ name: "extractFramesFromVideo",
44
+ description: `
45
+ Extracts frames from a video with precise timing control.
46
+
47
+ **Input:** Video URL (required), optional parameters for timing, frame rate, and output format
48
+ **Output:** PNG formate Frame URLs with metadata.
49
+ **Use when:** You need specific frames from a video segment, want to analyze particular time ranges, or need distinct frames fromthe video, or just need all frames from the video for further processing
50
+
51
+ **Key Features:**
52
+ - Time-based frame extraction (start time + duration)
53
+ - Configurable frame rate and deduplication threshold
54
+ - Frame metadata including timestamps and indices
55
+ - Memory-efficient processing for large videos`,
56
+ parameters: exports.extractFramesFromVideoSchema,
57
+ },
58
+ needsBrowser: false,
59
+ isInlineTool: false,
60
+ };