llmwrap

package
v1.0.0-beta.112 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 19, 2026 License: MIT Imports: 9 Imported by: 0

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

View Source
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

func ExtractJSON(content string) ([]byte, error)

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.

func Truncate

func Truncate(s string, n int) string

Truncate returns s capped at n bytes with an ellipsis suffix on over-long input. Used in error-message construction so an over-long LLM response doesn't blow up log lines or trajectory captures.

gh#190: the cap is walked back to the nearest preceding rune boundary so a multi-byte UTF-8 character can't be split across the cut. Without this, an LLM response containing CJK or emoji (3- or 4-byte runes) at the byte-n boundary produced invalid UTF-8 that slog's JSON handler then rendered as garbled "�" replacement sequences. The walk is at most 3 byte-steps for valid UTF-8 input (the longest legal Go-encoded rune is 4 bytes), so the cost is negligible vs. the readability win.

Types

type StampLogger

type StampLogger interface {
	Warn(msg string, args ...any)
}

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).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL