Skip to main content

Run the example agent

The Harnest repository includes examples/jev-triage: a managed graph with three steps: Jev classifies the ticket → an LLM drafts a reply → Harnest returns the reply. The validated routing decision stays in internal state and supplies context to the LLM. From the repository root, with a Harnest build that includes typed decisions:
Set JEV_LLM_MODEL to your LiteLLM provider/model identifier before a live run; the source default is the compile-only placeholder openai/your-model. The command above uses ollama_chat/qwen3.5:cloud, which requires a local Ollama service with that model and cloud access configured. You can also set JEV_LLM_API_BASE and JEV_LLM_API_KEY. For models that support it, JEV_LLM_REASONING_EFFORT="none" disables reasoning for this short drafting step; omit the variable to use the provider default. TYPESAFE_API_KEY also works and takes precedence when both are set. Ask “I was charged twice for the same order.” The public result contains the customer-facing reply; department, confidence, queue, and live/offline provenance remain internal. Billing and support require confidence of at least 0.8; other categories and evaluation failures recommend manual review. For a credential-free run or tests:
Offline mode replaces both Jev and the LLM: it uses a fixed billing decision internally and returns a draft labeled “Offline fixture”. Tests require no provider credentials. Session storage is in memory; restarting clears conversations. The agent recommends and drafts without sending tickets or changing accounts. LLM failures are reported as request errors.
Use the checkout’s Python runtime when your installed CLI predates typed decisions:
Export your key before serving, or prefix the last command with JEV_TRIAGE_OFFLINE=true.

Show or hide Jev results

The example hides decision events with this factory:
lifecycle/output.py
Jev still evaluates each ticket and the LLM still receives its recommendation. Callers receive the reply without a Jev result panel. Internal state remains available in Playground’s State inspector. Change it to OutputPolicy(decision_results=True) and recompile/restart to add separate decision_result events with the typed answers and routing outcome. The reply schema stays the same. This policy works with any registered decision provider, not just Jev. See Output policy.

Add Jev to your own agent

Replace the quickstart’s offline fixture with Jev. Reuse its lib/triage.py and tools/triage_ticket.py; the adapter below supports Choice questions, including batches, probabilities, and confidence. This is an application-local integration using the TypeSafe Python SDK. It does not require a packaged Jev extension.
1

Add the SDK and credentials

Add typesafe-sdk==0.7.1 to your agent’s existing project.dependencies in pyproject.toml, then run:
Get a key from the TypeSafe console. The example pins jev-1.13.0; check the model catalog before changing it.
2

Add the provider adapter

lib/jev.py
Harnest checks that every requested question is answered and each choice belongs to its declared options.
3

Replace the fixture registration

Replace lifecycle/decisions.py with this resource. The async context manager closes the SDK client at application shutdown.
lifecycle/decisions.py
SDK retries are disabled explicitly. See the asynchronous client reference for timeout and retry options.
4

Try a ticket

Run harnest serve . and ask your agent:
Use triage_ticket to classify: “I was charged twice for the same order.”
The tool calls Jev through context.decisions.evaluate(...) and returns a route or review recommendation.
Tune the confidence threshold with your own tickets. Routing remains your application’s responsibility; returning billing_agent does not invoke it.
The adapter has been checked with SDK 0.7.1 and mocked HTTP responses. Live predictions require your TypeSafe credentials. Harnest’s private decision traces do not control SDK logging; avoid SDK debug logging of customer payloads.
To support other primitives, extend the adapter using TypeSafe’s question contracts: map Jev Score to ScoreResult and Jev Noul to PredicateResult, then declare those capabilities. The adapter above intentionally advertises only what it implements.