fix(ai): revert thinkingBudget to thinkingBudgetTokens

This commit is contained in:
2026-05-19 15:49:15 -07:00
parent 7c45fdc5cc
commit e12882d13b
6 changed files with 0 additions and 346 deletions

View File

@@ -1,48 +0,0 @@
const fs = require('fs');
const file = 'vibn-frontend/app/api/mcp/route.ts';
let code = fs.readFileSync(file, 'utf8');
// 1. Fix toolFsWrite
const oldFsWriteReturn = ` return NextResponse.json({
result: { path, bytesWritten: Buffer.byteLength(content, "utf8") },
});`;
const newFsWriteReturn = ` const { createHash } = require('crypto');
const bytes = Buffer.byteLength(content, "utf8");
const sha256 = createHash("sha256").update(content, "utf8").digest("hex");
return NextResponse.json({
result: { ok: true, path, bytes, sha256 },
});`;
code = code.replace(oldFsWriteReturn, newFsWriteReturn);
// 2. Fix toolFsEdit
const oldFsEditCmd = `const cmd = \`python3 -c "$(printf %s \${shq(pyB64)} | base64 -d)" <<< "$(printf %s \${shq(b64)} | base64 -d)"\`;`;
const newFsEditCmd = `const cmd = \`python3 -c "$(printf %s \${shq(pyB64)} | base64 -d)" <<< "$(printf %s \${shq(b64)} | base64 -d)" && echo "---" && sha256sum \${shq(path)} | cut -d' ' -f1 && wc -c < \${shq(path)}\`;`;
code = code.replace(oldFsEditCmd, newFsEditCmd);
const oldFsEditReturn = ` return NextResponse.json({
result: { path, replacements: parseInt(r.stdout.trim() || "0", 10) },
});`;
const newFsEditReturn = ` const stdoutParts = r.stdout.split('---');
const replacementsStr = stdoutParts[0].trim();
const hashAndSize = stdoutParts[1] ? stdoutParts[1].trim().split('\\n') : [];
return NextResponse.json({
result: {
ok: true,
path,
replacements: parseInt(replacementsStr || "0", 10),
sha256: hashAndSize[0] ? hashAndSize[0].trim() : undefined,
bytes: hashAndSize[1] ? parseInt(hashAndSize[1].trim(), 10) : undefined
},
});`;
code = code.replace(oldFsEditReturn, newFsEditReturn);
fs.writeFileSync(file, code);
console.log("Patched toolFsWrite and toolFsEdit");

View File

@@ -1,82 +0,0 @@
const fs = require('fs');
const file = 'vibn-frontend/app/api/mcp/route.ts';
let code = fs.readFileSync(file, 'utf8');
const oldNormalize = `function normalizeFsPath(p: string): string | NextResponse {
if (!p || typeof p !== "string") {
return NextResponse.json(
{ error: 'Param "path" is required' },
{ status: 400 },
);
}
let abs: string;
if (p.startsWith("/")) {
abs = p;
} else {
abs = \`\${FS_ROOT}/\${p}\`.replace(/\\/+/g, "/");
}
// Disallow .. traversal that escapes /workspace.
const norm = abs.replace(/\\/[^/]+\\/\\.\\.(?=\\/|$)/g, "").replace(/\\/+/g, "/");
if (!norm.startsWith(FS_ROOT) && norm !== FS_ROOT) {
return NextResponse.json(
{
error: \`Path "\${p}" is outside \${FS_ROOT}; use shell.exec for system paths.\`,
},
{ status: 400 },
);
}
return norm;
}`;
const newNormalize = `function normalizeFsPath(
p: string,
projectSlug?: string,
): string | NextResponse {
if (!p || typeof p !== "string") {
return NextResponse.json(
{ error: 'Param "path" is required' },
{ status: 400 },
);
}
const projectRoot = projectSlug ? \`\${FS_ROOT}/\${projectSlug}\` : FS_ROOT;
let abs: string;
if (p.startsWith("/")) {
abs = p;
} else {
abs = \`\${projectRoot}/\${p}\`.replace(/\\/+/g, "/");
}
const norm = abs.replace(/\\/[^/]+\\/\\.\\.(?=\\/|$)/g, "").replace(/\\/+/g, "/");
// When projectSlug is set, REJECT paths outside the project root.
if (projectSlug) {
if (!norm.startsWith(projectRoot) && norm !== projectRoot) {
return NextResponse.json(
{
ok: false,
error: \`PATH_OUTSIDE_PROJECT: path "\${p}" resolves to "\${norm}" which is outside the active project at "\${projectRoot}". Did you mean "\${projectRoot}/\${p.replace(/^\\/+/, "")}"?\`,
},
{ status: 400 },
);
}
} else {
// Workspace-level fallback (legacy behaviour)
if (!norm.startsWith(FS_ROOT) && norm !== FS_ROOT) {
return NextResponse.json(
{ error: \`Path "\${p}" is outside \${FS_ROOT}; use shell.exec for system paths.\` },
{ status: 400 },
);
}
}
return norm;
}`;
code = code.replace(oldNormalize, newNormalize);
code = code.replace(/const path = normalizeFsPath\(String\(params\.path \?\? ""\)\);/g, 'const path = normalizeFsPath(String(params.path ?? ""), project.slug);');
code = code.replace(/const path = normalizeFsPath\(String\(params\.path \?\? "\/workspace"\)\);/g, 'const path = normalizeFsPath(String(params.path ?? "/workspace"), project.slug);');
code = code.replace(/const cwd = normalizeFsPath\(String\(params\.cwd \?\? "\/workspace"\)\);/g, 'const cwd = normalizeFsPath(String(params.cwd ?? "/workspace"), project.slug);');
code = code.replace(/const targetPath = normalizeFsPath\(String\(params\.targetPath \?\? ""\)\);/g, 'const targetPath = normalizeFsPath(String(params.targetPath ?? ""), project.slug);');
fs.writeFileSync(file, code);
console.log("Patched normalizeFsPath with projectSlug scoping");

