Changelog
All notable changes to the Protolink project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Upgrade to the latest published release before following the notes below.
- pip
- uv
pip install --upgrade protolink
uv add --upgrade protolink
Release Notes
[0.6.8] - 2026-07-30
This patch release introduces first-party Retrieval-Augmented Generation
(RAG), a deterministic infer-loop benchmark for evaluating model
correctness, tool use, delegation, semantic agent routing, recovery, and
performance, and a substantially expanded local observability workflow.
Telemetry traces can now be inspected and replayed in the dashboard through
the protolink dashboard CLI command, alongside improved Registry and Runs
views. The CLI also gains explicit version reporting, while richer parse errors
and benchmark artifacts make local-model behavior easier to diagnose,
compare, and improve.
Added
- Added first-party Retrieval-Augmented Generation through the
Knowledgefacade andcreate_knowledge(): dependency-free in-memory and persistent SQLite indexes, automatic loading/chunking/embedding, vector, keyword, and hybrid search, metadata filters, MMR, reranking, managed index lifecycle, normalized hits, structured citations, and async/blocking APIs. - Added retrieval-only adapters for user-owned Chroma collections, Pinecone
indexes, Qdrant collections, arbitrary
Retrieverimplementations, and sync or async search functions. External clients, credentials, embedding compatibility, and index ownership remain with the application. - Added
Agent(..., knowledge=..., retrieval="auto"|"always"|"required"), generatedsearch_<name>tools,Agent.add_knowledge(),@agent.retriever, and deterministicAgent.ask()/agent.sync.ask()returningRAGAnswertext, hits, and citations. Knowledge reads participate in policy, approvals, cancellation, budgets, telemetry, task metadata, and the existing native/JSON-fallback inference loop. Raw knowledge passages are ephemeral to the active authorized model loop and are omitted from persistent conversation history, task boundaries, and telemetry. - Added the dependency-free
examples/rag_agent.pyand a complete RAG guide covering managed indexes, existing vector databases, custom retrievers, retrieval modes, citations, source lifecycle, and operational safety. - Added a deterministic, repository-local infer-loop benchmark that exercises
the real
AgentClient,Task, coordinatorAgent, provider adapter, model inference loop, local tools, delegated agents, runtime events, and telemetry against controlled inputs and independently recorded outcomes. - Added benchmark coverage for direct answers, coordinator-owned tool calls, delegated tool calls, delegated inference, structured output, grounding traps, and semantic routing choices. Routing cases require the coordinator to decide whether to answer directly, use a local tool, delegate a tool, or delegate inference; authoritative and decoy agents can return identical values so the action ledger and trace prove which agent was actually selected.
- Added deterministic
smoke,core, andfullbenchmark suites, including a 200-case full catalog, reproducible seeds, category and case filters, repetitions, warm-up controls, prompt-file overrides, and native-tool or portable JSON-action configurations. - Added strict, functional, and first-try benchmark scoring together with rescued-attempt counts, parse-recovery and hallucinated-action diagnostics, inference-step statistics, latency percentiles, scored wall time, provider call timing, repeat probes, and baseline comparison support.
- Added self-contained HTML benchmark reports plus JSON and CSV artifacts. The report keeps dense bar charts within a horizontally scrollable viewport and provides an attempt review for unresolved and recovered failures, including the original request, expected outcome, actual output, model decisions, successful actions, traces, and runtime errors.
- Added
InferParseErrorwith the failed response, attempt count, parser cause, and a concise explanation. - Added a local dashboard Telemetry explorer for
traces.jsonl, with CLI or browser-file loading, bounded recent-first paging, lazy trace detail, span waterfalls, grouped task records, and playable event replay. - Added session-only Registry and read-only Runs source controls, a redesigned searchable run replay workspace, a corrected span waterfall selection/timeline layout,
protolink --version, and the dashboard version label.
[0.6.7] - 2026-07-27
This patch release hardens the controlled inference path from task admission through provider calls, tool execution, delegation, streaming finalization, and observability. It keeps the portable JSON action protocol as the default for local and smaller models while making malformed-output recovery, prompt metadata, budgets, retries, and task lifecycle behavior more deterministic. Adds vLLM client support natively. Fixes Local Telemetry. Also adds the AI Courtroom Example.
Added
- Added
AgentClient.send_infer_task()and itsclient.synccounterpart. The helper requires a query and agent URL, creates the request withTask.create_infer(), supports optional user context, output schema, inference metadata, and native/A2A protocol selection, then returns the complete task fromsend_task(). - Added task-scoped budget accounting across every executable part in one task. Multiple
inferparts, explicittool_callparts, and physical provider retry attempts now consume one cumulativeBudgetEnforcer; inline nested tasks receive an isolated budget scope. - Added
BudgetEnforcer.check_next_step()and the optional advanced-runtimeLLM.infer(..., budget_enforcer=...)integration point for callers that need to share accounting across several inference invocations. - Added structured physical-attempt metadata to LLM lifecycle events. Transient retries report the failed and next attempt, delay, exception type, and message; completed calls report total attempts and current budget usage.
- Added durable
Artifact(kind="action_result")receipts for model-selected tools and delegated-agent calls. Receipts carry the runtimeaction_id, inference source/kind/step metadata, and completion status without copying internal tool or delegation results into client-visible task data. A later model failure, cancellation, or budget boundary no longer hides a side effect that already completed, while private conversation history retains the full observation. - Added focused regression coverage for pre-cancellation, external coroutine cancellation, abandoned streams, task-wide budgets, legacy override signatures, telemetry failures, provider retries, invalid tool arguments, deterministic prompts, strict JSON extraction, Anthropic action handling, and parallel native tool calls.
- Added vLLM client
VLLMLLM, which inheritsOpenAICompatibleLLM. - Added validated
create_llm(..., max_parse_failures=N)runtime configuration. The limit is kept separate from provider model parameters, so ProtoLink retry controls are never forwarded to Ollama, OpenAI, or compatible servers as generation options.
Changed
- Provider retries now count each actual request against LLM-call and input-token budgets. Provider runtime is checked again after every request, including a final model call. Completed tool and delegated-agent side effects are recorded before cancellation or runtime limits stop the next step, rather than being retroactively reported as if they never ran. A streaming provider call may retry only before any output chunk has been exposed to a consumer.
- Transient-error classification now recognizes common direct and response-wrapped provider status fields, numeric string statuses, provider exception names, HTTP 429/529/5xx messages, timeouts, overloads, and connection failures.
- Model-proposed tool arguments are validated and conservatively coerced before authorization, budget consumption, or
execution. Invalid arguments remain recoverable model feedback; a
TypeErrorraised inside tool business logic is treated as an execution failure rather than an argument mistake. - Duplicate-action protection now records only successful tool and Agent side effects, hashes bounded canonical signatures, includes the complete delegated prompt, and never suppresses a repeated final answer.
- Portable JSON prompts now use valid single-brace examples, deterministic JSON tool/Agent metadata, explicit capabilities, and clear instructions that metadata is untrusted data. Parse-repair examples advertise only actions available in the current run, keeping correction prompts concise for smaller models.
- Embedded JSON recovery now performs a linear, quote- and escape-aware scan and accepts exactly one valid top-level object. Ambiguous multiple objects are rejected; raw-response and parsed-payload diagnostics use deterministic, bounded head-and-tail previews while preserving field-level validation errors.
- Prompt-fallback parsing now conservatively normalizes common small-model response drift: structured
FinalAction.contentvalues are serialized losslessly, and a direct application object can become final content only when it contains no ProtoLink action-envelope fields. Full JSON fences, complete leading reasoning wrappers, and trailing commas receive syntax-only recovery; ambiguous objects, incomplete reasoning wrappers, and action-shaped payloads with missing or unknown types still fail validation. - Action-parse retries now preserve the decoded outer action type as structured error context and return capability-aware correction feedback. Malformed or unavailable tool and Agent calls are explained explicitly, while retry examples include only actions that the current inference can dispatch.
- Agent discovery is now a best-effort delegation affordance: a Registry outage no longer prevents otherwise-local inference. Discovered ancestors are removed from the prompt, model-originated direct URL delegation is rejected, and delegation cycles are stopped before dispatch.
- Agent and direct-inference telemetry observers are non-authoritative. Hook/export failures are logged and isolated so they cannot change a successful model or tool result; streaming tasks now receive the same task start/end telemetry boundary as unary tasks.
- Anthropic action parsing and the shared streamed Chat Completions normalizer reject ambiguous parallel tool calls
instead of merging fragments. The synthetic delegation tool names
protolink_call_agentandprotolink_call_agent_toolare reserved and cannot be shadowed by a local tool.
Fixed
- Fixed pre-canceled
RunContextvalues so task, LLM, tool, and streaming paths stop before mutating history or starting work. - Fixed failed unary tasks so their failed snapshots are persisted before the original exception is re-raised.
- Fixed multi-part tasks so each completed output is attached and snapshotted immediately. A later part failure keeps the earlier output visible instead of losing all partial progress.
- Fixed cancellation during post-tool telemetry so an already-returned explicit tool result is attached exactly once,
persisted, and correlated through
completed_after_cancellationmetadata before cancellation completes. - Fixed external
asynciocancellation so task state and snapshots are updated while the cancellation still propagates to the caller; protocol-requested cancellation continues to return the canceled task/event contract. - Fixed early streaming-consumer closure so an unfinished task is marked canceled and persisted instead of remaining
orphaned in
workingstate. - Fixed Anthropic requests so system instructions come from the task-local
ConversationHistory, multiple system entries are preserved, streamedpartial_jsonarguments take precedence over an initial empty input object, and paralleltool_useblocks fail explicitly. - Fixed prompt serialization for quotes, newlines, booleans, nested schemas, unordered tools/skills, and legacy Python type metadata.
- Fixed failed conversation turns so they remain isolated by default, while a failed turn with a completed
action_resultreceipt retains the matching observation for safe resume and retry behavior. - Fixed non-JSON/circular action results so history receives a bounded serialization fallback rather than losing the observation after an external side effect has completed.
- Fixed streamed tool/delegation result events so client-visible metadata keeps correlation but omits private internal result data. A failing external event observer is disabled without disabling runtime-owned action receipts.
- Fixed internal receipt callbacks so they do not implicitly activate optional call-metrics/token-estimation work on otherwise unobserved Agent inference.
- Fixed delegated task handling so only a remote
completedtask with a real output produces a successfulagent_call_result; failed, canceled, input-required, non-terminal, and empty completions are propagated explicitly. Full-task and response-only transports are both accepted by distinguishing returned output from the outbound request by stable item ID. - Fixed partial-history persistence failures so they are logged without replacing an active budget, cancellation, or execution exception after a completed side effect.
- Fixed repeated small-model/Ollama parse failures when an otherwise-valid final action placed the requested
application object directly in
contentinstead of encoding it as a string. - Fixed Registry discovery for both serialized and in-process
AgentCardresponses. - Fixed nested local telemetry so parent and child task traces are both preserved.
Compatibility Notes
- No provider or model integration was removed. JSON action mode remains the default compatibility path for Ollama, llama.cpp, LM Studio, and generic OpenAI-compatible backends, and correction prompts are smaller when tools or delegation are unavailable.
- The new budget parameters are optional. Agent preserves custom pre-0.6.7
call_llm(),call_llm_stream(),execute_tool(), andLLM.infer()override signatures; the shared enforcer is passed to aninfer()override only when that callable declares the keyword or accepts**kwargs. - Budget limits now apply cumulatively to a complete task and to physical retry attempts. A multi-part or retrying task that previously reset counters between calls can therefore stop earlier when it reaches its configured limit.
- Model-produced Agent targets must be Registry-advertised names, not URLs. Anthropic and streamed Chat Completions paths reject multiple tool actions in one inference step, and portable responses containing multiple valid JSON objects are now rejected as ambiguous.
- Cancellation remains best effort for synchronous provider/tool code and already-issued external side effects. The runtime cannot forcibly interrupt synchronous work running on the event-loop thread. If a tool or delegation has already returned, ProtoLink preserves its result and stops subsequent work at the next execution boundary.
[0.6.6] - 2026-07-17
This release adds normalized run-report regression diffing, a small opt-in built-in tool set, and an explicit
description of ProtoLink's A2A architecture without replacing its small Python runtime API.
AgentCard, Task, Message, Part, and Artifact remain ProtoLink's ergonomic runtime primitives.
An HTTP agent can now opt into a separate, versioned A2A 1.0 inbound and outbound translation boundary with
Agent(..., a2a=True). The default False preserves existing ProtoLink clients, native endpoints, transports
and handle_task(Task) implementations.
Added
- Normalized run-report regression diffing
- Added
RunReportDiff,RunReportDifference,RunReportDiffConfig,RunReportTolerance,ALL_RUN_REPORT_SECTIONS,normalize_run_report(),diff_run_reports(), andassert_run_matches()for comparing baseline and candidate reports. Regression suites normally record final reports, but the helpers do not require a particular task lifecycle state. - Comparisons normalize known ProtoLink runtime-envelope identifiers, timestamps, and sequence counters while preserving repeated identifier relationships, report structured path-level changes, and support configurable ignored paths and numeric tolerances without mutating the source reports. Application-owned payloads and report metadata remain exact by default.
- Added
protolink run diff BASELINE CANDIDATE --store runs.db [--json]for offline comparison of two stored reports. The command exits0for a match,1for behavioral changes, and2when either report is missing. - Text and JSON CLI diff output apply the default redaction policy to compared values. The core
RunReportDiff.to_dict()API remains raw unless the caller supplies a redaction policy. - Added the provider-free
examples/run_regression_diff.pywalkthrough for pinning a baseline, detecting a changed result, and using the assertion helper in tests.
- Added
- Opt-in dependency-free built-in tools
- Added
web_search(),fetch_url(),calculator(), andcurrent_datetime()factories, exported fromprotolink.toolsand registered explicitly withagent.add_tool(factory()). web_searchselectsengine="brave"by default, documented keyless English Wikipedia search withengine="wikipedia", or keyless best-effort DuckDuckGo HTML search withengine="duckduckgo". All three use the same bounded normalized result contract with no silent provider fallback. Brave readsBRAVE_SEARCH_API_KEYonly at invocation; DuckDuckGo challenge and markup-drift responses fail explicitly, while recognized sponsored entries are retained and labeled.- Added
examples/builtin_web_search.py, an offline-safe CLI walkthrough that registers the tool through an Agent policy, defaults to the reliable keyless Wikipedia engine, and exposes engine, freshness, and result-count controls. - The web tools declare
network.read; URL fetch rejects non-public targets and bounds redirects, response types, and content size. Search and fetched content remain untrusted external data, and applications can restrict the allow-by-default policy withCapabilityPolicy. - Agent dict/YAML round-trips preserve built-in tool identities and first-party
CapabilityPolicyrules without serializing executable custom policies, approval callbacks, or the Brave API key.
- Added
- Opt-in A2A 1.0 HTTP interoperability
Agent(..., transport="http", a2a=True)now exposesGET /.well-known/agent-card.jsonandPOST /while retaining every native endpoint. The flag defaults toFalse, is available through the read-onlyagent.a2aproperty, and round-trips through dict/YAML configuration.- The adapter implements
SendMessage,GetTask,ListTasks, andCancelTask, with standard card, task, message, part, artifact, security, timestamp, version, content-type, and error translation for its advertised scope. - Blocking and non-blocking execution, filtering, pagination, cancellation, and authenticated principal/tenant task isolation reuse the existing
handle_task(Task)execution path. - The process-local task index retains at most 1,024 tasks for one hour, prunes expired or oldest inactive work first, and never evicts an active operation to admit a new task.
- Outbound A2A 1.0 translation
AgentClient(..., a2a=True),Agent.call_agent(), and their synchronous facades can discover and call A2A 1.0 JSON-RPC peers without ana2a-sdkruntime dependency.protocol="auto"prefers the native ProtoLink contract and selects A2A for an A2A-only peer.protocol="protolink"goes directly to the native route;protocol="a2a"skips the native-vs-A2A choice but still discovers and validates the standard Agent Card and compatible JSON-RPC interface.- Advertised A2A interfaces must share the discovered Agent Card's origin by default. The compact
Agentfacade always keeps that secure policy;a2a_allow_cross_origin=Trueremains an explicitAgentClienttrust override for controlled split-origin deployments. - Outbound calls reuse the configured HTTP transport's authentication, TLS, limits, pooling, metrics, and request headers.
SendMessageis non-idempotent and is not retried automatically. - ProtoLink preserves the caller's local task ID while retaining the remote A2A task ID, context, state, timestamp, and agent URL for continuation and cancellation. The protocol-selection cache is bounded to 1,024 peers for five minutes, and local-to-remote task-ID mappings are bounded to 1,024 entries for one hour.
- Cancellation reason and metadata translate through A2A
CancelTask. A blocking outbound call cannot be canceled until its response reveals the server-assigned task ID;"auto"never guesses by sending a local ID to the native cancellation route. send_message()raises for an artifact-only A2A result so callers usesend_task()and retain the full task artifacts.
- Execution-aware message translation
- Inbound A2A user text remains a ProtoLink
Part(type="text")for custom handlers. The default Agent engine recognizestask.metadata["a2a_inbound"]and treats that text as an inference request when an LLM is configured. Outbound ProtoLinkinferprompts become standard A2A text. - Standard text, data, raw/file, URI, message, artifact, and task-state forms translate directly. ProtoLink-specific tool-call, flow, runtime-context, and control-plane semantics remain native-only contracts.
- Inbound A2A user text remains a ProtoLink
- A2A verification harness
- Added a provider-free test agent, focused adapter tests, and a manually dispatched workflow pinned to the official A2A TCK commit documented in A2A Core and 1.0 Compatibility.
- The current unmodified JSON-RPC MUST run reports
67 passed, 1 failed, 167 skipped, 30 deselected. The remaining failure is the documented upstreamCORE-SEND-003metadata defect, so this release does not claim a complete TCK pass.
Changed
- Reworked the README around ProtoLink's lightweight, A2A-first, pluggable-agent design, with a provider-free one-agent quickstart, progressive configuration, local and small-model support, structured flows, and the CLI dashboard.
- Updated the concept, agent, client, server, transport, getting-started, index, and example documentation to distinguish ProtoLink's A2A-based runtime model from A2A 1.0 wire compatibility at the HTTP adapter boundary.
- Clarified that native
AgentCardserialization, registry services, structured flows, non-HTTP transports, and control-plane endpoints remain ProtoLink runtime contracts rather than additional A2A 1.0 operations.
Compatibility Notes
- This release is additive for existing ProtoLink applications: it does not remove or rename the
Agent,Task,AgentClient, transport, or native endpoint APIs. a2a=Falsekeeps HTTP native-only.a2a=Truerequires the exact HTTP transport and adds standard inbound routes plus outbound translation; native endpoints and native protocol selection remain available.- Agent-originated A2A calls always enforce same-origin discovery. A card advertising a JSON-RPC interface on another scheme, host, or effective port is rejected before that interface receives a request. For an explicitly trusted split-origin deployment, construct a dedicated
AgentClient(..., a2a_allow_cross_origin=True). - In
"auto"mode, the client probes ProtoLink's native card first and falls back to the standard A2A card only after404or405. It does not resubmit a task through another protocol after authentication, connection, timeout, or server errors. - The A2A task index is bounded but remains process-local and in-memory. It contains only tasks submitted through the inbound adapter and disappears on restart; multi-worker or restart-durable deployments still need a shared task router or store.
- Outbound protocol decisions and task-ID mappings are also bounded, process-local caches. Losing or expiring a mapping prevents continuation or cancellation by the original local task ID.
- Optional A2A message metadata, extensions, and reference task IDs are validated at the boundary but are not all retained by ProtoLink's smaller runtime models.
- The standard Agent Card route is intentionally public; the JSON-RPC task endpoint uses the Agent's configured authenticator.
Roadmap
- A2A
SendStreamingMessageandSubscribeToTasksupport. - A2A task push-notification configuration and delivery.
- Extended authenticated A2A Agent Cards.
[0.6.5] - 2026-07-14
Added
- Native gRPC transport
- Added
GRPCTransportand the"grpc"factory alias for unary task requests, server-streaming task events, metadata-based credentials, deadlines, and pooled async channels. - Added standard
grpc.health.v1.Healthreporting and server reflection, with constructor switches for deployments that disable either service. - Added gRPC transport conformance and integration coverage plus the provider-free
examples/grpc_agent.pyexample.
- Added
- TLS and mutual TLS
- Added the top-level
TLSConfigAPI for shared certificate trust, server identity, and optional client-certificate verification across HTTP, SSE JSON-RPC, WebSocket, and gRPC. - Added secure
https://,wss://, andgrpcs://URL handling, with TLS owned consistently by concrete transport instances. - Added certificate-backed integration coverage and
examples/tls_agent.py, while keeping transport encryption independent from application authentication and authorization.
- Added the top-level
- Shared production transport contract
- Added
TransportConfig,TransportLimits, andRetryPolicyfor consistent payload bounds, request/stream concurrency, explicit idempotent retries, keepalive, graceful shutdown, response deduplication, and dependency-free metrics across every built-in transport. - Added
TransportCapabilities,TransportMetricsSnapshot, and the publicTransportRequestContextextension type for capability inspection, operational counters, correlation IDs, idempotency keys, and retry-attempt tracking. - Added typed connection, timeout, protocol, remote, and payload-limit errors carrying URL, request ID, retryability, and protocol-native status metadata.
- Added
/healthzand/readyzAgent and Registry probes, configurable WebSocket ping/pong behavior, loop-owned pooled-resource cleanup, and idempotent transport lifecycle methods.
- Added
- Multi-transport Agent metadata
- Added optional
AgentCard.interfaces/AgentInterfacemetadata so one Agent can advertise additional protocol endpoints while retaining its primary URL and transport. - Serialized this metadata as
additionalInterfacesfor wire compatibility and preserved it through AgentCard round trips.
- Added optional
- Added
examples/transport_production.pywith provider-free configuration, capability, health, and metric inspection.
Changed
- Unified transport construction across
Agent,AgentClient, andRegistry: string aliases remain the zero-configuration prototyping path, while TLS, limits, retries, keepalive, and protocol-specific settings are configured on a concrete transport object passed to the facade. - Agent serialization now restores its primary and Registry transports with independent TLS identities and production configurations.
ClientRequestSpecnow declares operation idempotency explicitly. Retries remain disabled by default and run only when the request specification, method, and typed failure all permit a safe retry.- HTTP, SSE JSON-RPC, WebSocket, gRPC, and RuntimeTransport now enforce the same serialized payload and concurrency contract, so in-process tests exercise the same resource boundaries as network deployments.
- Correlation IDs remain stable across retry attempts, while idempotency keys suppress concurrent duplicate execution and replay completed responses within the configured process-local cache window.
- Expanded the Transport, Agent, Client, Registry, and AgentCard documentation with complete signatures, defaults, protocol mappings, operational rationale, custom-transport guidance, and production examples. The documentation landing-page IDE now includes gRPC and production transport configuration with incremental line editing.
Removed
- Removed facade-level
tls=andtransport_config=constructor arguments fromAgent,AgentClient, andRegistry. Advanced settings now have one owner and one API: the concrete transport instance.
Fixed
- Fixed SSE task streams so final nested LLM events no longer close the stream before the final task-status update.
- Fixed concurrent duplicate idempotent requests so they await one in-flight operation instead of executing the same handler more than once.
- Fixed HTTP health probes so
/healthzand/readyzremain available when application authentication is enabled. - Fixed transport shutdown across background-thread and caller event loops by closing pooled clients and channels on the event loop that owns them.
- Fixed gRPC shutdown so loop-local cached channels are closed and removed correctly, including repeated
start()andstop()calls. - Fixed HTTP and SSE server-side request/stream accounting so shared concurrency limits and transport metrics apply on both sides of a connection.
- Fixed SSE terminal-frame parsing so the final task event is emitted exactly once.
- Fixed failed or cancelled WebSocket and gRPC idempotent operations so they release waiting duplicates without poisoning the completed-response cache.
- Fixed WebSocket pooling after timeouts, protocol corruption, and abandoned streams so unread frames cannot leak into a later request.
- Fixed Agent configuration round trips so restored Registry transports retain the Agent's serialized authentication strategy and credentials.
- Fixed short-lived SQLite storage, run-store, and doctor connections so every database handle closes deterministically after use.
- Fixed source-distribution contents so generated Docusaurus output and
docs/node_modulesare excluded from PyPI packages.
[0.6.4] - 2026-07-03
Added
- Added
QuietLogger, a no-opBaseLoggerimplementation for agents and integrations that need the logging interface without emitting output. - Added the ProtoLink Whitepaper.
- Added task-local LLM history scopes for concurrent agent execution, including same-session locking for persistent conversation state.
- Added
RunStore,SQLiteRunStore,TaskRecord, andRunReportRecordfor durable task snapshots and run-report persistence. - Added registry entry liveness metadata, optional TTL pruning, persistent registry entry storage, and
RegistryClient.heartbeat(). - Added transport conformance coverage for Runtime, HTTP, and WebSocket agent contracts.
- Added developer tooling commands for
doctor, registry inspection, run listing/replay, and a local dashboard with registry health, HTTP agent ping, HTTP agent chat, run replay, and a disabled Studio preview. - Added
examples/devtools_dashboard.py, a provider-free dashboard demo with multiple registered agents, persisted run reports, and optional--serve-liveHTTP mode for clickable dashboard ping/chat.
To try it:
protolink doctor
python examples/devtools_dashboard.py --output-dir .protolink-devtools
protolink run replay dashboard_demo_1 --store .protolink-devtools/runs.db
protolink dashboard --store .protolink-devtools/runs.db --open
Changed
- Tightened GitHub Actions so Ruff, blocking
ty check protolink, multi-version tests, package build checks, and strict docs builds run as first-class CI gates. - Migrated the documentation site from MkDocs Material to Docusaurus with a custom ProtoLink theme, preserved docs corpus, Mermaid diagrams, admonitions, tabs, and GitHub Pages artifact deployment.
- Split LLM response parsing and fallback action repair into
protolink.llms.parsing, keeping the publicLLMfacade stable while making the infer loop easier to maintain.
Fixed
- Fixed
Agent.start(register=False)so the lifecycle now honors the publicregisterargument. - Fixed RuntimeTransport async request-parser handling.
- Fixed WebSocket route registration, stale client-connection reuse, and task-stream closure semantics.
- Hardened
BearerTokenAuthso bearer JWTs now verify HMAC signatures, algorithms, registered time claims, and optional issuer/audience constraints instead of accepting unsigned demo payloads.
[v0.6.3] - 2026-06-26
Added
- Context manifests and enforceable run budgets
- Added
ContextManifest,ContextItem, andbuild_context_manifest()so applications can inspect estimated system, history, tool/delegation, user, total, and context-window usage before every LLM call. - Added
BudgetPolicy,BudgetEnforcer,BudgetDecision,BudgetUsage, andBudgetExceededErrorto enforceRunBudgetlimits for steps, LLM calls, tool calls, runtime seconds, input tokens, and output tokens. LLM.infer()now emits additivecontext_prepared,llm_call_started,llm_call_completed,budget_warning, andbudget_exceededevents while preserving existing low-level LLM events.RunEventnow promotes those events into stablecontext.prepared,llm.call.started,llm.call.completed,budget.warning, andbudget.exceededtypes for UI and golden-run consumers.LLMModelProfilenow accepts descriptive capability metadata such assupports_tools,supports_streaming,supports_json_schema, andtokenizerwithout becoming a live model catalog.
- Added
- State inspection and state control reports
- Added
StateOperationRequest,StateStoreReport, andStateOperationResultfor typed describe, reset, and compact reports over agent state. - Added
Agent.describe_state(),Agent.reset_state(), andAgent.compact_state()plus matchingAgentClientrequest specs forPOST /state/describe,POST /state/reset, andPOST /state/compact. - State operations run through runtime policy capabilities (
state.describe,state.reset,state.compact, andllm.history.compact) before reading or mutating state.
- Added
- Run reports, replay, and redaction
- Added
RunReport,RunRecorder,RunReplay,assert_run_events(),assert_no_denied_actions(), andassert_budget_under()for durable app-facing run summaries and golden-run integration tests. - Added
RedactionPolicyandDEFAULT_REDACTION_POLICYso reports and local telemetry share one recursive secret-masking surface. RunEventnow exposes optionalspan_id,parent_span_id,action_id,parent_action_id, anddelegation_idfields for causal UI routes and replay tools.
- Added
- Runnable integration examples
- Added provider-free
examples/v063_*.pyscripts covering context budgets, request-spec history compaction, state control endpoints, run reports/replay/redaction, and an abstract ProtoAgent-style policy mesh with tool capabilities and approval previews.
- Added provider-free
Changed
-
Agent codebase reafctor with MixIns: Agent is now the stable public facade, with behavior split into:
engine.py: task execution, streaming, LLM calls, delegationmixins.py: lifecycle, control plane, communication, tools, config, serializationhelpers.py: state request normalizationsync.py: SyncAgent_typing.py: internal structural typing support for mixins
-
LLM history compaction: instead of having it as a tool which will just stress the model's context more, it's now a client/server spec, so it's called via an endpoint.
- Kept the LLM-owned
HistoryCompactorcomponent withrecent,tokens, andsummarystrategies plus structured before/after results. LLM.compact_history()remains as a concise facade while compaction algorithms and isolated summary prompts live in the dedicated component.- Added
HistoryCompactionRequest,Agent.compact_history(), andAgentClient.COMPACT_HISTORY_REQUEST(POST /llm/history/compact) so agents can compact persistent context through the same client/server spec pattern as other control endpoints.
- Kept the LLM-owned
[v0.6.2] - 2026-06-24
Added
- Built-in LLM history compaction
- Added the LLM-owned
HistoryCompactorcomponent withrecent,tokens, andsummarystrategies plus structured before/after results. LLM.compact_history()remains as a concise facade while compaction algorithms, summaries, prompts, and tool construction live in the dedicated component.- Added the reserved
protolink_compact_historyruntime tool so agents can compact persistent context in response to explicit user requests. - Compaction preserves the leading system prompt and protected recent turns; summary generation is isolated and atomic on provider failures.
- Added the LLM-owned
- Tests:
- Added Starlette, FastAPI, and WebSocket regression coverage for nested
ToolOutputstream payloads.
- Added Starlette, FastAPI, and WebSocket regression coverage for nested
Fixed
- Nested transport payload serialization
- Starlette and FastAPI SSE backends now recursively normalize nested framework objects before encoding JSON-RPC event frames.
- Delegated and tool-result events containing a
ToolOutputdataclass incontentormetadatano longer terminate the stream withTypeError: Object of type ToolOutput is not JSON serializable. - WebSocket streaming now uses the same shared recursive serializer for consistent event payloads across network transports.
Changed
- Documented recursive JSON normalization and structured tool-result behavior in the transport and client streaming guides.
[v0.6.1] - 2026-06-21
Added
-
Live task cancellation
- Added
CancellationToken,TaskCancellationRequest, and an active-task registry that separates serializable canceled state from process-local execution control. - Added direct and remote task-ID cancellation through
Agent.cancel_task()andAgentClient.cancel_task()across HTTP, SSE JSON-RPC, WebSocket, and RuntimeTransport. - Default task, streaming, LLM, tool, and delegated-agent paths now propagate cancellation and produce a final
canceledtask state instead of a failure event. - Added
examples/task_cancellation.pyplus direct, streaming, runtime, and WebSocket cancellation coverage.
- Added
-
Runtime context and run events
- Added
RunContext,RunBudget,RunEvent,EventSink, andInMemoryEventSinkfor typed run metadata, stable progress streams, and golden-run testing. - Default agent execution now normalizes runtime context into
task.metadata["run_context"]while preserving legacysession_idandtrace_idmetadata.
- Added
-
Runtime actions, policy, and approvals
- Added
RunAction, structured artifact descriptors,CapabilityPolicy,ActionAuthorizer, and typed approval request/decision contracts. - Tools can declare extensible capabilities and attach preview artifacts; policy is enforced immediately before direct, model-selected, and delegated actions execute.
RunEventnow promotes action, policy, and approval activity into stable event types for application streams and golden-run tests.- Added
examples/runtime_policy_and_approvals.py, a provider-free walkthrough of previews, approvals, normalized events, and denied side effects.
- Added
-
Optional LLM budget metrics
- Added
LLMModelProfileandLLM.configure_metrics()for context-window and cost metadata without changing provider request payloads. LLM.infer()now emits livellm_contextandllm_call_metricsevents when telemetry or anevent_callbackis attached.- Local traces now aggregate LLM call count, latency, token usage, context high-water marks, and estimated cost in LLM span metadata.
- Added the optional
protolink[metrics]extra for sharper token estimates withtiktoken; core installs still use a dependency-free estimate.
- Added
[v0.6.0] - 2026-06-19
Added
-
Task lifecycle enforcement
Task.statenow uses enforcedTaskStatetransitions instead of acting as a loose label.- Added terminal-state awareness through
Task.is_terminalforcompleted,failed, andcanceledtasks. - Added lifecycle helpers:
Task.begin(),Task.require_input(), andTask.cancel(). - Successful state transitions are recorded in
task.metadata["state_history"]. - Direct task construction now normalizes serialized state values and rebuilds the last-item cache.
-
Agent-managed task states
- Default
Agent.execute_task()now moves non-terminal tasks toworking, finalizes successful runs ascompleted, marks error outputs and exceptions asfailed, and supportsinput-requiredstatus outputs. - Streaming task handling now emits lifecycle-aware status updates and includes the final serialized task in final status event metadata.
TaskLifecyclenow applies protocol-safe transition paths before completing, requiring input, failing, or canceling tasks.
- Default
-
LLM history serialization helper
- Added
protolink.llms.serialization.json_history_default()for framework object serialization in LLM conversation history. - Base and Anthropic LLM history injection now serialize dataclasses,
to_dict()objects, andmodel_dump()objects consistently.
- Added
-
First-run developer experience
- Added top-level exports for common primitives such as
Agent,AgentCard,Task,Tool,Pipeline,create_llm, and local tracing utilities. - Added the
protolink init agentCLI command with runnablebasicandtoolstarter templates.
- Added top-level exports for common primitives such as
-
Local observability
- Added
LocalTraceTelemetryandLocalTraceRecorderfor in-memory and JSONL task trace replay. - Local traces now capture trace IDs, span hierarchy, LLM action events, retry counts, token estimates, model metadata, and redacted payloads.
- Added
-
Typed LLM action protocol
- Added typed
FinalAction,ToolCallAction,AgentCallAction, andLLMActionResultmodels for theinfer()execution loop. - Added provider-native action acquisition for OpenAI, Anthropic, Gemini, DeepSeek, Grok, Ollama, llama.cpp, LM Studio, and OpenAI-compatible servers where supported.
- Added native streaming action acquisition through
call_action_stream()so providers can stream text while buffering tool-call deltas into one validated runtime action. - Added provider-neutral tool schema builders and synthetic native delegation tools for agent calls.
- Added typed
-
Structured route decisions
- Added
RouteDecisionplusPart.route(...)andPart.decision(...)for serializable, trace-visible flow routing. Routernow prefers structured route parts and JSON-shaped route decisions before falling back to legacy[ROUTE: key]text tags.- Legacy text-tag routing now records the chosen route as structured task metadata and a route part for replayability.
- Added
-
First-class tool JSON Schema
- Native
Toolwrappers now infer full JSON Schema objects for inputs and outputs instead of flat parameter maps or return type strings. - Added nested schema preservation for Pydantic models, dataclasses, typed dictionaries, enums, arrays, objects, unions, and literals.
- Added runtime validation/coercion for tool arguments before execution, including custom
BaseToolimplementations with JSON Schema input contracts. - Tool examples now flow into advertised
AgentSkill.examples.
- Native
-
Docs
- Added an end-to-end runtime cancellation guide covering active registration, cooperative checkpoints, control-plane transport behavior, final events, and best-effort side-effect guarantees.
- Updated README task semantics to describe
Task.stateandmetadata["state_history"]. - Added Agent documentation for default task lifecycle behavior and streaming status updates.
- Expanded model and transport docs for task lifecycle states, terminal states, transition history, and new task helper methods.
- Added CLI documentation and local trace telemetry documentation.
- Expanded LLM documentation for the typed
infer()cycle, JSON vs native action modes, native streaming tool-call behavior, and provider support matrix. - Updated flow docs for structured route decisions and updated tool/model docs for first-class JSON Schema, Pydantic support, runtime validation, and skill examples.
-
Tests
- Added cancellation coverage for typed request round-trips, pre-canceled inference, interrupted async tools, final stream status, custom remote handlers, and WebSocket control channels.
- Added lifecycle coverage for direct task construction, invalid transitions,
Task.complete(), successful agent execution, and failed tool execution. - Added regression coverage for delegated
ToolOutputserialization in the LLM inference loop. - Added coverage for top-level exports, CLI scaffolding, local trace capture, redaction, and retry metadata.
- Added regression coverage for native action dispatch, native streaming action dispatch, provider tool-call normalization, streamed tool-call delta accumulation, and Ollama's opt-in native tool mode.
- Added coverage for route decision part round-trips, structured Router branching, nested/Pydantic tool schema inference, runtime argument coercion, custom
BaseToolschema validation, and AgentSkill examples.
Changed
protolink.modelsnow exportsTaskState.- Task validation now accepts empty message, artifact, and metadata containers and validates
Task.stateas aTaskState. - Flow execution no longer auto-wraps plain user messages without executable parts into inferred prompts.
- Flow transition bridging now ignores structured
routeanddecisioncontrol parts when preparing downstream agent prompts. - Telemetry hooks now accept optional LLM metadata and expose detailed inference-loop events through
on_llm_event(). - LLM prompt selection now separates JSON action prompts from native provider tool prompts, preventing native providers from seeing JSON tool-call instructions while keeping small/local models on the simple JSON protocol by default.
- Ollama, llama.cpp, LM Studio, and OpenAI-compatible local servers now use native tool calling only when
supports_tool_calling=True; otherwise they retain the JSON fallback path. .ruff_cache/is now ignored by git.
Infer Loop Updates:
- The LLM no longer directly drives execution through fragile raw text.
- Every step converges into typed actions: FinalAction, ToolCallAction, AgentCallAction.
- Native providers like OpenAI/Anthropic/Gemini use real provider tool calling instead of being forced through prompt JSON.
- Small/local models still get the simpler JSON protocol, which is the right call for Ollama/Gemma-style reliability.
- Streaming now has a real action boundary through call_action_stream(), instead of pretending chunks are immediately executable.
- The loop has retries, parse failure limits, duplicate-action detection, tool argument correction, unknown-tool correction, and structured events for observability.
Fixed
- Fixed delegated agent tool results crashing LLM history injection when the remote tool output is hydrated as a
ToolOutputdataclass. - Fixed task execution leaving tasks in non-terminal states after successful default agent execution.
- Fixed invalid direct lifecycle jumps such as
submitted -> completedby requiring transition throughworking.
[v0.5.8] - 2026-06-11
Added
-
SSE JSON-RPC streaming transport
- Added
SSEJSONRPCTransportfortext/event-streamtask streams over HTTP. - Registered transport aliases:
"sse","json-rpc", and"sse-json-rpc". - Starlette and FastAPI backends now serialize streaming endpoint events as JSON-RPC-style SSE envelopes.
- Added
-
Agent-level LLM streaming
Agent.handle_task_streaming()now streams task status, LLM events, tool progress, artifacts, and completion.LLM.infer()acceptsstreaming=Trueand an optionalevent_callbackobserver for chunks, tool calls, agent calls, parse errors, and final output.AgentClient.send_task_streaming()now validates transport streaming support before subscribing.client.sync.send_task_streaming()provides a blocking iterator for scripts and CLI interfaces.- Agent cards now reflect the selected transport's streaming capability for discovery and registry filtering.
AgentCard.to_dict()andAgentCard.from_dict()now preserve thetransportfield.
-
Local and OpenAI-compatible LLMs
- Added
OpenAICompatibleLLMfor servers exposing/v1/chat/completionsand/v1/models. - Added
LMStudioLLMfor LM Studio's local OpenAI-compatible server. - Added provider keys
"lmstudio"and"openai-compatible".
- Added
-
Tests
- Added focused coverage for lazy mock LLM creation, SSE JSON-RPC event parsing,
AgentClientstreaming checks, sync streaming iteration, and agent LLM stream attachment.
- Added focused coverage for lazy mock LLM creation, SSE JSON-RPC event parsing,
Changed
- Provider, server LLM, and transport exports are now lazy-loaded so optional SDKs are only required when the selected provider or transport needs them.
create_llm()lazy factory entries now cover all documented providers, including Grok, Hugging Face, LM Studio, OpenAI-compatible servers, and Mock LLMs.- Agent
verbosity=0now suppresses transport server access logs more aggressively. - Documentation updated for streaming, SSE JSON-RPC, LM Studio, OpenAI-compatible local servers, and the new client/server transport flow.
[v0.5.7] - 2026-06-07
Added
-
Authentication now works with all transports (http, websocket)
- Integrated to Agent. Now passable to agent as an argument
authenticator: Optional Authenticator instance for verifying incoming requests to this agent.credentials: Optional credentials string used for authenticating outgoing requests.
- Integrated to Agent. Now passable to agent as an argument
-
Import / Export Agent from/to
yaml- Agent can now serialize itself and save to yaml file
to_yaml: Saves the agent configuration to a YAML file
- Agent can now load from yaml file
from_yaml: Loads the agent configuration from a YAML file
- Agent can now serialize itself and save to yaml file
[v0.5.6] - 2026-05-17
Added
-
Flows Refactor & Upgrade
- Semantic Context Injection: Flows dynamically build instruction prompts based on their downstream topology. This prompt is injected into the
task.flow_state["prompt"]for executing agents to utilize seamlessly. This way agents are aware of their downstream context and can format their output accordingly. - Correct Task management. Added flow_state to Task, so that we provide additional context to the agents.
- NEW Flow Examples for each Use case (Graph, Pipeline, Parallel, Router).
- Removed Structured Agent
- Better State Management
- Flow Sync Module
- Semantic Context Injection: Flows dynamically build instruction prompts based on their downstream topology. This prompt is injected into the
-
Other
- Agent Sync Module
- LLM Sync Module
- Added GuardRails:
- Added context for Agent ID and prevent agent from calling himself.
- Removed self from fetched agents.
- Agent Discovery TTL
- Mock LLM for testing
Fixed
- HUGE BUG fix: Agent URL received from registry was wrong most of the time.
[v0.5.5] - 2026-05-16
Changed
NEW Feature - State (API Refactor)
- State Management: Refactored agent state management, specifically around conversation history persistence. The syntax has been simplyfied:
agent = Agent(
card=card,
...
state=["conversation"], # Session memory is not reset between tasks
)
Added
-
protolink.state module. The State class manages:
- Session memory - Session memory is not reset between tasks
- Conversation history - Conversation history persistence
- Tool call history - Tool call history persistence
- Flow state - Flow state persistence
-
DSA Optimization:
- Conversation History: Use Message Double Ended Queue for O(1) append and pop operations.
- Registry Storage: Optimize agent pop operations to O(1)
- and more...
[v0.5.4] - 2026-05-12
Changed
- Agent Lifecycle: Fixed issues with agent start/stop logic, specifically around event loop tasks and background threads. The syntax has been simplyfied:
- Proper Thread Management: Removed asyncio event loop and background threads for starting/stopping.
agent.start()
agent.stop()
That's it. The start() method will start the agent in a background thread and will properly wait for all queues to empty. The stop() function will properly wait for all queues to empty, and gracefully shutdown the agent and background threads.
[v0.5.3] - 2026-05-03
Fixed
- Tooling Schema: Tool schema is now correctly inferred from the function signature and type hints. It is also correctly appended to the Agent Card prompt, so other agents are aware of available tools and schemas.
[v0.5.2] - 2026-05-02
Added
- Logging Module: Added explicit
filelogger (json) andconsolelogger (color). - Plug in Logging to the Agent using the
loggerargument. If none is provided, a default logger using the ConsoleLogger, so the IO is appended to the terminal. - Added context memory:
- "none" - No context memory.
- "session" - Session based context memory. Agent remembers all messages exchanged during the current session with other agents.
Memory is configured in the agent using the
memoryargument. If none is provided, no memory is used.
[v0.5.1] - 2026-04-28
Added
- Telemetry: Add LangSmith and Langfuse telemetry implementations
- BaseTelemetry: Add base telemetry class
- LangfuseTelemetry: Langfuse telemetry implementation
- LangsmithTelemetry: Langsmith telemetry implementation
- MultiTelemetry: Multiplex multiple telemetry implementations.
- Agent: Plug in to the Agent using the
telemetryargument. If none is provided, no telemetry is collected.
[v0.5.0] - 2026-04-22
Added
- Flows: Build deterministic execution paths out of the box (
Pipeline,Parallel,Router,Graph). - StructuredAgent: Wrap any complex flow to run autonomously as a generic, network-ready A2A agent.
[v0.4.8] - 2026-04-19
Historical patch release.
[v0.4.7] - 2026-02-08
Added
- LLM Inference Guardrails:
- Implemented robust guardrails for LLM inference.
- Added agent calling for delegated inference.
- Final result processing.
- NEW GrokLLM:
- Ticket Example
- Verbosity in Agent and Registry and more...
[v0.4.6] - 2026-02-05
Added
- LLM Automated Inference:
- Implemented robust tool calling capabilities.
- Added agent calling for delegated inference.
- Final result processing.
- Agent Orchestration:
- Centralized handling for LLM inference, tool execution, and result aggregation.
Changed
- LLM API: Refactored for better type safety and extensibility.
- Agent Constructor: Simplified initialization options.
- Transport Factory: Improved factory patterns for transport creation.
Fixed
- Agent Stability: Resolved race conditions in agent message handling.
- HTTP Backend: Fixed issues with stream termination.
[v0.4.5] - 2026-01-26
Added
- LLM Automated Inference:
- Implemented robust tool calling capabilities.
- Added agent calling for delegated inference.
- Final result processing.
- Agent Orchestration:
- Centralized handling for LLM inference, tool execution, and result aggregation.
Changed
- LLM API: Refactored for better type safety and extensibility.
- Agent Constructor: Simplified initialization options.
- Transport Factory: Improved factory patterns for transport creation.
Fixed
- Agent Stability: Resolved race conditions in agent message handling.
- HTTP Backend: Fixed issues with stream termination.
< [v0.4.4]
Changelog starts after this version.
Roadmap
The near-term roadmap focuses on hardening the runtime paths that production agent systems depend on most.
Upcoming Features
- Agent Task Handling: Enforced task lifecycle transitions and state history.
- Delegated Inference: Typed tool and agent actions in the LLM inference loop.
- Storage: In-memory and SQLite storage implementations.
- Observability: Local trace replay plus Langfuse and LangSmith integrations.
- Integrations: MCP adapter for external tool servers.
- Transport Layer: Add a production-ready gRPC transport implementation and factory registration.
- State Modules: Expand tool, task, and flow state modules beyond their current storage-backed extension points.
- OpenTelemetry: Add first-class OpenTelemetry export alongside the existing telemetry integrations.