expose shell metadata in call responses

This commit is contained in:
lda
2026-08-30 03:05:58 +07:00 Verified
parent cf0ec7b403
commit 2587b07b4a
6 changed files with 90 additions and 6 deletions
+11 -1
View File
@@ -6,7 +6,15 @@ from .events import (
event_from_execution_result,
event_from_history_output,
)
from .models import CallError, CallEvent, CallEventKind, CallResponse, CallResult
from .models import (
CallError,
CallEvent,
CallEventKind,
CallResponse,
CallResult,
ShellInfo,
ShellStatus,
)
from .shell import (
Shell,
isolate_output_history,
@@ -26,6 +34,8 @@ __all__ = [
"Shell",
"event_from_history_output",
"generate_good_names",
"ShellInfo",
"ShellStatus",
"isolate_output_history",
"run_cell_and_collect",
"setup_shell",
+6 -1
View File
@@ -6,7 +6,7 @@ from uuid import uuid4
from wonderwords import RandomWord
from .models import CallResponse
from .models import CallResponse, ShellInfo
from .shell import Shell
@@ -50,6 +50,10 @@ class App:
self.last_shell = shell_name
return shell_name, self.shells[shell_name]
def list_shells(self) -> list[ShellInfo]:
"""Return frontend-safe metadata for all known shells."""
return [shell.describe() for shell in self.shells.values()]
def run_code(
self,
code: str,
@@ -68,6 +72,7 @@ class App:
collapsed=collapsed,
result=result,
events=events,
shell=shell.describe(),
)
+16
View File
@@ -12,6 +12,8 @@ CallEventKind = Literal[
"error",
]
ShellStatus = Literal["ready", "running", "error"]
@dataclass
class CallEvent:
@@ -55,3 +57,17 @@ class CallResponse:
collapsed: bool
result: CallResult
events: list[CallEvent]
shell: ShellInfo
@dataclass
class ShellInfo:
"""Frontend-safe snapshot describing one persistent shell."""
shell_id: str
name: str
status: ShellStatus
execution_count: int
created_at: str
last_used_at: str | None
capabilities: tuple[str, ...]
+43 -3
View File
@@ -1,4 +1,6 @@
from collections import defaultdict
from datetime import datetime, timezone
from uuid import uuid4
from IPython.core.interactiveshell import InteractiveShell
from IPython.core.pylabtools import (
@@ -14,7 +16,7 @@ from .events import (
event_from_execution_result,
event_from_history_output,
)
from .models import CallEvent, CallResult
from .models import CallEvent, CallResult, ShellInfo, ShellStatus
class Shell:
@@ -22,6 +24,11 @@ class Shell:
def __init__(self, name: str):
self.name = name
self.shell_id = uuid4().hex
self.created_at = datetime.now(timezone.utc).isoformat()
self.last_used_at: str | None = None
self.status: ShellStatus = "ready"
self._last_execution_count = 0
self._shell: InteractiveShell | None = None
@property
@@ -45,7 +52,40 @@ class Shell:
call_id: str,
) -> tuple[CallResult, list[CallEvent]]:
"""Execute one cell and return its result plus ordered output events."""
return run_cell_and_collect(self.init_shell(), code, call_id=call_id)
self.status = "running"
try:
call_result, events = run_cell_and_collect(
self.init_shell(),
code,
call_id=call_id,
)
except Exception:
self.status = "error"
raise
else:
self.status = "ready"
self.last_used_at = datetime.now(timezone.utc).isoformat()
self._last_execution_count = call_result.execution_count or 0
return call_result, events
def describe(self) -> ShellInfo:
"""Return metadata without initializing an unused shell."""
return ShellInfo(
shell_id=self.shell_id,
name=self.name,
status=self.status,
execution_count=self._last_execution_count,
created_at=self.created_at,
last_used_at=self.last_used_at,
capabilities=(
"stdout",
"stderr",
"display_data",
"execute_result",
"error",
"matplotlib-inline",
),
)
def isolate_output_history(shell: InteractiveShell) -> None:
@@ -76,7 +116,7 @@ def run_cell_and_collect(
execution = shell.run_cell(code, store_history=True)
records = tuple(
history_manager.outputs.get(execution.execution_count, ())
)
) if execution.execution_count is not None else ()
events = [
event_from_history_output(
record,