View File

@@ -1,73 +0,0 @@
const fs = require('fs');
const file = 'vibn-frontend/app/api/chat/route.ts';
let code = fs.readFileSync(file, 'utf8');
// Fix 4: apps_containers_list -> apps_containers_ps
code = code.replace(/apps_containers_list \{ uuid \}/g, 'apps_containers_ps { uuid }');
// Fix 5: Soften ok field rule
const oldOkRule = `- **Trust the \\\`ok\\\` field.** Every tool result carries \\\`ok: true | false\\\`. If \\\`ok\\\` is false (or \\\`exitCode\\\` is non-zero, or \\\`healthCheck.status\\\` is >= 400), the operation FAILED. Do not describe a failed operation as successful. Surface the error verbatim and propose a next step.`;
const newOkRule = `- **Read tool results carefully.** A tool FAILED when ANY of these signals are present: \\\`ok: false\\\`, \\\`error: "..."\\\`, a non-zero \\\`exitCode\\\`, or a \\\`healthCheck.status\\\` >= 400. If NONE of those signals are present, look at the actual content of the response to decide whether the operation succeeded. Many read-only tools return data directly without an \\\`ok\\\` field — that's not a failure.`;
code = code.replace(oldOkRule, newOkRule);
// Fix 7: Path conventions
const oldDirRule = `- **Directory:** the tool resolves paths relative to the active project root — you can pass \\\`command: "npm run dev"\\\` directly. (If you need to manually \\\`cd\\\`, use the project slug.)`;
const newDirRule = `- **Directory:** Tool paths are scoped to your project root automatically. Pass \\\`command: "npm run dev"\\\` directly — no \\\`cd\\\` prefix needed. The tool rejects any \\\`fs_*\\\` write outside \\\`/workspace/<slug>/\\\`.`;
code = code.replace(oldDirRule, newDirRule);
const oldPathConv = `**fs_* path convention for this project:** Pass paths relative to \\\`/workspace/\${activeProject.slug ?? "<slug>"}/\\\` — e.g. \\\`src/app/page.tsx\\\`, not \\\`/workspace/\${activeProject.slug ?? "<slug>"}/src/app/page.tsx\\\` and not \\\`getacquired-style/src/app/page.tsx\\\`. The tool layer rejects paths outside the project root.`;
const newPathConv = `**Path convention for fs_* tools:** Pass paths relative to the project root — \\\`src/app/page.tsx\\\`, NOT \\\`/workspace/\${activeProject.slug ?? "<slug>"}/src/app/page.tsx\\\` and NOT \\\`\${activeProject.slug ?? "<slug>"}/src/app/page.tsx\\\`. The tool layer rejects writes outside the project root with a \\\`PATH_OUTSIDE_PROJECT\\\` error suggesting the corrected path.`;
code = code.replace(oldPathConv, newPathConv);
// Fix 8: fs_tree recommendation
const devContainerStart = `**Start a coding session:** \\\`devcontainer_ensure { projectId }\\\` (idempotent; first call ~10s, then instant).`;
const devContainerStartNew = `**Start a coding session:** \\\`devcontainer_ensure { projectId }\\\` (idempotent; first call ~10s, then instant).
**Orient yourself once.** On the first code-modifying turn of a chat, call \\\`fs_tree\\\` once to learn the repo layout. Don't re-run it on every turn — the layout doesn't change between user messages.`;
code = code.replace(devContainerStart, devContainerStartNew);
// Fix 9: browser_console
const visualQaBlock = `**Visual QA:** \\\`request_visual_qa { targetPath }\\\` critiques a UI file against a 5-dim design rubric. **Call this whenever you modify visual UI code** before returning the \\\`previewUrl\\\`. If it returns actionable issues, fix them with \\\`fs_edit\\\` before ending the turn. Skip for backend / SQL / config / non-visual changes.`;
const visualQaBlockNew = `**Visual QA:** \\\`request_visual_qa { targetPath }\\\` critiques a UI file against a 5-dim design rubric. **Call this whenever you modify visual UI code** before returning the \\\`previewUrl\\\`. If it returns actionable issues, fix them with \\\`fs_edit\\\` before ending the turn. Skip for backend / SQL / config / non-visual changes.
**Verify the page actually renders:**
- After \\\`dev_server_start\\\` returns a \\\`previewUrl\\\` AND \\\`healthCheck.status === 200\\\`, for any UI-facing turn, call \\\`browser_console { url: previewUrl }\\\` to capture frontend console errors. Hydration errors, missing assets, and uncaught exceptions show up here even when the server is technically "running".
- If \\\`browser_console\\\` returns errors, fix them with \\\`fs_edit\\\` before declaring done. A green \\\`healthCheck\\\` plus a clean console is the real "done" signal for UI work.
- Skip this for backend / SQL / config-only changes.`;
code = code.replace(visualQaBlock, visualQaBlockNew);
// Fix 10: Market research stack
const commonQuestionsBlock = `## Common questions → tools
- "What is project X?" → \\\`projects_get { projectId }\\\`
- "What's running / has a domain?" → \\\`apps_list { projectId }\\\` (or workspace-wide without projectId)
- "Show logs / containers / env" → \\\`apps_list\\\` to resolve uuid, then \\\`apps_logs\\\` / \\\`apps_containers_list\\\` / \\\`apps_envs_list\\\`
- "Find an OSS X" → \\\`github_search\\\` (include \\\`license:mit\\\` by default), then \\\`github_file\\\` to read README / docker-compose
- "What do the docs say about Y?" → \\\`http_fetch\\\``;
// Oops, we changed apps_containers_list to apps_containers_ps in Fix 4, so let's match the updated one:
const commonQuestionsBlockMatched = `## Common questions → tools
- "What is project X?" → \\\`projects_get { projectId }\\\`
- "What's running / has a domain?" → \\\`apps_list { projectId }\\\` (or workspace-wide without projectId)
- "Show logs / containers / env" → \\\`apps_list\\\` to resolve uuid, then \\\`apps_logs\\\` / \\\`apps_containers_ps\\\` / \\\`apps_envs_list\\\`
- "Find an OSS X" → \\\`github_search\\\` (include \\\`license:mit\\\` by default), then \\\`github_file\\\` to read README / docker-compose
- "What do the docs say about Y?" → \\\`http_fetch\\\``;
const marketResearchBlock = `
## Helping the user pick what to build
Vibn has a market-research toolkit for non-technical founders who need data on their target niche. Use it when the user is undecided, validating an idea, or comparing markets:
- **"How big is the market for X in <location>?"** → \\\`market_categories_suggest { niche }\\\` to propose Google Business categories, then \\\`market_research_run\\\` after the user approves. Returns TAM count, sample domains, and review data. NOTE: \\\`market_research_run\\\` costs real money — always confirm with the user and pass \\\`user_explicitly_approved: true\\\`.
- **"What are competitors spending on Google Ads?"** → \\\`market_seo_analyze { domain }\\\`. Returns organic traffic, paid traffic, ad spend, and top paid keywords. Use to tell the user how aggressive a market is.
- **"What software do these businesses already use?"** → \\\`tech_stack_analyze { urls, software_category_id }\\\`. Detects WordPress, Shopify, named competitors, and any custom domains/scripts you pass. Use to find "X businesses use WordPress but lack Y" market gaps.
- **"What are customers complaining about?"** → \\\`market_aggregate_insights { category, location }\\\`. Returns top review topics — use the actual words customers use as marketing copy and value-prop seeds.
- **"Who are the players in this niche?"** → \\\`market_competitor_research { niche }\\\`. Returns proprietary competitors with pricing AND open-source alternatives that could be forked.
These are conversational research tools — they don't build anything. Use them BEFORE scaffolding when the user is exploring direction; SKIP them once the user has committed to building.`;
code = code.replace(commonQuestionsBlockMatched, commonQuestionsBlockMatched + marketResearchBlock);
fs.writeFileSync(file, code);
console.log("Applied Phase 2 and 3 prompt fixes");

View File

@@ -1,19 +0,0 @@
const fs = require('fs');
const file = 'vibn-agent-runner/src/tools/context.ts';
let code = fs.readFileSync(file, 'utf8');
const newProps = ` coolify: {
apiUrl: string;
apiToken: string;
};
mcpToken: string;
vibnApiUrl: string;
projectId?: string;`;
code = code.replace(` coolify: {
apiUrl: string;
apiToken: string;
};`, newProps);
fs.writeFileSync(file, code);
console.log("Patched context.ts");

View File

@@ -1,69 +0,0 @@
const fs = require('fs');
const file = 'vibn-agent-runner/src/server.ts';
let code = fs.readFileSync(file, 'utf8');
// Update the type signature for the request body
const oldSig = ` } = req.body as {
sessionId?: string;
projectId?: string;
appName?: string;
appPath?: string;
giteaRepo?: string;
task?: string;
continueTask?: boolean;
autoApprove?: boolean;
coolifyAppUuid?: string;
};`;
const newSig = ` mcpToken, vibnApiUrl
} = req.body as {
sessionId?: string;
projectId?: string;
appName?: string;
appPath?: string;
giteaRepo?: string;
task?: string;
continueTask?: boolean;
autoApprove?: boolean;
coolifyAppUuid?: string;
mcpToken?: string;
vibnApiUrl?: string;
};`;
code = code.replace(oldSig, newSig);
const oldCtx = ` const ctx: ToolContext = {
workspaceRoot: repoRoot,
gitea: {
apiUrl: GITEA_API_URL,
apiToken: GITEA_API_TOKEN,
username: GITEA_USERNAME,
},
coolify: {
apiUrl: process.env.COOLIFY_API_URL || '',
apiToken: process.env.COOLIFY_API_TOKEN || '',
},
memoryUpdates: [],
};`;
const newCtx = ` const ctx: ToolContext = {
workspaceRoot: repoRoot,
gitea: {
apiUrl: GITEA_API_URL,
apiToken: GITEA_API_TOKEN,
username: GITEA_USERNAME,
},
coolify: {
apiUrl: process.env.COOLIFY_API_URL || '',
apiToken: process.env.COOLIFY_API_TOKEN || '',
},
mcpToken: mcpToken || '',
vibnApiUrl: vibnApiUrl || 'http://localhost:3000',
projectId,
memoryUpdates: [],
};`;
code = code.replace(oldCtx, newCtx);
fs.writeFileSync(file, code);
console.log("Patched Runner server.ts");

