Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ Each answer's log line shows the cached percentage.
points, Sharesight holdings flattened into tables, markdown tables (Yahoo) squeezed (padding and rule
rows dropped, `1.20067e+11` shown as `120.067B`, NaN as `-`), results capped at 12,000 characters; an
identical call within one request gets a short "same as earlier" note instead of a second copy;
`cache_ttl` shares results between concurrent users.
`cache_ttl` shares results between users: 30 seconds for Yahoo, 30 minutes for Sharesight (so a portfolio
answer can be up to 30 minutes old).
- **Compact history:** stored HTML is shown to the model as plain text (ticker links become the
symbol, tags and Yahoo URLs dropped), lines cut to 240 characters and the bot's own to 160.
- **Smaller prompts:** the system prompt is about half its previous size, the repeated instruction
Expand Down
3 changes: 2 additions & 1 deletion mcp_servers.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
],
"slim": "sharesight",
"gate": "portfolio",
"max_concurrent": 1
"max_concurrent": 1,
"cache_ttl": 1800
}
}
}
16 changes: 16 additions & 0 deletions tests/test_mcp.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
import json
from pathlib import Path
from types import SimpleNamespace as N

from lib.mcp.results import diet, slim_result, squeeze_tables, table_records, tidy_sharesight
Expand Down Expand Up @@ -112,6 +113,21 @@ async def test_call_slims_and_caches_identical_concurrent_calls():
assert len(s.session.calls) == 2


async def test_sharesight_results_are_cached_for_thirty_minutes(monkeypatch):
cfg = json.loads((Path(__file__).parent.parent / "mcp_servers.json").read_text())["mcpServers"]["sharesight"]
assert cfg["cache_ttl"] == 1800
clock = [1000.0]
monkeypatch.setattr("lib.mcp.server.time", N(monotonic=lambda: clock[0]))
s = make_server(cache_ttl=cfg["cache_ttl"])
await s.call("get_a", {"portfolio_id": 1})
clock[0] += 1799
await s.call("get_a", {"portfolio_id": 1})
assert len(s.session.calls) == 1 # still inside the 30 minutes
clock[0] += 2
await s.call("get_a", {"portfolio_id": 1})
assert len(s.session.calls) == 2 # expired, fetched again


async def test_no_cache_by_default_and_not_connected_message():
s = make_server()
await s.call("get_a", {})
Expand Down
Loading