Interface LLMConfigurationSource
- Functional Interface:
- This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.
Registered on the bridge with SCOPBridge.llmConfigurationSource(LLMConfigurationSource),
this layer sits in front of the @RoleSpec/@AgentSpec annotations:
whatever it names wins, and whatever it leaves out keeps its annotation value.
Consumers point at a location instead of reimplementing the precedence rule.
Three properties are part of the contract, not of any one implementation:
- Field-level. Only the fields the source names are applied.
- Not cached.
forAgent(String)is called on every resolution and must re-read its backing store, so an edit is visible to the next resolution in the same process. - No silent fallback. A source that exists but cannot be read must throw
LLMConfigurationExceptionrather than answer with annotation values.
A source is trusted infrastructure, not input. An overlay can set
endpoint and apiKeyEnv, and those two together are more than they
look: apiKeyEnv names any environment variable or System property
visible to the process — EnvLoader checks System properties
first, and it loads the whole .env file into them — and endpoint
decides where the resulting value is sent as a bearer token, along with the request
body. Whoever controls a source can therefore read a secret that has nothing to do
with LLMs and exfiltrate it, without any access to the code. Give a source the same
trust you give the deployment's own configuration.
Two consequences worth stating plainly. A source can supply model for an
agent whose annotations declare none, so it can enable LLM dispatch for an agent the
developer never configured for it. And each resolution logs the lookup key, the fields
the source contributed, and the endpoint and apiKeyEnv values when it
sets them — neither is itself a secret — so a redirection leaves a trace.
- Since:
- 0.16.4
-
Method Summary
Modifier and TypeMethodDescriptionstatic LLMConfigurationSourceReadsTNSAI_LLM_<AGENT>_<FIELD>throughEnvLoader, which checks System properties before environment variables, so-DKEY=valueand.envloading work uniformly with the rest of the codebase.static LLMConfigurationSourceReads<folder>/<agentName>.json, re-read on every call.The settings this source holds for one agent.static LLMConfigurationSourcenoOp()A source that holds nothing; the bridge default, so the layer is opt-in.
-
Method Details
-
forAgent
The settings this source holds for one agent.- Parameters:
agentName- the agent's name — seeSCOPBridge.resolveLLMSpec(Object, Object, Object, String)for how it is derived- Returns:
- the overlay for that agent, or
Optional.empty()if this source holds none - Throws:
LLMConfigurationException- if settings exist for the agent but cannot be read
-
noOp
A source that holds nothing; the bridge default, so the layer is opt-in. -
folder
Reads<folder>/<agentName>.json, re-read on every call.The file is a flat JSON object whose keys are a subset of
provider,model,temperature,maxTokens,endpointandapiKeyEnv. A missing file yieldsOptional.empty(); an empty object yields an overlay that names no field. An unknown key is an error rather than a no-op, so that a misspelledtempraturefails loudly instead of silently doing nothing.Write access to this directory is configuration authority — see the trust paragraph on
LLMConfigurationSource. It is not limited to choosing a model: naming anapiKeyEnvreads any environment variable or System property the process can see, and anendpointdecides where that value is sent. Treat the folder as part of the deployment's trusted configuration, not as a place untrusted input lands.The agent name is a lookup key, not a path: a name containing a path separator, a NUL, or
..is rejected rather than resolved, and the resolved file must still lie inside the folder.Lookup is as case-sensitive as the underlying filesystem, so
Researcherandresearcherare one entry on a case-folding filesystem (macOS APFS, which also folds Unicode normalisation forms) and two on a case-sensitive one.A file over 1 MiB is refused rather than read; a real one is a few hundred bytes.
- Parameters:
folder- directory holding one JSON file per agent- Throws:
NullPointerException- iffolderisnull
-
environment
ReadsTNSAI_LLM_<AGENT>_<FIELD>throughEnvLoader, which checks System properties before environment variables, so-DKEY=valueand.envloading work uniformly with the rest of the codebase.<AGENT>is the agent name upper-cased with every non-alphanumeric character replaced by_;<FIELD>is one ofPROVIDER,MODEL,TEMPERATURE,MAX_TOKENS,ENDPOINT,API_KEY_ENV. So aResearcheragent's model comes fromTNSAI_LLM_RESEARCHER_MODEL.This extends to provider, model, temperature and maxTokens the precedence
LLMConfigurationalready applies to base URL and API key.Because the key is normalised, agent names that differ only in punctuation (
data-analystanddata_analyst) map to the same variable.The interface's "not cached" property holds for System properties and environment variables, which are read on every call, but not for a
.envfile:EnvLoaderloads that once per JVM, so editing it — including removing an override — takes effect only after a restart.
-