View File

@@ -1,55 +0,0 @@
const fs = require('fs');
const file = 'vibn-frontend/app/api/projects/[projectId]/agent/sessions/route.ts';
let code = fs.readFileSync(file, 'utf8');
// Inject the workspace API key fetching logic
if (!code.includes('listWorkspaceApiKeys')) {
code = code.replace(
'import { query } from "@/lib/db-postgres";',
'import { query } from "@/lib/db-postgres";\nimport { listWorkspaceApiKeys, mintWorkspaceApiKey, revealWorkspaceApiKey } from "@/lib/auth/workspace-auth";'
);
const injectCode = `
const wsResult = await query<{ workspace_id: string }>(
\`SELECT vibn_workspace_id as workspace_id FROM fs_projects WHERE id = $1 LIMIT 1\`,
[projectId]
);
if (!wsResult.length) {
return NextResponse.json({ error: "Project not found" }, { status: 404 });
}
const workspaceId = wsResult[0].workspace_id;
// Grab or mint a default API key for the runner to use
let mcpToken = "";
const keys = await listWorkspaceApiKeys(workspaceId);
let defaultKey = keys.find((k: any) => k.name === 'default' && !k.revoked_at);
if (!defaultKey) {
const minted = await mintWorkspaceApiKey({ workspaceId, name: 'default', createdBy: session.user.id, scopes: ['workspace:*'] });
mcpToken = minted.token;
} else {
const revealed = await revealWorkspaceApiKey(workspaceId, defaultKey.id);
if (revealed) mcpToken = revealed.token;
else {
const minted = await mintWorkspaceApiKey({ workspaceId, name: 'default', createdBy: session.user.id, scopes: ['workspace:*'] });
mcpToken = minted.token;
}
}
// Add VIBN_API_URL so the runner knows where to send MCP requests
const vibnApiUrl = process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000";
`;
code = code.replace(
'const sessionId = rows[0].id;',
'const sessionId = rows[0].id;\n' + injectCode
);
code = code.replace(
'coolifyAppUuid,\n }),',
'coolifyAppUuid,\n mcpToken,\n vibnApiUrl\n }),'
);
fs.writeFileSync(file, code);
console.log("Patched session route to forward MCP token");
}