Documentation
¶
Overview ¶
Package virtualmodel defines the protocol-agnostic primitives for virtual models. Concrete provider-specific implementations and registries live in the anthropic and openai sub-packages — this top-level package contains only the base interface and shared value types.
These primitives back the production /virtual/v1/* endpoint (onboarding, demos, dry-runs without a real upstream provider) and are also reused as an in-process LLM substitute by test packages such as protocoltest and servertest. The production endpoint is the package's primary surface; test consumers are secondary and use GenericRegistry directly rather than RegisterDefaults — see README.md "Positioning & registration discipline".
Index ¶
- Constants
- func EmitChunks(ctx context.Context, chunks []string, perChunkDelay time.Duration, ...) error
- func ResolveChunkDelay(totalDelay time.Duration, chunkCount int) time.Duration
- func ToolCallDisplayContent(args map[string]interface{}) string
- type BaseMockModel
- type EmitGate
- type ErrorCategory
- type ErrorInjectingModel
- type ErrorInjection
- type ErrorStage
- type GenericRegistry
- func (r *GenericRegistry[T]) Clear()
- func (r *GenericRegistry[T]) Get(id string) T
- func (r *GenericRegistry[T]) Has(id string) bool
- func (r *GenericRegistry[T]) List() []T
- func (r *GenericRegistry[T]) ListModels() []Model
- func (r *GenericRegistry[T]) Register(vm T) error
- func (r *GenericRegistry[T]) Unregister(id string)
- type MidStreamMode
- type MockUsage
- type Model
- type SharedMockSpec
- type ToolCallConfig
- type VirtualModel
- type VirtualModelType
Constants ¶
const DefaultMockDescription = "A virtual model that returns fixed responses for testing"
DefaultMockDescription is the description returned by mock virtual models when their config does not provide an explicit one.
const DefaultMockOwnedBy = "tingly-box-virtual"
DefaultMockOwnedBy is the OwnedBy value reported by every built-in mock virtual model in the OpenAI-compatible models list.
const DefaultStreamChunkDelay = 50 * time.Millisecond
DefaultStreamChunkDelay is the per-chunk sleep used by stream helpers when no explicit total simulated delay is configured.
Variables ¶
This section is empty.
Functions ¶
func EmitChunks ¶
func EmitChunks(ctx context.Context, chunks []string, perChunkDelay time.Duration, emit func(index int, chunk string) bool) error
EmitChunks returns the context error if cancellation happens while waiting or if the emit callback stops accepting chunks.
func ResolveChunkDelay ¶
ResolveChunkDelay computes the per-chunk sleep duration for a stream.
- if totalDelay > 0 and chunkCount > 0 → totalDelay / chunkCount
- otherwise → DefaultStreamChunkDelay
This is the shared latency-distribution rule used by all mock streams across protocols.
func ToolCallDisplayContent ¶
ToolCallDisplayContent extracts display text from tool call arguments. It checks for "message" and "question" keys, returning the first non-empty value found.
Types ¶
type BaseMockModel ¶
type BaseMockModel struct {
ID string
Name string
Description string
Type VirtualModelType
Delay time.Duration
}
BaseMockModel is the protocol-neutral half of an in-memory mock virtual model. Protocol-specific mocks embed it and only need to add their own Handle*/Handle*Stream methods. All identity / metadata methods of the VirtualModel interface live here.
func (*BaseMockModel) GetDescription ¶
func (b *BaseMockModel) GetDescription() string
func (*BaseMockModel) GetID ¶
func (b *BaseMockModel) GetID() string
func (*BaseMockModel) GetName ¶
func (b *BaseMockModel) GetName() string
func (*BaseMockModel) GetType ¶
func (b *BaseMockModel) GetType() VirtualModelType
func (*BaseMockModel) SimulatedDelay ¶
func (b *BaseMockModel) SimulatedDelay() time.Duration
func (*BaseMockModel) ToModel ¶
func (b *BaseMockModel) ToModel() Model
ToModel returns the OpenAI-compatible models-list entry for this mock.
type EmitGate ¶ added in v0.260604.1
type EmitGate struct {
// contains filtered or unexported fields
}
EmitGate is a counting gate used by mock streams to honor mid-stream injection. After Allow() has returned true `cutoff` times, all subsequent Allow() calls return false. Callers should bail out of the stream loop the first time Allow() returns false to avoid emitting events past the cutoff.
A cutoff of <= 0 disables the gate (Allow() always returns true).
func NewEmitGate ¶ added in v0.260604.1
NewEmitGate constructs a gate. Pass the return value of MidStreamCutoff (or -1 to disable).
type ErrorCategory ¶ added in v0.260611.1
type ErrorCategory string
ErrorCategory categorizes error models for filtering and catalog purposes.
const ( ErrorCategoryRateLimit ErrorCategory = "rate_limit" // Rate limiting (429) ErrorCategoryUpstream ErrorCategory = "upstream" // Upstream server errors (5xx) ErrorCategoryTimeout ErrorCategory = "timeout" // Request timeout ErrorCategoryOverloaded ErrorCategory = "overloaded" // Service overloaded ErrorCategoryInvalid ErrorCategory = "invalid" // Invalid request ErrorCategoryAuth ErrorCategory = "auth" // Authentication/authorization ErrorCategoryNetwork ErrorCategory = "network" // Network connectivity ErrorCategoryMalformed ErrorCategory = "malformed" // Malformed response )
type ErrorInjectingModel ¶ added in v0.260604.1
type ErrorInjectingModel interface {
ErrorInjection() *ErrorInjection
}
ErrorInjectingModel is the optional interface a mock virtual model implements to declare a synthetic failure. The virtualserver handler type-asserts to this interface before dispatching the request.
type ErrorInjection ¶ added in v0.260604.1
type ErrorInjection struct {
Stage ErrorStage
// PreContent fields: HTTP status (defaults to 500 if zero) and an
// optional message that the handler renders into the protocol-specific
// error envelope (OpenAI: error.message; Anthropic: error.error.message).
// Type defaults to "api_error" if empty.
Status int
Message string
Type string
// MidStream fields: number of stream events to emit before tripping
// (default 1; values <= 0 are treated as 1), and how to terminate.
AfterEvents int
MidStreamMode MidStreamMode
}
ErrorInjection describes a synthetic failure that a mock virtual model should simulate. Attach one to MockScenario.Error (or MockModelConfig.Error) and the virtualserver handler honors it without any real upstream involvement.
Two stages are supported, and they exercise different gateway paths:
- PreContent: HTTP status + error body, no streaming started. The gateway's firstChunkGate stays buffered → failover retries.
- MidStream: handler writes a 200 + Content-Type + AfterEvents real events, then either closes the TCP connection or emits a final SSE error event. firstChunkGate is already committed → failover MUST NOT retry.
func ExtractErrorInjection ¶ added in v0.260604.1
func ExtractErrorInjection(vm any) *ErrorInjection
ExtractErrorInjection reports the model's error injection configuration, or nil if the model does not implement ErrorInjectingModel or has none set.
type ErrorStage ¶ added in v0.260604.1
type ErrorStage int
ErrorStage selects when in the request lifecycle a mock model's error injection fires.
const ( // ErrorStagePreContent is a failure before any response body is written: // the handler returns the configured HTTP status with an error JSON envelope // and never invokes the model's Handle* methods past that point. This is // the case that priority-routing failover MUST retry — the gate stays // buffered, the orchestrator sees a retryable status and discards. ErrorStagePreContent ErrorStage = iota // ErrorStageMidStream is a failure after the handler has already started // streaming. The model emits AfterEvents real stream events, then the // handler applies MidStreamMode: it either hijacks and closes the TCP // connection (truncated stream from the client's POV) or emits a single // SSE error event before stopping. This is the case that priority-routing // failover MUST NOT retry — the gate has committed, bytes left the process. ErrorStageMidStream )
type GenericRegistry ¶
type GenericRegistry[T VirtualModel] struct { // contains filtered or unexported fields }
GenericRegistry is a thread-safe registry of virtual models indexed by ID, parameterised by a protocol-specific VirtualModel sub-interface T. Each protocol sub-package (anthropic, openai, ...) instantiates its own Registry alias so models cannot leak across protocols.
func NewGenericRegistry ¶
func NewGenericRegistry[T VirtualModel]() *GenericRegistry[T]
NewGenericRegistry creates an empty registry.
func (*GenericRegistry[T]) Clear ¶
func (r *GenericRegistry[T]) Clear()
Clear removes all registered models.
func (*GenericRegistry[T]) Get ¶
func (r *GenericRegistry[T]) Get(id string) T
Get returns the virtual model for id, or the zero value of T if not registered.
func (*GenericRegistry[T]) Has ¶
func (r *GenericRegistry[T]) Has(id string) bool
Has reports whether a model with the given ID is registered.
func (*GenericRegistry[T]) List ¶
func (r *GenericRegistry[T]) List() []T
List returns all registered virtual models.
func (*GenericRegistry[T]) ListModels ¶
func (r *GenericRegistry[T]) ListModels() []Model
ListModels returns all registered models in the OpenAI-compatible Model format.
func (*GenericRegistry[T]) Register ¶
func (r *GenericRegistry[T]) Register(vm T) error
Register adds a virtual model. Returns an error if the ID is already taken.
func (*GenericRegistry[T]) Unregister ¶
func (r *GenericRegistry[T]) Unregister(id string)
Unregister removes a virtual model by ID. No-op if not present.
type MidStreamMode ¶ added in v0.260604.1
type MidStreamMode int
MidStreamMode selects how a mid-stream failure terminates the stream after AfterEvents events have been emitted to the wire.
const ( // MidStreamModeConnectionClose hijacks the underlying TCP connection and // closes it. The client sees an EOF / abrupt disconnect mid-stream — // exactly the shape an unstable upstream produces when it dies during a // long response. MidStreamModeConnectionClose MidStreamMode = iota // MidStreamModeErrorEvent emits one final protocol-specific error event // (SSE "event: error" frame) before returning. The stream is well-formed // up to that point; the client sees an in-band error. MidStreamModeErrorEvent )
type MockUsage ¶ added in v0.260604.1
type MockUsage struct {
PromptTokens int64 // input_tokens / prompt_tokens
CompletionTokens int64 // output_tokens / completion_tokens
CachedInputTokens int64 // OpenAI prompt_tokens_details.cached_tokens / Anthropic cache_read_input_tokens
CacheCreationInputTokens int64 // Anthropic cache_creation_input_tokens (no OpenAI analogue)
ReasoningTokens int64 // OpenAI completion_tokens_details.reasoning_tokens
}
MockUsage carries deterministic token-usage values that a mock model emits over its streaming wire format. All fields are optional; a zero value means "do not advertise this dimension". Used so streaming converters / observers can be tested for completeness (cache and reasoning tokens, not just plain prompt/completion).
type Model ¶
type Model struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
OwnedBy string `json:"owned_by"`
}
Model represents a virtual model in the models list (OpenAI-compatible format).
type SharedMockSpec ¶
type SharedMockSpec struct {
// Error metadata (only meaningful when Error != nil)
}
SharedMockSpec describes a built-in mock that is identical across protocols (anthropic + openai). Each protocol's RegisterDefaults converts a SharedMockSpec into its own protocol-specific MockModelConfig.
Entries returned by SharedDefaultMocks are user-facing demo defaults: they are mounted into the production /virtual/v1/* endpoint and visible to end users via the virtual provider. Test-only fixtures must NOT be added here; tests should build their own GenericRegistry rather than pollute the production defaults set.
func ExtendedErrorSpecs ¶ added in v0.260611.1
func ExtendedErrorSpecs() []SharedMockSpec
ExtendedErrorSpecs returns additional error scenarios for testing. These are opt-in - register via RegisterExtendedErrorMocks in per-protocol packages.
func SharedDefaultMocks ¶
func SharedDefaultMocks() []SharedMockSpec
SharedDefaultMocks returns the mocks registered by BOTH the Anthropic and OpenAI default registries. Per-protocol unique entries (e.g. virtual-claude-3 for Anthropic, virtual-gpt-4 for OpenAI, the compact transforms) live in their respective sub-packages.
func StreamTestMockSpecs ¶ added in v0.260604.1
func StreamTestMockSpecs() []SharedMockSpec
StreamTestMockSpecs returns deterministic stream-test fixtures (static + tool variants) that advertise the full usage shape — prompt, completion, cached input, cache-creation input, and reasoning tokens. These are opt-in (NOT in SharedDefaultMocks): consumers wire them into their own registry via RegisterStreamTestMocks helpers in the per-protocol sub-packages.
type ToolCallConfig ¶
type ToolCallConfig struct {
Name string `json:"name" yaml:"name"`
Arguments map[string]interface{} `json:"arguments" yaml:"arguments"`
}
ToolCallConfig defines a tool call to be returned by the virtual model.
type VirtualModel ¶
type VirtualModel interface {
GetID() string
GetName() string
GetDescription() string
GetType() VirtualModelType
SimulatedDelay() time.Duration
ToModel() Model
}
VirtualModel is the base interface common to all virtual model types. Provider-specific extensions are defined in the anthropic and openai sub-packages, each adding the Handle methods for that protocol.
type VirtualModelType ¶
type VirtualModelType string
VirtualModelType represents the type/category of a virtual model.
const ( // VirtualModelTypeStatic represents static mock models that return fixed responses. VirtualModelTypeStatic VirtualModelType = "static" // VirtualModelTypeProxy represents proxy/transform models that modify requests before forwarding. VirtualModelTypeProxy VirtualModelType = "proxy" // VirtualModelTypeTool represents tool models that return tool_use blocks. VirtualModelTypeTool VirtualModelType = "tool" )
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package anthropic provides Anthropic-protocol virtual models.
|
Package anthropic provides Anthropic-protocol virtual models. |
|
Package benchmark is the vmodel benchmark: a shared, real-world mock-provider foundation.
|
Package benchmark is the vmodel benchmark: a shared, real-world mock-provider foundation. |
|
check
Package check holds the protocol-neutral, reusable check logic for the vmodel benchmark: the RoundTripResult view of a single gateway round trip and the named Assertion library that operates on it.
|
Package check holds the protocol-neutral, reusable check logic for the vmodel benchmark: the RoundTripResult view of a single gateway round trip and the named Assertion library that operates on it. |
|
examples/client
command
Stand-alone benchmark client driver: starts an in-process LocalServer (vmodel-backed) and drives it with the BenchmarkClient against both the OpenAI Chat and Anthropic Messages routes, printing a metrics summary.
|
Stand-alone benchmark client driver: starts an in-process LocalServer (vmodel-backed) and drives it with the BenchmarkClient against both the OpenAI Chat and Anthropic Messages routes, printing a metrics summary. |
|
examples/server
command
Stand-alone benchmark mock server: starts a local HTTP server backed by the production virtualmodel registries (with their default mock models pre-registered) so external benchmark drivers can hit a realistic vmodel surface over loopback.
|
Stand-alone benchmark mock server: starts a local HTTP server backed by the production virtualmodel registries (with their default mock models pre-registered) so external benchmark drivers can hit a realistic vmodel surface over loopback. |
|
scenario
Package scenario holds the reusable mock-provider fixtures for the vmodel benchmark: named Scenarios, each carrying per-format MockResponseBuilders and a set of check.Assertions.
|
Package scenario holds the reusable mock-provider fixtures for the vmodel benchmark: named Scenarios, each carrying per-format MockResponseBuilders and a set of check.Assertions. |
|
Package vmodelclient provides in-process implementations of the client interfaces backed by vmodel registries.
|
Package vmodelclient provides in-process implementations of the client interfaces backed by vmodel registries. |
|
Package openai provides OpenAI-protocol virtual models.
|
Package openai provides OpenAI-protocol virtual models. |
|
Package virtualserver provides the HTTP handler for virtual model endpoints.
|
Package virtualserver provides the HTTP handler for virtual model endpoints. |