fix: enforce security profile language across DAVE
All checks were successful
Codex Template Compliance / template-compliance (pull_request) Successful in 10s
Build / test-and-image (pull_request) Successful in 56s

This commit is contained in:
2026-07-06 09:14:55 +02:00
parent dce8c278a5
commit 73af4abfa2
9 changed files with 98 additions and 17 deletions

View File

@@ -49,9 +49,11 @@ test('dynamic presence sends a grounded message and persists a variable next eva
const now = new Date('2026-07-06T12:00:00Z');
const outcome = await presence.tick(now);
assert.deepEqual(outcome, { sent: true, reason: 'sent' });
assert.match(messages[0], /^\[DAVE \/\/ ACTIVE\]/);
assert.match(messages[0], /^\[DAVE \/\/ AKTIV\]/);
assert.match(messages[0], /Belege:/);
assert.match(calls[0].prompt, /dynamic presence evaluation, not a fixed scheduled briefing/i);
assert.equal(calls[0].options.mode, 'presence');
assert.equal(calls[0].options.preferredLanguage, 'de');
assert.equal(presence.status().sentToday, 1);
assert.equal(presence.status().nextEvaluationAt, '2026-07-06T12:22:30.000Z');
assert.equal((await presence.tick(new Date('2026-07-06T12:05:00Z'))).reason, 'not_due');

View File

@@ -44,6 +44,24 @@ test('Telegram AI chat reports missing LLM configuration', async () => {
assert.match(await assistant.reply('hello', { chatId: 1 }), /unavailable/i);
});
test('Telegram AI chat enforces the encrypted profile language in provider prompts', async () => {
const calls = [];
const assistant = new TelegramChatAssistant({
provider: {
isConfigured: true,
async complete(systemPrompt, userMessage) {
calls.push({ systemPrompt, userMessage });
return { text: 'Antwort auf Deutsch.' };
},
},
getPreferredLanguage: () => 'de',
});
assert.equal(await assistant.reply('Kurzer Lagecheck', { chatId: 42 }), 'Antwort auf Deutsch.');
assert.match(calls[0].systemPrompt, /REQUIRED RESPONSE LANGUAGE: German \(de\)/);
assert.match(calls[0].userMessage, /All user-visible prose in the final answer must be German/);
});
test('Telegram chat context is compact and operationally useful', () => {
const context = JSON.parse(buildTelegramChatContext({
meta: { generatedAt: '2026-07-05T10:00:00Z' },

View File

@@ -131,6 +131,30 @@ test('repeated tool calls during finalization fail closed without leaking protoc
assert.equal(result.notify, false);
});
test('agent propagates preferred German language through tool and finalization prompts', async () => {
const prompts = [];
let call = 0;
const agent = new TerminalAgent({
provider: {
isConfigured: true,
async complete(systemPrompt) {
prompts.push(systemPrompt);
call++;
return call === 1
? { text: JSON.stringify({ type: 'tool_call', tool: 'get_status', arguments: {}, rationale: 'Status prüfen' }) }
: { text: JSON.stringify({ type: 'final', answer: 'Die Systemlage ist stabil.', confidence: 'high', evidence: [], notify: false, priority: 'routine' }) };
},
},
registry: new TerminalToolRegistry([{ name: 'get_status', handler: async () => ({ status: 'healthy' }) }]),
maxSteps: 1,
});
const result = await agent.run('Lage?', { preferredLanguage: 'de' });
assert.equal(result.answer, 'Die Systemlage ist stabil.');
assert.match(prompts[0], /REQUIRED RESPONSE LANGUAGE: German \(de\)/);
assert.match(prompts[1], /REQUIRED RESPONSE LANGUAGE: German \(de\)/);
});
test('scheduled presence cannot create pending mutating actions', async () => {
let executions = 0;
const agent = new TerminalAgent({