Documentation
¶
Overview ¶
Package llmwrap holds helpers shared across the ADR-045 Phase 1 research-graph chain components (nl_classify, route_search, execute_subqueries, assess_sufficiency, synthesize_answer).
Two scopes:
- LLM-response shape helpers (PR 5): extracting a balanced JSON object out of a model's response (markdown fences + prose preface), and capping a string at N bytes with an ellipsis suffix for error-line readability. Used by the three LLM- wrapping components (route_search, assess_sufficiency, synthesize_answer).
- TriplePublisher (PR 6): the graph.mutation publish surface each component uses to stamp orchestration triples on the research-pipeline loop entity (research.classify.complete, research.route.action, etc.). Required by R0-R6 rule chain — the rule engine watches ENTITY_STATES, so per-stage completion must land as entity-state triples for rules to trigger. Used by all five components (LLM-wrapping and code-only alike).
The chat-completion adapter stays per-component so each component can keep a narrowly-purposed Router/Assessor/Synthesizer interface in its handler; only the cross-cutting helpers live here.
Index ¶
Constants ¶
const ErrPayloadTruncateBytes = 512
ErrPayloadTruncateBytes caps the raw-payload snippet rendered in error messages. 512 keeps the structured-emit JSON's action enum, per-action arg keys, and short rationales visible even when the model wrapped its emit in long prose.
Variables ¶
This section is empty.
Functions ¶
func ExtractJSON ¶
ExtractJSON pulls a balanced JSON object out of an LLM response. Many models wrap structured emits in ```json fences or prose preface; this helper strips fences, then walks the first balanced {...} substring while tracking JSON string-literal context (so a `}` inside a string value, e.g. a rationale field like "axes spanning {time, entity_type}", does not truncate the extraction mid-object). Backslash-escaped quotes inside strings do not toggle the string-context flag.
Returns an error if the trimmed content contains no `{`, or if the balanced-brace walker reaches end-of-input with unmatched depth.
func StampOrchestrationTriples ¶
func StampOrchestrationTriples(ctx context.Context, pub TriplePublisher, logger StampLogger, stage, loopID string, triples []message.Triple) error
StampOrchestrationTriples is the common per-stage emission path the five research-graph components share: call the TriplePublisher with the pre-built triple batch and log warn on failure. Failure is non-fatal at the handler level — the per-stage envelope already landed in AGENT_LOOPS via the chain's KV writes, so the operator sees the chain stall in trajectory data even when triple stamping fails. Returning the error lets handler-level metrics count it; the helper does not retry beyond the publisher's built-in retry budget.
pub == nil is treated as observability-disabled (degraded mode): the helper logs warn and returns nil rather than panicking. This matches the contract NewNATSTriplePublisher establishes — nil natsclient.Client → nil publisher → degraded chain visibility.
Types ¶
type StampLogger ¶
StampLogger is the subset of *slog.Logger the StampOrchestrationTriples helper needs. Defined to keep the helper unit-testable without forcing a slog handler into the test (a *slog.Logger satisfies it directly).
type TriplePublisher ¶
type TriplePublisher interface {
AddTriple(ctx context.Context, triple message.Triple) error
AddTriplesBatch(ctx context.Context, triples []message.Triple) error
}
TriplePublisher is the narrow surface the research-graph chain components use to stamp orchestration triples on the research-pipeline loop entity (e.g., research.classify.complete, research.route.action). Each per-stage completion stamps a small atomic batch sharing one Subject so graph-ingest's per-Subject CAS path preserves the rule- matching contract (R2 / R4 branches read action / sufficient triples paired with their respective complete triples — a partial write would corrupt the dispatch).
Two emission shapes:
- AddTriple: single-triple convenience. Available for symmetry with the agentictools.TriplePublisher pattern; the chain's per-stage stamps all batch.
- AddTriplesBatch: atomic per-Subject. The graph-ingest handler groups triples by Subject and CAS-applies them per entity, so a batch sharing one Subject is fully atomic.
Production satisfies it with *natsClient adapter; tests substitute an in-memory recorder so the per-component handler suites don't need a live NATS connection.
func NewNATSTriplePublisher ¶
func NewNATSTriplePublisher(client *natsclient.Client) TriplePublisher
NewNATSTriplePublisher builds a TriplePublisher backed by the graph.mutation NATS surfaces. Returns nil when client is nil — the research-graph components treat a nil publisher as "no graph emission" and log warn at handler dispatch (the chain becomes observability-only rather than fatal).