@tyvm/knowhow 0.0.143 → 0.0.145
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/bin/knowhow.js +22 -20
- package/package.json +1 -1
- package/scripts/migrate-usage-json.js +147 -0
- package/src/agents/base/base.ts +65 -10
- package/src/agents/tools/patch.ts +84 -2
- package/src/agents/tools/textSearch.ts +98 -3
- package/src/chat/modules/AgentModule.ts +129 -6
- package/src/chat/modules/SessionsModule.ts +6 -0
- package/src/chat/types.ts +14 -0
- package/src/chat.ts +11 -0
- package/src/cli.ts +2 -0
- package/src/clients/anthropic.ts +56 -1
- package/src/clients/contextLimits.ts +40 -0
- package/src/clients/gemini.ts +59 -5
- package/src/clients/http.ts +85 -4
- package/src/clients/index.ts +4 -0
- package/src/clients/openai.ts +179 -31
- package/src/clients/pricing/fireworks.ts +50 -1
- package/src/clients/pricing/index.ts +1 -1
- package/src/clients/pricing/models.ts +3 -1
- package/src/clients/pricing/openai.ts +2 -2
- package/src/clients/pricing/qwen.ts +80 -0
- package/src/clients/qwen.ts +16 -0
- package/src/clients/types.ts +69 -1
- package/src/clients/xai.ts +73 -4
- package/src/commands/agent.ts +20 -1
- package/src/commands/sandbox.ts +139 -114
- package/src/index.ts +9 -0
- package/src/processors/Base64ImageDetector.ts +46 -7
- package/src/processors/GemmaToolProcessor.ts +163 -0
- package/src/processors/index.ts +1 -0
- package/src/services/AgentSyncFs.ts +37 -0
- package/src/services/SessionManager.ts +14 -0
- package/src/services/Tools.ts +3 -0
- package/src/services/modules/computerUse.ts +216 -0
- package/src/services/modules/index.ts +47 -9
- package/src/services/modules/types.ts +23 -1
- package/src/types.ts +3 -0
- package/tests/clients/contextLimits.test.ts +4 -0
- package/tests/clients/openai.images.test.ts +105 -0
- package/tests/clients/pricing.test.ts +6 -0
- package/tests/compressor/usageBase64.json +159 -0
- package/tests/compressor/usageBase64.test.ts +175 -0
- package/tests/patching/fixtures/transcript-mangles/agent-sync-fs-nested-catch.json +9 -0
- package/tests/patching/fixtures/transcript-mangles/automation-functions-crossed.json +9 -0
- package/tests/patching/fixtures/transcript-mangles/fruit-ninja-confirmed-retirement.json +8 -0
- package/tests/patching/patchFileOutput.test.ts +112 -1
- package/tests/patching/transcriptMangleRegression.test.ts +125 -0
- package/tests/processors/Base64ImageDetector.test.ts +36 -1
- package/tests/unit/commands/sandbox.test.ts +350 -0
- package/ts_build/package.json +1 -1
- package/ts_build/src/agents/base/base.d.ts +8 -1
- package/ts_build/src/agents/base/base.js +37 -3
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/tools/patch.d.ts +1 -0
- package/ts_build/src/agents/tools/patch.js +35 -2
- package/ts_build/src/agents/tools/patch.js.map +1 -1
- package/ts_build/src/agents/tools/textSearch.js +56 -2
- package/ts_build/src/agents/tools/textSearch.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.d.ts +14 -1
- package/ts_build/src/chat/modules/AgentModule.js +73 -5
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/chat/modules/SessionsModule.js +4 -0
- package/ts_build/src/chat/modules/SessionsModule.js.map +1 -1
- package/ts_build/src/chat/types.d.ts +11 -0
- package/ts_build/src/chat.js +7 -0
- package/ts_build/src/chat.js.map +1 -1
- package/ts_build/src/cli.d.ts +2 -1
- package/ts_build/src/cli.js +1 -0
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/clients/anthropic.js +28 -1
- package/ts_build/src/clients/anthropic.js.map +1 -1
- package/ts_build/src/clients/contextLimits.js +25 -0
- package/ts_build/src/clients/contextLimits.js.map +1 -1
- package/ts_build/src/clients/gemini.js +48 -4
- package/ts_build/src/clients/gemini.js.map +1 -1
- package/ts_build/src/clients/http.d.ts +2 -0
- package/ts_build/src/clients/http.js +66 -9
- package/ts_build/src/clients/http.js.map +1 -1
- package/ts_build/src/clients/index.d.ts +1 -0
- package/ts_build/src/clients/index.js +4 -0
- package/ts_build/src/clients/index.js.map +1 -1
- package/ts_build/src/clients/openai.d.ts +6 -1
- package/ts_build/src/clients/openai.js +131 -33
- package/ts_build/src/clients/openai.js.map +1 -1
- package/ts_build/src/clients/pricing/fireworks.d.ts +4 -1
- package/ts_build/src/clients/pricing/fireworks.js +33 -1
- package/ts_build/src/clients/pricing/fireworks.js.map +1 -1
- package/ts_build/src/clients/pricing/index.d.ts +1 -1
- package/ts_build/src/clients/pricing/index.js +6 -2
- package/ts_build/src/clients/pricing/index.js.map +1 -1
- package/ts_build/src/clients/pricing/models.d.ts +2 -1
- package/ts_build/src/clients/pricing/models.js +4 -1
- package/ts_build/src/clients/pricing/models.js.map +1 -1
- package/ts_build/src/clients/pricing/openai.js +2 -2
- package/ts_build/src/clients/pricing/openai.js.map +1 -1
- package/ts_build/src/clients/pricing/qwen.d.ts +5 -0
- package/ts_build/src/clients/pricing/qwen.js +30 -0
- package/ts_build/src/clients/pricing/qwen.js.map +1 -0
- package/ts_build/src/clients/qwen.d.ts +4 -0
- package/ts_build/src/clients/qwen.js +15 -0
- package/ts_build/src/clients/qwen.js.map +1 -0
- package/ts_build/src/clients/types.d.ts +12 -0
- package/ts_build/src/clients/xai.d.ts +1 -0
- package/ts_build/src/clients/xai.js +56 -9
- package/ts_build/src/clients/xai.js.map +1 -1
- package/ts_build/src/commands/agent.js +10 -1
- package/ts_build/src/commands/agent.js.map +1 -1
- package/ts_build/src/commands/sandbox.js +79 -80
- package/ts_build/src/commands/sandbox.js.map +1 -1
- package/ts_build/src/index.d.ts +2 -0
- package/ts_build/src/index.js +1 -0
- package/ts_build/src/index.js.map +1 -1
- package/ts_build/src/processors/Base64ImageDetector.js +22 -3
- package/ts_build/src/processors/Base64ImageDetector.js.map +1 -1
- package/ts_build/src/processors/GemmaToolProcessor.d.ts +14 -0
- package/ts_build/src/processors/GemmaToolProcessor.js +97 -0
- package/ts_build/src/processors/GemmaToolProcessor.js.map +1 -0
- package/ts_build/src/processors/index.d.ts +1 -0
- package/ts_build/src/processors/index.js +3 -1
- package/ts_build/src/processors/index.js.map +1 -1
- package/ts_build/src/services/AgentSyncFs.js +17 -0
- package/ts_build/src/services/AgentSyncFs.js.map +1 -1
- package/ts_build/src/services/SessionManager.js +12 -0
- package/ts_build/src/services/SessionManager.js.map +1 -1
- package/ts_build/src/services/Tools.d.ts +2 -0
- package/ts_build/src/services/Tools.js.map +1 -1
- package/ts_build/src/services/modules/computerUse.d.ts +163 -0
- package/ts_build/src/services/modules/computerUse.js +3 -0
- package/ts_build/src/services/modules/computerUse.js.map +1 -0
- package/ts_build/src/services/modules/index.d.ts +1 -0
- package/ts_build/src/services/modules/index.js +23 -6
- package/ts_build/src/services/modules/index.js.map +1 -1
- package/ts_build/src/services/modules/types.d.ts +4 -0
- package/ts_build/src/types.d.ts +3 -0
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/workers/tools/index.d.ts +1 -1
- package/ts_build/tests/clients/contextLimits.test.js +2 -0
- package/ts_build/tests/clients/contextLimits.test.js.map +1 -1
- package/ts_build/tests/clients/openai.images.test.d.ts +1 -0
- package/ts_build/tests/clients/openai.images.test.js +94 -0
- package/ts_build/tests/clients/openai.images.test.js.map +1 -0
- package/ts_build/tests/clients/pricing.test.js +4 -0
- package/ts_build/tests/clients/pricing.test.js.map +1 -1
- package/ts_build/tests/compressor/usageBase64.test.d.ts +1 -0
- package/ts_build/tests/compressor/usageBase64.test.js +109 -0
- package/ts_build/tests/compressor/usageBase64.test.js.map +1 -0
- package/ts_build/tests/patching/patchFileOutput.test.js +82 -0
- package/ts_build/tests/patching/patchFileOutput.test.js.map +1 -1
- package/ts_build/tests/patching/transcriptMangleRegression.test.d.ts +1 -0
- package/ts_build/tests/patching/transcriptMangleRegression.test.js +104 -0
- package/ts_build/tests/patching/transcriptMangleRegression.test.js.map +1 -0
- package/ts_build/tests/processors/Base64ImageDetector.test.js +24 -0
- package/ts_build/tests/processors/Base64ImageDetector.test.js.map +1 -1
- package/ts_build/tests/unit/commands/sandbox.test.d.ts +1 -0
- package/ts_build/tests/unit/commands/sandbox.test.js +258 -0
- package/ts_build/tests/unit/commands/sandbox.test.js.map +1 -0
- package/x-home.png +0 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const openai_1 = require("../../src/clients/openai");
|
|
4
|
+
describe("GenericOpenAiClient image message conversion", () => {
|
|
5
|
+
const imageUrl = "data:image/jpeg;base64,/9j/4AAQSkZJRg==";
|
|
6
|
+
let client;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
client = new openai_1.GenericOpenAiClient("test-key");
|
|
9
|
+
});
|
|
10
|
+
it("moves tool image output to a user message for Chat Completions", () => {
|
|
11
|
+
const messages = [{
|
|
12
|
+
role: "tool",
|
|
13
|
+
tool_call_id: "call_1",
|
|
14
|
+
name: "loadImageAsBase64",
|
|
15
|
+
content: [{
|
|
16
|
+
type: "image_url",
|
|
17
|
+
image_url: { url: imageUrl, detail: "high" },
|
|
18
|
+
}],
|
|
19
|
+
}];
|
|
20
|
+
const converted = client.toChatCompletionMessages(messages);
|
|
21
|
+
expect(converted).toEqual([
|
|
22
|
+
{
|
|
23
|
+
role: "tool",
|
|
24
|
+
tool_call_id: "call_1",
|
|
25
|
+
content: [{
|
|
26
|
+
type: "text",
|
|
27
|
+
text: "Image output attached in the following user message.",
|
|
28
|
+
}],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
role: "user",
|
|
32
|
+
content: [{
|
|
33
|
+
type: "image_url",
|
|
34
|
+
image_url: { url: imageUrl, detail: "high" },
|
|
35
|
+
}],
|
|
36
|
+
},
|
|
37
|
+
]);
|
|
38
|
+
});
|
|
39
|
+
it("uses input_image parts for the Responses API", () => {
|
|
40
|
+
const converted = client.toResponseContent([
|
|
41
|
+
{ type: "text", text: "Screenshot" },
|
|
42
|
+
{ type: "image_url", image_url: { url: imageUrl, detail: "low" } },
|
|
43
|
+
]);
|
|
44
|
+
expect(converted).toEqual([
|
|
45
|
+
{ type: "input_text", text: "Screenshot" },
|
|
46
|
+
{ type: "input_image", image_url: imageUrl, detail: "low" },
|
|
47
|
+
]);
|
|
48
|
+
});
|
|
49
|
+
it.each([
|
|
50
|
+
{ type: "audio_url", audio_url: { url: "data:audio/wav;base64,UklGRg==" } },
|
|
51
|
+
{ type: "video_url", video_url: { url: "data:video/mp4;base64,AAAAIGZ0eXA=" } },
|
|
52
|
+
])("rejects unsupported $type Responses API content instead of dropping it", (part) => {
|
|
53
|
+
expect(() => client.toResponseContent([
|
|
54
|
+
{ type: "text", text: "Media" },
|
|
55
|
+
part,
|
|
56
|
+
])).toThrow(`OpenAI Responses API conversion does not support ${part.type} content.`);
|
|
57
|
+
});
|
|
58
|
+
it("attaches a tool image as input_image in a Responses API request", async () => {
|
|
59
|
+
const create = jest.fn().mockResolvedValue({
|
|
60
|
+
id: "resp_1",
|
|
61
|
+
output: [],
|
|
62
|
+
usage: undefined,
|
|
63
|
+
});
|
|
64
|
+
client.client = { responses: { create } };
|
|
65
|
+
await client.createChatResponse({
|
|
66
|
+
model: "gpt-5.4",
|
|
67
|
+
reasoning_effort: "none",
|
|
68
|
+
messages: [{
|
|
69
|
+
role: "tool",
|
|
70
|
+
tool_call_id: "call_1",
|
|
71
|
+
content: [{
|
|
72
|
+
type: "image_url",
|
|
73
|
+
image_url: { url: imageUrl, detail: "auto" },
|
|
74
|
+
}],
|
|
75
|
+
}],
|
|
76
|
+
});
|
|
77
|
+
expect(create.mock.calls[0][0].input).toEqual([
|
|
78
|
+
{
|
|
79
|
+
type: "function_call_output",
|
|
80
|
+
call_id: "call_1",
|
|
81
|
+
output: "Image output attached in the following user message.",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
role: "user",
|
|
85
|
+
content: [{
|
|
86
|
+
type: "input_image",
|
|
87
|
+
image_url: imageUrl,
|
|
88
|
+
detail: "auto",
|
|
89
|
+
}],
|
|
90
|
+
},
|
|
91
|
+
]);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=openai.images.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.images.test.js","sourceRoot":"","sources":["../../../tests/clients/openai.images.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,6 +21,8 @@ describe("Model Pricing Coverage", () => {
|
|
|
21
21
|
...pricing_1.GeminiTextPricing,
|
|
22
22
|
...pricing_1.AnthropicTextPricing,
|
|
23
23
|
...pricing_1.XaiTextPricing,
|
|
24
|
+
...pricing_1.FireworksTextPricing,
|
|
25
|
+
...pricing_1.FireworksEmbeddingPricing,
|
|
24
26
|
};
|
|
25
27
|
describe("Text completion models have pricing", () => {
|
|
26
28
|
for (const [provider, providerModels] of Object.entries(types_1.Models)) {
|
|
@@ -92,6 +94,8 @@ describe("Model Pricing Coverage", () => {
|
|
|
92
94
|
...pricing_1.GeminiTextPricing,
|
|
93
95
|
...pricing_1.AnthropicTextPricing,
|
|
94
96
|
...pricing_1.XaiTextPricing,
|
|
97
|
+
...pricing_1.FireworksTextPricing,
|
|
98
|
+
...pricing_1.FireworksEmbeddingPricing,
|
|
95
99
|
})
|
|
96
100
|
.filter(([, p]) => p && p.deprecated === true)
|
|
97
101
|
.map(([id]) => id));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pricing.test.js","sourceRoot":"","sources":["../../../tests/clients/pricing.test.ts"],"names":[],"mappings":";;AAYA,2CAayB;AAEzB,
|
|
1
|
+
{"version":3,"file":"pricing.test.js","sourceRoot":"","sources":["../../../tests/clients/pricing.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../../src/utils");
|
|
4
|
+
const TokenCompressor_1 = require("../../src/processors/TokenCompressor");
|
|
5
|
+
const services_1 = require("../../src/services");
|
|
6
|
+
describe("TokenCompressor - usage.json with base64 images", () => {
|
|
7
|
+
let tokenCompressor;
|
|
8
|
+
const usagePath = "tests/compressor/usageBase64.json";
|
|
9
|
+
beforeAll(() => {
|
|
10
|
+
const { Tools } = (0, services_1.services)();
|
|
11
|
+
tokenCompressor = new TokenCompressor_1.TokenCompressor(Tools);
|
|
12
|
+
});
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
tokenCompressor.clearStorage();
|
|
15
|
+
});
|
|
16
|
+
test("fixture is large enough to require compression", async () => {
|
|
17
|
+
const fileContents = (await (0, utils_1.readFile)(usagePath)).toString();
|
|
18
|
+
const estimatedTokens = Math.ceil(fileContents.length / 4);
|
|
19
|
+
console.log(`usage.json size: ${fileContents.length} chars (~${estimatedTokens} tokens)`);
|
|
20
|
+
expect(estimatedTokens).toBeGreaterThan(4000);
|
|
21
|
+
});
|
|
22
|
+
test("compressContent should materially shrink the file (not leave it raw)", async () => {
|
|
23
|
+
const fileContents = (await (0, utils_1.readFile)(usagePath)).toString();
|
|
24
|
+
const originalLen = fileContents.length;
|
|
25
|
+
const start = Date.now();
|
|
26
|
+
const compressed = tokenCompressor.compressContent(fileContents, usagePath);
|
|
27
|
+
const elapsed = Date.now() - start;
|
|
28
|
+
console.log(`compressContent took ${elapsed}ms`);
|
|
29
|
+
console.log(`original: ${originalLen} chars`);
|
|
30
|
+
console.log(`compressed: ${compressed.length} chars`);
|
|
31
|
+
console.log(`ratio: ${((compressed.length / originalLen) * 100).toFixed(2)}%`);
|
|
32
|
+
console.log(`compressed preview:\n${compressed.substring(0, 400)}`);
|
|
33
|
+
expect(compressed.length).toBeLessThan(originalLen * 0.5);
|
|
34
|
+
const surfacedTokens = Math.ceil(compressed.length / 4);
|
|
35
|
+
console.log(`surfaced tokens: ${surfacedTokens}`);
|
|
36
|
+
expect(surfacedTokens).toBeLessThan(50000);
|
|
37
|
+
});
|
|
38
|
+
test("compressMessage on a tool message shrinks the base64 payload", async () => {
|
|
39
|
+
const fileContents = (await (0, utils_1.readFile)(usagePath)).toString();
|
|
40
|
+
const toolMessage = {
|
|
41
|
+
role: "tool",
|
|
42
|
+
tool_call_id: "call_readfile_usage",
|
|
43
|
+
name: "readFile",
|
|
44
|
+
content: fileContents,
|
|
45
|
+
};
|
|
46
|
+
await tokenCompressor.compressMessage(toolMessage);
|
|
47
|
+
const resultContent = toolMessage.content;
|
|
48
|
+
console.log(`tool message content after compress: ${resultContent.length} chars`);
|
|
49
|
+
console.log(`preview:\n${resultContent.substring(0, 300)}`);
|
|
50
|
+
expect(typeof resultContent).toBe("string");
|
|
51
|
+
expect(resultContent.length).toBeLessThan(fileContents.length * 0.5);
|
|
52
|
+
});
|
|
53
|
+
test("createProcessor compresses a fresh readFile tool response batch", async () => {
|
|
54
|
+
const fileContents = (await (0, utils_1.readFile)(usagePath)).toString();
|
|
55
|
+
const messages = [
|
|
56
|
+
{ role: "user", content: "read the usage file" },
|
|
57
|
+
{
|
|
58
|
+
role: "assistant",
|
|
59
|
+
content: "",
|
|
60
|
+
tool_calls: [
|
|
61
|
+
{
|
|
62
|
+
id: "call_readfile_usage",
|
|
63
|
+
type: "function",
|
|
64
|
+
function: { name: "readFile", arguments: "{}" },
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
role: "tool",
|
|
70
|
+
tool_call_id: "call_readfile_usage",
|
|
71
|
+
name: "readFile",
|
|
72
|
+
content: fileContents,
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
const processor = tokenCompressor.createProcessor();
|
|
76
|
+
const modified = messages.map((m) => ({ ...m }));
|
|
77
|
+
await processor(messages, modified);
|
|
78
|
+
const toolMsg = modified[2];
|
|
79
|
+
const toolContent = toolMsg.content;
|
|
80
|
+
console.log(`processor result tool content: ${toolContent.length} chars (orig ${fileContents.length})`);
|
|
81
|
+
console.log(`preview:\n${toolContent.substring(0, 300)}`);
|
|
82
|
+
expect(toolContent.length).toBeLessThan(fileContents.length * 0.5);
|
|
83
|
+
});
|
|
84
|
+
test("multimodal image_url base64 parts are NOT compressed (documents the context-blowup gap)", async () => {
|
|
85
|
+
const bigBase64 = "/9j/2wBDAAYEBQYFBAYGBQYH" + "A".repeat(1_400_000);
|
|
86
|
+
const dataUrl = `data:image/jpeg;base64,${bigBase64}`;
|
|
87
|
+
const imageMessage = {
|
|
88
|
+
role: "tool",
|
|
89
|
+
tool_call_id: "call_screenshot",
|
|
90
|
+
name: "screenshot",
|
|
91
|
+
content: [
|
|
92
|
+
{ type: "text", text: "screenshot captured" },
|
|
93
|
+
{ type: "image_url", image_url: { url: dataUrl } },
|
|
94
|
+
],
|
|
95
|
+
};
|
|
96
|
+
const beforeLen = JSON.stringify(imageMessage.content).length;
|
|
97
|
+
await tokenCompressor.compressMessage(imageMessage);
|
|
98
|
+
const afterLen = JSON.stringify(imageMessage.content).length;
|
|
99
|
+
const parts = imageMessage.content;
|
|
100
|
+
const imagePart = parts.find((p) => p.type === "image_url");
|
|
101
|
+
console.log(`multimodal content before: ${beforeLen} chars`);
|
|
102
|
+
console.log(`multimodal content after: ${afterLen} chars`);
|
|
103
|
+
console.log(`image_url still base64? ${imagePart.image_url.url.startsWith("data:image")}`);
|
|
104
|
+
console.log(`image_url length: ${imagePart.image_url.url.length}`);
|
|
105
|
+
expect(imagePart.image_url.url.startsWith("data:image")).toBe(true);
|
|
106
|
+
expect(afterLen).toBeGreaterThan(beforeLen * 0.9);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
//# sourceMappingURL=usageBase64.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usageBase64.test.js","sourceRoot":"","sources":["../../../tests/compressor/usageBase64.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -184,4 +184,86 @@ describe("patchFile nested-object + leading-context additions regression", () =>
|
|
|
184
184
|
expect(countChar(updated, "}")).toBe(countChar(original, "}"));
|
|
185
185
|
});
|
|
186
186
|
});
|
|
187
|
+
describe("patchFile repeated Prisma query regression", () => {
|
|
188
|
+
const testFile = "/tmp/patch-repeated-prisma-regression.ts";
|
|
189
|
+
const original = `async function reconcile() {
|
|
190
|
+
const orphaned = await prisma.githubRunnerJob.findMany({
|
|
191
|
+
where: {
|
|
192
|
+
status: "running",
|
|
193
|
+
updatedAt: { lt: cutoff },
|
|
194
|
+
...this.runnerJobEnvironmentFilter(),
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const expired = await prisma.githubRunnerJob.findMany({
|
|
199
|
+
where: {
|
|
200
|
+
status: { in: ["dispatched", "running"] },
|
|
201
|
+
leaseExpiresAt: { lt: now },
|
|
202
|
+
leaseToken: { not: null },
|
|
203
|
+
...this.runnerJobEnvironmentFilter(),
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const retryable = await prisma.githubRunnerJob.findMany({
|
|
208
|
+
where: {
|
|
209
|
+
status: "retry_wait",
|
|
210
|
+
attemptCount: { lt: MAX_ATTEMPTS },
|
|
211
|
+
nextRetryAt: { lte: now },
|
|
212
|
+
...this.runnerJobEnvironmentFilter(),
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const queued = await prisma.githubRunnerJob.findMany({
|
|
217
|
+
where: {
|
|
218
|
+
status: "queued",
|
|
219
|
+
leaseToken: null,
|
|
220
|
+
sandboxId: null,
|
|
221
|
+
...this.runnerJobEnvironmentFilter(),
|
|
222
|
+
},
|
|
223
|
+
orderBy: [{ createdAt: "asc" }],
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
`;
|
|
227
|
+
beforeEach(() => fs.writeFileSync(testFile, original));
|
|
228
|
+
it("only removes the requested repeated spread properties or rejects without writing", async () => {
|
|
229
|
+
const patch = `@@ -100,2 +100,1 @@
|
|
230
|
+
updatedAt: { lt: cutoff },
|
|
231
|
+
- ...this.runnerJobEnvironmentFilter(),
|
|
232
|
+
@@ -200,2 +200,1 @@
|
|
233
|
+
leaseToken: { not: null },
|
|
234
|
+
- ...this.runnerJobEnvironmentFilter(),
|
|
235
|
+
@@ -300,2 +300,1 @@
|
|
236
|
+
nextRetryAt: { lte: now },
|
|
237
|
+
- ...this.runnerJobEnvironmentFilter(),
|
|
238
|
+
@@ -400,2 +400,1 @@
|
|
239
|
+
sandboxId: null,
|
|
240
|
+
- ...this.runnerJobEnvironmentFilter(),
|
|
241
|
+
`;
|
|
242
|
+
const result = await boundPatch(testFile, patch);
|
|
243
|
+
const updated = fs.readFileSync(testFile, "utf8");
|
|
244
|
+
if (result.includes("❌ Patch failed")) {
|
|
245
|
+
expect(updated).toBe(original);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const expected = original.replace(/^\s*\.\.\.this\.runnerJobEnvironmentFilter\(\),\n/gm, "");
|
|
249
|
+
expect(updated).toBe(expected);
|
|
250
|
+
expect(updated).toContain('status: "queued",');
|
|
251
|
+
expect(updated).toContain("leaseToken: null,");
|
|
252
|
+
expect(updated).toContain("sandboxId: null,");
|
|
253
|
+
expect(updated).toContain("attemptCount: { lt: MAX_ATTEMPTS },");
|
|
254
|
+
expect(updated).toContain("orderBy: [{ createdAt: \"asc\" }],");
|
|
255
|
+
});
|
|
256
|
+
it("detects the unrelated removals from the recorded corruption", () => {
|
|
257
|
+
const requestedPatch = `@@ -30,2 +30,1 @@
|
|
258
|
+
sandboxId: null,
|
|
259
|
+
- ...this.runnerJobEnvironmentFilter(),
|
|
260
|
+
`;
|
|
261
|
+
const corrupted = original
|
|
262
|
+
.replace(' status: "queued",\n', "")
|
|
263
|
+
.replace(" leaseToken: null,\n", "")
|
|
264
|
+
.replace(" sandboxId: null,\n", "")
|
|
265
|
+
.replace(" ...this.runnerJobEnvironmentFilter(),\n", "");
|
|
266
|
+
expect((0, patch_1.autoCorrectionPreservesChanges)(original, corrupted, requestedPatch)).toBe(false);
|
|
267
|
+
});
|
|
268
|
+
});
|
|
187
269
|
//# sourceMappingURL=patchFileOutput.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patchFileOutput.test.js","sourceRoot":"","sources":["../../../tests/patching/patchFileOutput.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"patchFileOutput.test.js","sourceRoot":"","sources":["../../../tests/patching/patchFileOutput.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const patch_1 = require("../../src/agents/tools/patch");
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const os = __importStar(require("os"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const fixtureDir = path.join(__dirname, "fixtures", "transcript-mangles");
|
|
41
|
+
const loadFixture = (name) => JSON.parse(fs.readFileSync(path.join(fixtureDir, `${name}.json`), "utf8"));
|
|
42
|
+
const mockToolService = { getContext: () => ({ Events: null }) };
|
|
43
|
+
const boundPatch = patch_1.patchFile.bind(mockToolService);
|
|
44
|
+
function replaceOnce(source, before, after) {
|
|
45
|
+
expect(source.split(before)).toHaveLength(2);
|
|
46
|
+
return source.replace(before, after);
|
|
47
|
+
}
|
|
48
|
+
function expectedAgentSyncFs(source) {
|
|
49
|
+
let expected = replaceOnce(source, ` * consecutive calls can reveal when a cache prefix was invalidated.\n */`, ` * consecutive calls can reveal when a cache prefix was invalidated.\n *\n * To prevent exponential file growth, if the new entry's message thread\n * fully contains the previous entry's thread as a prefix, the previous\n * thread is replaced with { PREV_CACHE_HIT: true } so only the new\n * messages (the delta) are stored alongside the new usage data.\n */`);
|
|
50
|
+
expected = replaceOnce(expected, ` entries.push(entry);`, ` // If the new entry's messages are a superset of the last entry's\n // messages (i.e. the last thread is a prefix of the new thread),\n // collapse the last entry's messages to { PREV_CACHE_HIT: true }\n // and store only the new delta — preventing exponential growth.\n if (entries.length > 0) {\n const lastEntry = entries[entries.length - 1];\n const prevMessages: any[] = lastEntry?.messages;\n const newMessages: any[] = entry?.messages;\n if (\n Array.isArray(prevMessages) &&\n Array.isArray(newMessages) &&\n prevMessages.length > 0 &&\n newMessages.length >= prevMessages.length &&\n JSON.stringify(newMessages.slice(0, prevMessages.length)) ===\n JSON.stringify(prevMessages)\n ) {\n // Replace the previous full thread with a compact sentinel\n lastEntry.messages = [{ PREV_CACHE_HIT: true }];\n }\n }\n\n entries.push(entry);`);
|
|
51
|
+
return expected;
|
|
52
|
+
}
|
|
53
|
+
function expectedAutomation(source) {
|
|
54
|
+
const anchor = `export function automationPath(name: string): string {\n const safe = name.replace(/[^a-zA-Z0-9_-]/g, "_");\n return path.join(STORE_DIR, \`\${safe}.ts\`);\n}\n`;
|
|
55
|
+
const parser = `\n/**\n * Extract the structured "skill card" from an automation script. We look for a\n * leading block comment (before any executable code) and read JSDoc-style tags:\n * @description one-liner of what it does\n * @useWhen the situation/trigger that should make an agent pick this\n * @startState what the screen must look like BEFORE running\n * @endState what the screen will look like AFTER it finishes\n * @window the required window (title/app) it operates on\n * @notes anything else worth knowing (limits, caveats)\n * Tag text may wrap onto continuation lines. Returns undefined when no\n * recognizable header is present.\n */\nexport function parseAutomationDoc(script: string): AutomationDoc | undefined {\n const block = script.match(/^\\s*\\/\\*\\*?([\\s\\S]*?)\\*\\//);\n if (!block) return undefined;\n // Strip leading " * " decoration from each comment line.\n const body = block[1]\n .split("\\n")\n .map((l) => l.replace(/^\\s*\\*?\\s?/, ""))\n .join("\\n");\n\n const tags: Record<string, string> = {};\n let current: string | null = null;\n const known = new Set([\n "description",\n "usewhen",\n "startstate",\n "endstate",\n "window",\n "notes",\n ]);\n for (const rawLine of body.split("\\n")) {\n const line = rawLine.trimEnd();\n const m = line.match(/^@(\\w+)\\s*(.*)$/);\n if (m && known.has(m[1].toLowerCase())) {\n current = m[1].toLowerCase();\n tags[current] = m[2].trim();\n } else if (current && line.trim()) {\n tags[current] = (tags[current] + " " + line.trim()).trim();\n }\n }\n if (!Object.keys(tags).length) return undefined;\n const doc: AutomationDoc = {\n description: tags["description"],\n useWhen: tags["usewhen"],\n startState: tags["startstate"],\n endState: tags["endstate"],\n window: tags["window"],\n notes: tags["notes"],\n };\n // Drop empty keys for a tidy summary.\n for (const k of Object.keys(doc) as (keyof AutomationDoc)[]) {\n if (!doc[k]) delete doc[k];\n }\n return Object.keys(doc).length ? doc : undefined;\n}\n`;
|
|
56
|
+
let expected = replaceOnce(source, anchor, anchor + parser);
|
|
57
|
+
expected = replaceOnce(expected, ` return spec;`, ` return { ...spec, doc: parseAutomationDoc(spec.script), filePath: automationPath(spec.name) };`);
|
|
58
|
+
expected = replaceOnce(expected, ` return { name, script: fs.readFileSync(p, "utf8") };`, ` const script = fs.readFileSync(p, "utf8");\n return { name, script, doc: parseAutomationDoc(script), filePath: p };`);
|
|
59
|
+
expected = replaceOnce(expected, ` return { name, script: parsed.script };`, ` return {\n name,\n script: parsed.script,\n doc: parseAutomationDoc(parsed.script || ""),\n filePath: legacy,\n };`);
|
|
60
|
+
return expected;
|
|
61
|
+
}
|
|
62
|
+
describe("patchFile transcript-derived mangling regressions", () => {
|
|
63
|
+
async function expectExactEditOrSafeRejection(name, buildExpected) {
|
|
64
|
+
const fixture = loadFixture(name);
|
|
65
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "patch-transcript-"));
|
|
66
|
+
const testFile = path.join(dir, `${name}.ts`);
|
|
67
|
+
fs.writeFileSync(testFile, fixture.sourceBefore);
|
|
68
|
+
try {
|
|
69
|
+
const result = await boundPatch(testFile, fixture.patch);
|
|
70
|
+
const actual = fs.readFileSync(testFile, "utf8");
|
|
71
|
+
if (result.includes("❌ Patch failed")) {
|
|
72
|
+
expect(actual).toBe(fixture.sourceBefore);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
expect(actual).toBe(buildExpected(fixture.sourceBefore));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
it("agent-sync-fs patch applies exactly or rejects without changing the file", async () => {
|
|
83
|
+
await expectExactEditOrSafeRejection("agent-sync-fs-nested-catch", expectedAgentSyncFs);
|
|
84
|
+
});
|
|
85
|
+
it("automation patch applies exactly or rejects without changing the file", async () => {
|
|
86
|
+
await expectExactEditOrSafeRejection("automation-functions-crossed", expectedAutomation);
|
|
87
|
+
});
|
|
88
|
+
it("fruit-ninja confirmed-retirement patch applies exactly", async () => {
|
|
89
|
+
const fixture = loadFixture("fruit-ninja-confirmed-retirement");
|
|
90
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "patch-transcript-"));
|
|
91
|
+
const testFile = path.join(dir, "fruitNinjaPrecision.ts");
|
|
92
|
+
fs.writeFileSync(testFile, fixture.sourceBefore);
|
|
93
|
+
try {
|
|
94
|
+
const result = await boundPatch(testFile, fixture.patch);
|
|
95
|
+
expect(result).not.toContain("❌ Patch failed");
|
|
96
|
+
const actual = fs.readFileSync(testFile, "utf8");
|
|
97
|
+
expect(actual).toBe(fixture.expectedAfter);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
//# sourceMappingURL=transcriptMangleRegression.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcriptMangleRegression.test.js","sourceRoot":"","sources":["../../../tests/patching/transcriptMangleRegression.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -183,6 +183,30 @@ describe("Base64ImageDetector", () => {
|
|
|
183
183
|
},
|
|
184
184
|
});
|
|
185
185
|
});
|
|
186
|
+
it("should process tool messages with JSON string containing an ARRAY of image_url parts", () => {
|
|
187
|
+
const imageDataUrl = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k=";
|
|
188
|
+
const toolResponseJson = JSON.stringify([
|
|
189
|
+
{
|
|
190
|
+
type: "image_url",
|
|
191
|
+
image_url: { url: imageDataUrl },
|
|
192
|
+
},
|
|
193
|
+
]);
|
|
194
|
+
const originalMessages = [];
|
|
195
|
+
const modifiedMessages = [
|
|
196
|
+
{
|
|
197
|
+
role: "tool",
|
|
198
|
+
content: toolResponseJson,
|
|
199
|
+
tool_call_id: "call_arr",
|
|
200
|
+
},
|
|
201
|
+
];
|
|
202
|
+
const processor = detector.createProcessor();
|
|
203
|
+
processor(originalMessages, modifiedMessages);
|
|
204
|
+
expect(Array.isArray(modifiedMessages[0].content)).toBe(true);
|
|
205
|
+
const content = modifiedMessages[0].content;
|
|
206
|
+
expect(content).toHaveLength(1);
|
|
207
|
+
expect(content[0].type).toBe("image_url");
|
|
208
|
+
expect(content[0].image_url.url).toBe(imageDataUrl);
|
|
209
|
+
});
|
|
186
210
|
it("should process tool messages with plain base64 string", () => {
|
|
187
211
|
const validPngBase64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";
|
|
188
212
|
const originalMessages = [];
|