@empiricalrun/test-gen 0.76.0 → 0.78.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.
- package/CHANGELOG.md +47 -0
- package/dist/agent/base/index.d.ts +25 -21
- package/dist/agent/base/index.d.ts.map +1 -1
- package/dist/agent/base/index.js +50 -37
- package/dist/agent/browsing/run.d.ts +1 -2
- package/dist/agent/browsing/run.d.ts.map +1 -1
- package/dist/agent/browsing/run.js +3 -9
- package/dist/agent/browsing/utils.d.ts +2 -9
- package/dist/agent/browsing/utils.d.ts.map +1 -1
- package/dist/agent/browsing/utils.js +5 -109
- package/dist/agent/chat/agent-loop.d.ts +5 -5
- package/dist/agent/chat/agent-loop.d.ts.map +1 -1
- package/dist/agent/chat/agent-loop.js +3 -8
- package/dist/agent/chat/exports.d.ts +6 -5
- package/dist/agent/chat/exports.d.ts.map +1 -1
- package/dist/agent/chat/exports.js +4 -9
- package/dist/agent/chat/index.d.ts +2 -2
- package/dist/agent/chat/index.d.ts.map +1 -1
- package/dist/agent/chat/index.js +23 -35
- package/dist/agent/chat/models.d.ts +0 -2
- package/dist/agent/chat/models.d.ts.map +1 -1
- package/dist/agent/chat/models.js +12 -26
- package/dist/agent/chat/prompt/pw-utils-docs.d.ts +1 -1
- package/dist/agent/chat/prompt/pw-utils-docs.d.ts.map +1 -1
- package/dist/agent/chat/prompt/pw-utils-docs.js +52 -0
- package/dist/agent/chat/prompt/repo.d.ts.map +1 -1
- package/dist/agent/chat/prompt/repo.js +11 -22
- package/dist/agent/chat/prompt/test-case-def.d.ts +2 -0
- package/dist/agent/chat/prompt/test-case-def.d.ts.map +1 -0
- package/dist/agent/chat/prompt/test-case-def.js +44 -0
- package/dist/agent/chat/state.d.ts +8 -14
- package/dist/agent/chat/state.d.ts.map +1 -1
- package/dist/agent/chat/state.js +15 -60
- package/dist/agent/chat/utils.d.ts +2 -2
- package/dist/agent/chat/utils.d.ts.map +1 -1
- package/dist/agent/chat/utils.js +14 -7
- package/dist/agent/cli.d.ts.map +1 -1
- package/dist/agent/cli.js +49 -58
- package/dist/agent/code-review/executor/index.d.ts +5 -0
- package/dist/agent/code-review/executor/index.d.ts.map +1 -0
- package/dist/agent/code-review/executor/index.js +13 -0
- package/dist/agent/code-review/index.d.ts +8 -3
- package/dist/agent/code-review/index.d.ts.map +1 -1
- package/dist/agent/code-review/index.js +118 -21
- package/dist/agent/code-review/parser.d.ts +5 -0
- package/dist/agent/code-review/parser.d.ts.map +1 -0
- package/dist/agent/code-review/parser.js +70 -0
- package/dist/agent/code-review/types.d.ts +36 -0
- package/dist/agent/code-review/types.d.ts.map +1 -0
- package/dist/agent/code-review/types.js +13 -0
- package/dist/agent/cua/index.d.ts.map +1 -1
- package/dist/agent/cua/index.js +18 -2
- package/dist/agent/cua/model.d.ts.map +1 -1
- package/dist/agent/cua/model.js +4 -1
- package/dist/agent/cua/pw-codegen/pw-pause/index.d.ts.map +1 -1
- package/dist/agent/triage/index.d.ts +3 -3
- package/dist/agent/triage/index.d.ts.map +1 -1
- package/dist/agent/triage/index.js +16 -20
- package/dist/agent/video-analysis/executor/index.d.ts +5 -0
- package/dist/agent/video-analysis/executor/index.d.ts.map +1 -0
- package/dist/agent/video-analysis/executor/index.js +10 -0
- package/dist/agent/video-analysis/index.d.ts +2 -2
- package/dist/agent/video-analysis/index.d.ts.map +1 -1
- package/dist/agent/video-analysis/index.js +38 -13
- package/dist/artifacts/index.d.ts +1 -1
- package/dist/artifacts/index.d.ts.map +1 -1
- package/dist/artifacts/index.js +3 -1
- package/dist/artifacts/utils.d.ts.map +1 -1
- package/dist/bin/index.js +11 -21
- package/dist/constants/index.d.ts +14 -0
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/index.js +33 -1
- package/dist/file/server.d.ts +1 -3
- package/dist/file/server.d.ts.map +1 -1
- package/dist/file/server.js +0 -13
- package/dist/file-info/adapters/file-system/index.d.ts.map +1 -1
- package/dist/file-info/adapters/file-system/reader.d.ts.map +1 -1
- package/dist/file-info/adapters/file-system/reader.js +8 -1
- package/dist/file-info/adapters/github/index.d.ts.map +1 -1
- package/dist/file-info/adapters/github/reader.d.ts +1 -1
- package/dist/file-info/adapters/github/reader.d.ts.map +1 -1
- package/dist/file-info/adapters/github/reader.js +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/tools/analyse-video/index.d.ts +5 -0
- package/dist/tools/analyse-video/index.d.ts.map +1 -0
- package/dist/tools/analyse-video/index.js +56 -0
- package/dist/tools/create-pull-request/index.js +4 -6
- package/dist/tools/create-pull-request/utils.d.ts +1 -1
- package/dist/tools/definitions/{fetch-video-analysis.d.ts → analyse-video.d.ts} +17 -12
- package/dist/tools/definitions/analyse-video.d.ts.map +1 -0
- package/dist/tools/definitions/analyse-video.js +60 -0
- package/dist/tools/definitions/review-pull-request.d.ts +3 -0
- package/dist/tools/definitions/review-pull-request.d.ts.map +1 -0
- package/dist/tools/definitions/review-pull-request.js +16 -0
- package/dist/tools/definitions/str_replace_editor.d.ts +1 -0
- package/dist/tools/definitions/str_replace_editor.d.ts.map +1 -1
- package/dist/tools/definitions/str_replace_editor.js +4 -1
- package/dist/tools/definitions/test-gen-browser.d.ts +0 -3
- package/dist/tools/definitions/test-gen-browser.d.ts.map +1 -1
- package/dist/tools/definitions/test-gen-browser.js +33 -8
- package/dist/tools/delete-file/index.d.ts.map +1 -1
- package/dist/tools/delete-file/index.js +1 -19
- package/dist/tools/executor/base.d.ts +32 -0
- package/dist/tools/executor/base.d.ts.map +1 -0
- package/dist/tools/executor/base.js +131 -0
- package/dist/tools/executor/index.d.ts +3 -22
- package/dist/tools/executor/index.d.ts.map +1 -1
- package/dist/tools/executor/index.js +7 -100
- package/dist/tools/executor/utils/checkpoint.d.ts +1 -1
- package/dist/tools/executor/utils/checkpoint.d.ts.map +1 -1
- package/dist/tools/executor/utils/checkpoint.js +6 -2
- package/dist/tools/executor/utils/git.d.ts +2 -2
- package/dist/tools/executor/utils/git.d.ts.map +1 -1
- package/dist/tools/executor/utils/git.js +7 -3
- package/dist/tools/executor/utils/index.d.ts +5 -3
- package/dist/tools/executor/utils/index.d.ts.map +1 -1
- package/dist/tools/executor/utils/index.js +23 -2
- package/dist/tools/fetch-session-diff/index.js +2 -2
- package/dist/tools/file-operations/create.d.ts.map +1 -1
- package/dist/tools/file-operations/create.js +1 -4
- package/dist/tools/file-operations/index.d.ts +2 -1
- package/dist/tools/file-operations/index.d.ts.map +1 -1
- package/dist/tools/file-operations/index.js +4 -1
- package/dist/tools/file-operations/insert.d.ts +1 -2
- package/dist/tools/file-operations/insert.d.ts.map +1 -1
- package/dist/tools/file-operations/insert.js +1 -4
- package/dist/tools/file-operations/replace.d.ts.map +1 -1
- package/dist/tools/file-operations/replace.js +21 -25
- package/dist/tools/file-operations/shared/helpers.d.ts +3 -5
- package/dist/tools/file-operations/shared/helpers.d.ts.map +1 -1
- package/dist/tools/file-operations/shared/helpers.js +1 -5
- package/dist/tools/grep/index.d.ts.map +1 -1
- package/dist/tools/grep/index.js +18 -11
- package/dist/tools/index.d.ts +5 -5
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +17 -16
- package/dist/tools/merge-conflicts/index.d.ts.map +1 -1
- package/dist/tools/merge-conflicts/index.js +1 -1
- package/dist/tools/rename-file/index.js +1 -1
- package/dist/tools/review-pull-request/index.d.ts.map +1 -1
- package/dist/tools/review-pull-request/index.js +44 -65
- package/dist/tools/run-test.d.ts.map +1 -1
- package/dist/tools/run-test.js +25 -3
- package/dist/tools/test-gen-browser.d.ts.map +1 -1
- package/dist/tools/test-gen-browser.js +51 -47
- package/dist/tools/upgrade-packages/index.d.ts.map +1 -1
- package/dist/tools/upgrade-packages/index.js +4 -0
- package/dist/tools/upgrade-packages/utils.d.ts +1 -0
- package/dist/tools/upgrade-packages/utils.d.ts.map +1 -1
- package/dist/tools/upgrade-packages/utils.js +1 -0
- package/dist/trace-utils/index.d.ts +1 -1
- package/dist/trace-utils/index.d.ts.map +1 -1
- package/dist/trace-utils/index.js +1 -1
- package/dist/utils/dedup/dedup-image.d.ts +22 -0
- package/dist/utils/dedup/dedup-image.d.ts.map +1 -0
- package/dist/utils/dedup/dedup-image.js +26 -0
- package/dist/utils/dedup/find-threshold.d.ts +2 -0
- package/dist/utils/dedup/find-threshold.d.ts.map +1 -0
- package/dist/utils/dedup/find-threshold.js +42 -0
- package/dist/utils/hash.d.ts +2 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +24 -0
- package/dist/utils/model.d.ts +1 -1
- package/dist/utils/model.d.ts.map +1 -1
- package/dist/utils/model.js +7 -5
- package/dist/utils/repo-tree.d.ts +0 -1
- package/dist/utils/repo-tree.d.ts.map +1 -1
- package/dist/utils/repo-tree.js +2 -14
- package/dist/utils/slug.js +1 -1
- package/dist/video-core/agent-orchestrator.d.ts +13 -0
- package/dist/video-core/agent-orchestrator.d.ts.map +1 -0
- package/dist/video-core/agent-orchestrator.js +59 -0
- package/dist/video-core/index.d.ts +39 -0
- package/dist/video-core/index.d.ts.map +1 -0
- package/dist/video-core/index.js +134 -0
- package/dist/video-core/model-limits.d.ts +4 -0
- package/dist/video-core/model-limits.d.ts.map +1 -0
- package/dist/video-core/model-limits.js +73 -0
- package/dist/video-core/storage-manager.d.ts +5 -0
- package/dist/video-core/storage-manager.d.ts.map +1 -0
- package/dist/video-core/storage-manager.js +62 -0
- package/dist/video-core/types.d.ts +13 -0
- package/dist/video-core/types.d.ts.map +1 -0
- package/dist/video-core/types.js +2 -0
- package/dist/video-core/utils.d.ts +15 -0
- package/dist/video-core/utils.d.ts.map +1 -0
- package/dist/video-core/utils.js +194 -0
- package/dist/video-core/xml-parser.d.ts +3 -0
- package/dist/video-core/xml-parser.d.ts.map +1 -0
- package/dist/video-core/xml-parser.js +27 -0
- package/package.json +6 -6
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/agent/chat/prompt/index.d.ts +0 -6
- package/dist/agent/chat/prompt/index.d.ts.map +0 -1
- package/dist/agent/chat/prompt/index.js +0 -200
- package/dist/agent/code-review/prompt.d.ts +0 -2
- package/dist/agent/code-review/prompt.d.ts.map +0 -1
- package/dist/agent/code-review/prompt.js +0 -55
- package/dist/agent/diagnosis-agent/index.d.ts +0 -11
- package/dist/agent/diagnosis-agent/index.d.ts.map +0 -1
- package/dist/agent/diagnosis-agent/index.js +0 -88
- package/dist/agent/diagnosis-agent/strict-mode-violation.d.ts +0 -10
- package/dist/agent/diagnosis-agent/strict-mode-violation.d.ts.map +0 -1
- package/dist/agent/diagnosis-agent/strict-mode-violation.js +0 -30
- package/dist/tools/definitions/extract-frames-from-video.d.ts +0 -39
- package/dist/tools/definitions/extract-frames-from-video.d.ts.map +0 -1
- package/dist/tools/definitions/extract-frames-from-video.js +0 -60
- package/dist/tools/definitions/fetch-video-analysis.d.ts.map +0 -1
- package/dist/tools/definitions/fetch-video-analysis.js +0 -61
- package/dist/tools/extract-frames-from-video/index.d.ts +0 -7
- package/dist/tools/extract-frames-from-video/index.d.ts.map +0 -1
- package/dist/tools/extract-frames-from-video/index.js +0 -145
- package/dist/tools/fetch-video-analysis/index.d.ts +0 -5
- package/dist/tools/fetch-video-analysis/index.d.ts.map +0 -1
- package/dist/tools/fetch-video-analysis/index.js +0 -149
- package/dist/tools/fetch-video-analysis/open-ai.d.ts +0 -6
- package/dist/tools/fetch-video-analysis/open-ai.d.ts.map +0 -1
- package/dist/tools/fetch-video-analysis/open-ai.js +0 -37
- package/dist/tools/fetch-video-analysis/utils.d.ts +0 -16
- package/dist/tools/fetch-video-analysis/utils.d.ts.map +0 -1
- package/dist/tools/fetch-video-analysis/utils.js +0 -121
- package/dist/tools/fetch-video-analysis/video-analysis.d.ts +0 -7
- package/dist/tools/fetch-video-analysis/video-analysis.d.ts.map +0 -1
- package/dist/tools/fetch-video-analysis/video-analysis.js +0 -70
- package/dist/tools/file-operations/shared/git-helper.d.ts +0 -4
- package/dist/tools/file-operations/shared/git-helper.d.ts.map +0 -1
- package/dist/tools/file-operations/shared/git-helper.js +0 -29
- package/dist/utils/dedup-image-fs.d.ts +0 -27
- package/dist/utils/dedup-image-fs.d.ts.map +0 -1
- package/dist/utils/dedup-image-fs.js +0 -88
- package/dist/utils/dedup-image.d.ts +0 -25
- package/dist/utils/dedup-image.d.ts.map +0 -1
- package/dist/utils/dedup-image.js +0 -80
- package/dist/utils/local-ffmpeg-client.d.ts +0 -27
- package/dist/utils/local-ffmpeg-client.d.ts.map +0 -1
- package/dist/utils/local-ffmpeg-client.js +0 -299
- package/eslint.config.mjs +0 -43
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
export declare const SYSTEM_PROMPT = "\nYou are an expert code reviewer that specializes in reviewing Playwright test code. You are\nprovided with tools to fetch diff for a code review, where a test has been added, test modified,\nor some configuration has changed.\n\n# Your goals\n- Identify code smells in test code - see below\n- Call out test data assumptions or lack of clean up\n\n# Output format\n- You are expected to return two sections in your response: describe_code_change and code_review_comments\n- describe_code_change: A brief summary of what the code change is doing. This should be 4-6 sentences in a bullet list.\n- code_review_comments: A bulleted list of code review comments that catch for any of the specific bits below or other\n red flags you might see in the code. Each comment should be 1-2 sentences.\n\nReturn these as XML tags with markdown inside them\n\n<describe_code_change>\n- ...\n</describe_code_change>\n\n<code_review_comments>\n- ...\n</code_review_comments>\n\n# Specific bits to catch in the code review\n\n## Code smells to look for\n- Any form of try-catch or exception handling is a code smell in test code. If there's an\n exception, the test should fail\n- Any conditionals (if, switch, ternary) in test code is a code smell. Tests are expected to be\n deterministic. If you see conditionals, check if there's a comment explaining why it's needed.\n Critically review the comment -- if it's not convincing, call it out as a code smell.\n\n## Ensure Playwright best practices\n- Use locators instead of selectors: waitForSelector, $, $$ are bad - use locators instead (e.g. locator.waitFor)\n- If the test relies on some Playwright APIs that do not auto-wait (e.g. isVisible(), count()), we need to ensure \n they are used AFTER some action that ensures the page has loaded. If nothing, at least it should have a waitForTimeout\n- Don't use waitForLoadState or networkidle - these are not required since Playwright auto-waits after navigations\n\n## Call out test data assumptions\n- If new test data is created (e.g. creating a new entity in the app, doing some actions on it) - it should be cleaned up\n at the end of the test. If not, call it out.\n- If the test data cannot be cleaned up, are we using some random names to ensure no conflicts in future test runs?\n- If the test assumes some data exists (e.g. a user with a specific email) - call it out. It might fail across other\n environments.\n- No hard coded URLs - use relative URLs instead - that can work across environments.\n- Dependency on static data that can change across environments (e.g. number of rows in a table) should be avoided.\n\n## Remove debug artifacts\n- If there are console.logs or page.screenshot usage, call it out. They should be removed before merging.\n";
|
|
2
|
-
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../src/agent/code-review/prompt.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,4sFAmDzB,CAAC"}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SYSTEM_PROMPT = void 0;
|
|
4
|
-
exports.SYSTEM_PROMPT = `
|
|
5
|
-
You are an expert code reviewer that specializes in reviewing Playwright test code. You are
|
|
6
|
-
provided with tools to fetch diff for a code review, where a test has been added, test modified,
|
|
7
|
-
or some configuration has changed.
|
|
8
|
-
|
|
9
|
-
# Your goals
|
|
10
|
-
- Identify code smells in test code - see below
|
|
11
|
-
- Call out test data assumptions or lack of clean up
|
|
12
|
-
|
|
13
|
-
# Output format
|
|
14
|
-
- You are expected to return two sections in your response: describe_code_change and code_review_comments
|
|
15
|
-
- describe_code_change: A brief summary of what the code change is doing. This should be 4-6 sentences in a bullet list.
|
|
16
|
-
- code_review_comments: A bulleted list of code review comments that catch for any of the specific bits below or other
|
|
17
|
-
red flags you might see in the code. Each comment should be 1-2 sentences.
|
|
18
|
-
|
|
19
|
-
Return these as XML tags with markdown inside them
|
|
20
|
-
|
|
21
|
-
<describe_code_change>
|
|
22
|
-
- ...
|
|
23
|
-
</describe_code_change>
|
|
24
|
-
|
|
25
|
-
<code_review_comments>
|
|
26
|
-
- ...
|
|
27
|
-
</code_review_comments>
|
|
28
|
-
|
|
29
|
-
# Specific bits to catch in the code review
|
|
30
|
-
|
|
31
|
-
## Code smells to look for
|
|
32
|
-
- Any form of try-catch or exception handling is a code smell in test code. If there's an
|
|
33
|
-
exception, the test should fail
|
|
34
|
-
- Any conditionals (if, switch, ternary) in test code is a code smell. Tests are expected to be
|
|
35
|
-
deterministic. If you see conditionals, check if there's a comment explaining why it's needed.
|
|
36
|
-
Critically review the comment -- if it's not convincing, call it out as a code smell.
|
|
37
|
-
|
|
38
|
-
## Ensure Playwright best practices
|
|
39
|
-
- Use locators instead of selectors: waitForSelector, $, $$ are bad - use locators instead (e.g. locator.waitFor)
|
|
40
|
-
- If the test relies on some Playwright APIs that do not auto-wait (e.g. isVisible(), count()), we need to ensure
|
|
41
|
-
they are used AFTER some action that ensures the page has loaded. If nothing, at least it should have a waitForTimeout
|
|
42
|
-
- Don't use waitForLoadState or networkidle - these are not required since Playwright auto-waits after navigations
|
|
43
|
-
|
|
44
|
-
## Call out test data assumptions
|
|
45
|
-
- If new test data is created (e.g. creating a new entity in the app, doing some actions on it) - it should be cleaned up
|
|
46
|
-
at the end of the test. If not, call it out.
|
|
47
|
-
- If the test data cannot be cleaned up, are we using some random names to ensure no conflicts in future test runs?
|
|
48
|
-
- If the test assumes some data exists (e.g. a user with a specific email) - call it out. It might fail across other
|
|
49
|
-
environments.
|
|
50
|
-
- No hard coded URLs - use relative URLs instead - that can work across environments.
|
|
51
|
-
- Dependency on static data that can change across environments (e.g. number of rows in a table) should be avoided.
|
|
52
|
-
|
|
53
|
-
## Remove debug artifacts
|
|
54
|
-
- If there are console.logs or page.screenshot usage, call it out. They should be removed before merging.
|
|
55
|
-
`;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { TraceClient } from "@empiricalrun/llm";
|
|
2
|
-
import { TestErrorDiagnosisDetails } from "@empiricalrun/shared-types";
|
|
3
|
-
import { CustomLogger } from "../../bin/logger";
|
|
4
|
-
export declare function createTaskUsingFailureDiagnosis({ trace, diagnosis, logger, }: {
|
|
5
|
-
trace?: TraceClient;
|
|
6
|
-
diagnosis: TestErrorDiagnosisDetails;
|
|
7
|
-
logger?: CustomLogger;
|
|
8
|
-
}): Promise<{
|
|
9
|
-
task: string;
|
|
10
|
-
}>;
|
|
11
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/diagnosis-agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAEvE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAoChD,wBAAsB,+BAA+B,CAAC,EACpD,KAAK,EACL,SAAS,EACT,MAAM,GACP,EAAE;IACD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,yBAAyB,CAAC;IACrC,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAqE5B"}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createTaskUsingFailureDiagnosis = createTaskUsingFailureDiagnosis;
|
|
4
|
-
const llm_1 = require("@empiricalrun/llm");
|
|
5
|
-
const strict_mode_violation_1 = require("./strict-mode-violation");
|
|
6
|
-
const responseFormat = {
|
|
7
|
-
type: "json_schema",
|
|
8
|
-
json_schema: {
|
|
9
|
-
name: "test-case-auto-fix-summary",
|
|
10
|
-
strict: true,
|
|
11
|
-
schema: {
|
|
12
|
-
type: "object",
|
|
13
|
-
properties: {
|
|
14
|
-
observation: {
|
|
15
|
-
type: "array",
|
|
16
|
-
items: {
|
|
17
|
-
type: "string",
|
|
18
|
-
},
|
|
19
|
-
description: "Detailed observation of what changed between successful and failed test screenshots",
|
|
20
|
-
},
|
|
21
|
-
action: {
|
|
22
|
-
type: "string",
|
|
23
|
-
description: "Direct action to fix the test in natural language without code snippets or options",
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
required: ["observation", "action"],
|
|
27
|
-
additionalProperties: false,
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
async function createTaskUsingFailureDiagnosis({ trace, diagnosis, logger, }) {
|
|
32
|
-
const failureDiagnosisSpan = trace?.span({
|
|
33
|
-
name: "auto-fix",
|
|
34
|
-
input: {
|
|
35
|
-
diagnosisId: diagnosis.diagnosisId,
|
|
36
|
-
},
|
|
37
|
-
});
|
|
38
|
-
logger?.log("Trying to fix the test using failure diagnosis. Fetching key moments of the diagnosis");
|
|
39
|
-
const resp = await fetch(diagnosis.keyMomentsUrl);
|
|
40
|
-
// TODO: check for response to be not ok
|
|
41
|
-
if (resp.ok) {
|
|
42
|
-
logger?.success("Successfully fetched key moments of the diagnosis");
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
logger?.warn("Failed to fetch key moments of the diagnosis");
|
|
46
|
-
}
|
|
47
|
-
const screenshotsData = await resp.json();
|
|
48
|
-
const llm = new llm_1.LLM({
|
|
49
|
-
provider: "openai",
|
|
50
|
-
defaultModel: "o1",
|
|
51
|
-
trace: failureDiagnosisSpan,
|
|
52
|
-
});
|
|
53
|
-
// TODO: make this dynamic in nature. the prompts should be made receipe
|
|
54
|
-
// which will help to get rid of if else logic
|
|
55
|
-
// receipe to have:
|
|
56
|
-
// 1. selection criteria
|
|
57
|
-
// 2. job to be done - in this case generate a prompt
|
|
58
|
-
let prompt;
|
|
59
|
-
if (diagnosis.failed_run_metadata.stack.includes("strict mode violation")) {
|
|
60
|
-
prompt = (0, strict_mode_violation_1.fixStrictModeViolationPrompt)({
|
|
61
|
-
screenshotsData,
|
|
62
|
-
diagnosis,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
if (prompt) {
|
|
66
|
-
const llmResponse = await llm.createChatCompletion({
|
|
67
|
-
messages: prompt,
|
|
68
|
-
modelParameters: {
|
|
69
|
-
max_completion_tokens: 40_000,
|
|
70
|
-
},
|
|
71
|
-
responseFormat,
|
|
72
|
-
});
|
|
73
|
-
const { observation, action } = JSON.parse(llmResponse?.content);
|
|
74
|
-
failureDiagnosisSpan?.update({
|
|
75
|
-
output: {
|
|
76
|
-
observation,
|
|
77
|
-
action,
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
return {
|
|
81
|
-
task: action,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
// TODO: handle default prompt
|
|
85
|
-
return {
|
|
86
|
-
task: "",
|
|
87
|
-
};
|
|
88
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { TestErrorDiagnosisDetails } from "@empiricalrun/shared-types";
|
|
2
|
-
import OpenAI from "openai";
|
|
3
|
-
export declare function fixStrictModeViolationPrompt({ screenshotsData, diagnosis, }: {
|
|
4
|
-
screenshotsData: {
|
|
5
|
-
success: string[];
|
|
6
|
-
failure: string[];
|
|
7
|
-
};
|
|
8
|
-
diagnosis: TestErrorDiagnosisDetails;
|
|
9
|
-
}): OpenAI.Chat.Completions.ChatCompletionMessageParam[];
|
|
10
|
-
//# sourceMappingURL=strict-mode-violation.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"strict-mode-violation.d.ts","sourceRoot":"","sources":["../../../src/agent/diagnosis-agent/strict-mode-violation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,MAAM,MAAM,QAAQ,CAAC;AAoB5B,wBAAgB,4BAA4B,CAAC,EAC3C,eAAe,EACf,SAAS,GACV,EAAE;IACD,eAAe,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC1D,SAAS,EAAE,yBAAyB,CAAC;CACtC,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,0BAA0B,EAAE,CAiBvD"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.fixStrictModeViolationPrompt = fixStrictModeViolationPrompt;
|
|
4
|
-
const llm_1 = require("@empiricalrun/llm");
|
|
5
|
-
const promptTemplate_0 = "{{#section \"system\"}}\nAs a software engineer, your task is to identify a fix for a failing Playwright test by analyzing screenshots of both the failed and successful test steps.\n\nKey issues for test failures include:\n- Duplicate elements for the same Playwright selector.\n\nInstructions:\n1. Examine the provided successful and failed test screenshots.\n2. Identify the correct element for action based on these observations on the successful test run screenshots.\n3. Sometimes the exact same locator is not available on failed test run screenshot, you need to identify the intent from successful test screenshots and apply that intent in failed test run screenshot to identify the right locator to interact with\n4. Evaluate the playwright selector options provided to you to execute the action. Pick the selector which best matches the intent of the test.\n5. Propose a precise action that addresses the issue.\n\nExample:\n- observation: \n - Current step failure: await page.getByText(\"Audience\").click()\n - Two similar buttons named \"Audience\" exist in the failed run screenshots\n - The successful test run clicked on \"Untracked Audience\"\n - The failed test run should click on \"Untracked Audience\"\n - Available locators: await page.getByText(\"Untracked Audience\").click() contain the selector for Untracked Audience\n- action: Replace failing line with await page.getByText(\"Untracked Audience\").click()\n\nYour action should:\n- Be directly actionable and free of ambiguity, as it will guide another LLM to generate code.\n- Be in natural language and not just code snippet.\n- Be verified as feasible on the failure screen before responding.\n- Choose from the provided possible actions that can be executed on the failure screen.\n- Action should adhere to the format mentioned in the example, i.e. it should start with \"Replace the failing line\" and the updated code with replaced selector following it.\n\nEnsure the action is executable based on the failure screen context before providing it.\n{{/section}}\n\n{{#section \"user\"}}\nSuccessful test screenshots\n\n{{images successScreenshots}}\n\nFailed test screenshots\n\n{{images failedScreenshots}}\n\nStep where test failed:\n{{failingLine}}\n\nOptions for Playwright selectors to perform actions on a failed test screen:\n{{selectorOptions}}\n\n{{/section}}\n\n";
|
|
6
|
-
function extractLocatorOptions(errorStack) {
|
|
7
|
-
// This regex matches a chain of locator API calls following the pattern:
|
|
8
|
-
// functionName(arguments) optionally chained with .functionName(arguments)
|
|
9
|
-
const regex = /aka\s+((?:[A-Za-z0-9_]+\([^)]*\)(?:\.[A-Za-z0-9_]+\([^)]*\))*))/g;
|
|
10
|
-
const options = [];
|
|
11
|
-
let match;
|
|
12
|
-
while ((match = regex.exec(errorStack)) !== null) {
|
|
13
|
-
if (match[1]) {
|
|
14
|
-
options.push(match[1]);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return options;
|
|
18
|
-
}
|
|
19
|
-
function fixStrictModeViolationPrompt({ screenshotsData, diagnosis, }) {
|
|
20
|
-
const compiledPrompt = (0, llm_1.compilePrompt)(promptTemplate_0, {
|
|
21
|
-
failingLine: diagnosis.failingLine,
|
|
22
|
-
successScreenshots: screenshotsData.success,
|
|
23
|
-
failedScreenshots: screenshotsData.failure,
|
|
24
|
-
selectorOptions: extractLocatorOptions(diagnosis.failed_run_metadata.stack).join("\n"),
|
|
25
|
-
}, {
|
|
26
|
-
imageDetail: "high",
|
|
27
|
-
modelProvider: "openai",
|
|
28
|
-
});
|
|
29
|
-
return compiledPrompt;
|
|
30
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -1,60 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-video-analysis.d.ts","sourceRoot":"","sources":["../../../src/tools/definitions/fetch-video-analysis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,CAAC,MAAM,KAAK,CAAC;AAEpB,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2C9B,CAAC;AAEH,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAC7C,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAcpC,CAAC"}
|
|
@@ -1,61 +0,0 @@
|
|
|
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.fetchVideoAnalysis = exports.videoAnalysisSchema = void 0;
|
|
7
|
-
const zod_1 = __importDefault(require("zod"));
|
|
8
|
-
exports.videoAnalysisSchema = 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 analyze."),
|
|
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
|
-
model: zod_1.default
|
|
31
|
-
.string()
|
|
32
|
-
.default("gemini-2.5-pro")
|
|
33
|
-
.optional()
|
|
34
|
-
.describe("Gemini LLM model identifier to use for analysis defaults to gemini-2.5-pro"),
|
|
35
|
-
featureFlag: zod_1.default
|
|
36
|
-
.enum([
|
|
37
|
-
"none",
|
|
38
|
-
"send-all-frames",
|
|
39
|
-
"separate-threshold",
|
|
40
|
-
"ai-based-frames",
|
|
41
|
-
])
|
|
42
|
-
.default("none")
|
|
43
|
-
.optional()
|
|
44
|
-
.describe("Feature flag to use for analysis defaults to none"),
|
|
45
|
-
})
|
|
46
|
-
.optional(),
|
|
47
|
-
});
|
|
48
|
-
exports.fetchVideoAnalysis = {
|
|
49
|
-
schema: {
|
|
50
|
-
name: "fetchVideoAnalysis",
|
|
51
|
-
description: `
|
|
52
|
-
Analyzes Playwright test execution videos to identify test failures and UI issues.
|
|
53
|
-
|
|
54
|
-
**Input:** The video URL is mandatory (supports webm, mp4). DO NOT specify params UNLESS the user has explicitly asked for a specific param value to be tested.
|
|
55
|
-
**Output:** analysis summary of what happened during the test execution.
|
|
56
|
-
**Use when:** You have a failing test with a video recording and need to understand what went wrong`,
|
|
57
|
-
parameters: exports.videoAnalysisSchema,
|
|
58
|
-
},
|
|
59
|
-
needsBrowser: false,
|
|
60
|
-
isInlineTool: false,
|
|
61
|
-
};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Tool } from "@empiricalrun/shared-types";
|
|
2
|
-
import type { z } from "zod";
|
|
3
|
-
import { type extractFramesFromVideoSchema } from "../definitions/extract-frames-from-video";
|
|
4
|
-
type ExtractFramesInput = z.infer<typeof extractFramesFromVideoSchema>;
|
|
5
|
-
export declare const extractFramesFromVideo: Tool<ExtractFramesInput>;
|
|
6
|
-
export {};
|
|
7
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/extract-frames-from-video/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,IAAI,EAEL,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAI7B,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,0CAA0C,CAAC;AAElD,KAAK,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AA0EvE,eAAO,MAAM,sBAAsB,EAAE,IAAI,CAAC,kBAAkB,CAkH3D,CAAC"}
|
|
@@ -1,145 +0,0 @@
|
|
|
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 = void 0;
|
|
7
|
-
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
8
|
-
const fs_1 = require("fs");
|
|
9
|
-
const file_1 = require("../../utils/file");
|
|
10
|
-
const local_ffmpeg_client_1 = require("../../utils/local-ffmpeg-client");
|
|
11
|
-
const extract_frames_from_video_1 = require("../definitions/extract-frames-from-video");
|
|
12
|
-
function parseTimeToSeconds(timeString) {
|
|
13
|
-
const timeRegex = /^(\d{1,2}):(\d{2})$/;
|
|
14
|
-
const match = timeString.match(timeRegex);
|
|
15
|
-
if (!match || match.length < 3) {
|
|
16
|
-
throw new Error(`Invalid time format: ${timeString}. Expected MM:SS format (e.g., "01:32")`);
|
|
17
|
-
}
|
|
18
|
-
const minutesStr = match[1];
|
|
19
|
-
const secondsStr = match[2];
|
|
20
|
-
if (!minutesStr || !secondsStr) {
|
|
21
|
-
throw new Error(`Invalid time format: ${timeString}. Expected MM:SS format (e.g., "01:32")`);
|
|
22
|
-
}
|
|
23
|
-
const minutes = parseInt(minutesStr, 10);
|
|
24
|
-
const seconds = parseInt(secondsStr, 10);
|
|
25
|
-
if (seconds >= 60) {
|
|
26
|
-
throw new Error(`Invalid seconds: ${seconds}. Seconds must be 0-59`);
|
|
27
|
-
}
|
|
28
|
-
return minutes * 60 + seconds;
|
|
29
|
-
}
|
|
30
|
-
function getExtractFramesParams(params) {
|
|
31
|
-
return {
|
|
32
|
-
fps: params?.fps ?? 30,
|
|
33
|
-
threshold: params?.threshold ?? 0.001,
|
|
34
|
-
startTime: params?.startTime
|
|
35
|
-
? parseTimeToSeconds(params.startTime)
|
|
36
|
-
: undefined,
|
|
37
|
-
duration: params?.duration
|
|
38
|
-
? parseTimeToSeconds(params.duration)
|
|
39
|
-
: undefined,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
function hashExtractParams(videoUrl, params) {
|
|
43
|
-
const sortedParams = Object.keys(params)
|
|
44
|
-
.sort()
|
|
45
|
-
.reduce((acc, key) => {
|
|
46
|
-
acc[key] = params[key];
|
|
47
|
-
return acc;
|
|
48
|
-
}, {});
|
|
49
|
-
const json = JSON.stringify({ videoUrl, ...sortedParams });
|
|
50
|
-
return node_crypto_1.default
|
|
51
|
-
.createHash("sha256")
|
|
52
|
-
.update(json)
|
|
53
|
-
.digest("hex")
|
|
54
|
-
.substring(0, 16);
|
|
55
|
-
}
|
|
56
|
-
exports.extractFramesFromVideo = {
|
|
57
|
-
...extract_frames_from_video_1.extractFramesFromVideo,
|
|
58
|
-
execute: async ({ input, trace, }) => {
|
|
59
|
-
const { videoUrl } = input;
|
|
60
|
-
const params = getExtractFramesParams(input.params);
|
|
61
|
-
const videoUrlHash = hashExtractParams(videoUrl, params);
|
|
62
|
-
const WORKING_DIR = `./extract-frames-artifacts/${videoUrlHash}`;
|
|
63
|
-
// const R2_BASE_URL = `https://video-analysis.empirical.run/${videoUrlHash}`;
|
|
64
|
-
const extractionSpan = trace?.span({
|
|
65
|
-
name: "extract-frames-from-video",
|
|
66
|
-
input: { videoUrl, params },
|
|
67
|
-
});
|
|
68
|
-
try {
|
|
69
|
-
const response = await fetch(videoUrl, { method: "HEAD" });
|
|
70
|
-
if (!response.ok) {
|
|
71
|
-
return {
|
|
72
|
-
result: `Failed to access video: ${response.statusText}`,
|
|
73
|
-
isError: true,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
const ffmpegClient = new local_ffmpeg_client_1.LocalFFmpegClient();
|
|
77
|
-
const extractionResult = await ffmpegClient.extractVideoFrames(videoUrl, WORKING_DIR, {
|
|
78
|
-
fps: params.fps,
|
|
79
|
-
threshold: params.threshold,
|
|
80
|
-
startTime: params.startTime,
|
|
81
|
-
duration: params.duration,
|
|
82
|
-
});
|
|
83
|
-
const { totalFramesCount, uniqueFrames, videoDurationSeconds } = extractionResult;
|
|
84
|
-
// Create response metadata
|
|
85
|
-
const extractFramesResponse = {
|
|
86
|
-
videoUrl,
|
|
87
|
-
videoDurationSeconds,
|
|
88
|
-
totalFramesCount,
|
|
89
|
-
extractedFramesCount: uniqueFrames.length,
|
|
90
|
-
timeRange: params.startTime !== undefined || params.duration !== undefined
|
|
91
|
-
? {
|
|
92
|
-
startTime: params.startTime || 0,
|
|
93
|
-
duration: params.duration || 0,
|
|
94
|
-
endTime: (params.startTime || 0) + (params.duration || 0),
|
|
95
|
-
}
|
|
96
|
-
: undefined,
|
|
97
|
-
frames: uniqueFrames.map((frame) => ({
|
|
98
|
-
index: frame.metadata.index,
|
|
99
|
-
path: frame.metadata.path,
|
|
100
|
-
frameId: `frame_${frame.metadata.index}`,
|
|
101
|
-
})),
|
|
102
|
-
};
|
|
103
|
-
// Convert frames to base64 images for multimodal response
|
|
104
|
-
const frameImageParts = await Promise.all(uniqueFrames.map(async (frame) => {
|
|
105
|
-
try {
|
|
106
|
-
const imageBuffer = await fs_1.promises.readFile(frame.metadata.path);
|
|
107
|
-
const base64Data = imageBuffer.toString("base64");
|
|
108
|
-
return {
|
|
109
|
-
type: "image/png",
|
|
110
|
-
base64Data: base64Data,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
console.warn(`Failed to read frame ${frame.metadata.path}:`, error);
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
}));
|
|
118
|
-
await (0, file_1.safeCleanupDirectory)(WORKING_DIR, "extract-frames-tool");
|
|
119
|
-
// Filter out any failed frame reads
|
|
120
|
-
const validFrameImageParts = frameImageParts.filter((part) => part !== null);
|
|
121
|
-
return {
|
|
122
|
-
result: [
|
|
123
|
-
{
|
|
124
|
-
type: "text",
|
|
125
|
-
text: JSON.stringify(extractFramesResponse, null, 2),
|
|
126
|
-
},
|
|
127
|
-
...validFrameImageParts,
|
|
128
|
-
],
|
|
129
|
-
isError: false,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
catch (error) {
|
|
133
|
-
console.error("Error in extractFramesFromVideo", error);
|
|
134
|
-
extractionSpan?.end();
|
|
135
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
136
|
-
return {
|
|
137
|
-
result: `Error extracting frames from video: ${message}`,
|
|
138
|
-
isError: true,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
finally {
|
|
142
|
-
extractionSpan?.end();
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { Tool } from "@empiricalrun/shared-types";
|
|
2
|
-
import type { z } from "zod";
|
|
3
|
-
import { type videoAnalysisSchema } from "../definitions/fetch-video-analysis";
|
|
4
|
-
export declare const fetchVideoAnalysis: Tool<z.infer<typeof videoAnalysisSchema>>;
|
|
5
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/fetch-video-analysis/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,IAAI,EAKL,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAI7B,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,qCAAqC,CAAC;AAuC7C,eAAO,MAAM,kBAAkB,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAsKxE,CAAC"}
|