feat: add local agent MCP tools and optional source-grounded AI answers
Core CI / core (ubuntu-latest) (push) Failing after 3m6s
Core CI / core (macos-latest) (push) Canceled after 0s
Core CI / core (windows-latest) (push) Canceled after 0s
Core CI / desktop (ubuntu-latest) (push) Successful in 5m41s
Core CI / desktop (macos-latest) (push) Canceled after 0s
Core CI / desktop (windows-latest) (push) Canceled after 0s

This commit is contained in:
karl committed 2026-10-12 20:28:38 +02:00
1 parent 70746ef428
commit f5b03c6fb0
27 files changed
+2988 -13

No files matched your search

+33
View File
@@ -0,0 +1,33 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import {AiRevision,aiConfigurationProblem,aiQuestionProblem,aiEndpointLabel,aiSourceEligible} from '../src/ai-state.ts';
const config=()=>({enabled:false,base_url:'',model:'',api_key:null});
test('optional generation is disabled initially and requires an explicit endpoint/model',()=>{
assert.match(aiConfigurationProblem(config()),/disabled/);
assert.match(aiConfigurationProblem({...config(),enabled:true}),/endpoint/);
assert.equal(aiConfigurationProblem({...config(),enabled:true,base_url:'http://localhost:1234/v1',model:'local-model'}),null);
assert.equal(aiConfigurationProblem({...config(),enabled:true,base_url:'https://chosen.example/v1',model:'chosen-model',api_key:'session-key'}),null);
});
test('unsafe URL credentials and query parameters cannot leak through configuration errors',()=>{
const secret='private-session-key';
for(const base_url of [`https://user:${secret}@example.com/v1`,`https://example.com/v1?key=${secret}`,'file:///secret']){
const error=aiConfigurationProblem({...config(),enabled:true,base_url,model:'m'});
assert.ok(error);assert.ok(!error.includes(secret));
}
assert.equal(aiEndpointLabel(`https://user:${secret}@example.com/v1?key=${secret}`),'https://example.com');
});
test('UTF8 byte budgets and actual text source types gate explicit questions',()=>{
assert.ok(aiQuestionProblem('界'.repeat(700)));
assert.equal(aiQuestionProblem('What notice is required?'),null);
assert.equal(aiSourceEligible({kind:'page',number:2}),true);
assert.equal(aiSourceEligible({kind:'timestamp_ms',number:100}),false);
assert.equal(aiSourceEligible({kind:'page',number:2},true),false);
assert.equal(aiSourceEligible(undefined),false);
});
test('selection/configuration changes invalidate older preparation and answers',()=>{
const revision=new AiRevision();revision.select('first:page2');const old=revision.current();
revision.select('second:page1');assert.equal(revision.accepts(old),false);
const selected=revision.current();revision.select('second:page1');assert.equal(revision.accepts(selected),true);
revision.invalidate();assert.equal(revision.accepts(selected),false);
});