Skip to content

Feature: TypeSafe decision service integration - #2061

Open
jimador wants to merge 37 commits into
feature/classification-contractsfrom
feature/jev-primitives
Open

jimador wants to merge 37 commits into
feature/classification-contractsfrom
feature/jev-primitives

Conversation

@jimador

@jimador jimador commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

New implementation of TypeSafe decision services on top of the classification and decision contracts in #2062. TypeSafe is the provider, Jev is the default model, and the public boundary is DecisionService rather than a native SDK client or an LlmService.

The integration follows the same factory shape as the OpenAI and Anthropic providers. TypeSafeModelsConfig extends TypeSafeModelFactory, and TypeSafeModelFactory implements ByokFactory<DecisionService>. build() returns the configured default model, build(model) creates another independently identified TypeSafe decision service, and buildValidated() verifies the current credential before returning the default service. This gives applications the normal Embabel BYOK and multiple-model patterns without pretending that a decision model is a chat model.

classDiagram
    ModelMetadata <|-- ClassificationService
    ClassificationService <|-- DecisionService
    ByokFactory~DecisionService~ <|.. TypeSafeModelFactory
    TypeSafeModelFactory <|-- TypeSafeModelsConfig
    TypeSafeModelFactory --> DecisionService : build(model)
    DecisionService <|.. TypeSafeDecisionService
    TypeSafeDecisionService --> TypeSafeClient : internal boundary
Loading
flowchart LR
    Workflow[Embabel workflow] --> Contract[DecisionService]
    Contract --> FrameworkObservation[ObservedDecisionService]
    FrameworkObservation --> Adapter[TypeSafeDecisionService]
    Adapter --> SDK[TypeSafe SDK client]
    SDK --> Guard[Guarded TypeSafe API]
    Guard --> HTTP[Spring RestClient]
    HTTP --> Provider[TypeSafe / Jev]
Loading

The implementation keeps four boundaries explicit:

  • DecisionService and ClassificationService own provider-neutral requests, results, metadata, provenance, and framework observability.
  • TypeSafeDecisionService maps closed-category choices and proposition assessments without adding application policy. It never invents a no-match result or an acceptance threshold.
  • TypeSafeModelFactory owns the provider settings, credential source, shared guarded transport, model selection, and BYOK validation contract.
  • Spring auto-configuration exposes the factory and the default typeSafeDecisionService, backs off when that named service is replaced, and follows the existing model-provider package and configuration conventions.

A factory can create any number of TypeSafe decision services by model name. jev-latest remains the default, but the API does not hard-code Jev as the only model. Other decision providers can implement the same contracts without depending on TypeSafe or its SDK.

Classification uses the request's closed category set and validates that the returned probability distribution has the same support and sums to one. Proposition assessment preserves Jev's probability as pTrue, with exactly 0.5 represented as inconclusive. Successful results preserve the resolved model, provider, and request ID. Provider availability failures and invalid successful responses remain distinct, cancellation propagates, and raw provider bodies, credentials, URLs, model names, and exception chains are kept out of logs and public failures.

Observability is present at the framework, provider, and HTTP layers. The framework emits embabel.ai.classification or embabel.ai.decision; the guarded provider boundary emits embabel.typesafe.request; and application-owned RestClient instrumentation can emit http.client.requests. Tags and logs use bounded operation and outcome values. The implementation does not put prompts, category descriptions, propositions, responses, credentials, or raw exceptions into telemetry.

The reference guide documents the architecture, Spring configuration, BYOK usage, multiple models, failure semantics, transport behavior, observability, and the path out of experimental status. The API is tagged experimental so integration feedback can still shape it, while the implementation, tests, and documentation are written for continued maintenance.

This stack incorporates Rod's design feedback on #2057 and is related to #2049, #2050, #2051, #2052, #2057, the earlier prototype in #2059, and the experimental proposal.

Validation completed locally before push:

  • mvn -U -B -Dmaven.gitcommitid.skip=true test verify — all 84 reactor modules passed
  • focused TypeSafe, auto-configuration, and starter tests passed
  • AsciiDoc processing passed
  • Spotless passed across the full reactor
  • Open Code Review completed with zero findings across the final production and documentation diff
  • Jev approved the documentation voice and API-comment voice with 0.91 probability and documentation completeness with 0.82 probability

@jimador
jimador marked this pull request as ready for review September 24, 2026 19:49

@igordayen igordayen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jimador - few comments, manual review, to consider, thanks

Comment thread embabel-agent-dependencies/pom.xml Outdated
Comment thread embabel-agent-jev/src/main/java/com/embabel/agent/jev/api/JevClientOptions.java Outdated
Comment thread embabel-agent-docs/src/main/asciidoc/reference/typesafe/page.adoc Outdated
@jimador jimador changed the title Prototype implementation of Jev primitives and Spring integration Prototype implementation of TypeSafe primitives and Spring integration Sep 25, 2026
@jimador jimador changed the title Prototype implementation of TypeSafe primitives and Spring integration TypeSafe primitives and integration Sep 25, 2026

@igordayen igordayen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jimador looks good, nothing blocking, few minor suggestions, thanks


/** Internal boundary: unsafe transport failures never reach SDK retry diagnostics. */
@Internal
public final class GuardedTypeSafeApi extends TypeSafeApi {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please consider splitting the artifact into a public part and a supporting helper with private functions

@jimador
jimador marked this pull request as draft September 25, 2026 03:08
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
…acts

Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
…stry

Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
@jimador
jimador force-pushed the feature/jev-primitives branch from 725cfd6 to 17ba1e4 Compare September 25, 2026 18:33
@jimador jimador changed the title TypeSafe primitives and integration Prototype: TypeSafe decision service integration Sep 25, 2026
@jimador
jimador changed the base branch from main to feature/classification-contracts September 25, 2026 18:34
@jimador
jimador marked this pull request as ready for review September 25, 2026 18:34
@jimador
jimador added this pull request to stack #2067 September 25, 2026 18:45
@jimador jimador changed the title Prototype: TypeSafe decision service integration feat: TypeSafe decision service integration Sep 25, 2026
@igordayen igordayen changed the title feat: TypeSafe decision service integration Feature: TypeSafe decision service integration Sep 25, 2026
@igordayen

Copy link
Copy Markdown
Contributor

Please review SonarCube violations, thanks

@jimador
jimador force-pushed the feature/jev-primitives branch from d17ae2d to 86210a1 Compare September 28, 2026 05:19
@sonarqubecloud

Copy link
Copy Markdown

@jimador
jimador requested a review from igordayen September 28, 2026 06:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants