openvibers/openvibe.codes Commits

Apply model plan overrides from Dock task requests (#416)

OP OpenVibers committed 2 days ago · aadf140a62 · 2 files, +24 −2

* Apply model plan overrides from Dock task requests

* Merge remote-tracking branch 'origin/main' into fix/codes-dock-model-plan

Changes

ddiff --git a/server/http/tasks-api.js b/server/http/tasks-api.js
iindex b876f1a..6bd8cc4 100644
---- a/server/http/tasks-api.js
++++ b/server/http/tasks-api.js
@@@ -270,7 +270,7 @@ function createTasksApi({ config, store, keys, run, harnesses, actorLimits, task
// Something new: OpenVibe AI builds it on openvibe.space, like the site's own handover. No Codes task is
// started: the answer is where to press Build. Files ride with a task, never with a handover.
if (mode === 'create') {
-- if (repoIn || named.length || uploaded.length) {
++ if (repoIn || named.length || uploaded.length || b.plan != null || b.preset != null) {
return problem(req, res, 422, 'codes.create_invalid', 'Something new starts in OpenVibe AI, where you can add the repository and the files there.');
}
return res.json({ id: null, url: start.spaceHref({ text }) });
@@@ -327,6 +327,13 @@ function createTasksApi({ config, store, keys, run, harnesses, actorLimits, task
|| (conductor ? await conductor.projectFor(token, p.subject) : null);
} catch { project = null; }
if (!project) return problem(req, res, 409, 'codes.no_project', 'Codes could not find or make a project for you on OpenVibe.Services: sign in again and retry.');
++ if (b.plan != null || b.preset != null) {
++ if (!modelPlans) return problem(req, res, 503, 'codes.model_plans_unavailable', 'model plans are unavailable');
++ try {
++ const selected = await modelPlans.select(p.subject, project, { plan: b.plan ?? null, preset: b.preset ?? null });
++ args = { ...args, plan: selected.plan, plan_source: selected.source, preset: selected.preset, model_fallbacks: selected.fallbacks };
++ } catch (e) { return problem(req, res, e.status || 500, e.code || 'codes.model_plan_invalid', e.message); }
++ }
const jobInput = (repo, prompt) => JSON.stringify({ repo, prompt, permission: 'edit' });
let firstRow = null;
try {
@@@ -335,7 +342,8 @@ function createTasksApi({ config, store, keys, run, harnesses, actorLimits, task
const names = targets.map((x) => x.repository.replace(/^OpenVibers\//, ''));
for (const [i, x] of targets.entries()) {
const note = `\n\n(This request spans ${names.join(', ')}. This task is the ${names[i]} part; the others are separate tasks. Change only what this repository needs, and keep the names and behaviour consistent with the other parts.)`;
-- const each = parseArgs(jobInput(x.url, `${text}${note}`.slice(0, 16000)));
++ const each = { ...parseArgs(jobInput(x.url, `${text}${note}`.slice(0, 16000))),
++ ...(args.plan ? { plan: args.plan, plan_source: args.plan_source, preset: args.preset, model_fallbacks: args.model_fallbacks } : {}) };
const row = await taskStore.start({ subject: p.subject, project, args: each, attachmentIds: i === 0 ? ids : [], mode: 'openvibe' });
if (!firstRow) firstRow = row;
}
ddiff --git a/test/model-plan-api.test.js b/test/model-plan-api.test.js
iindex 8ec79ba..62f81f8 100644
---- a/test/model-plan-api.test.js
++++ b/test/model-plan-api.test.js
@@@ -68,6 +68,20 @@ const { PRESETS } = require('../engine/model-plan');
assert.equal(page.status, 200);
assert.match(page.text, /Save model plan/);
});
++ await check('the Dock task shape forwards its plan or preset to the AI harness', async () => {
++ const request = { text: 'Fix the parser', mode: 'repo', repo: 'https://github.com/a/b' };
++ const chosen = await t.get('/api/v1/tasks', { as: ada, method: 'POST', json: { ...request, preset: 'Deep' } });
++ assert.equal(chosen.status, 201, chosen.text);
++ assert.equal(submitted.at(-1).args.plan.mode, 'pair');
++ assert.equal(submitted.at(-1).args.preset, 'Deep');
++ assert.equal(submitted.at(-1).args.plan_source, 'task');
++ const override = await t.get('/api/v1/tasks', { as: ada, method: 'POST', json: { ...request, plan: PRESETS.Fast } });
++ assert.equal(override.status, 201, override.text);
++ assert.equal(submitted.at(-1).args.plan.mode, 'single');
++ assert.equal(submitted.at(-1).args.plan_source, 'task');
++ const both = await t.get('/api/v1/tasks', { as: ada, method: 'POST', json: { ...request, plan: PRESETS.Fast, preset: 'Deep' } });
++ assert.equal(both.status, 422);
++ });
await check('weekly admin page is owner-only and tuning requires its button', async () => {
const other = await t.get('/admin/model-plans', { as: ada });
assert.equal(other.status, 403);