Values on the wire, and the domain values they name.
Split from :mod:symfonic.platform.transport, which is the router itself. The
router decides who may ask; this decides what a header, a query parameter or
a stored record looks like as JSON. Neither needs to change when the other
does, and one of them is the file a deployment reads when it wants to know what
the API returns.
kind_of(event: Any) -> str
The event's kind as a plain string, whatever type carries it.
Source code in src/symfonic/platform/wire.py
| def kind_of(event: Any) -> str:
"""The event's kind as a plain string, whatever type carries it."""
kind = getattr(event, "kind", None)
return getattr(kind, "value", None) or str(kind or "chunk")
|
memory_layer(name: str | None) -> Any
The memory layer a query parameter names, or None for every layer.
Source code in src/symfonic/platform/wire.py
| def memory_layer(name: str | None) -> Any:
"""The memory layer a query parameter names, or ``None`` for every layer."""
if name is None:
return None
from symfonic.capabilities.memory import MemoryLayer
try:
return MemoryLayer(name)
except ValueError:
raise ValueError(f"unknown layer: {name!r}") from None
|
memory_scope(scope: Any) -> Any
The memory scope a framework scope names.
Delegated rather than converted here: the memory package owns the one
translation between the two spellings of a scope, and a second one in a
transport is how they drift.
Source code in src/symfonic/platform/wire.py
| def memory_scope(scope: Any) -> Any:
"""The memory scope a framework scope names.
Delegated rather than converted here: the memory package owns the one
translation between the two spellings of a scope, and a second one in a
transport is how they drift.
"""
from symfonic.capabilities.memory import as_memory_scope
return as_memory_scope(scope)
|
record_body
record_body(record: Any) -> dict[str, Any]
One stored record as JSON a browser can render.
Source code in src/symfonic/platform/wire.py
| def record_body(record: Any) -> dict[str, Any]:
"""One stored record as JSON a browser can render."""
return {
"id": record.record_id,
"layer": getattr(record.layer, "value", str(record.layer)),
"content": record.text,
"scope_path": record.scope_path,
"salience": record.salience,
"origin": record.origin,
"revision": record.revision,
"metadata": dict(record.metadata or {}),
}
|
scope_for_tenant(tenant: str) -> Any
The scope a tenant header names.
One level, because a header names a tenant and nothing deeper. A router
that read a principal or a session from headers too would be deriving
authorisation from something the caller controls, which is the platform's
own rule about where a scope may come from.
Source code in src/symfonic/platform/wire.py
| def scope_for_tenant(tenant: str) -> Any:
"""The scope a tenant header names.
One level, because a header names a tenant and nothing deeper. A router
that read a principal or a session from headers too would be deriving
authorisation from something the caller controls, which is the platform's
own rule about where a scope may come from.
"""
from symfonic.agent.types import FrameworkTenantScope
from symfonic.core.scope import ScopeLevel
return FrameworkTenantScope.from_path([ScopeLevel(kind="tenant", id=tenant)])
|
text_of
text_of(value: Any) -> str
Whatever the turn produced, as text a JSON body can carry.
Structural rather than typed: the router is a mapper and must not learn
the result type, which differs between a run and a stream chunk and is
free to gain fields without this file changing.
Source code in src/symfonic/platform/wire.py
| def text_of(value: Any) -> str:
"""Whatever the turn produced, as text a JSON body can carry.
Structural rather than typed: the router is a mapper and must not learn
the result type, which differs between a run and a stream chunk and is
free to gain fields without this file changing.
"""
for attribute in ("content", "text", "final_response", "delta"):
found = getattr(value, attribute, None)
if isinstance(found, str) and found:
return found
return str(value)
|