fix: isolate visual tool failures from agent runs

This commit is contained in:
john
2026-07-27 19:20:23 +08:00
parent 7002007128
commit 17c59fde71
10 changed files with 444 additions and 16 deletions
+66
View File
@@ -20,6 +20,7 @@ async function withFakeGoosedSession(
const workingDir = fs.mkdtempSync(path.join(os.tmpdir(), 'memind-memory-v2-'));
const harnessEntries = [];
const replyBodies = [];
const startBodies = [];
const updateBodies = [];
let activeConversation = conversation;
let server;
@@ -32,6 +33,7 @@ async function withFakeGoosedSession(
const body = rawBody ? JSON.parse(rawBody) : {};
if (req.method === 'POST' && req.url === '/agent/start') {
startBodies.push(body);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ id: 'session-1' }));
return;
@@ -98,6 +100,7 @@ async function withFakeGoosedSession(
workingDir,
harnessEntries,
replyBodies,
startBodies,
updateBodies,
});
} finally {
@@ -1353,6 +1356,69 @@ test('submitSessionReplyForUser fails closed when historical image scrub is unsu
});
});
test('visual fallback session removes read_image while preserving the text task path', async () => {
await withFakeGoosedSession(async ({
apiTarget,
workingDir,
replyBodies,
startBodies,
}) => {
const baseAuth = createMemoryTestUserAuth(workingDir);
const userAuth = {
...baseAuth,
async getAgentSessionPolicy() {
return {
gooseMode: 'chat',
enableContextMemory: true,
extensionOverrides: [
{ name: 'memory', available_tools: [] },
{ name: 'developer', available_tools: ['read_image'] },
],
};
},
async ownsSession() {
return true;
},
async canUseChat() {
return { ok: true };
},
async getUserById() {
return { id: 'user-1' };
},
async resolveUserPolicies() {
return { unrestricted: true, policies: {} };
},
};
const proxy = createTkmindProxy({
apiTarget,
apiSecret: 'test-secret',
userAuth,
});
await proxy.startSessionForUser(
'user-1',
{ disableImageReading: true },
);
await proxy.submitSessionReplyForUser(
'user-1',
'session-1',
'request-visual-fallback',
{
id: 'message-visual-fallback',
role: 'user',
content: [{ type: 'text', text: '跳过视觉检查,继续修改页面' }],
},
{ disableImageReading: true },
);
assert.deepEqual(
startBodies[0].extension_overrides,
[{ name: 'memory', available_tools: [] }],
);
assert.equal(replyBodies.length, 1);
});
});
test('submitSessionReplyForUser applies the shared Qwen vision preprocessing path', async () => {
await withFakeGoosedSession(async ({ apiTarget, workingDir, replyBodies }) => {
const proxy = createTkmindProxy({