Skip to content

fix(memory): require a base_url for the hindsight backend - #301

Merged
yusiwen merged 1 commit into
masterfrom
fix/memory-requires-base-url
Oct 27, 2026
Merged

yusiwen merged 1 commit into
masterfrom
fix/memory-requires-base-url

Conversation

@yusiwen

@yusiwen yusiwen commented Oct 27, 2026

Copy link
Copy Markdown
Owner

What changed

  • agent/memory.go: the hard-coded https://memory.yusiwen.cn/dp-api default and the hard-coded
    hermes bank are gone. NewHTTPMemoryClient(baseURL, bank) now returns an error for an empty base
    URL, so a client cannot exist without an endpoint; the bank comes from the caller and falls back to
    default.
  • main.go: memoryStore passes memory.bank and lets the constructor fail; the composition root
    already logs a store it cannot build and runs without memory.
  • agent/memory_test.go: the two "default base" assertions are replaced by
    TestHTTPMemoryClientRequiresAnEndpoint (empty and blank rejected, the error names base_url, the
    bank defaults, a named bank survives), and the stub server's paths use a test bank.
  • memory_wiring_test.go: the hindsight case asserts the configured base and the bank, and a new test
    pins that a hindsight spec with no base_url is an error.
  • Docs: CODEBASE.md (endpoint required, bank from config), config.example.json ("'hindsight'
    requires base_url"), docs/memory-decision.md (the endpoint rule is enforced, not just stated), and
    docs/roadmap.md's B2 evidence keeps its baseline wording with a note that the default is gone.
  • Test count 1228 → 1230 in the two places that state it.

Why

{"memory": {"backend": "hindsight"}} — the backend named, no endpoint — built a client whose base URL
fell back to a hard-coded service. Every run would have sent its prompt to a deployment the user never
named, while the decision record promised that the endpoint is theirs to write. The code enforced the
"own config file" half of that sentence and not the "endpoint" half.

The bank had the same defect in miniature: memory.bank existed in the config, was parsed, was read by
nobody, and the client used one deployment's bank name. It now comes from the config.

Verification

  • go test ./... -count=1 → 16 packages ok; go vet and gofmt -l clean.
  • Mutation check: the empty-base refusal disabled → TestHTTPMemoryClientRequiresAnEndpoint fails with
    an empty base URL was accepted; restored, it passes.
  • grep -rn 'memory.yusiwen.cn' --include=*.go . → no hits; the only remaining mention is the roadmap's
    pinned B2 evidence line, which now says the default no longer exists.
  • git log --format='%h %G? %s' → G.

Honest scope

  • The OPENAI_API_KEY fallback in auth() is untouched: it is a separate item (S4 of [memory] Local store, wired recall, and one explicit writer #293) about which
    credential is sent, not where.
  • The adapter's recall/list decoders still read the old response fields (S4). This PR only removes the
    default endpoint and makes the config authoritative.
  • Existing configs that used backend: hindsight without a base_url were pointing at the author's
    service; they now fail at startup with a message that names the missing key. That is the intended
    change, and it is stated in the report.

Follow-ups

Refs #293

`{"memory": {"backend": "hindsight"}}` — no endpoint, just the backend name —
built a client whose base_url fell back to a hard-coded service, so the config
silently sent every prompt to a deployment the user never named. The decision
record says a network backend is "reachable only by explicit configuration: an
endpoint written in the user's own config file"; the code enforced the file and
not the endpoint.

`NewHTTPMemoryClient` now takes the bank and refuses an empty base URL, so
`memoryStore` returns an error the composition root already logs and runs
without memory. There is no default endpoint anywhere in the tree.

The bank had the same problem in a smaller way: `hermes` was hard-coded while
`memory.bank` existed in the config and was read by nobody. It now comes from
the config and falls back to `default`, which is Hindsight's own default tenant
name rather than one deployment's.

Docs move with it: CODEBASE says the endpoint is required, the example config
says a hindsight backend must name one, the decision record says the endpoint
rule is enforced rather than stated, and the roadmap's B2 evidence keeps its
baseline wording with a note that that default no longer exists.

Verified: go test ./... -count=1, 16 packages ok; go vet and gofmt clean; the
gate mutation-checked (the empty-base refusal disabled fails
TestHTTPMemoryClientRequiresAnEndpoint, restored it passes).

Refs #293
@yusiwen yusiwen added bug Something isn't working security Security hardening, sandbox or SSRF residual labels Oct 27, 2026
@yusiwen
yusiwen merged commit 10d1627 into master Oct 27, 2026
9 checks passed
@yusiwen
yusiwen deleted the fix/memory-requires-base-url branch October 27, 2026 09:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working security Security hardening, sandbox or SSRF residual

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant