Documentation
¶
Overview ¶
Package proxias is a deterministic execution plane for LLM applications. Seen as a UI, human prose is turned into commands or queries before an LLM sees it, and their results are turned back into prose.
The ControlPlane is the entry point. An action is whatever an ActionExecutionEngine runs for a request: a plain function as much as a workflow, a process or a pipeline. An IntentClassifier, ideally a fast System-1 component, names which of the engine's actions a request asks for and with which parameters (a CompositeIntentClassifier splits it into a selector and a parameter extractor). The ActionExecutionEngine runs them, and an ActionExecutionSynthesizer turns their results back into a response, usually in a single LLM pass. A request that asks for no action is answered by the ReasoningEngine, usually an LLM, as is.
Proxias is a library: transports (gRPC, CLI...) and every application concern live in the host. The model of Proxias is the OpenAI chat completions API, which NewChatCompletionHandler serves over net/http, and the anthropic package implements the components with Claude.
Index ¶
- Constants
- func IdentityFrom[T any](ctx context.Context) T
- func NewChatCompletionHandler(controlPlane ControlPlane) http.Handler
- func WithActionDescriptors(ctx context.Context, descs []ActionDescriptor) context.Context
- func WithAgentIdentity(ctx context.Context, id AgentIdentity) context.Context
- func WithIdentity[T any](ctx context.Context, id T) context.Context
- func WithUserIdentity(ctx context.Context, id UserIdentity) context.Context
- func WriteChatCompletionResponse(w http.ResponseWriter, r ChatCompletionResponse)
- type ActionDescriptor
- type ActionExecutionEngine
- type ActionExecutionIntent
- type ActionExecutionIntentParameterExtractor
- type ActionExecutionIntentParameterExtractorFunc
- type ActionExecutionIntentSelector
- type ActionExecutionIntentSelectorFunc
- type ActionExecutionResult
- type ActionExecutionSynthesis
- type ActionExecutionSynthesizer
- type ActionExecutionSynthesizerFunc
- type AgentIdentity
- type AgentIdentityProvider
- type ChatCacheControl
- type ChatCompletion
- type ChatCompletionBuilder
- type ChatCompletionChoice
- type ChatCompletionChunk
- type ChatCompletionChunkChoice
- type ChatCompletionDelta
- type ChatCompletionFunctionCallDelta
- type ChatCompletionRequest
- type ChatCompletionResponse
- type ChatCompletionToolCallDelta
- type ChatContent
- type ChatContentPart
- type ChatContentPartType
- type ChatFinishReason
- type ChatFunction
- type ChatFunctionCall
- type ChatImageURL
- type ChatMessage
- type ChatMessageRole
- type ChatPromptTokensDetails
- type ChatStreamOptions
- type ChatTool
- type ChatToolCall
- type ChatUsage
- type CompositeIntentClassifier
- type ControlPlane
- type HeaderIdentityProvider
- type IdentityProvider
- type IdentityProviderFunc
- type Intent
- type IntentClassifier
- type IntentClassifierFunc
- type Middleware
- func NewActionInterceptionMiddleware(classifier IntentClassifier, engine ActionExecutionEngine, ...) (Middleware, error)
- func NewAgentIdentityMiddleware(p AgentIdentityProvider) (Middleware, error)
- func NewIdentityMiddleware[T any](p IdentityProvider[T]) (Middleware, error)
- func NewReasoningMiddleware(engine ReasoningEngine) (Middleware, error)
- func NewUserIdentityMiddleware(p UserIdentityProvider) (Middleware, error)
- type ProcessFunc
- type Prompt
- type ReasoningEngine
- type ReasoningEngineFunc
- type UserIdentity
- type UserIdentityProvider
Constants ¶
const ( DefaultUserIdentityHeader = "OpenAI-Organization" DefaultAgentIdentityHeader = "User-Agent" )
DefaultUserIdentityHeader and DefaultAgentIdentityHeader are the headers that NewUserHeaderIdentityProvider and NewAgentHeaderIdentityProvider read when given no name: the headers that OpenAI clients send. OpenAI has no header for an end user, so the user default is the organization that the client is billed to, which is the tenant a proxy usually sees; the agent default is the User-Agent that the OpenAI SDKs and the harnesses built on them set to name themselves (for instance "OpenAI/Python 1.40.0").
Variables ¶
This section is empty.
Functions ¶
func IdentityFrom ¶
IdentityFrom returns the identity of type T that the context carries, or the zero value of T if it carries none.
func NewChatCompletionHandler ¶
func NewChatCompletionHandler(controlPlane ControlPlane) http.Handler
NewChatCompletionHandler makes an http.Handler that serves controlPlane over HTTP, as the chat completions endpoint of the OpenAI API: mount it on "POST /v1/chat/completions".
It reads the request with DecodeChatCompletionRequest (400 if it cannot, 413 if it is too large), has the control plane process it, and writes the ChatCompletionResponse back as is with WriteChatCompletionResponse: its status, its headers and its body, which is flushed as it is read, so that a stream reaches the client as it is produced. The error of a control plane that fails is not sent to the client (502): it is the host's to log, for instance with a decorator of the control plane.
func WithActionDescriptors ¶
func WithActionDescriptors(ctx context.Context, descs []ActionDescriptor) context.Context
WithActionDescriptors returns a context that carries the descriptors of the actions that a request may ask for. The ActionInterceptionMiddleware sets them before the rest of the chain, so that a reasoning engine can tell what the application can do.
func WithAgentIdentity ¶
func WithAgentIdentity(ctx context.Context, id AgentIdentity) context.Context
WithAgentIdentity returns a context that carries the identity of the agent that made a request, as WithIdentity[AgentIdentity] does.
func WithIdentity ¶
WithIdentity returns a context that carries an identity of any type T, one per type: use it for an identity that is a struct of the host's (with a name, an email) rather than a UserIdentity. NewIdentityMiddleware sets it for the rest of the chain.
func WithUserIdentity ¶
func WithUserIdentity(ctx context.Context, id UserIdentity) context.Context
WithUserIdentity returns a context that carries the identity of the user of a request, as WithIdentity[UserIdentity] does.
func WriteChatCompletionResponse ¶
func WriteChatCompletionResponse(w http.ResponseWriter, r ChatCompletionResponse)
WriteChatCompletionResponse writes the response to w: its headers, its status (200 if it has none, 500 if it is not one) and its body, flushed as it is read so that a stream reaches the client as it is produced. It closes the Body. A failure to write, the client having gone away, or to read the Body after the status is sent, has nothing left to tell: the response ends there.
Types ¶
type ActionDescriptor ¶
type ActionDescriptor struct {
// ID is the unique identifier of the action.
ID string `json:"id"`
// Name is a human friendly name, for display purposes.
Name string `json:"name"`
// Description is a human friendly description of what the action does. A classifier chooses among the
// actions with it.
Description string `json:"description"`
// InputSchema is the JSON Schema of the action's parameters, if it has any.
InputSchema map[string]any `json:"schema,omitempty"`
}
ActionDescriptor describes an action to the IntentClassifier, and to the model behind it, if any: what it is called, what it does and how it is called (its InputSchema).
func ActionDescriptorsFrom ¶
func ActionDescriptorsFrom(ctx context.Context) []ActionDescriptor
ActionDescriptorsFrom returns the action descriptors that the context carries, or nil if it carries none.
type ActionExecutionEngine ¶
type ActionExecutionEngine interface {
// ActionDescriptors describes the actions that this engine provides.
// Implementations may narrow that list based on the specifics of the ChatCompletionRequest.
ActionDescriptors(context.Context, ChatCompletionRequest) ([]ActionDescriptor, error)
// ExecuteActions runs the actions, and returns exactly one result per action execution.
ExecuteActions(context.Context, ChatCompletionRequest, []ActionExecutionIntent) ([]ActionExecutionResult, error)
}
ActionExecutionEngine is where the deterministic, compiled actions live: it describes them and runs them. An action is whatever the engine runs for a request: a plain function as much as a workflow, a process or a pipeline.
Error Handling: implementations must return a non-nil error if the engine itself fails (a registry or a queue that is down...). These are infrastructure errors, and the control plane returns them: they are not synthesized into a response for the user. An action that cannot run for a reason the user should hear of is not such an error: its ActionExecutionResult has a failing Status, and Data that says why. That covers invalid input, missing required parameters, and an action ID that the engine does not know.
type ActionExecutionIntent ¶
type ActionExecutionIntent struct {
// ActionID is the ID of the action to run.
ActionID string `json:"action_id"`
// Params are the values of the action's parameters, by name, as its InputSchema describes them.
Params map[string]any `json:"params,omitempty"`
}
ActionExecutionIntent asks to run an action: it is the command, or the query, that a request was turned into. The action is run by the ActionExecutionEngine with Params, and the synthesizer receives the result along with this intent.
The control plane does not check that the ActionID is one of those described: an engine answers an unknown action with a failed ActionExecutionResult.
type ActionExecutionIntentParameterExtractor ¶
type ActionExecutionIntentParameterExtractor interface {
ExtractParameters(ctx context.Context, req ChatCompletionRequest, matchedDescs []ActionDescriptor) ([]ActionExecutionIntent, error)
}
ActionExecutionIntentParameterExtractor binds user prose to strongly typed action parameter schemas. It acts as Stage 2 of a CompositeIntentClassifier, taking the targeted action descriptors identified during Stage 1 selection and extracting the populated parameter maps. A parameter that the request does not give is left out of the map: the action, which knows what it requires, fails with a result that says what is missing.
Error Handling: return a non-nil error if parameter extraction itself fails, these are internal infrastructure level errors and won't be synthesized into a user-facing response by the control plane.
type ActionExecutionIntentParameterExtractorFunc ¶
type ActionExecutionIntentParameterExtractorFunc func(ctx context.Context, req ChatCompletionRequest, matchedDescs []ActionDescriptor) ([]ActionExecutionIntent, error)
ActionExecutionIntentParameterExtractorFunc is an ActionExecutionIntentParameterExtractor as a function.
func (ActionExecutionIntentParameterExtractorFunc) ExtractParameters ¶
func (f ActionExecutionIntentParameterExtractorFunc) ExtractParameters(ctx context.Context, req ChatCompletionRequest, matchedDescs []ActionDescriptor) ([]ActionExecutionIntent, error)
ExtractParameters implements ActionExecutionIntentParameterExtractor.
type ActionExecutionIntentSelector ¶
type ActionExecutionIntentSelector interface {
Select(context.Context, ChatCompletionRequest, []ActionDescriptor) ([]ActionDescriptor, error)
}
ActionExecutionIntentSelector performs ideally fast System-1 triage on an incoming chat completion request to determine the most appropriate actions. It acts as Stage 1 of a CompositeIntentClassifier, evaluating user prose to decide whether a chat completion request maps to specific action IDs or requires open-ended reasoning, without spending tokens on full parameter extraction. Returning an empty slice indicates that no suitable actions were found.
Error Handling: return a non-nil error if action selection itself fails, these are internal infrastructure level errors and won't be synthesized into a user-facing response by the control plane.
type ActionExecutionIntentSelectorFunc ¶
type ActionExecutionIntentSelectorFunc func(context.Context, ChatCompletionRequest, []ActionDescriptor) ([]ActionDescriptor, error)
ActionExecutionIntentSelectorFunc is an ActionExecutionIntentSelector as a function.
func (ActionExecutionIntentSelectorFunc) Select ¶
func (f ActionExecutionIntentSelectorFunc) Select(ctx context.Context, req ChatCompletionRequest, descs []ActionDescriptor) ([]ActionDescriptor, error)
Select implements ActionExecutionIntentSelector.
type ActionExecutionResult ¶
type ActionExecutionResult struct {
// ActionID is the action that ran.
ActionID string `json:"action_id"`
// ExecutionID is a unique identifier for this particular execution of the action,
// this can be used to track its status in case of asynchronous execution.
ExecutionID string `json:"execution_id,omitempty"`
// Status represents the current execution status of the action, indicating if it was successful or not.
// Its vocabulary is the engine's own ("completed", "failed", "running"...): the synthesizer, which knows
// that engine, interprets it.
Status string `json:"status"`
// Data contains the output of the action execution, if any.
// This data can also describe an error if the action failed, in which case the status
// should indicate a failure.
Data map[string]any `json:"data,omitempty"`
}
ActionExecutionResult is what an action answered after being executed. If an action does not provide a result, it should still return an ActionExecutionResult.
type ActionExecutionSynthesis ¶
type ActionExecutionSynthesis struct {
Request ChatCompletionRequest `json:"request,omitzero"`
Intent Intent `json:"intent,omitzero"`
ExecutionResults []ActionExecutionResult `json:"execution_results,omitempty"`
}
ActionExecutionSynthesis is what an ActionExecutionSynthesizer makes a response of.
type ActionExecutionSynthesizer ¶
type ActionExecutionSynthesizer interface {
Synthesize(context.Context, ActionExecutionSynthesis) (ChatCompletionResponse, error)
}
ActionExecutionSynthesizer translates raw execution results into human-readable responses. It serves as the outbound translation layer in Proxias, transforming structured execution results into human-readable prose or UI specs as a ChatCompletionResponse.
Error Handling: return a non-nil error if synthesis itself fails to generate a ChatCompletionResponse.
type ActionExecutionSynthesizerFunc ¶
type ActionExecutionSynthesizerFunc func(context.Context, ActionExecutionSynthesis) (ChatCompletionResponse, error)
ActionExecutionSynthesizerFunc is an ActionExecutionSynthesizer as a function.
func (ActionExecutionSynthesizerFunc) Synthesize ¶
func (f ActionExecutionSynthesizerFunc) Synthesize(ctx context.Context, synthesis ActionExecutionSynthesis) (ChatCompletionResponse, error)
Synthesize implements ActionExecutionSynthesizer.
type AgentIdentity ¶
type AgentIdentity string
AgentIdentity identifies the agent (the harness or application) that makes a request, as a host defines it. The empty identity means the agent is unknown.
func AgentIdentityFrom ¶
func AgentIdentityFrom(ctx context.Context) AgentIdentity
AgentIdentityFrom returns the agent identity that the context carries, or the empty identity if it carries none.
type AgentIdentityProvider ¶
type AgentIdentityProvider IdentityProvider[AgentIdentity]
AgentIdentityProvider provides the identity of the agent that made a request.
type ChatCacheControl ¶
ChatCacheControl marks the end of a part that the provider may cache.
type ChatCompletion ¶
type ChatCompletion struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []ChatCompletionChoice `json:"choices"`
Usage *ChatUsage `json:"usage,omitempty"`
}
ChatCompletion is a whole answer: the body of a response to a request that did not ask for a stream.
type ChatCompletionBuilder ¶
type ChatCompletionBuilder struct {
// contains filtered or unexported fields
}
ChatCompletionBuilder makes the ChatCompletions that answer a request without a model: a text, or calls of tools for the harness to run. Give one to NewChatCompletionResponse, which streams it if the request asked for a stream. The completions of a builder share its model, ID and creation time.
func NewChatCompletionBuilder ¶
func NewChatCompletionBuilder(req ChatCompletionRequest) ChatCompletionBuilder
NewChatCompletionBuilder returns a builder of the completions that answer req.
func (ChatCompletionBuilder) BuildText ¶
func (b ChatCompletionBuilder) BuildText(text string) ChatCompletion
BuildText is the completion that answers with text.
func (ChatCompletionBuilder) BuildToolCalls ¶
func (b ChatCompletionBuilder) BuildToolCalls(calls ...ChatToolCall) ChatCompletion
BuildToolCalls is the completion that asks the harness to run calls of its tools.
type ChatCompletionChoice ¶
type ChatCompletionChoice struct {
Index int `json:"index"`
Message ChatMessage `json:"message"`
FinishReason ChatFinishReason `json:"finish_reason"`
}
ChatCompletionChoice is one answer of a ChatCompletion.
type ChatCompletionChunk ¶
type ChatCompletionChunk struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []ChatCompletionChunkChoice `json:"choices"`
// Usage is only in the last chunk, and only if the request asked for it.
Usage *ChatUsage `json:"usage,omitempty"`
}
ChatCompletionChunk is a piece of a streamed answer: the data of an event of the stream.
type ChatCompletionChunkChoice ¶
type ChatCompletionChunkChoice struct {
Index int `json:"index"`
Delta ChatCompletionDelta `json:"delta"`
FinishReason *ChatFinishReason `json:"finish_reason"`
}
ChatCompletionChunkChoice is the piece of one answer of a ChatCompletionChunk. FinishReason is nil until the last chunk of the answer, which is null on the wire.
type ChatCompletionDelta ¶
type ChatCompletionDelta struct {
Role ChatMessageRole `json:"role,omitempty"`
Content string `json:"content,omitempty"`
ToolCalls []ChatCompletionToolCallDelta `json:"tool_calls,omitempty"`
}
ChatCompletionDelta is what a chunk adds to the answer.
type ChatCompletionFunctionCallDelta ¶
type ChatCompletionFunctionCallDelta struct {
Name string `json:"name,omitempty"`
Arguments string `json:"arguments,omitempty"`
}
ChatCompletionFunctionCallDelta is a piece of the function of a tool call: its name in the first piece, then pieces of its arguments. Unlike ChatFunctionCall, an empty field is left out.
type ChatCompletionRequest ¶
type ChatCompletionRequest struct {
// Model is the model that the harness asks for.
Model string `json:"model,omitempty"`
// Stream tells that the harness wants the answer streamed.
Stream bool `json:"stream,omitempty"`
// StreamOptions are the options of a streamed answer, if the harness set any: a request without stream
// options must not gain some, as OpenAI refuses them without a stream.
StreamOptions *ChatStreamOptions `json:"stream_options,omitempty"`
// Messages are the messages said so far, the one to complete last.
Messages []ChatMessage `json:"messages"`
// Tools are the tools that the harness offers to the model.
Tools []ChatTool `json:"tools,omitempty"`
// ToolChoice is the tool_choice of the request as it is: a string, or an object.
ToolChoice json.RawMessage `json:"tool_choice,omitempty"`
// ParallelToolCalls is nil if the harness did not say.
ParallelToolCalls *bool `json:"parallel_tool_calls,omitempty"`
// MaxTokens and MaxCompletionTokens limit the answer. The second is the current name of the first.
MaxTokens int64 `json:"max_tokens,omitempty"`
MaxCompletionTokens int64 `json:"max_completion_tokens,omitempty"`
// Stop is the stop of the request as it is: a string, or a list of strings.
Stop json.RawMessage `json:"stop,omitempty"`
// Header is the headers of the HTTP request that carried it, if it came over HTTP. They hold what the
// body does not: the credentials, the tenant, a trace to follow. They are secrets, never to log.
Header http.Header `json:"-"`
// Extra are the fields of the JSON object that the type does not name: they are kept, and written back.
Extra map[string]json.RawMessage `json:"-"`
}
ChatCompletionRequest is a chat completion request as the harness sent it: the body of OpenAI's chat completions API, of which it names the fields that Proxias and its adapters read. The others are in Extra.
func DecodeChatCompletionRequest ¶
func DecodeChatCompletionRequest(r *http.Request) (ChatCompletionRequest, error)
DecodeChatCompletionRequest reads a chat completions request received over HTTP: its body, and its headers, of which it keeps a copy. An error is returned if the body cannot be read, is not a JSON chat completions request, has no messages, or has a message whose content is neither a string, a list nor null.
A host limits the size of the body (http.MaxBytesReader), and finds the error of a body that is too large with errors.As.
func (ChatCompletionRequest) LastMessage ¶
func (r ChatCompletionRequest) LastMessage() ChatMessage
LastMessage is the last of the messages, the one to complete, or the zero ChatMessage if there are none.
func (ChatCompletionRequest) MarshalJSON ¶
func (r ChatCompletionRequest) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler. The fields of Extra are written, unless a typed field has the same name.
func (ChatCompletionRequest) MaxOutputTokens ¶
func (r ChatCompletionRequest) MaxOutputTokens() int64
MaxOutputTokens is the limit of the answer, or 0 if the harness set none.
func (*ChatCompletionRequest) UnmarshalJSON ¶
func (r *ChatCompletionRequest) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler. The fields the type does not name are kept in Extra.
func (ChatCompletionRequest) UsageRequested ¶
func (r ChatCompletionRequest) UsageRequested() bool
UsageRequested tells whether the harness asked for the usage in a streamed answer.
type ChatCompletionResponse ¶
type ChatCompletionResponse struct {
// Status is the HTTP status code of the response.
Status int
// Header is the headers of the response: its Content-Type, "text/event-stream" for a stream...
Header http.Header
// Body is the content of the response, if any.
Body io.ReadCloser
}
ChatCompletionResponse is what the ControlPlane answers: an HTTP response that the host writes back to its client, a stream included. It is the answer of OpenAI's chat completions API, forwarded as it came from the model's provider or made with NewChatCompletionResponse and NewChatCompletionStream.
Whoever receives a ChatCompletionResponse owns its Body, if there is one, and must close it. A response that comes with an error has none.
func NewChatCompletionResponse ¶
func NewChatCompletionResponse(req ChatCompletionRequest, completion ChatCompletion) (ChatCompletionResponse, error)
NewChatCompletionResponse makes the response of completion to req: the completion as it is or, if req asked for a stream, a stream of it, its usage at the end if req asked for it. Make completion with ChatCompletionBuilder. Chunks produced over time, as a provider streams them, are for NewChatCompletionStream.
func NewChatCompletionStream ¶
func NewChatCompletionStream(produce func(emit func(ChatCompletionChunk) error) error) ChatCompletionResponse
NewChatCompletionStream makes the response of a streamed answer, of the chunks that produce emits: they are events of the stream, followed by its end. The response is returned at once and produce runs in the background, until it returns or the response's Body is closed, which makes emit fail. If produce returns an error, reading the Body fails with it, and the stream has no end event.
type ChatCompletionToolCallDelta ¶
type ChatCompletionToolCallDelta struct {
Index int `json:"index"`
ID string `json:"id,omitempty"`
Type string `json:"type,omitempty"`
Function ChatCompletionFunctionCallDelta `json:"function"`
}
ChatCompletionToolCallDelta is a piece of a tool call: the first one gives the ID and the name of the function, the next ones pieces of its arguments. Index tells which call of the answer it is a piece of.
type ChatContent ¶
type ChatContent []ChatContentPart
ChatContent is the content of a message: a list of parts. On the wire it is a string, which is one text part, or a list of parts, or null, which is no part.
func (ChatContent) MarshalJSON ¶
func (c ChatContent) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler. A lone text part is a string, as the harnesses that sent one expect, unless it has a breakpoint or fields that a string cannot hold.
func (ChatContent) Text ¶
func (c ChatContent) Text() string
Text is the text parts of the content, joined by new lines.
func (*ChatContent) UnmarshalJSON ¶
func (c *ChatContent) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler.
type ChatContentPart ¶
type ChatContentPart struct {
Type ChatContentPartType `json:"type"`
Text string `json:"text,omitempty"`
// ImageURL is the image of a ChatContentPartTypeImageURL part.
ImageURL *ChatImageURL `json:"image_url,omitempty"`
// CacheControl is a cache breakpoint. It is not part of OpenAI's API, but harnesses that talk to Claude
// through an OpenAI-compatible endpoint send it, and it must reach the provider that understands it.
CacheControl *ChatCacheControl `json:"cache_control,omitempty"`
// Extra are the fields of the JSON object that the type does not name: they are kept, and written back.
Extra map[string]json.RawMessage `json:"-"`
}
ChatContentPart is a part of the content of a message.
func (ChatContentPart) MarshalJSON ¶
func (r ChatContentPart) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler. The fields of Extra are written, unless a typed field has the same name.
func (*ChatContentPart) UnmarshalJSON ¶
func (r *ChatContentPart) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler. The fields the type does not name are kept in Extra.
type ChatContentPartType ¶
type ChatContentPartType string
ChatContentPartType is the type of a ChatContentPart.
const ( // ChatContentPartTypeText is a part of text. ChatContentPartTypeText ChatContentPartType = "text" // ChatContentPartTypeImageURL is an image, by address or as a data URL. ChatContentPartTypeImageURL ChatContentPartType = "image_url" )
type ChatFinishReason ¶
type ChatFinishReason string
ChatFinishReason is why a model stopped: "stop", "length", "tool_calls" or "content_filter".
const ( // ChatFinishReasonStop is a natural end, or a stop sequence. ChatFinishReasonStop ChatFinishReason = "stop" // ChatFinishReasonLength is an answer cut at the limit of tokens. ChatFinishReasonLength ChatFinishReason = "length" // ChatFinishReasonToolCalls is an answer that asks for tool calls. ChatFinishReasonToolCalls ChatFinishReason = "tool_calls" // ChatFinishReasonContentFilter is an answer the provider declined to give. ChatFinishReasonContentFilter ChatFinishReason = "content_filter" )
type ChatFunction ¶
type ChatFunction struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Parameters map[string]any `json:"parameters,omitempty"`
// Extra are the fields of the JSON object that the type does not name: they are kept, and written back.
Extra map[string]json.RawMessage `json:"-"`
}
ChatFunction is the function of a ChatTool, its Parameters being a JSON Schema.
func (ChatFunction) MarshalJSON ¶
func (r ChatFunction) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler. The fields of Extra are written, unless a typed field has the same name.
func (*ChatFunction) UnmarshalJSON ¶
func (r *ChatFunction) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler. The fields the type does not name are kept in Extra.
type ChatFunctionCall ¶
type ChatFunctionCall struct {
Name string `json:"name"`
// JSON representation of the arguments for the tool function call.
Arguments string `json:"arguments"`
// Extra are the fields of the JSON object that the type does not name: they are kept, and written back.
Extra map[string]json.RawMessage `json:"-"`
}
ChatFunctionCall is the function of a ChatToolCall: its name, and its arguments as a JSON text.
func (ChatFunctionCall) MarshalJSON ¶
func (r ChatFunctionCall) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler. The fields of Extra are written, unless a typed field has the same name.
func (*ChatFunctionCall) UnmarshalJSON ¶
func (r *ChatFunctionCall) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler. The fields the type does not name are kept in Extra.
type ChatImageURL ¶
type ChatImageURL struct {
URL string `json:"url"`
Detail string `json:"detail,omitempty"`
// Extra are the fields of the JSON object that the type does not name: they are kept, and written back.
Extra map[string]json.RawMessage `json:"-"`
}
ChatImageURL is the image of a part: a web address, or a data URL (data:image/png;base64,...).
func (ChatImageURL) MarshalJSON ¶
func (r ChatImageURL) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler. The fields of Extra are written, unless a typed field has the same name.
func (*ChatImageURL) UnmarshalJSON ¶
func (r *ChatImageURL) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler. The fields the type does not name are kept in Extra.
type ChatMessage ¶
type ChatMessage struct {
Role ChatMessageRole `json:"role"`
// Content is null for an assistant message that only calls tools, which is what the response must say too.
Content ChatContent `json:"content"`
// ToolCalls are the calls that an assistant message asks for.
ToolCalls []ChatToolCall `json:"tool_calls,omitempty"`
// ToolCallID is the call that a tool message answers.
ToolCallID string `json:"tool_call_id,omitempty"`
// Name is the name of the user or model that sent the message, if applicable.
Name string `json:"name,omitempty"`
// Extra are the fields of the JSON object that the type does not name: they are kept, and written back.
Extra map[string]json.RawMessage `json:"-"`
}
ChatMessage is one message of a ChatCompletionRequest, or the message of an answer.
func (ChatMessage) HasToolRole ¶
func (m ChatMessage) HasToolRole() bool
HasToolRole tells whether the message holds the result of a tool (or, formerly, of a function) that ran, as opposed to a message of a user or of a model.
func (ChatMessage) MarshalJSON ¶
func (m ChatMessage) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler. The fields of Extra are written, unless a typed field has the same name.
func (*ChatMessage) UnmarshalJSON ¶
func (m *ChatMessage) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler. The fields the type does not name are kept in Extra.
type ChatMessageRole ¶
type ChatMessageRole string
ChatMessageRole defines the role of a message in the chat completion. In other words it allows indicating who generated a particular message in the chat history.
const ( // ChatMessageRoleUser represents a user message in the chat completion. // Purpose: Contains the prompt, questions, or instructions sent by a human user. // Origin: Provided by the end-user interacting with an application/harness. ChatMessageRoleUser ChatMessageRole = "user" // ChatMessageRoleSystem represents a system message in the chat completion. // See ChatMessageRoleDeveloper for more details. ChatMessageRoleSystem ChatMessageRole = "system" // ChatMessageRoleDeveloper formally "system", represents an internal message. // Purpose: indicates that a message sets the persona, behavior, boundaries, and global context of the model. // Essentially guides the model's tone or dicatates formatting rules (e.g. "always return JSON"), // dictates guardrails, constraints, or safety measures for the model's behavior. // In most models it carries the highest level of authority over the model's behavior. // Origin: Usually set by harness/application developers, hidden from users. ChatMessageRoleDeveloper ChatMessageRole = "developer" // ChatMessageRoleAssistant represents an assistant message in the chat completion. // Purpose: Store the model's generated responses. Used to feed conversation history back to the model. // Because chat completion APIs are generally stateless, this provides a mechanism to maintain conversation // context across multiple turns. // Can also be used for few-shots prompting to mock how user and assistant turns to show the model how it should behave. // Origin: Generated by the model in response to user and system messages, or by backend code/harnesses when few-shots prompting is used. ChatMessageRoleAssistant ChatMessageRole = "assistant" // ChatMessageRoleFunction represents a function message in the chat completion. // See ChatMessageRoleTool for more details. ChatMessageRoleFunction ChatMessageRole = "function" // ChatMessageRoleTool represents a tool message in the chat completion. // Purpose: Passes the output/results of an external function back to the model after a tool call. // When a model calls an external tool, it stops generating text responses and outputs // "tool calls" requests instead. Code runs these tools locally and passes the output back to the model. // using the tool role, so the model can read it and formulate its final answer. // Origin: Executed by backend code. ChatMessageRoleTool ChatMessageRole = "tool" )
type ChatPromptTokensDetails ¶
type ChatPromptTokensDetails struct {
CachedTokens int64 `json:"cached_tokens"`
}
ChatPromptTokensDetails tells apart the prompt tokens that were read from the provider's cache.
type ChatStreamOptions ¶
type ChatStreamOptions struct {
IncludeUsage bool `json:"include_usage,omitempty"`
// Extra are the fields of the JSON object that the type does not name: they are kept, and written back.
Extra map[string]json.RawMessage `json:"-"`
}
ChatStreamOptions are the options of a streamed answer.
func (ChatStreamOptions) MarshalJSON ¶
func (r ChatStreamOptions) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler. The fields of Extra are written, unless a typed field has the same name.
func (*ChatStreamOptions) UnmarshalJSON ¶
func (r *ChatStreamOptions) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler. The fields the type does not name are kept in Extra.
type ChatTool ¶
type ChatTool struct {
Type string `json:"type"`
Function ChatFunction `json:"function"`
// Extra are the fields of the JSON object that the type does not name: they are kept, and written back.
Extra map[string]json.RawMessage `json:"-"`
}
ChatTool is a tool that the harness offers to the model.
func (ChatTool) MarshalJSON ¶
MarshalJSON implements json.Marshaler. The fields of Extra are written, unless a typed field has the same name.
func (*ChatTool) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler. The fields the type does not name are kept in Extra.
type ChatToolCall ¶
type ChatToolCall struct {
ID string `json:"id"`
Type string `json:"type"`
Function ChatFunctionCall `json:"function"`
// Extra are the fields of the JSON object that the type does not name: they are kept, and written back.
Extra map[string]json.RawMessage `json:"-"`
}
ChatToolCall is a call of a function that a model asks for, in a message.
func (ChatToolCall) MarshalJSON ¶
func (r ChatToolCall) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler. The fields of Extra are written, unless a typed field has the same name.
func (*ChatToolCall) UnmarshalJSON ¶
func (r *ChatToolCall) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler. The fields the type does not name are kept in Extra.
type ChatUsage ¶
type ChatUsage struct {
PromptTokens int64 `json:"prompt_tokens"`
CompletionTokens int64 `json:"completion_tokens"`
TotalTokens int64 `json:"total_tokens"`
PromptTokensDetails *ChatPromptTokensDetails `json:"prompt_tokens_details,omitempty"`
}
ChatUsage is what an answer cost, in tokens.
type CompositeIntentClassifier ¶
type CompositeIntentClassifier struct {
// contains filtered or unexported fields
}
CompositeIntentClassifier is an IntentClassifier made of two stages, so that each can be a different, small and fast component: an ActionExecutionIntentSelector chooses the actions, and a ActionExecutionIntentParameterExtractor then extracts the parameters of those that were chosen, and of those only.
func NewCompositeIntentClassifier ¶
func NewCompositeIntentClassifier(selector ActionExecutionIntentSelector, paramExtractor ActionExecutionIntentParameterExtractor) *CompositeIntentClassifier
NewCompositeIntentClassifier makes a CompositeIntentClassifier of a selector and a parameter extractor.
func (*CompositeIntentClassifier) Classify ¶
func (c *CompositeIntentClassifier) Classify(ctx context.Context, req ChatCompletionRequest, descs []ActionDescriptor) (Intent, error)
Classify selects the actions the request asks for, then extracts their parameters. Nothing is extracted if no action was selected: the intent is then a reasoning intent.
type ControlPlane ¶
type ControlPlane interface {
// Process answers req. An error is an infrastructure failure of one of the steps, or of the context: a
// action that cannot run for a reason the user should hear of is not an error, it is a
// ActionExecutionResult for the synthesizer.
//
// An error of a step is wrapped with the proxias: prefix, once, here: the steps' own errors carry only
// their stage. A context error is returned as is.
//
// Process does not recover from panics: the host does, if it wants to.
Process(ctx context.Context, req ChatCompletionRequest) (ChatCompletionResponse, error)
}
ControlPlane answers a request by running it through a chain of Middleware: the first step that answers it bypasses the rest. A chain of an ActionInterceptionMiddleware, which runs the actions a request asks for, and then a ReasoningMiddleware, which answers the rest, is the usual one.
func NewControlPlane ¶
func NewControlPlane(middlewares ...Middleware) (ControlPlane, error)
NewControlPlane makes a ControlPlane of the middleware, in the order they are given: the first is the first to see a request. It returns an error if there is none, or if one of them is nil.
The chain is built once, here, so that a request costs only the calls of the steps it goes through.
type HeaderIdentityProvider ¶
type HeaderIdentityProvider[T ~string] struct { // HeaderName is the name of the header to read, in any case. HeaderName string }
HeaderIdentityProvider provides an identity from a header of the HTTP request that carried the request. It trusts the header: it is for a host that sits behind something that sets it (a gateway) or that checked it already. A request that did not come over HTTP, or that lacks the header, has the zero identity.
func NewAgentHeaderIdentityProvider ¶
func NewAgentHeaderIdentityProvider(headerName string) *HeaderIdentityProvider[AgentIdentity]
NewAgentHeaderIdentityProvider returns a HeaderIdentityProvider of AgentIdentity that reads the given header, or DefaultAgentIdentityHeader if headerName is empty.
func NewHeaderIdentityProvider ¶
func NewHeaderIdentityProvider[T ~string](headerName string) *HeaderIdentityProvider[T]
NewHeaderIdentityProvider returns a HeaderIdentityProvider that reads the header of the given name.
func NewUserHeaderIdentityProvider ¶
func NewUserHeaderIdentityProvider(headerName string) *HeaderIdentityProvider[UserIdentity]
NewUserHeaderIdentityProvider returns a HeaderIdentityProvider of UserIdentity that reads the given header, or DefaultUserIdentityHeader if headerName is empty.
func (*HeaderIdentityProvider[T]) ProvideIdentity ¶
func (h *HeaderIdentityProvider[T]) ProvideIdentity(_ context.Context, req ChatCompletionRequest) (T, error)
ProvideIdentity returns the value of the header, which is empty when the request does not carry it. It never fails.
type IdentityProvider ¶
type IdentityProvider[T any] interface { ProvideIdentity(ctx context.Context, req ChatCompletionRequest) (T, error) }
IdentityProvider tells who a request is from. It is generic so that the same shape serves the user and the agent, see UserIdentityProvider and AgentIdentityProvider. An error means the identity could not be determined, and fails the request; an unknown identity is the zero value of T, not an error.
type IdentityProviderFunc ¶
type IdentityProviderFunc[T any] func(ctx context.Context, req ChatCompletionRequest) (T, error)
IdentityProviderFunc is an IdentityProvider of a function, for an identity that comes from anywhere: a token, a session, a database.
func (IdentityProviderFunc[T]) ProvideIdentity ¶
func (f IdentityProviderFunc[T]) ProvideIdentity(ctx context.Context, req ChatCompletionRequest) (T, error)
ProvideIdentity calls f.
type Intent ¶
type Intent struct {
ActionExecutions []ActionExecutionIntent
}
Intent represents the classified outcome of an inbound chat completion request. It contains information about which actions should be executed and with what parameters. An Intent with no ActionExecutions indicates that the request requires open-ended reasoning rather than specific action execution: it is answered by the ReasoningEngine.
func (Intent) IsReasoningIntent ¶
IsReasoningIntent tells whether the request asks for no action, and requires open-ended reasoning.
type IntentClassifier ¶
type IntentClassifier interface {
Classify(context.Context, ChatCompletionRequest, []ActionDescriptor) (Intent, error)
}
IntentClassifier translates an inbound chat completion request into a typed Intent. It serves as the primary inbound translation component evaluating human prose against specific action descriptors to determine the request requires code execution through actions or open-ended reasoning. Harnesses commonly leave this to an LLM in its ReAct loop, which is slow, costly and non-deterministic. An IntentClassifier is meant to be fast: local rules, or a discriminative, system-1 model.
It is given the actions that the request may ask for, with their InputSchema, and returns an Intent that names the actions to run and their parameters. An Intent with no action executions means that the request asks for none: it goes to the ReasoningEngine.
Error Handling: return a non-nil error if classification itself fails, these errors are internal infrastructure level errors and won't be synthesized into a user-facing response by the control plane.
type IntentClassifierFunc ¶
type IntentClassifierFunc func(context.Context, ChatCompletionRequest, []ActionDescriptor) (Intent, error)
IntentClassifierFunc is an IntentClassifier as a function.
func (IntentClassifierFunc) Classify ¶
func (f IntentClassifierFunc) Classify(ctx context.Context, req ChatCompletionRequest, descs []ActionDescriptor) (Intent, error)
Classify calls f.
type Middleware ¶
type Middleware func(next ProcessFunc) ProcessFunc
Middleware is a step of the chain of a ControlPlane. It receives the rest of the chain as next, and returns the step itself. A step either answers the request and does not call next, which bypasses the rest of the chain, or it calls next with the request it wants the rest to see: a step may change the request, or add data to the context, before it does.
A request is passed by value, so changing its fields changes only the copy that next receives. Its slices, maps and Extra fields are shared with the caller, so a step replaces them rather than editing them in place:
req.Messages = append([]ChatMessage{system}, req.Messages...) // not: req.Messages[0] = system
A step that changes the model, for instance, is a middleware of a few lines:
func routeModel(next ProcessFunc) ProcessFunc {
return func(ctx context.Context, req ChatCompletionRequest) (ChatCompletionResponse, error) {
req.Model = chooseModel(req)
return next(ctx, req)
}
}
func NewActionInterceptionMiddleware ¶
func NewActionInterceptionMiddleware(classifier IntentClassifier, engine ActionExecutionEngine, synthesizer ActionExecutionSynthesizer) (Middleware, error)
NewActionInterceptionMiddleware makes the middleware that runs the actions a request asks for: the classifier names them, the engine runs them, and the synthesizer makes the response. A request that asks for no action is passed on to the rest of the chain, with the descriptors of the actions in its context. It returns an error if one of the components is nil.
func NewAgentIdentityMiddleware ¶
func NewAgentIdentityMiddleware(p AgentIdentityProvider) (Middleware, error)
NewAgentIdentityMiddleware is NewIdentityMiddleware for the AgentIdentity: the rest of the chain reads it with AgentIdentityFrom. It returns an error if the provider is nil.
func NewIdentityMiddleware ¶
func NewIdentityMiddleware[T any](p IdentityProvider[T]) (Middleware, error)
NewIdentityMiddleware returns a Middleware that asks the provider who a request is from, and puts the identity in the context for the rest of the chain, to read with IdentityFrom[T]. It never changes or answers the request. An error of the provider is returned wrapped with its stage, and the rest of the chain does not run. It returns an error if the provider is nil.
func NewReasoningMiddleware ¶
func NewReasoningMiddleware(engine ReasoningEngine) (Middleware, error)
NewReasoningMiddleware makes the middleware that answers the requests no action fits: the reasoning engine is given the request and the action descriptors of the context. It always answers, so it ends a chain: it does not call next. It returns an error if the engine is nil.
func NewUserIdentityMiddleware ¶
func NewUserIdentityMiddleware(p UserIdentityProvider) (Middleware, error)
NewUserIdentityMiddleware is NewIdentityMiddleware for the UserIdentity: the rest of the chain reads it with UserIdentityFrom. It returns an error if the provider is nil.
type ProcessFunc ¶
type ProcessFunc func(ctx context.Context, req ChatCompletionRequest) (ChatCompletionResponse, error)
ProcessFunc is ControlPlane.Process as a function: what a Middleware receives as its next, and what it returns. A ProcessFunc answers a request, or fails.
type Prompt ¶
type Prompt struct {
// contains filtered or unexported fields
}
Prompt builds the text of a prompt for an LLM from paragraphs, titled sections and bullet points, so that the components that talk to a model do not assemble strings by hand. The text is plain Markdown: a section is a "## " heading, a bullet point a "- " line.
Blocks come out in the order they were added. Consecutive bullet points, and bullet points that follow a section, are on consecutive lines (a bullet point list belongs to the section above it); everything else is separated by a blank line. A Prompt is not safe for concurrent use. Use NewPrompt; its methods return the Prompt, to chain them.
func (*Prompt) AddBulletPoint ¶
AddBulletPoint adds a bullet point. A blank text is ignored. The lines of a text that has several are indented under its bullet.
func (*Prompt) AddLabeledBulletPoint ¶
AddLabeledBulletPoint adds a bullet point of the form "- label: text", to list things that have a name (an identifier, a term) along with what they are. A blank label is ignored, and a blank text leaves only the label.
func (*Prompt) AddParagraph ¶
AddParagraph adds text as is. A blank text is ignored.
func (*Prompt) AddSection ¶
AddSection adds a section: a title, and its content, if any. Bullet points added right after it are part of the section. A blank title is ignored.
type ReasoningEngine ¶
type ReasoningEngine interface {
Reason(ctx context.Context, req ChatCompletionRequest, descs []ActionDescriptor) (ChatCompletionResponse, error)
}
ReasoningEngine is responsible for handling open-ended reasoning tasks that are not tied to specific action executions. It takes a ChatCompletionRequest and produces a ChatCompletionResponse. The reasoning engine may use the provided action descriptors to inform its reasoning process.
It is typically the host's LLM: a request that asks for no action usually goes to it as is.
Error Handling: return a non-nil error if reasoning itself fails.
type ReasoningEngineFunc ¶
type ReasoningEngineFunc func(ctx context.Context, req ChatCompletionRequest, descs []ActionDescriptor) (ChatCompletionResponse, error)
ReasoningEngineFunc is a ReasoningEngine as a function.
func (ReasoningEngineFunc) Reason ¶
func (f ReasoningEngineFunc) Reason(ctx context.Context, req ChatCompletionRequest, descs []ActionDescriptor) (ChatCompletionResponse, error)
Reason implements ReasoningEngine.
type UserIdentity ¶
type UserIdentity string
UserIdentity identifies the user on whose behalf a request is made, as a host defines it (an ID, an email). The empty identity means the user is unknown.
func UserIdentityFrom ¶
func UserIdentityFrom(ctx context.Context) UserIdentity
UserIdentityFrom returns the user identity that the context carries, or the empty identity if it carries none.
type UserIdentityProvider ¶
type UserIdentityProvider IdentityProvider[UserIdentity]
UserIdentityProvider provides the identity of the user of a request.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
adapters
|
|
|
anthropic
Package anthropic implements the components of Proxias with Claude, through the official Anthropic SDK.
|
Package anthropic implements the components of Proxias with Claude, through the official Anthropic SDK. |
|
openai
Package openai implements the components of Proxias with a model served by an OpenAI-compatible chat completions API: OpenAI itself, or any provider or server that speaks it.
|
Package openai implements the components of Proxias with a model served by an OpenAI-compatible chat completions API: OpenAI itself, or any provider or server that speaks it. |
|
examples
|
|
|
basic
command
Command basic is a hello world of Proxias: a ControlPlane with a single action, say_hello_world, that a request answers without any LLM, and Claude (set ANTHROPIC_API_KEY) for what no action fits.
|
Command basic is a hello world of Proxias: a ControlPlane with a single action, say_hello_world, that a request answers without any LLM, and Claude (set ANTHROPIC_API_KEY) for what no action fits. |
|
sandbox
command
Command harness is a sandbox for the middleware chain: it serves a ControlPlane as the OpenAI chat completions endpoint, so that a real harness (OpenClaw, see `task sandbox:openclaw`) can talk to it.
|
Command harness is a sandbox for the middleware chain: it serves a ControlPlane as the OpenAI chat completions endpoint, so that a real harness (OpenClaw, see `task sandbox:openclaw`) can talk to it. |