dev → 1.0.2 — Registry Toolkit Managers, Setup CRUD & Storage/Filesystem Scopes¤
Summary¤
This release aggregates everything on the branch relative to dev. The headline is the Registry Toolkit: four
agent-facing Agno tools (services_manager, kins_manager, tools_manager, load_manager) that collapse the many
individual registry tools into four entrypoints, each driven by a single discriminated-union action argument.
Around it, the setup service was narrowed to setup-level CRUD + visibility (the version lifecycle is now
platform-owned), the storage and filesystem services gained record visibility and context scopes (including the
read-only cross-owner USERS / ORGANIZATIONS scopes, detailed in the 1.0.2.dev6 / 1.0.2.dev7 notes), and a set of
supporting toolkits, content validation, and framework plumbing landed.
Breaking changes are marked (breaking). Storage/filesystem specifics are covered in
docs/changelog/1.0.2.dev6.mdanddocs/changelog/1.0.2.dev7.md; they are summarised here for completeness.
Added¤
Registry Toolkit — four agent-facing managers¤
A new surface under src/digitalkin/community/agno/toolkits/registry/. Each manager is one Agno tool taking one
discriminated action; the union is the tool's LLM schema, and a malformed action comes back as a clean fail envelope
the model self-corrects from (never a raised traceback).
services_manager(ServicesManager, SERVICE setups) —get,create(shareable service from name + config JSON),search,load(returns the service's stored config content),update,delete,change_visibility.kins_manager(KinsManager, ARCHETYPE setups) —get,search,update,delete,change_visibility.tools_manager(ToolsManager, TOOL_MODULE setups) —get,search,update,delete,change_visibility; it administers tool setups only and never makes a tool callable (nocreate).load_manager(LoadManager) — an external-execution tool (toolaction) that resolves a discovered tool setup into a liveModuleToolkitand appends it to the agent's tool list, making it callable in the same turn. Idempotent persetup_id, with distinct not-found / wrong-family / already-loaded / rebind-conflict messages.
Shared plumbing (registry/base.py, registry/action.py):
RegistryObjectToolKit(aDkToolkit) carrying theRegistryActionCtxaction context, theensure_kindtype guard that refuses cross-type access (e.g.kins_managerreading a tool, or a mutation on the wrong kind / a deleted id), a fail-safe_guard/_dispatchenvelope, best-effort setup-cache invalidation after writes, and_jsonablenormalisation that echoesvisibilityback in caller vocabulary (VISIBILITY_INTERNAL→internal).- Tools register with
skip_entrypoint_processing+ an explicit schema, so args are validated in_runvia aTypeAdapter(including models that serialise the nestedactionas a JSON string). - Shared actions
GetAction/SearchAction/UpdateAction/DeleteAction/ChangeVisibilityAction.searchis semantic (nearest-match, capped at 25): it drops versionless (non-instantiable) rows, and itstruncatedflag is a genuine next-page signal read on the rendered page (readslimit + 1, so a full page of exactlylimitrows is not falsely reported as truncated). Content-bearing actions run anamecontrol-char validator and an unsafe-content-key validator.
Content validation¤
SetupContentValidator(src/digitalkin/utils/setup_content_validator.py) — validates a setup'scontentagainst the backing module's config JSON schema before a create/update by compiling a throwaway strict Pydantic model: resolves$ref/$defs(cycle-breaking), nests objects, types array elements andadditionalPropertiesmaps, closesenum/consttoLiteral, honours nullability, forbids undeclared keys unless opted in, and enforces numeric/string/array/object constraints. Plusreject_control_chars(C0 control chars in strings) andreject_unsafe_keys(recursively rejects content keys carrying non-BMP/control characters that storage would silently drop).
Supporting Agno toolkits & tool loading¤
DkToolkit(toolkits/base.py) — shared base for all DigitalKin Agno toolkits: the canonical{"output"|"error", "metadata"}JSON envelope (_ok/_fail) and best-effort AG-UI custom-event emission (_notify); toolkits never raise into the agent loop.ChatHistoryTools(toolkits/chat_history.py) — a token-cheap two-step chat-history surface replacing Agno's full-dumpget_chat_history:outline_chat_history(metadata-only index with role/preview/size + paging) thenread_chat_messages(full content by id, with truncation and media as references).UserProfileTools(toolkits/user_profile.py) —get_user_profileexposing the current user's name/email/plan/credits, lazily fetched and cached.DefaultToolkits(toolkits/defaults.py) — a one-callbuild()assembling the default toolkits (chat history, user profile, the three registry managers whencontext.setupis wired, andLoadManagerbound to the live tool list) withbind_host()for two-phase agent construction.ModuleToolkit(module_toolkit.py) — an Agno Toolkit wrapping a remote SDK tool module's tools over gRPC: explicit-schema functions, SDK sentinel-protocol parsing, multimodal image extraction intoToolResult.images, AG-UI event relay, timeouts, and per-call cost/timing metadata.ToolCallMetadata/ToolOutputMetadata(community/agno/models.py) — cost/timing metadata models for module tool calls (response time, API calls, cost estimate, credits, result counts) with serialisers andextract_tool_metadata; both exported fromcommunity.agno.
Services, models & settings¤
RegistryStrategy.search_setups(query, setup_ids, module_ids, module_types, statuses, visibilities, limit, offset)returningSetupSummary(a search-safe view that never carriesconfig); implemented inDefaultRegistry(in-memory) andGrpcRegistry(newSearchSetupsRPC). Plussearch_tools/search_kins/search_servicesconvenience views andget_service_setup(setup_id).SetupStrategy.change_visibility(setup_dict)(public/private/internal) and thecreate_service_setup(name, content)convenience wrapper, both returningSetupData.SetupDatagainsstatus: RegistrySetupStatusandvisibility: Visibility(defaultUNSPECIFIED, coerced from proto enum names).StorageRecordgainsvisibility: Visibility.- New
SetupSummarymodel;RegistryModuleType.SERVICEmember;SetupInfo.module_name/SetupInfo.module_type. - New
services.Contextenum (filesystem scopes) andstorage.Visibilityenum (UNSPECIFIED/PUBLIC/PRIVATE/INTERNAL), with read-only cross-ownerUSERS/ORGANIZATIONSscopes. StreamErrorCode.SETUP_VALIDATION_ERROR.- New
models/settings/registry.py:RegistrySettings(search_timeout_sdefault 10.0, env prefixDIGITALKIN_REGISTRY_) with a cachedget_registry_settings()singleton.
Module & context¤
ModuleContext.resolve_tool(setup_id)— resolves a registry setup id into aToolModuleInfoand caches it, while re-runningregistry.get_setupauthorization on every call (even cache hits).ModuleContext.get_module_config_schema(module_id, *, llm_format=False)— fetches a module's config-setup JSON schema (used to validatecontentbefore create/update).ModuleContext.setup— a new borrowedSetupStrategy | Nonefield/param, letting setup-CRUD toolkits reach the servicer's shared setup service.BaseModule.build_registry_documentation()— assembles registry docs from the author description plus a markdown non-utility trigger table;BaseModule.registry_typeClassVar (defaultUNSPECIFIED), overridden toARCHETYPEonArchetypeModuleandTOOL_MODULEonToolModule.preload_instance(base +SingleJobManager) gainssetupandinvalidate_setupparams, wired ontocontext.setupandcontext.callbacks.invalidate_setupbeforeprepare().
Changed¤
- (breaking)
RegistryModuleType.TOOL = "tool"renamed toTOOL_MODULE = "tool_module"to mirror the protoModuleTypenames. - (breaking) Setup service narrowed to setup-level CRUD + visibility:
create_setupreturnsSetupData(wasstr) and takes{name, content}(owner/org/module resolved server-side);get_setupis keyed bysetup_id(was name) and returns the current version populated;update_setupreturnsSetupData(wasbool) and takes{setup_id, name, content}.DefaultSetupis now a pure in-memory store;GrpcSetupinput-guard failures raiseValueError(wasValidationError). - (breaking) Storage: the
scope: Literal["mission","setup"]argument becamecontext: Context(defaultMISSIONS) acrossstore/read/update/remove/list/remove_collection/upsert, anddata_typebecame theDataTypeenum (was a string). See1.0.2.dev6. - (breaking) Filesystem:
get_file/get_files(FileFilter) takecontext: Context(was a"mission"/"setup"string); writes stay mission-scoped. See1.0.2.dev7. RegistryStrategy.search()droppedorganization_id, addedlimit/offsetpagination, and now matches module name and documentation (case-insensitive); the gRPC path movedDiscoverModules→SearchModulesand honours the tightenedsearch_timeout_sdeadline.RegistryStrategy.register()gainsmodule_typeanddocumentationparams;ModuleServerregistration now sends the module'sregistry_typeandbuild_registry_documentation()output.GrpcRegistryre-raisesPermissionDeniedErrorunwrapped across its RPCs and fail-closes enum encoding (_encode_enumraises on Python/proto drift rather than silently dropping a filter).GrpcStorage/GrpcFilesystemnow send a context- kind wire enum (server resolves the concrete id from request metadata) and mapVisibilityto the wire enum;visibilityis forwarded on writes andvisibilitieson list.AgnoStreamAdaptersuffixes manager tool-call display names with the resolved action (e.g.services_manager→services_manager_create,load_manager→load_manager_tool) so the front can tell collapsed operations apart (cosmetic; LLM function name and HITL matching unchanged).AgnoHitlRunnerresolvesload_managerpauses in-process and auto-continues the run (bounded to 20 iterations), so discover → load → use reads as a single turn; it only surfaces a pause when a genuine frontend tool remains, and emits aRunErrorEvent(auto_continue_limit) on exceeding the bound.BaseModule.descriptionis now optional (defaults to"").ModuleServicertool-cache methods gained hit/set/expire/build/invalidate logging.
Fixed¤
ModuleContext._create_single_tool_function: a fatalstream.errorframe (e.g.SETUP_ACCESS_DENIED) in a tool-call stream now raisesToolCallError(new, incommunication/exceptions.py) instead of yielding as a benign result, so a denied sub-call aborts the parent run.ModuleRunnerwraps setup resolve / model-build / tool-cache in aValidationErrorguard that emitsSETUP_VALIDATION_ERRORviaon_fatal(with a missing-fields summary) rather than crashing the run.ToolReference.resolve_toolreturnsNone(dropping the selection) when no enabled trigger matches, instead of caching aToolModuleInfowith emptytools.- Enum robustness:
ModuleInfonormalizes legacymodule_type("tool"→tool_module,"kin"→archetype);RegistrySetupStatus._missing_/Visibility._missing_coerce proto/any-case names and fall back toUNSPECIFIED, so reads never crash on unknown states. GrpcStorageListRecords/ReadRecordlog-and-skip a foreign-shaped record that fails validation instead of failing the whole call.PausedRunStore.collect_pendingskips tool calls already resolved in-process, so aload_managercall handled by the runner no longer leaks to the front as an unimplementable frontend tool; on auto-continue after a load, the runner clears Agno's tools-factory cache so the just-loaded function is immediately callable.StorageMixin.store_storage/upsert_storageconvert thedata_typestring toDataType[...]before delegating.BaseServervCPU detection guarded bysys.platform == "linux"(falls back toos.cpu_count()elsewhere).- Gateway BiDi dial-back close: a read parked before
outgoing_donenow switches to the close-grace timeout once outputs drain, instead of parking to the full RPC deadline. - Removed prohibited
getattr(...)attribute access inhitl.pyin favour of direct typed access.
Removed¤
- (breaking) All standalone setup-version RPCs and listing from the setup strategy/implementations:
create_setup_version,get_setup_version,search_setup_versions,update_setup_version,delete_setup_version, andlist_setups— the version lifecycle is now platform-owned via the setup'scurrent_setup_version. - The
Scope = Literal["mission","setup"]alias instorage_strategy.py(superseded byContext). organization_idfrom the registrysearch()API.
Tests¤
- Agno toolkits — a new
tests/community/agno/toolkits/suite (~9 files):DkToolkitenvelope/notifications; the registry managers (manage_*dispatch, ~54 tests) covering setup-schema content validation, control-char and empty-content rejection, and visibility enforcement; plus the load manager, chat-history tools, the default-toolkit assembler, and user-profile tools. - Agno adapter/module — dynamic tool-loading tests (real
agnodep),ModuleToolkitoutput/event-stream tests, and adapter coverage for the action-suffixed manager tool names. - Modules — registry-documentation assembly and fatal
stream.errorabort suites; expanded tool-cache / tool-reference tests (resolve+save, cache-hit permission re-checks, permission-denied propagation). - Services — new
DefaultRegistryand registry-hardening (enum encode/decode symmetry, scoped settings) suites; gRPC registry expanded for trimmed search summaries andsearch_setupsmapping/filtering; storage expanded for record visibility and cross-owner context; filesystem context-kind forwarding; the setup gRPC suite largely rewritten around the reduced CRUD surface (no-RPC-on-missing-fields, version pinning). - Gateway / Core — dial-back close-after-fatal and stream-error propagation;
module_runnerM4 producer regression.
Roughly 13 new test suites added and ~16 existing files expanded.