openvibers/openvibe.actor Commits
The answer checker knows today's date, so a correct web answer about a recent release is not refused as 'in the future' (#107)
Changes
@@@ -45,7 +45,10 @@ const checkerFor = (agentId, checkers, opts) => checkersFor(agentId, checkers, o* Ask each checker in turn until one gives a verdict: a checker that answers nothing usable (a provider error, no JSON)* passes the turn to the next; only when none gives a verdict is the result unavailable (and never delivered).*/--async function check({ task, answer, sources = [], evidence = [], agentId, mode, checkers, signal }) {++async function check({ task, answer, sources = [], evidence = [], agentId, mode, checkers, signal, now = Date.now }) {++ // The checker knows today's date: without it, a model whose training ends earlier refused a correct web answer for a++ // release "dated Oct 21, 2026, which is in the future and plainly impossible" (2026-10-24, a task from Chat's Vibe).++ const today = new Date(now()).toISOString().slice(0, 10);const list = checkersFor(agentId, checkers, { mode, grounded: evidence.length > 0 });if (!list.length) return { ok: false, unavailable: true, reason: 'no model is available to check this answer', cost_usd: 0 };let cost = 0;@@@ -65,7 +68,7 @@ async function check({ task, answer, sources = [], evidence = [], agentId, mode,for (const c of list) {try {const r = await c.chat({-- messages: [{ role: 'system', content: SYSTEM }, { role: 'user', content: `=== Task ===\n${String(task).slice(0, 6000)}\n\n=== The agent's answer (prose to the person) ===\n${String(answer).slice(0, 12000)}\n=== End of answer ===${cited}${tools}` }],++ messages: [{ role: 'system', content: `${SYSTEM}\nToday is ${today} (UTC). A date on or before today is in the past or present, never in the future; recent releases, prices and events up to today are possible.` }, { role: 'user', content: `=== Task ===\n${String(task).slice(0, 6000)}\n\n=== The agent's answer (prose to the person) ===\n${String(answer).slice(0, 12000)}\n=== End of answer ===${cited}${tools}` }],json: true, maxTokens: 160, signal,});cost += r.cost_usd || 0;@@@ -154,7 +154,7 @@ function createEngine({ config, s, adapters, stream, webhooks = null, now = () =continue;}await setState(id, 'verifying', { agentForEvent: agentId });-- const verdict = await check({ task: row.task, answer: out.text, sources: out.sources || [], evidence: out.evidence || [], agentId, mode: row.mode, checkers: adapters.checkers, signal });++ const verdict = await check({ task: row.task, answer: out.text, sources: out.sources || [], evidence: out.evidence || [], agentId, mode: row.mode, checkers: adapters.checkers, signal, now: () => now() });await meter(verdict.cost_usd);await emit(id, { kind: 'output', step: 'check', agent: agentId, text: `${verdict.ok ? 'Checked' : 'Check failed'}${verdict.by ? ` by ${verdict.by}${verdict.cross ? '' : ' (same family)'}` : ''}: ${verdict.reason || ''}`.slice(0, 2000), is_error: !verdict.ok });if (verdict.ok) {nnew file mode 100644@@@ -0,0 +1,21 @@++'use strict';++// The answer checker (server/agents/check.js) is told today's date: a checker model whose training ends earlier refused++// a correct web answer for a release "dated Oct 21, 2026, which is in the future and plainly impossible" (2026-10-24, a++// web search from Vibe on openvibe.chat). The date is UTC, from the clock the engine passes.++const assert = require('assert');++const { check: checkAnswer } = require('../server/agents/check');++++(async () => {++ const seen = [];++ const deepseek = async (o) => { seen.push(o.messages[0].content); return { text: '{"ok": true, "reason": "addresses the task"}', cost_usd: 0.0001, model: 'deepseek-flash' }; };++ const verdict = await checkAnswer({++ task: 'What is the latest Node.js release?', answer: 'Node.js v24.22.1, released Oct 21, 2026 (https://nodejs.org).',++ sources: ['https://nodejs.org'], agentId: 'openai-agent', mode: 'balanced', checkers: { deepseek },++ now: () => Date.UTC(2026, 9, 24, 22, 30),++ });++ assert.strictEqual(verdict.ok, true);++ assert.strictEqual(verdict.by, 'deepseek');++ assert.ok(seen[0].includes('Today is 2026-10-24 (UTC). A date on or before today is in the past or present, never in the future'), seen[0].slice(-300));++ assert.ok(seen[0].startsWith('You check an AI agent\'s answer'), 'the rules come first, the date after them');++ console.log('check today: all checks passed');++})().catch((e) => { console.error(e); process.exit(1); });
@@ -45,7 +45,10 @@ const checkerFor = (agentId, checkers, opts) => checkersFor(agentId, checkers, o
@@ -45,7 +45,10 @@ const checkerFor = (agentId, checkers, opts) => checkersFor(agentId, checkers, o
* Ask each checker in turn until one gives a verdict: a checker that answers nothing usable (a provider error, no JSON)
* Ask each checker in turn until one gives a verdict: a checker that answers nothing usable (a provider error, no JSON)
* passes the turn to the next; only when none gives a verdict is the result unavailable (and never delivered).
* passes the turn to the next; only when none gives a verdict is the result unavailable (and never delivered).
*/
*/
-async function check({ task, answer, sources = [], evidence = [], agentId, mode, checkers, signal }) {
+async function check({ task, answer, sources = [], evidence = [], agentId, mode, checkers, signal, now = Date.now }) {
+ // The checker knows today's date: without it, a model whose training ends earlier refused a correct web answer for a
+ // release "dated Oct 21, 2026, which is in the future and plainly impossible" (2026-10-24, a task from Chat's Vibe).
+ const today = new Date(now()).toISOString().slice(0, 10);
const list = checkersFor(agentId, checkers, { mode, grounded: evidence.length > 0 });
const list = checkersFor(agentId, checkers, { mode, grounded: evidence.length > 0 });
if (!list.length) return { ok: false, unavailable: true, reason: 'no model is available to check this answer', cost_usd: 0 };
if (!list.length) return { ok: false, unavailable: true, reason: 'no model is available to check this answer', cost_usd: 0 };
let cost = 0;
let cost = 0;
@@ -65,7 +68,7 @@ async function check({ task, answer, sources = [], evidence = [], agentId, mode,
@@ -65,7 +68,7 @@ async function check({ task, answer, sources = [], evidence = [], agentId, mode,
for (const c of list) {
for (const c of list) {
try {
try {
const r = await c.chat({
const r = await c.chat({
- messages: [{ role: 'system', content: SYSTEM }, { role: 'user', content: `=== Task ===\n${String(task).slice(0, 6000)}\n\n=== The agent's answer (prose to the person) ===\n${String(answer).slice(0, 12000)}\n=== End of answer ===${cited}${tools}` }],
+ messages: [{ role: 'system', content: `${SYSTEM}\nToday is ${today} (UTC). A date on or before today is in the past or present, never in the future; recent releases, prices and events up to today are possible.` }, { role: 'user', content: `=== Task ===\n${String(task).slice(0, 6000)}\n\n=== The agent's answer (prose to the person) ===\n${String(answer).slice(0, 12000)}\n=== End of answer ===${cited}${tools}` }],
json: true, maxTokens: 160, signal,
json: true, maxTokens: 160, signal,
});
});
cost += r.cost_usd || 0;
cost += r.cost_usd || 0;
@@ -154,7 +154,7 @@ function createEngine({ config, s, adapters, stream, webhooks = null, now = () =
@@ -154,7 +154,7 @@ function createEngine({ config, s, adapters, stream, webhooks = null, now = () =
continue;
continue;
}
}
await setState(id, 'verifying', { agentForEvent: agentId });
await setState(id, 'verifying', { agentForEvent: agentId });
- const verdict = await check({ task: row.task, answer: out.text, sources: out.sources || [], evidence: out.evidence || [], agentId, mode: row.mode, checkers: adapters.checkers, signal });
+ const verdict = await check({ task: row.task, answer: out.text, sources: out.sources || [], evidence: out.evidence || [], agentId, mode: row.mode, checkers: adapters.checkers, signal, now: () => now() });
await meter(verdict.cost_usd);
await meter(verdict.cost_usd);
await emit(id, { kind: 'output', step: 'check', agent: agentId, text: `${verdict.ok ? 'Checked' : 'Check failed'}${verdict.by ? ` by ${verdict.by}${verdict.cross ? '' : ' (same family)'}` : ''}: ${verdict.reason || ''}`.slice(0, 2000), is_error: !verdict.ok });
await emit(id, { kind: 'output', step: 'check', agent: agentId, text: `${verdict.ok ? 'Checked' : 'Check failed'}${verdict.by ? ` by ${verdict.by}${verdict.cross ? '' : ' (same family)'}` : ''}: ${verdict.reason || ''}`.slice(0, 2000), is_error: !verdict.ok });
if (verdict.ok) {
if (verdict.ok) {
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+'use strict';
+// The answer checker (server/agents/check.js) is told today's date: a checker model whose training ends earlier refused
+// a correct web answer for a release "dated Oct 21, 2026, which is in the future and plainly impossible" (2026-10-24, a
+// web search from Vibe on openvibe.chat). The date is UTC, from the clock the engine passes.
+const assert = require('assert');
+const { check: checkAnswer } = require('../server/agents/check');
+
+(async () => {
+ const seen = [];
+ const deepseek = async (o) => { seen.push(o.messages[0].content); return { text: '{"ok": true, "reason": "addresses the task"}', cost_usd: 0.0001, model: 'deepseek-flash' }; };
+ const verdict = await checkAnswer({
+ task: 'What is the latest Node.js release?', answer: 'Node.js v24.22.1, released Oct 21, 2026 (https://nodejs.org).',
+ sources: ['https://nodejs.org'], agentId: 'openai-agent', mode: 'balanced', checkers: { deepseek },
+ now: () => Date.UTC(2026, 9, 24, 22, 30),
+ });
+ assert.strictEqual(verdict.ok, true);
+ assert.strictEqual(verdict.by, 'deepseek');
+ assert.ok(seen[0].includes('Today is 2026-10-24 (UTC). A date on or before today is in the past or present, never in the future'), seen[0].slice(-300));
+ assert.ok(seen[0].startsWith('You check an AI agent\'s answer'), 'the rules come first, the date after them');
+ console.log('check today: all checks passed');
+})().catch((e) => { console.error(e); process.exit(1); });