feat: add response cache and compact output mode
Response cache (api-client.ts):
- In-memory TTL cache (5 min default) avoids duplicate API calls
when LLMs repeat the same tool call within a conversation.
- Cache key = full URL with params; only 200 OK responses are cached.
- Exposed via client.cache for manual clear() if needed.
- Configurable TTL via TorrentClawClient constructor.
Compact mode (search_content tool):
- New compact boolean parameter (default: false).
- When true, magnet links use short form magnet:?xt=urn:btih:{hash}
(~60 chars) instead of full magnets with trackers (~300 chars).
- Short magnets are still valid and clickable (DHT peer discovery).
- Also generates a magnet from info_hash even when API returns null.
- Saves ~10K chars per typical search (5 torrents x 10 results).
Tests: 100 total (15 new), all passing.
This commit is contained in:
parent
e011c0f63e
commit
bf459740fe
5 changed files with 349 additions and 9 deletions
|
|
@ -396,6 +396,128 @@ describe("formatSearchResults", () => {
|
|||
expect(text).toContain("10.0 GB");
|
||||
});
|
||||
|
||||
it("compact mode uses short magnet links", () => {
|
||||
const hash = "aaf1e71c0a0e3b1c0f1a2b3c4d5e6f7a8b9c0d1e";
|
||||
const fullMagnet = `magnet:?xt=urn:btih:${hash}&dn=Inception&tr=udp://tracker.example.com:6969&tr=udp://tracker2.example.com:6969`;
|
||||
const response: SearchResponse = {
|
||||
total: 1,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
results: [
|
||||
{
|
||||
id: 42,
|
||||
imdbId: null,
|
||||
tmdbId: null,
|
||||
contentType: "movie",
|
||||
title: "Inception",
|
||||
titleOriginal: null,
|
||||
year: 2010,
|
||||
overview: null,
|
||||
posterUrl: null,
|
||||
backdropUrl: null,
|
||||
genres: null,
|
||||
ratingImdb: null,
|
||||
ratingTmdb: null,
|
||||
hasTorrents: true,
|
||||
torrents: [
|
||||
{
|
||||
infoHash: hash,
|
||||
quality: "1080p",
|
||||
codec: null,
|
||||
sourceType: null,
|
||||
sizeBytes: "2147483648",
|
||||
seeders: 100,
|
||||
leechers: 5,
|
||||
magnetUrl: fullMagnet,
|
||||
source: "yts",
|
||||
qualityScore: 85,
|
||||
uploadedAt: null,
|
||||
languages: [],
|
||||
audioCodec: null,
|
||||
hdrType: null,
|
||||
releaseGroup: null,
|
||||
isProper: null,
|
||||
isRepack: null,
|
||||
isRemastered: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const compact = formatSearchResults(response, { compact: true });
|
||||
const full = formatSearchResults(response);
|
||||
|
||||
// Compact: short magnet with just the hash
|
||||
expect(compact).toContain(`magnet:?xt=urn:btih:${hash}`);
|
||||
// Compact: no tracker URLs
|
||||
expect(compact).not.toContain("tracker.example.com");
|
||||
// Full: includes the full magnet URL with trackers
|
||||
expect(full).toContain(fullMagnet);
|
||||
// Compact output should be shorter
|
||||
expect(compact.length).toBeLessThan(full.length);
|
||||
// Both include the info hash
|
||||
expect(compact).toContain(`Info hash: ${hash}`);
|
||||
expect(full).toContain(`Info hash: ${hash}`);
|
||||
});
|
||||
|
||||
it("compact mode generates magnet even when magnetUrl is null", () => {
|
||||
const hash = "b".repeat(40);
|
||||
const response: SearchResponse = {
|
||||
total: 1,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
results: [
|
||||
{
|
||||
id: 1,
|
||||
imdbId: null,
|
||||
tmdbId: null,
|
||||
contentType: "movie",
|
||||
title: "No Magnet",
|
||||
titleOriginal: null,
|
||||
year: 2024,
|
||||
overview: null,
|
||||
posterUrl: null,
|
||||
backdropUrl: null,
|
||||
genres: null,
|
||||
ratingImdb: null,
|
||||
ratingTmdb: null,
|
||||
hasTorrents: true,
|
||||
torrents: [
|
||||
{
|
||||
infoHash: hash,
|
||||
quality: "720p",
|
||||
codec: null,
|
||||
sourceType: null,
|
||||
sizeBytes: "1073741824",
|
||||
seeders: 10,
|
||||
leechers: 0,
|
||||
magnetUrl: null,
|
||||
source: "test",
|
||||
qualityScore: 50,
|
||||
uploadedAt: null,
|
||||
languages: [],
|
||||
audioCodec: null,
|
||||
hdrType: null,
|
||||
releaseGroup: null,
|
||||
isProper: null,
|
||||
isRepack: null,
|
||||
isRemastered: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const compact = formatSearchResults(response, { compact: true });
|
||||
const full = formatSearchResults(response);
|
||||
|
||||
// Compact always generates a magnet from info_hash
|
||||
expect(compact).toContain(`magnet:?xt=urn:btih:${hash}`);
|
||||
// Full mode: no magnet when magnetUrl is null
|
||||
expect(full).not.toContain("Magnet:");
|
||||
});
|
||||
|
||||
it("shows streaming info when available", () => {
|
||||
const response: SearchResponse = {
|
||||
total: 1,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue