feat(code-runtime-python): add the fd-3 frame protocol
Introduce @deepseek-ai/dsh-code-runtime-python with the versionless
JSON-lines protocol between the Node host and the CPython subprocess:
the host-side hostile-frame codec (validateChildFrame, encodeJsonPlain,
checkDoneValue, hasUnsafeIntegerToken, hasNonLosslessNumber,
logTruncationMarker) and the Python-side wire-vocabulary mirror
(py/protocol.py).
This is the protocol layer of the code-runtime-python stack, split from
#436 and based on the multi-language seam extension. The PythonCodeRuntime
implementation and its Python JSON codec land in the backend-core PR on
top of this branch.
Ship the minimal buildable package skeleton (package.json, tsconfig,
tsdown, barrel index, invariant companion, bilingual README) because the
workspace-constraint, coverage, and invariant-topology gates require the
package to exist and build the moment its directory does; the backend-core
PR extends those files rather than creating them.
Align py/protocol.py with src/protocol.ts (the round-12 review of #436
found LogMessage.truncated, DoneMessage.error.kind, and Namespace.errorClass
stale) and guard the two runtime-executed surfaces (PROTOCOL_FD and the log
truncation marker) with a real-python3 cross-language mirror e2e test.
2026-07-31 18:51:03 +08:00
|
|
|
"""Wire protocol vocabulary for the Python side of dsh-code-runtime-python.
|
|
|
|
|
|
|
|
|
|
Mirrors ``src/protocol.ts``. Frames travel on fd 3 as JSON-lines (one JSON
|
|
|
|
|
object per line). The host validates every inbound frame; this side trusts
|
|
|
|
|
host replies.
|
2026-07-31 19:20:28 +08:00
|
|
|
|
|
|
|
|
The wire uses the JSON key ``global`` (a Python keyword), so the frame
|
|
|
|
|
``TypedDict``s that carry it are declared with the functional syntax rather than
|
|
|
|
|
class bodies: a class attribute cannot be named ``global``, and a ``global_``
|
|
|
|
|
attribute would describe a key the wire never sends. Optional-field messages
|
|
|
|
|
pair a required base with a ``total=False`` subclass so a required field such as
|
|
|
|
|
``type`` cannot be dropped while ``value``/``error``/``truncated`` stay optional.
|
feat(code-runtime-python): add the fd-3 frame protocol
Introduce @deepseek-ai/dsh-code-runtime-python with the versionless
JSON-lines protocol between the Node host and the CPython subprocess:
the host-side hostile-frame codec (validateChildFrame, encodeJsonPlain,
checkDoneValue, hasUnsafeIntegerToken, hasNonLosslessNumber,
logTruncationMarker) and the Python-side wire-vocabulary mirror
(py/protocol.py).
This is the protocol layer of the code-runtime-python stack, split from
#436 and based on the multi-language seam extension. The PythonCodeRuntime
implementation and its Python JSON codec land in the backend-core PR on
top of this branch.
Ship the minimal buildable package skeleton (package.json, tsconfig,
tsdown, barrel index, invariant companion, bilingual README) because the
workspace-constraint, coverage, and invariant-topology gates require the
package to exist and build the moment its directory does; the backend-core
PR extends those files rather than creating them.
Align py/protocol.py with src/protocol.ts (the round-12 review of #436
found LogMessage.truncated, DoneMessage.error.kind, and Namespace.errorClass
stale) and guard the two runtime-executed surfaces (PROTOCOL_FD and the log
truncation marker) with a real-python3 cross-language mirror e2e test.
2026-07-31 18:51:03 +08:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from typing import Any, Literal, TypedDict, Union
|
|
|
|
|
|
|
|
|
|
# The protocol fd from the child's perspective. Node passes
|
|
|
|
|
# ``stdio: [pipe, pipe, pipe, pipe]`` so the fourth entry (fd 3) is the
|
|
|
|
|
# framed-JSON channel; stdout/stderr stay clear for the program's own output.
|
|
|
|
|
PROTOCOL_FD = 3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ErrorClass(TypedDict):
|
|
|
|
|
"""A namespace's program-visible exception class: rejected calls raise its
|
|
|
|
|
instances carrying the failed member name on ``memberNameProperty``."""
|
|
|
|
|
|
|
|
|
|
name: str
|
|
|
|
|
memberNameProperty: str
|
|
|
|
|
|
|
|
|
|
|
2026-07-31 19:20:28 +08:00
|
|
|
# ``global`` is a Python keyword, so the required part is declared functionally
|
|
|
|
|
# to hold the real wire key; ``errorClass`` is optional per the TS `errorClass?`.
|
|
|
|
|
_NamespaceRequired = TypedDict("_NamespaceRequired", {"global": str, "names": "list[str]"})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Namespace(_NamespaceRequired, total=False):
|
|
|
|
|
"""One binding namespace declaration: the ``global`` name, its function
|
|
|
|
|
``names``, and an optional program-visible ``errorClass`` for rejected calls."""
|
|
|
|
|
|
|
|
|
|
errorClass: ErrorClass
|
feat(code-runtime-python): add the fd-3 frame protocol
Introduce @deepseek-ai/dsh-code-runtime-python with the versionless
JSON-lines protocol between the Node host and the CPython subprocess:
the host-side hostile-frame codec (validateChildFrame, encodeJsonPlain,
checkDoneValue, hasUnsafeIntegerToken, hasNonLosslessNumber,
logTruncationMarker) and the Python-side wire-vocabulary mirror
(py/protocol.py).
This is the protocol layer of the code-runtime-python stack, split from
#436 and based on the multi-language seam extension. The PythonCodeRuntime
implementation and its Python JSON codec land in the backend-core PR on
top of this branch.
Ship the minimal buildable package skeleton (package.json, tsconfig,
tsdown, barrel index, invariant companion, bilingual README) because the
workspace-constraint, coverage, and invariant-topology gates require the
package to exist and build the moment its directory does; the backend-core
PR extends those files rather than creating them.
Align py/protocol.py with src/protocol.ts (the round-12 review of #436
found LogMessage.truncated, DoneMessage.error.kind, and Namespace.errorClass
stale) and guard the two runtime-executed surfaces (PROTOCOL_FD and the log
truncation marker) with a real-python3 cross-language mirror e2e test.
2026-07-31 18:51:03 +08:00
|
|
|
|
2026-07-31 19:20:28 +08:00
|
|
|
|
|
|
|
|
class BootMessage(TypedDict):
|
|
|
|
|
"""Host → child, first frame on fd 3. Carries every cap and the namespaces."""
|
|
|
|
|
|
|
|
|
|
type: Literal["boot"]
|
|
|
|
|
cpuSeconds: int
|
|
|
|
|
addressSpaceBytes: int
|
|
|
|
|
maxLogBytes: int
|
|
|
|
|
maxValueBytes: int
|
|
|
|
|
namespaces: "list[Namespace]"
|
feat(code-runtime-python): add the fd-3 frame protocol
Introduce @deepseek-ai/dsh-code-runtime-python with the versionless
JSON-lines protocol between the Node host and the CPython subprocess:
the host-side hostile-frame codec (validateChildFrame, encodeJsonPlain,
checkDoneValue, hasUnsafeIntegerToken, hasNonLosslessNumber,
logTruncationMarker) and the Python-side wire-vocabulary mirror
(py/protocol.py).
This is the protocol layer of the code-runtime-python stack, split from
#436 and based on the multi-language seam extension. The PythonCodeRuntime
implementation and its Python JSON codec land in the backend-core PR on
top of this branch.
Ship the minimal buildable package skeleton (package.json, tsconfig,
tsdown, barrel index, invariant companion, bilingual README) because the
workspace-constraint, coverage, and invariant-topology gates require the
package to exist and build the moment its directory does; the backend-core
PR extends those files rather than creating them.
Align py/protocol.py with src/protocol.ts (the round-12 review of #436
found LogMessage.truncated, DoneMessage.error.kind, and Namespace.errorClass
stale) and guard the two runtime-executed surfaces (PROTOCOL_FD and the log
truncation marker) with a real-python3 cross-language mirror e2e test.
2026-07-31 18:51:03 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class RunMessage(TypedDict):
|
|
|
|
|
"""Host → child, sent after ``boot-ack``. Carries only the program body."""
|
|
|
|
|
|
|
|
|
|
type: Literal["run"]
|
|
|
|
|
program: str
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BootAckMessage(TypedDict):
|
|
|
|
|
"""Child → host: resource limits applied, ready for the run message."""
|
|
|
|
|
|
|
|
|
|
type: Literal["boot-ack"]
|
|
|
|
|
|
|
|
|
|
|
2026-07-31 19:20:28 +08:00
|
|
|
# ``global`` wire key: whole message declared functionally, all fields required.
|
|
|
|
|
CallMessage = TypedDict(
|
|
|
|
|
"CallMessage",
|
|
|
|
|
{"type": Literal["call"], "id": int, "global": str, "name": str, "args": Any},
|
|
|
|
|
)
|
feat(code-runtime-python): add the fd-3 frame protocol
Introduce @deepseek-ai/dsh-code-runtime-python with the versionless
JSON-lines protocol between the Node host and the CPython subprocess:
the host-side hostile-frame codec (validateChildFrame, encodeJsonPlain,
checkDoneValue, hasUnsafeIntegerToken, hasNonLosslessNumber,
logTruncationMarker) and the Python-side wire-vocabulary mirror
(py/protocol.py).
This is the protocol layer of the code-runtime-python stack, split from
#436 and based on the multi-language seam extension. The PythonCodeRuntime
implementation and its Python JSON codec land in the backend-core PR on
top of this branch.
Ship the minimal buildable package skeleton (package.json, tsconfig,
tsdown, barrel index, invariant companion, bilingual README) because the
workspace-constraint, coverage, and invariant-topology gates require the
package to exist and build the moment its directory does; the backend-core
PR extends those files rather than creating them.
Align py/protocol.py with src/protocol.ts (the round-12 review of #436
found LogMessage.truncated, DoneMessage.error.kind, and Namespace.errorClass
stale) and guard the two runtime-executed surfaces (PROTOCOL_FD and the log
truncation marker) with a real-python3 cross-language mirror e2e test.
2026-07-31 18:51:03 +08:00
|
|
|
|
|
|
|
|
|
2026-07-31 19:20:28 +08:00
|
|
|
_LogMessageRequired = TypedDict("_LogMessageRequired", {"type": Literal["log"], "text": str})
|
feat(code-runtime-python): add the fd-3 frame protocol
Introduce @deepseek-ai/dsh-code-runtime-python with the versionless
JSON-lines protocol between the Node host and the CPython subprocess:
the host-side hostile-frame codec (validateChildFrame, encodeJsonPlain,
checkDoneValue, hasUnsafeIntegerToken, hasNonLosslessNumber,
logTruncationMarker) and the Python-side wire-vocabulary mirror
(py/protocol.py).
This is the protocol layer of the code-runtime-python stack, split from
#436 and based on the multi-language seam extension. The PythonCodeRuntime
implementation and its Python JSON codec land in the backend-core PR on
top of this branch.
Ship the minimal buildable package skeleton (package.json, tsconfig,
tsdown, barrel index, invariant companion, bilingual README) because the
workspace-constraint, coverage, and invariant-topology gates require the
package to exist and build the moment its directory does; the backend-core
PR extends those files rather than creating them.
Align py/protocol.py with src/protocol.ts (the round-12 review of #436
found LogMessage.truncated, DoneMessage.error.kind, and Namespace.errorClass
stale) and guard the two runtime-executed surfaces (PROTOCOL_FD and the log
truncation marker) with a real-python3 cross-language mirror e2e test.
2026-07-31 18:51:03 +08:00
|
|
|
|
2026-07-31 19:20:28 +08:00
|
|
|
|
|
|
|
|
class LogMessage(_LogMessageRequired, total=False):
|
feat(code-runtime-python): add the fd-3 frame protocol
Introduce @deepseek-ai/dsh-code-runtime-python with the versionless
JSON-lines protocol between the Node host and the CPython subprocess:
the host-side hostile-frame codec (validateChildFrame, encodeJsonPlain,
checkDoneValue, hasUnsafeIntegerToken, hasNonLosslessNumber,
logTruncationMarker) and the Python-side wire-vocabulary mirror
(py/protocol.py).
This is the protocol layer of the code-runtime-python stack, split from
#436 and based on the multi-language seam extension. The PythonCodeRuntime
implementation and its Python JSON codec land in the backend-core PR on
top of this branch.
Ship the minimal buildable package skeleton (package.json, tsconfig,
tsdown, barrel index, invariant companion, bilingual README) because the
workspace-constraint, coverage, and invariant-topology gates require the
package to exist and build the moment its directory does; the backend-core
PR extends those files rather than creating them.
Align py/protocol.py with src/protocol.ts (the round-12 review of #436
found LogMessage.truncated, DoneMessage.error.kind, and Namespace.errorClass
stale) and guard the two runtime-executed surfaces (PROTOCOL_FD and the log
truncation marker) with a real-python3 cross-language mirror e2e test.
2026-07-31 18:51:03 +08:00
|
|
|
"""Child → host: one captured text chunk, streamed eagerly.
|
|
|
|
|
|
|
|
|
|
``truncated`` is set only on the frame that IS the child ledger's truncation
|
|
|
|
|
marker (not program output), so the host stops capturing at the same point
|
|
|
|
|
the child did — mirrors the TS `truncated?`.
|
|
|
|
|
"""
|
|
|
|
|
|
2026-07-31 19:20:28 +08:00
|
|
|
truncated: bool
|
feat(code-runtime-python): add the fd-3 frame protocol
Introduce @deepseek-ai/dsh-code-runtime-python with the versionless
JSON-lines protocol between the Node host and the CPython subprocess:
the host-side hostile-frame codec (validateChildFrame, encodeJsonPlain,
checkDoneValue, hasUnsafeIntegerToken, hasNonLosslessNumber,
logTruncationMarker) and the Python-side wire-vocabulary mirror
(py/protocol.py).
This is the protocol layer of the code-runtime-python stack, split from
#436 and based on the multi-language seam extension. The PythonCodeRuntime
implementation and its Python JSON codec land in the backend-core PR on
top of this branch.
Ship the minimal buildable package skeleton (package.json, tsconfig,
tsdown, barrel index, invariant companion, bilingual README) because the
workspace-constraint, coverage, and invariant-topology gates require the
package to exist and build the moment its directory does; the backend-core
PR extends those files rather than creating them.
Align py/protocol.py with src/protocol.ts (the round-12 review of #436
found LogMessage.truncated, DoneMessage.error.kind, and Namespace.errorClass
stale) and guard the two runtime-executed surfaces (PROTOCOL_FD and the log
truncation marker) with a real-python3 cross-language mirror e2e test.
2026-07-31 18:51:03 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class DoneErrorField(TypedDict):
|
|
|
|
|
"""Child → host: the failure carried on a ``done`` frame. ``kind`` is one of
|
|
|
|
|
the three the host validates; ``message`` is the traceback or diagnostic."""
|
|
|
|
|
|
|
|
|
|
kind: Literal["exception", "invalid-output", "output-limit"]
|
|
|
|
|
message: str
|
|
|
|
|
|
|
|
|
|
|
2026-07-31 19:20:28 +08:00
|
|
|
_DoneMessageRequired = TypedDict("_DoneMessageRequired", {"type": Literal["done"]})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DoneMessage(_DoneMessageRequired, total=False):
|
feat(code-runtime-python): add the fd-3 frame protocol
Introduce @deepseek-ai/dsh-code-runtime-python with the versionless
JSON-lines protocol between the Node host and the CPython subprocess:
the host-side hostile-frame codec (validateChildFrame, encodeJsonPlain,
checkDoneValue, hasUnsafeIntegerToken, hasNonLosslessNumber,
logTruncationMarker) and the Python-side wire-vocabulary mirror
(py/protocol.py).
This is the protocol layer of the code-runtime-python stack, split from
#436 and based on the multi-language seam extension. The PythonCodeRuntime
implementation and its Python JSON codec land in the backend-core PR on
top of this branch.
Ship the minimal buildable package skeleton (package.json, tsconfig,
tsdown, barrel index, invariant companion, bilingual README) because the
workspace-constraint, coverage, and invariant-topology gates require the
package to exist and build the moment its directory does; the backend-core
PR extends those files rather than creating them.
Align py/protocol.py with src/protocol.ts (the round-12 review of #436
found LogMessage.truncated, DoneMessage.error.kind, and Namespace.errorClass
stale) and guard the two runtime-executed surfaces (PROTOCOL_FD and the log
truncation marker) with a real-python3 cross-language mirror e2e test.
2026-07-31 18:51:03 +08:00
|
|
|
"""Child → host: the program settled. ``value`` and ``error`` are optional per the TS mirror."""
|
|
|
|
|
|
|
|
|
|
value: Any
|
|
|
|
|
error: DoneErrorField
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ChildToHost = Union[BootAckMessage, CallMessage, LogMessage, DoneMessage]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ReplyOk(TypedDict):
|
|
|
|
|
type: Literal["reply"]
|
|
|
|
|
id: int
|
|
|
|
|
ok: Literal[True]
|
|
|
|
|
value: Any
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ReplyErr(TypedDict):
|
|
|
|
|
type: Literal["reply"]
|
|
|
|
|
id: int
|
|
|
|
|
ok: Literal[False]
|
|
|
|
|
message: str
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ReplyMessage = Union[ReplyOk, ReplyErr]
|
2026-07-31 19:20:28 +08:00
|
|
|
# The host sends ``boot`` and ``run`` before any ``reply``, so the child-facing
|
|
|
|
|
# inbound union covers all three, not replies alone.
|
|
|
|
|
HostToChild = Union[BootMessage, RunMessage, ReplyMessage]
|
feat(code-runtime-python): add the fd-3 frame protocol
Introduce @deepseek-ai/dsh-code-runtime-python with the versionless
JSON-lines protocol between the Node host and the CPython subprocess:
the host-side hostile-frame codec (validateChildFrame, encodeJsonPlain,
checkDoneValue, hasUnsafeIntegerToken, hasNonLosslessNumber,
logTruncationMarker) and the Python-side wire-vocabulary mirror
(py/protocol.py).
This is the protocol layer of the code-runtime-python stack, split from
#436 and based on the multi-language seam extension. The PythonCodeRuntime
implementation and its Python JSON codec land in the backend-core PR on
top of this branch.
Ship the minimal buildable package skeleton (package.json, tsconfig,
tsdown, barrel index, invariant companion, bilingual README) because the
workspace-constraint, coverage, and invariant-topology gates require the
package to exist and build the moment its directory does; the backend-core
PR extends those files rather than creating them.
Align py/protocol.py with src/protocol.ts (the round-12 review of #436
found LogMessage.truncated, DoneMessage.error.kind, and Namespace.errorClass
stale) and guard the two runtime-executed surfaces (PROTOCOL_FD and the log
truncation marker) with a real-python3 cross-language mirror e2e test.
2026-07-31 18:51:03 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def log_truncation_marker(max_bytes: int) -> str:
|
|
|
|
|
"""Return the in-band marker for a log ledger that exhausted its budget.
|
|
|
|
|
|
|
|
|
|
Byte-identical text on both sides of the wire so a truncated run reads the
|
|
|
|
|
same however the cap was hit.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
return f"[dsh-code-runtime-python] log capture truncated at {max_bytes} bytes"
|