TypeSafe AI
Since Camel 4.23
Only producer is supported
The TypeSafe AI component evaluates explicit state against Noul (yes/no), Choice (one category), and Score (ordered rubric) questions using TypeSafe AI’s HTTP API. Jev is the default model; the model option can select another model supported by the API. It calls the service directly using the JDK HTTP client and Camel JSON utilities. For semantic conditions in Java, XML and YAML, use the TypeSafe AI language supplied by this component.
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-typesafe-ai</artifactId>
<version>x.x.x</version>
</dependency> URI format
typesafe-ai:name[?options] name identifies an endpoint; it is not sent to the model. Producers and predicates using the same URI share its client and configuration. Each endpoint owns one HTTP client, connection pool, and default executor. Reuse the same endpoint URI when its configuration is shared. Camel manages its lifecycle and cancels in-flight requests on stop. Java 21 and later also close the HTTP client explicitly; on Java 17, the JDK reclaims its remaining resources after it becomes unreachable.
Configuring Options
Camel components are configured on two separate levels:
-
component level
-
endpoint level
Configuring Component Options
At the component level, you set general and shared configurations that are, then, inherited by the endpoints. It is the highest configuration level.
For example, a component may have security settings, credentials for authentication, urls for network connection and so forth.
Some components only have a few options, and others may have many. Because components typically have pre-configured defaults that are commonly used, then you may often only need to configure a few options on a component; or none at all.
You can configure components using:
-
the Component DSL.
-
in a configuration file (
application.properties,*.yamlfiles, etc). -
directly in the Java code.
Configuring Endpoint Options
You usually spend more time setting up endpoints because they have many options. These options help you customize what you want the endpoint to do. The options are also categorized into whether the endpoint is used as a consumer (from), as a producer (to), or both.
Configuring endpoints is most often done directly in the endpoint URI as path and query parameters. You can also use the Endpoint DSL and DataFormat DSL as a type safe way of configuring endpoints and data formats in Java.
A good practice when configuring options is to use Property Placeholders.
Property placeholders provide a few benefits:
-
They help prevent using hardcoded urls, port numbers, sensitive information, and other settings.
-
They allow externalizing the configuration from the code.
-
They help the code to become more flexible and reusable.
The following two sections list all the options, firstly for the component followed by the endpoint.
Component Options
The TypeSafe AI component supports the following options which are listed below.
| Name | Description | Default | Type |
|---|---|---|---|
The API base URL. The client appends /v1/systemone. Redirects are not followed. | String | ||
Default configuration shared by TypeSafe AI endpoints. | TypeSafeAiConfiguration | ||
Maximum concurrent evaluations per endpoint, shared by producers and predicates. Excess requests fail immediately with RejectedExecutionException without being queued or sent. Must be positive. | 64 | int | |
The model ID or alias. Use a versioned ID to pin decision behavior. | jev-latest | String | |
A JSON object mapping question names to Noul, Choice or Score question objects. When set, producers evaluate the selected message state; otherwise the body must contain a complete request map. | String | ||
The timeout in milliseconds for the complete HTTP request and response body. Must be positive. | 30000 | long | |
The Simple expression selecting state for configured producer questions and the TypeSafe AI language. If not set, the message body is used. | String | ||
Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel’s routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing. | false | boolean | |
Store the producer response in this exchange property, preserving the original message body. | String | ||
Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc. | true | boolean | |
Default inclusive probability threshold for the TypeSafe AI language. Must be within 0,1. | 0.5 | double | |
Default half-width of the inclusive uncertainty band for the TypeSafe AI language. Zero disables the band. | 0 | double | |
Default action for the TypeSafe AI language within the uncertainty band: NonMatch or Fail. Enum values:
| NonMatch | UncertaintyPolicy | |
Required The API key used for Bearer authentication. | String |
Endpoint Options
The TypeSafe AI endpoint is configured using URI syntax:
typesafe-ai:name
With the following path and query parameters:
Query Parameters
| Name | Description | Default | Type |
|---|---|---|---|
The API base URL. The client appends /v1/systemone. Redirects are not followed. | String | ||
Maximum concurrent evaluations per endpoint, shared by producers and predicates. Excess requests fail immediately with RejectedExecutionException without being queued or sent. Must be positive. | 64 | int | |
The model ID or alias. Use a versioned ID to pin decision behavior. | jev-latest | String | |
A JSON object mapping question names to Noul, Choice or Score question objects. When set, producers evaluate the selected message state; otherwise the body must contain a complete request map. | String | ||
The timeout in milliseconds for the complete HTTP request and response body. Must be positive. | 30000 | long | |
The Simple expression selecting state for configured producer questions and the TypeSafe AI language. If not set, the message body is used. | String | ||
Store the producer response in this exchange property, preserving the original message body. | String | ||
Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel’s routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing. | false | boolean | |
Default inclusive probability threshold for the TypeSafe AI language. Must be within 0,1. | 0.5 | double | |
Default half-width of the inclusive uncertainty band for the TypeSafe AI language. Zero disables the band. | 0 | double | |
Default action for the TypeSafe AI language within the uncertainty band: NonMatch or Fail. Enum values:
| NonMatch | UncertaintyPolicy | |
Required The API key used for Bearer authentication. | String |
Configuration
Configure credentials through property placeholders or a supported vault:
camel.component.typesafe-ai.api-key={{env:TYPESAFE_API_KEY}}
camel.component.typesafe-ai.model=jev-1.13.0
camel.component.typesafe-ai.request-timeout=30000
camel.component.typesafe-ai.max-concurrent-requests=64 apiKey is a secret option. baseUrl defaults to https://api.typesafe.ai; the client appends /v1/systemone. A base path can address a proxy. HTTP redirects are not followed. Use HTTPS for the service; HTTP is useful for local testing.
model defaults to jev-latest. Pin a version when tuning thresholds; aliases can change behavior without a route change. The request map may explicitly override the endpoint’s model for that request. The response’s model identifies the model that answered. See available models.
Concurrent requests
maxConcurrentRequests limits concurrent evaluations to 64 per endpoint by default and must be positive. Producers and predicates using the same endpoint share this limit. A component property sets the default for each endpoint; an endpoint URI can override it, for example typesafe-ai:refund?maxConcurrentRequests=8. Different endpoints have independent limits.
When the limit is reached, the evaluation fails immediately with java.util.concurrent.RejectedExecutionException before request validation, serialization, or HTTP submission. No request is queued. The slot is released when the evaluation finishes, including on failure, timeout, interruption, or cancellation. Camel’s error handler can handle the rejection through onException(RejectedExecutionException.class).
Questions from properties
For a fixed set of questions, select state and retain the business message using properties:
camel.component.typesafe-ai.questions={"refund":{"type":"noul","instructions":"Is a refund requested?"}}
camel.component.typesafe-ai.state=${body}
camel.component.typesafe-ai.result-property=evaluation from("direct:route")
.to("typesafe-ai:refund")
.choice()
.when(simple("${exchangeProperty.evaluation[answers][refund][noul]} >= 0.8"))
.to("direct:refund-handler")
.otherwise().to("direct:general-handler"); No manually registered beans are needed. state is a Simple expression, defaulting to ${body}. For an InputStream, use ${bodyAs(String)}. Only the selected state is sent. Without resultProperty, the response replaces the message body.
Producer request and response
Without configured questions, the input body must be a Map<String, Object> with state and a nonempty questions map. An optional model overrides the endpoint default. Each named question is a map with type (noul, choice, or score), optional instructions, and the applicable criteria. Instructions may be omitted or null. Noul criteria and either yes/no description may also be omitted or null, matching the official Python SDK and OpenAPI schema. State, instructions, and descriptions can be text or structured maps/lists. Nested content supports strings, finite numbers, booleans, nulls, lists, and maps with string keys. Convert other objects explicitly before submitting them. The component does not collect exchange headers or properties automatically. Do not send an entire exchange as state.
The output is an org.apache.camel.util.json.JsonObject, which implements Map<String, Object>. It preserves the API’s JSON structure, including additional fields. Nested objects are maps, arrays are lists, and numeric values implement Number; use doubleValue() or longValue() rather than assuming a specific numeric class.
Missing or mismatched answers, invalid numeric ranges, unknown choices, and incomplete probability maps fail the exchange. The selected Choice must have maximal probability; ties are allowed. Probabilities and scores are preserved as returned. Like the official Python SDK, the component does not enforce a probability-sum tolerance or recompute a Score from its returned probabilities, which may have been rounded independently.
Token counts may be missing or null. Missing values remain absent and null values remain null; neither is replaced with zero. Present counts must be nonnegative integers.
Map<String, Object> request = Map.of(
"state", "Please refund the duplicate payment",
"questions", Map.of(
"refund", Map.of("type", "noul", "instructions", "Is a refund requested?",
"criteria", Map.of("true", "An explicit request for money back", "false", "No refund requested")),
"team", Map.of("type", "choice", "instructions", "Which team should handle this?",
"criteria", Map.of("billing", "Payments and refunds", "technical", "Product failures",
"other", "Neither team applies")),
"urgency", Map.of("type", "score", "instructions", "How urgent is this?",
"criteria", List.of("Routine", "Urgent", "Critical"))));
JsonObject response = template.requestBody("typesafe-ai:decisions", request, JsonObject.class);
JsonObject answers = response.getJsonObject("answers");
boolean requested = answers.getJsonObject("refund").getDouble("noul") >= 0.8;
String category = answers.getJsonObject("team").getString("choice");
double score = answers.getJsonObject("urgency").getDouble("score"); This mixed batch makes one HTTP request, with the same state for every question. There is no implicit batching across producer calls or predicates.
Answer | Mapping |
Noul |
|
Choice |
|
Score |
|
Response |
|
With resultProperty=evaluation, the producer stores the response in that exchange property and preserves the input body. It clears the property before each evaluation so failures cannot leave a stale result. The input request map is not mutated.
For category routing, submit one Choice question and route on its choice field. Independent Noul conditions instead preserve Camel Choice’s first-matching-branch semantics.
Timeouts and errors
Producer and language evaluations are synchronous. Each evaluation blocks the calling thread for a remote round trip and may incur token charges. There is no response cache or automatic retry. Loops and Camel redelivery can evaluate again; bound them and account for repeated calls.
requestTimeout bounds the HTTP request and complete response body. Connection, request and overall deadline failures all surface as java.util.concurrent.TimeoutException; an underlying JDK HTTP timeout is retained as the cause. Interruption and timeout cancel the HTTP future, including stalled response bodies. Cancellation cannot guarantee the service stopped processing or consumed no tokens.
An unsuccessful HTTP status raises TypeSafeAiHttpException with status code, request ID and Retry-After where available. Error bodies are omitted because they may contain submitted state. Invalid responses and network failures propagate. Language evaluations preserve the exception in Camel’s cause chain, so ordinary onException clauses can handle it. Failures never silently become a non-match. Endpoint stop cancels in-flight calls and rejects new evaluations until restart.
Only submit data permitted for the configured service. Test model decisions and thresholds against your application; structured output does not establish correctness.