Skip to content

1.0.2.dev6 → 1.0.2.dev7 — Filesystem Context Scopes (mission/setup/user/organization)¤

Summary¤

This release brings the filesystem service in line with the storage context model shipped in dev6. The string context: Literal["mission", "setup"] argument is replaced by a typed Context enum, extended with the two read-only cross-owner scopes USERS and ORGANIZATIONS. A file produced by one kin can now be read by another kin of the same user/organization, subject to server-side access control.

A small consistency fix also lands on the storage side: ContextStorage.UNSPECIFIED now maps to the unspecified wire enum instead of being silently treated as MISSIONS, matching the filesystem behaviour.

Only the context kind is sent on the wire — no id is transmitted by the client. The concrete owner (mission / setup / user / organization) is resolved server-side from the request context.

Requirement: needs agentic-mesh-protocol with the filesystem CONTEXT_USERS / CONTEXT_ORGANIZATIONS enum values. It is pulled in transitively by this SDK version.

What changed¤

Context — the owner/scope of a filesystem operation (replaces scope/context strings)¤

from digitalkin.models.services.services import Context


class ContextFile(Enum):
  UNSPECIFIED = "unspecified"
  MISSIONS = "mission"  # this mission (default)
  SETUP = "setup"  # this setup version
  USERS = "user"  # read-only: all kins of the same user
  ORGANIZATIONS = "organization"  # read-only: all kins of the same organization
  • MISSIONS (default) and SETUP are the read/write owner contexts.
  • USERS and ORGANIZATIONS are read-only cross-owner scopes (use them on reads: get_file / get_files).
  • The enum values are singular strings, so Pydantic still coerces legacy string contexts on FileFilter (e.g. FileFilter(context="setup")).

Read methods now take context: ContextFile:

Method Signature (relevant args)
get_file get_file(file_id, context=ContextFile.MISSIONS, *, include_content=False)
get_files get_files(filters, ...) where filters.context: ContextFile = ContextFile.MISSIONS

_context_enum maps every kind to its wire enum, including CONTEXT_USERS / CONTEXT_ORGANIZATIONS / CONTEXT_UNSPECIFIED.

Writes stay owner-scoped¤

upload_files / update_file / delete_files remain mission-scoped, exactly as before. Cross-owner scopes are read-only — you cannot write into another kin's user/organization space.

Storage: UNSPECIFIED consistency fix¤

ContextStorage.UNSPECIFIED now resolves to the unspecified: kind marker and maps to CONTEXT_UNSPECIFIED on the wire (server applies its default), instead of silently becoming CONTEXT_MISSIONS. Public callers are unaffected — the default context stays MISSIONS.

How to use¤

from digitalkin.models.services.services import Context
from digitalkin.services.filesystem.filesystem_strategy import FileFilter

# Read a file owned by the current mission (default)
record = await filesystem.get_file(file_id, include_content=True)

# Read a file from the setup-version scope
record = await filesystem.get_file(file_id, context=Context.SETUP)

# Cross-owner: list files shared by other kins of the same user.
# The server resolves the concrete user id; no id is sent by the client.
records, total = await filesystem.get_files(
  FileFilter(context=Context.USERS, prefix="reports/"),
)

# Same across the whole organization
records, total = await filesystem.get_files(FileFilter(context=Context.ORGANIZATIONS))

Migration¤

  • context="mission" / context="setup"Context: pass ContextFile.MISSIONS / ContextFile.SETUP to get_file. For FileFilter, the legacy strings still validate (Pydantic coerces them by value), but prefer the enum for clarity.
  • No change to write calls (upload_files / update_file / delete_files).
  • Import the enum from digitalkin.models.services.filesystem.

Minimal before/after:

# before
await filesystem.get_file(file_id, context="setup")
await filesystem.get_files(FileFilter(context="mission", prefix="x/"))

# after
from digitalkin.models.services.services import Context

await filesystem.get_file(file_id, context=Context.SETUP)
await filesystem.get_files(FileFilter(context=Context.MISSIONS, prefix="x/"))

Verification¤

  • tests/services/filesystem/test_grpc_filesystem.py::TestContextScopes locks the wire mapping for all kinds — MISSIONS, SETUP, USERS, ORGANIZATIONS, UNSPECIFIED — on both get_files and get_file.
  • tests/services/storage/test_grpc_storage.py::TestListData covers UNSPECIFIED → CONTEXT_UNSPECIFIED alongside the cross-owner storage scopes.