sandbox: B1 — get_translations wire protocol

Add the sandbox/get_translations message pair to the control-channel proto
and regenerate the checked-in gencode for both no-cross-import mirrors.
Mirror MSG_GET_TRANSLATIONS in both protocol.py files and register the
message pair in both messages.py REGISTRY copies.

Request {language, domains[]}; result {language, strings: {domain: raw
strings.json dict}} — main batches a group's custom domains into one call;
built-in domains never cross the wire.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paulus Schoutsen
2026-07-07 15:12:23 -04:00
co-authored by Claude Opus 4.8
parent b7d9bf6a5b
commit ca7b7a05a4
9 changed files with 192 additions and 118 deletions
File diff suppressed because one or more lines are too long
@@ -183,6 +183,22 @@ class CallServiceResult(_message.Message):
response: ServiceResponse
def __init__(self, response: _Optional[_Union[ServiceResponse, _Mapping]] = ...) -> None: ...
class GetTranslations(_message.Message):
__slots__ = ("language", "domains")
LANGUAGE_FIELD_NUMBER: _ClassVar[int]
DOMAINS_FIELD_NUMBER: _ClassVar[int]
language: str
domains: _containers.RepeatedScalarFieldContainer[str]
def __init__(self, language: _Optional[str] = ..., domains: _Optional[_Iterable[str]] = ...) -> None: ...
class GetTranslationsResult(_message.Message):
__slots__ = ("language", "strings")
LANGUAGE_FIELD_NUMBER: _ClassVar[int]
STRINGS_FIELD_NUMBER: _ClassVar[int]
language: str
strings: _struct_pb2.Struct
def __init__(self, language: _Optional[str] = ..., strings: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ...) -> None: ...
class Shutdown(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
@@ -38,6 +38,7 @@ REGISTRY: dict[str, tuple[type[Message], type[Message] | None]] = {
"sandbox/entry_setup": (pb.EntrySetup, pb.EntrySetupResult),
"sandbox/entry_unload": (pb.EntryUnload, pb.EntryUnloadResult),
"sandbox/call_service": (pb.CallService, pb.CallServiceResult),
"sandbox/get_translations": (pb.GetTranslations, pb.GetTranslationsResult),
"sandbox/shutdown": (pb.Shutdown, pb.ShutdownResult),
"sandbox/ping": (pb.Ping, pb.PingResult),
"sandbox/flow_init": (pb.FlowInit, pb.FlowResult),
@@ -32,6 +32,14 @@ Main → Sandbox calls:
the main→sandbox service mirroring path). Payload mirrors a
``ServiceCall``: ``(domain, service, target, service_data, context,
return_response)``. Returns either ``None`` or a service-response dict.
* ``sandbox/get_translations`` — pull a sandboxed integration's frontend
translation strings. Payload ``{language, domains: [str]}`` (main batches
every owned custom domain of one group into a single request). Response
``{language, strings: {domain: <raw strings.json dict>}}`` — the
un-flattened nesting a ``translations/<lang>.json`` holds, with ``title``
pre-filled from the integration name (main has no ``Integration`` for a
custom domain, so it cannot run that fallback). Built-in domains never
cross the wire — main reads its byte-identical disk copy.
Sandbox → Main calls:
@@ -92,6 +100,7 @@ MSG_READY: Final = "sandbox/ready"
MSG_ENTRY_SETUP: Final = "sandbox/entry_setup"
MSG_ENTRY_UNLOAD: Final = "sandbox/entry_unload"
MSG_CALL_SERVICE: Final = "sandbox/call_service"
MSG_GET_TRANSLATIONS: Final = "sandbox/get_translations"
MSG_SHUTDOWN: Final = "sandbox/shutdown"
# Sandbox → Main
@@ -111,6 +120,7 @@ __all__ = [
"MSG_ENTRY_SETUP",
"MSG_ENTRY_UNLOAD",
"MSG_FIRE_EVENT",
"MSG_GET_TRANSLATIONS",
"MSG_READY",
"MSG_REGISTER_ENTITY",
"MSG_REGISTER_SERVICE",
File diff suppressed because one or more lines are too long
@@ -183,6 +183,22 @@ class CallServiceResult(_message.Message):
response: ServiceResponse
def __init__(self, response: _Optional[_Union[ServiceResponse, _Mapping]] = ...) -> None: ...
class GetTranslations(_message.Message):
__slots__ = ("language", "domains")
LANGUAGE_FIELD_NUMBER: _ClassVar[int]
DOMAINS_FIELD_NUMBER: _ClassVar[int]
language: str
domains: _containers.RepeatedScalarFieldContainer[str]
def __init__(self, language: _Optional[str] = ..., domains: _Optional[_Iterable[str]] = ...) -> None: ...
class GetTranslationsResult(_message.Message):
__slots__ = ("language", "strings")
LANGUAGE_FIELD_NUMBER: _ClassVar[int]
STRINGS_FIELD_NUMBER: _ClassVar[int]
language: str
strings: _struct_pb2.Struct
def __init__(self, language: _Optional[str] = ..., strings: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ...) -> None: ...
class Shutdown(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
@@ -38,6 +38,7 @@ REGISTRY: dict[str, tuple[type[Message], type[Message] | None]] = {
"sandbox/entry_setup": (pb.EntrySetup, pb.EntrySetupResult),
"sandbox/entry_unload": (pb.EntryUnload, pb.EntryUnloadResult),
"sandbox/call_service": (pb.CallService, pb.CallServiceResult),
"sandbox/get_translations": (pb.GetTranslations, pb.GetTranslationsResult),
"sandbox/shutdown": (pb.Shutdown, pb.ShutdownResult),
"sandbox/ping": (pb.Ping, pb.PingResult),
"sandbox/flow_init": (pb.FlowInit, pb.FlowResult),
@@ -18,6 +18,7 @@ MSG_READY: Final = "sandbox/ready"
MSG_ENTRY_SETUP: Final = "sandbox/entry_setup"
MSG_ENTRY_UNLOAD: Final = "sandbox/entry_unload"
MSG_CALL_SERVICE: Final = "sandbox/call_service"
MSG_GET_TRANSLATIONS: Final = "sandbox/get_translations"
MSG_SHUTDOWN: Final = "sandbox/shutdown"
# Sandbox → Main
@@ -37,6 +38,7 @@ __all__ = [
"MSG_ENTRY_SETUP",
"MSG_ENTRY_UNLOAD",
"MSG_FIRE_EVENT",
"MSG_GET_TRANSLATIONS",
"MSG_READY",
"MSG_REGISTER_ENTITY",
"MSG_REGISTER_SERVICE",
+20
View File
@@ -153,6 +153,26 @@ message CallServiceResult {
optional ServiceResponse response = 1; // unset when no response returned
}
// --- get_translations (main -> sandbox) -----------------------------------
// Pull a sandboxed integration's frontend translation strings. Main issues
// this per sandbox group, batching every owned (custom) domain into one
// request. Built-in domains never cross the wire — main reads its own
// byte-identical disk copy.
message GetTranslations {
string language = 1; // single language per request (e.g. "en")
repeated string domains = 2; // the domains main wants strings for
}
message GetTranslationsResult {
string language = 1;
// { domain: <raw strings.json dict> } — the un-flattened nesting a
// translations/<lang>.json holds, with `title` already filled in from the
// integration name (main has no Integration for a custom domain so it
// cannot run that fallback). Domains the sandbox does not own are omitted.
google.protobuf.Struct strings = 2;
}
// --- shutdown / ping (main -> sandbox) ------------------------------------
message Shutdown {}