feat: make DAVE Telegram chat conversational
All checks were successful
Codex Template Compliance / template-compliance (pull_request) Successful in 8s
Build / test-and-image (pull_request) Successful in 52s

This commit is contained in:
2026-07-07 18:46:44 +02:00
parent c0fb9d1e66
commit a7f3f36d2b
10 changed files with 244 additions and 35 deletions

View File

@@ -1,4 +1,5 @@
import { TerminalToolRegistry } from './terminal-agent.mjs';
import { safeFetch } from '../../apis/utils/fetch.mjs';
export function createTerminalToolRegistry({
getData,
@@ -49,6 +50,39 @@ export function createTerminalToolRegistry({
.slice(0, limit)
.map(item => ({ title: clean(item.headline || item.title || item.text, 400), source: clean(item.source, 100), url: clean(item.url, 500) || null, timestamp: item.timestamp || item.date || null }));
}),
tool('web_search', 'Search the public web/news through GDELT for fresh corroborating evidence. Arguments: query, limit, hours.', { query: 'string', limit: 'number', hours: 'number' }, async args => {
const query = clean(args.query, 160);
if (!query) return { error: 'query_required', results: [] };
const limit = bounded(args.limit, 1, 10, 5);
const hours = bounded(args.hours, 1, 168, 48);
const start = new Date(Date.now() - hours * 60 * 60 * 1000).toISOString().replace(/[-:TZ.]/g, '').slice(0, 14);
const params = new URLSearchParams({
query,
mode: 'artlist',
format: 'json',
maxrecords: String(limit),
sort: 'datedesc',
startdatetime: start,
});
const data = await safeFetch(`https://api.gdeltproject.org/api/v2/doc/doc?${params}`, {
timeout: 20000,
retries: 1,
source: 'GDELT-WebSearch',
});
const articles = Array.isArray(data?.articles) ? data.articles : [];
return {
query,
windowHours: hours,
results: articles.slice(0, limit).map(item => ({
title: clean(item.title, 300),
source: clean(item.sourceCommonName || item.domain || item.sourceCountry, 120),
url: clean(item.url, 500) || null,
timestamp: item.seendate || item.datetime || null,
language: item.language || null,
})),
error: data?.error || null,
};
}),
tool('search_memory', 'Search persisted cross-sweep events. Arguments: query, limit.', { query: 'string', limit: 'number' }, async args => intelligenceStore?.queryMemory({ q: clean(args.query, 120), limit: bounded(args.limit, 1, 25, 8) }) || { available: false }),
tool('list_predictions', 'List persisted predictions and their current outcome states. Arguments: state, limit.', { state: 'string', limit: 'number' }, async args => intelligenceStore?.listPredictions({ state: clean(args.state, 30) || null, limit: bounded(args.limit, 1, 25, 8) }) || { available: false }),
tool('get_scenarios', 'Inspect current scenario watchlist states and confidence.', {}, async (_args, runtime) => {