induscode 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- induscode/__init__.py +56 -0
- induscode/addons/__init__.py +176 -0
- induscode/addons/contract.py +923 -0
- induscode/addons/dispatch/__init__.py +43 -0
- induscode/addons/dispatch/event_dispatcher.py +348 -0
- induscode/addons/dispatch/tool_interceptor.py +349 -0
- induscode/addons/host.py +469 -0
- induscode/addons/loader.py +314 -0
- induscode/addons/manifest.py +232 -0
- induscode/addons/surface.py +199 -0
- induscode/boot/__init__.py +108 -0
- induscode/boot/auth_vault.py +323 -0
- induscode/boot/boot.py +210 -0
- induscode/boot/contract.py +223 -0
- induscode/boot/invocation.py +117 -0
- induscode/boot/runners/__init__.py +42 -0
- induscode/boot/runners/link_runner.py +82 -0
- induscode/boot/runners/oneshot_runner.py +85 -0
- induscode/boot/runners/registry.py +46 -0
- induscode/boot/runners/repl_runner.py +340 -0
- induscode/boot/runners/session.py +549 -0
- induscode/boot/stages.py +198 -0
- induscode/boot/upgrade/__init__.py +36 -0
- induscode/boot/upgrade/apply.py +125 -0
- induscode/boot/upgrade/upgrades.py +136 -0
- induscode/briefing/__init__.py +115 -0
- induscode/briefing/compose.py +414 -0
- induscode/briefing/contract.py +528 -0
- induscode/briefing/macros.py +721 -0
- induscode/briefing/skills.py +417 -0
- induscode/capability_deck/__init__.py +233 -0
- induscode/capability_deck/bridge_ledger/__init__.py +66 -0
- induscode/capability_deck/bridge_ledger/key.py +181 -0
- induscode/capability_deck/bridge_ledger/ledger.py +276 -0
- induscode/capability_deck/bridge_ledger/network.py +336 -0
- induscode/capability_deck/builtin_bridge.py +358 -0
- induscode/capability_deck/cards/__init__.py +116 -0
- induscode/capability_deck/cards/bg_process.py +482 -0
- induscode/capability_deck/cards/memory.py +226 -0
- induscode/capability_deck/cards/saas.py +280 -0
- induscode/capability_deck/cards/task.py +256 -0
- induscode/capability_deck/cards/todo.py +312 -0
- induscode/capability_deck/contract.py +450 -0
- induscode/capability_deck/manifest.py +126 -0
- induscode/capability_deck/provision.py +217 -0
- induscode/channels/__init__.py +146 -0
- induscode/channels/contract.py +585 -0
- induscode/channels/framer.py +132 -0
- induscode/channels/link/__init__.py +50 -0
- induscode/channels/link/dialog.py +246 -0
- induscode/channels/link/driver.py +308 -0
- induscode/channels/link/server.py +217 -0
- induscode/channels/oneshot.py +178 -0
- induscode/channels/ops.py +140 -0
- induscode/channels/session_ops.py +172 -0
- induscode/conductor/__init__.py +240 -0
- induscode/conductor/catalog.py +309 -0
- induscode/conductor/conductor.py +1084 -0
- induscode/conductor/contract.py +1035 -0
- induscode/conductor/matcher.py +291 -0
- induscode/conductor/serialize.py +575 -0
- induscode/conductor/signal_hub.py +382 -0
- induscode/conductor/skill_parse.py +294 -0
- induscode/conductor/transcript_store.py +449 -0
- induscode/console/__init__.py +236 -0
- induscode/console/app.py +1677 -0
- induscode/console/components/__init__.py +62 -0
- induscode/console/components/banner.py +499 -0
- induscode/console/components/banner_sweep.py +188 -0
- induscode/console/components/emblem.py +181 -0
- induscode/console/components/status_bar.py +102 -0
- induscode/console/contract.py +836 -0
- induscode/console/input/__init__.py +107 -0
- induscode/console/input/chord.py +197 -0
- induscode/console/input/dir_reader.py +113 -0
- induscode/console/input/intents.py +258 -0
- induscode/console/input/providers.py +469 -0
- induscode/console/mount.py +137 -0
- induscode/console/overlays/__init__.py +94 -0
- induscode/console/overlays/auth.py +503 -0
- induscode/console/overlays/pickers.py +526 -0
- induscode/console/overlays/router.py +129 -0
- induscode/console/overlays/sessions.py +232 -0
- induscode/console/reducer.py +145 -0
- induscode/console/resume_picker.py +156 -0
- induscode/console/slash_commands/__init__.py +78 -0
- induscode/console/slash_commands/builtins.py +254 -0
- induscode/console/slash_commands/dynamic.py +217 -0
- induscode/console/slash_commands/integrations.py +949 -0
- induscode/console/slash_commands/transcript.py +404 -0
- induscode/console/slash_commands/workbench.py +430 -0
- induscode/console/startup.py +434 -0
- induscode/console/theme/__init__.py +44 -0
- induscode/console/theme/adapter.py +168 -0
- induscode/console/theme/palette.py +128 -0
- induscode/console/theme/resolve.py +123 -0
- induscode/console/theme/tokens.py +185 -0
- induscode/console_slash/__init__.py +111 -0
- induscode/console_slash/contract.py +185 -0
- induscode/console_slash/registry.py +140 -0
- induscode/console_slash/resolve.py +194 -0
- induscode/console_slash/shared.py +172 -0
- induscode/entry.py +108 -0
- induscode/insight/__init__.py +153 -0
- induscode/insight/collector.py +73 -0
- induscode/insight/replay.py +305 -0
- induscode/insight/wrapper.py +1115 -0
- induscode/kit/__init__.py +82 -0
- induscode/kit/clipboard_image.py +215 -0
- induscode/kit/external_editor.py +120 -0
- induscode/kit/image.py +188 -0
- induscode/kit/shell.py +89 -0
- induscode/kit/tool_fetch.py +288 -0
- induscode/launch/__init__.py +224 -0
- induscode/launch/catalog.py +310 -0
- induscode/launch/contract.py +569 -0
- induscode/launch/credentials.py +852 -0
- induscode/launch/invocation/__init__.py +39 -0
- induscode/launch/invocation/attachments.py +281 -0
- induscode/launch/invocation/flags.py +210 -0
- induscode/launch/invocation/read.py +369 -0
- induscode/launch/invocation/usage.py +110 -0
- induscode/launch/oauth.py +808 -0
- induscode/launch/packages.py +299 -0
- induscode/launch/pickers.py +291 -0
- induscode/py.typed +0 -0
- induscode/runtime_bridge/__init__.py +166 -0
- induscode/runtime_bridge/bridges/__init__.py +66 -0
- induscode/runtime_bridge/bridges/_drive.py +268 -0
- induscode/runtime_bridge/bridges/builtins.py +177 -0
- induscode/runtime_bridge/bridges/claude_cli.py +198 -0
- induscode/runtime_bridge/bridges/codex_cli.py +203 -0
- induscode/runtime_bridge/bridges/indusagi_cli.py +217 -0
- induscode/runtime_bridge/broker.py +397 -0
- induscode/runtime_bridge/contract.py +734 -0
- induscode/runtime_bridge/sink.py +351 -0
- induscode/sessions/__init__.py +25 -0
- induscode/sessions/contract.py +119 -0
- induscode/sessions/library.py +350 -0
- induscode/settings/__init__.py +47 -0
- induscode/settings/contract.py +313 -0
- induscode/settings/manager.py +268 -0
- induscode/transcript_export/__init__.py +109 -0
- induscode/transcript_export/contract.py +522 -0
- induscode/transcript_export/publish.py +455 -0
- induscode/transcript_export/sgr.py +566 -0
- induscode/transcript_export/template.py +319 -0
- induscode/transcript_export/theme_bridge.py +325 -0
- induscode/window_budget/__init__.py +76 -0
- induscode/window_budget/budget/__init__.py +26 -0
- induscode/window_budget/budget/estimate.py +273 -0
- induscode/window_budget/budget/gate.py +60 -0
- induscode/window_budget/budget/slice.py +145 -0
- induscode/window_budget/condenser.py +170 -0
- induscode/window_budget/contract.py +329 -0
- induscode/window_budget/summarize/__init__.py +33 -0
- induscode/window_budget/summarize/condense.py +212 -0
- induscode/window_budget/summarize/prompt.py +241 -0
- induscode/workspace/__init__.py +30 -0
- induscode/workspace/brand.py +96 -0
- induscode/workspace/locator.py +269 -0
- induscode-0.1.0.dist-info/METADATA +97 -0
- induscode-0.1.0.dist-info/RECORD +167 -0
- induscode-0.1.0.dist-info/WHEEL +4 -0
- induscode-0.1.0.dist-info/entry_points.txt +3 -0
- induscode-0.1.0.dist-info/licenses/CREDITS.md +22 -0
- induscode-0.1.0.dist-info/licenses/NOTICE +7 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""Operation registry — the single declarative source both halves of the link
|
|
2
|
+
consume (port of TS ``src/channels/ops.ts``).
|
|
3
|
+
|
|
4
|
+
The contract defines :func:`~induscode.channels.contract.define_ops` (freeze a
|
|
5
|
+
record of :class:`~induscode.channels.contract.Op` declarations into an
|
|
6
|
+
:data:`~induscode.channels.contract.OpRegistry`). This module adds the runtime
|
|
7
|
+
face the server needs and the driver leans on: a built registry carries its
|
|
8
|
+
``methods`` list (so a link client can be generated by walking the keys, never
|
|
9
|
+
hand-written) and a ``dispatch`` seam that looks an op up by ``method`` and
|
|
10
|
+
runs its ``handle`` — the data-driven replacement for a copied command switch.
|
|
11
|
+
|
|
12
|
+
Nothing here knows about transport or framing: dispatch takes the already
|
|
13
|
+
parsed ``method``/``params`` and the shared
|
|
14
|
+
:class:`~induscode.channels.contract.ChannelContext`, runs the op, and returns
|
|
15
|
+
its resolved result (or raises :class:`UnknownOpError` when no op is
|
|
16
|
+
registered). The server frames the outcome into a reply; the driver uses
|
|
17
|
+
``methods`` to build its thunks. One frozen registry drives both.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from collections.abc import Mapping
|
|
23
|
+
from dataclasses import dataclass, field
|
|
24
|
+
from typing import Any, Callable, Coroutine
|
|
25
|
+
|
|
26
|
+
from induscode.channels.contract import (
|
|
27
|
+
OP_ERROR,
|
|
28
|
+
ChannelContext,
|
|
29
|
+
Op,
|
|
30
|
+
OpRegistry,
|
|
31
|
+
define_ops,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"OpRegistryHandle",
|
|
36
|
+
"UnknownOpError",
|
|
37
|
+
"build_ops",
|
|
38
|
+
"define_ops",
|
|
39
|
+
"dispatch",
|
|
40
|
+
"has_op",
|
|
41
|
+
"methods_of",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class UnknownOpError(Exception):
|
|
46
|
+
"""Raised by :func:`dispatch` (and :meth:`OpRegistryHandle.dispatch`) when
|
|
47
|
+
the requested ``method`` has no registered :class:`Op`.
|
|
48
|
+
|
|
49
|
+
Carries the frozen ``OP_ERROR["unknownOp"]`` code so the server can frame
|
|
50
|
+
it into an error reply without re-deriving the category, and records the
|
|
51
|
+
offending ``method`` for logging.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, method: str) -> None:
|
|
55
|
+
super().__init__(f"Unknown op: {method}")
|
|
56
|
+
#: The JSON-RPC error category for an unregistered method.
|
|
57
|
+
self.code: int = OP_ERROR["unknownOp"]
|
|
58
|
+
#: The method name that resolved to no operation.
|
|
59
|
+
self.method: str = method
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
async def dispatch(
|
|
63
|
+
registry: OpRegistry,
|
|
64
|
+
method: str,
|
|
65
|
+
params: Any,
|
|
66
|
+
ctx: ChannelContext,
|
|
67
|
+
) -> Any:
|
|
68
|
+
"""Run one operation by name against the shared context.
|
|
69
|
+
|
|
70
|
+
Looks ``method`` up in ``registry``, then awaits its
|
|
71
|
+
``handle(params, ctx)``. The lone dispatch path for the server: there is
|
|
72
|
+
no per-method branch, only a map lookup. Raises :class:`UnknownOpError`
|
|
73
|
+
when the method is not registered and propagates whatever the handler
|
|
74
|
+
raises (the server maps that to an error reply).
|
|
75
|
+
|
|
76
|
+
:param registry: the frozen :data:`OpRegistry` to dispatch within
|
|
77
|
+
:param method: the wire method name to invoke
|
|
78
|
+
:param params: the already-parsed request payload (passed through verbatim)
|
|
79
|
+
:param ctx: the shared :class:`ChannelContext`
|
|
80
|
+
:returns: the operation result
|
|
81
|
+
"""
|
|
82
|
+
op = registry.get(method)
|
|
83
|
+
if op is None:
|
|
84
|
+
raise UnknownOpError(method)
|
|
85
|
+
return await op.handle(params, ctx)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def has_op(registry: OpRegistry, method: str) -> bool:
|
|
89
|
+
"""Whether ``method`` resolves to a registered :class:`Op` in ``registry``."""
|
|
90
|
+
return method in registry
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def methods_of(registry: OpRegistry) -> tuple[str, ...]:
|
|
94
|
+
"""The sorted wire method names a registry exposes — the driver's method
|
|
95
|
+
set."""
|
|
96
|
+
return tuple(sorted(registry.keys()))
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass(frozen=True, slots=True)
|
|
100
|
+
class OpRegistryHandle:
|
|
101
|
+
"""A built registry plus its runtime face: the method list and a bound
|
|
102
|
+
``dispatch``.
|
|
103
|
+
|
|
104
|
+
``methods`` is what a generated link client walks to build its thunks;
|
|
105
|
+
``dispatch`` is what the server calls per request. Both are bound to the
|
|
106
|
+
one frozen ``registry``, so the server-side dispatch and the client-side
|
|
107
|
+
method set can never drift from each other.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
#: The frozen registry — the single source of truth.
|
|
111
|
+
registry: OpRegistry
|
|
112
|
+
#: The sorted method names this registry exposes.
|
|
113
|
+
methods: tuple[str, ...]
|
|
114
|
+
#: Invoke an op by name against a context; see :func:`dispatch`.
|
|
115
|
+
dispatch: Callable[[str, Any, ChannelContext], Coroutine[Any, Any, Any]] = field(repr=False)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def build_ops(ops: Mapping[str, Op]) -> OpRegistryHandle:
|
|
119
|
+
"""Build an :class:`OpRegistryHandle` from a record of operation
|
|
120
|
+
declarations.
|
|
121
|
+
|
|
122
|
+
Freezes the input with :func:`define_ops`, then bundles it with its
|
|
123
|
+
derived method list and a ``dispatch`` bound to that frozen registry. This
|
|
124
|
+
is the lone sanctioned way to produce the object the server and the driver
|
|
125
|
+
both consume, so the dispatch map and the driver method set always derive
|
|
126
|
+
from one source.
|
|
127
|
+
|
|
128
|
+
:param ops: a record of method-name → :class:`Op`
|
|
129
|
+
:returns: the frozen registry handle
|
|
130
|
+
"""
|
|
131
|
+
registry = define_ops(ops)
|
|
132
|
+
|
|
133
|
+
async def bound_dispatch(method: str, params: Any, ctx: ChannelContext) -> Any:
|
|
134
|
+
return await dispatch(registry, method, params, ctx)
|
|
135
|
+
|
|
136
|
+
return OpRegistryHandle(
|
|
137
|
+
registry=registry,
|
|
138
|
+
methods=methods_of(registry),
|
|
139
|
+
dispatch=bound_dispatch,
|
|
140
|
+
)
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""Session ops — the concrete operation registry that drives the link
|
|
2
|
+
(port of TS ``src/channels/session-ops.ts``).
|
|
3
|
+
|
|
4
|
+
This is the single declarative source of every operation the link server
|
|
5
|
+
dispatches and the generated link client is built from. Each op binds a wire
|
|
6
|
+
``method`` name to a ``handle`` that delegates to the
|
|
7
|
+
:class:`~induscode.conductor.contract.SessionConductor` carried on the
|
|
8
|
+
:class:`~induscode.channels.contract.ChannelContext`; there is no per-method
|
|
9
|
+
dispatch ladder and no hand-written parallel client method. Adding a row here
|
|
10
|
+
adds both a server-handled method and a callable driver method.
|
|
11
|
+
|
|
12
|
+
The ops also own the :data:`~induscode.channels.contract.LinkSnapshot`
|
|
13
|
+
projection: the conductor exposes its internal
|
|
14
|
+
:class:`~induscode.conductor.contract.ConductorState`, and
|
|
15
|
+
:func:`project_snapshot` reshapes that into the flat, serializable wire
|
|
16
|
+
vocabulary a remote driver mirrors without holding a live conductor.
|
|
17
|
+
|
|
18
|
+
Port notes
|
|
19
|
+
----------
|
|
20
|
+
- Wire method names (``submit`` / ``abort`` / ``snapshot`` / ``resume`` /
|
|
21
|
+
``listModels`` / ``cycleModel``) and the snapshot field names/casing are
|
|
22
|
+
kept **verbatim** from TS for cross-host compatibility.
|
|
23
|
+
- TS param interfaces (``SubmitParams`` etc.) typed the registry statically;
|
|
24
|
+
the Python handlers index the decoded wire dict directly
|
|
25
|
+
(``params["input"]``, ``params["sessionId"]``, ``params["modelId"]``).
|
|
26
|
+
- TS ``ctx.conductor.cycleModel?.(…)`` (optional method) becomes a ``getattr``
|
|
27
|
+
probe for the Python conductor's ``cycle_model`` — same as the conductor
|
|
28
|
+
contract's own port note for optional members.
|
|
29
|
+
- ``usage`` rides the snapshot through the one app-wide codec
|
|
30
|
+
(:func:`~induscode.conductor.serialize.message_to_dict`, plan rule 2).
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
from typing import Any
|
|
36
|
+
|
|
37
|
+
from induscode.channels.contract import (
|
|
38
|
+
ChannelContext,
|
|
39
|
+
ConductorState,
|
|
40
|
+
LinkSnapshot,
|
|
41
|
+
Op,
|
|
42
|
+
OpRegistry,
|
|
43
|
+
ThinkingLevel,
|
|
44
|
+
define_ops,
|
|
45
|
+
)
|
|
46
|
+
from induscode.conductor.serialize import message_to_dict
|
|
47
|
+
|
|
48
|
+
__all__ = [
|
|
49
|
+
"DEFAULT_THINKING",
|
|
50
|
+
"SESSION_OPS",
|
|
51
|
+
"project_snapshot",
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
#: The reasoning effort reported when a snapshot carries none of its own.
|
|
55
|
+
DEFAULT_THINKING: ThinkingLevel = "off"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# ---------------------------------------------------------------------------
|
|
59
|
+
# Snapshot projection
|
|
60
|
+
# ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def project_snapshot(
|
|
64
|
+
state: ConductorState,
|
|
65
|
+
*,
|
|
66
|
+
thinking: ThinkingLevel | None = None,
|
|
67
|
+
sessionFile: str | None = None,
|
|
68
|
+
autoCondense: bool | None = None,
|
|
69
|
+
messageCount: int | None = None,
|
|
70
|
+
queuedCount: int | None = None,
|
|
71
|
+
) -> LinkSnapshot:
|
|
72
|
+
"""Project a conductor :class:`ConductorState` onto the wire
|
|
73
|
+
:data:`LinkSnapshot`.
|
|
74
|
+
|
|
75
|
+
The snapshot is the link vocabulary: flat, serializable, and derived from
|
|
76
|
+
— not a passthrough of — the conductor state. Busy flags are read off the
|
|
77
|
+
coarse phase, the model and session identity off the state and its head,
|
|
78
|
+
and the cumulative usage carried straight through (as its codec dict).
|
|
79
|
+
Field names/casing are the verbatim TS wire vocabulary; ``sessionFile`` is
|
|
80
|
+
omitted (not nulled) when absent, exactly as ``JSON.stringify`` dropped
|
|
81
|
+
the undefined TS field.
|
|
82
|
+
|
|
83
|
+
:param state: the immutable conductor state
|
|
84
|
+
:param thinking: reasoning effort the conductor does not surface on state
|
|
85
|
+
:param sessionFile: on-disk transcript file backing the session
|
|
86
|
+
:param autoCondense: whether auto-condense is engaged (default ``True``)
|
|
87
|
+
:param messageCount: nodes on the active transcript branch (default 0)
|
|
88
|
+
:param queuedCount: inputs queued behind the in-flight turn (default 0)
|
|
89
|
+
"""
|
|
90
|
+
snapshot: LinkSnapshot = {
|
|
91
|
+
"model": state.modelId,
|
|
92
|
+
"thinking": thinking if thinking is not None else DEFAULT_THINKING,
|
|
93
|
+
"streaming": state.phase == "streaming" or state.phase == "tooling",
|
|
94
|
+
"condensing": state.phase == "condensing",
|
|
95
|
+
"faulted": state.phase == "faulted",
|
|
96
|
+
"sessionId": state.head.sessionId,
|
|
97
|
+
"autoCondense": autoCondense if autoCondense is not None else True,
|
|
98
|
+
"messageCount": messageCount if messageCount is not None else 0,
|
|
99
|
+
"queuedCount": queuedCount if queuedCount is not None else 0,
|
|
100
|
+
"usage": message_to_dict(state.usage),
|
|
101
|
+
}
|
|
102
|
+
if sessionFile is not None:
|
|
103
|
+
snapshot["sessionFile"] = sessionFile
|
|
104
|
+
return snapshot
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# ---------------------------------------------------------------------------
|
|
108
|
+
# The op set
|
|
109
|
+
# ---------------------------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
async def _submit(params: Any, ctx: ChannelContext) -> LinkSnapshot:
|
|
113
|
+
"""Run a user turn to settlement and reply with a snapshot."""
|
|
114
|
+
state = await ctx.conductor.submit(params["input"])
|
|
115
|
+
return project_snapshot(state)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
async def _abort(params: Any, ctx: ChannelContext) -> LinkSnapshot:
|
|
119
|
+
"""Cancel the in-flight turn and reply with a snapshot."""
|
|
120
|
+
ctx.conductor.abort()
|
|
121
|
+
return project_snapshot(ctx.conductor.snapshot())
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
async def _snapshot(params: Any, ctx: ChannelContext) -> LinkSnapshot:
|
|
125
|
+
"""Read the current state, projected to a :data:`LinkSnapshot`."""
|
|
126
|
+
return project_snapshot(ctx.conductor.snapshot())
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
async def _resume(params: Any, ctx: ChannelContext) -> LinkSnapshot:
|
|
130
|
+
"""Restore a persisted session and reply with a snapshot."""
|
|
131
|
+
await ctx.conductor.resume(params["sessionId"])
|
|
132
|
+
return project_snapshot(ctx.conductor.snapshot())
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
async def _list_models(params: Any, ctx: ChannelContext) -> list[dict[str, Any]]:
|
|
136
|
+
"""List the model bound to the session (the active entry). Each row is the
|
|
137
|
+
wire ``ModelEntry`` shape ``{"id", "active"}``."""
|
|
138
|
+
active = ctx.conductor.snapshot().modelId
|
|
139
|
+
return [{"id": active, "active": True}]
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
async def _cycle_model(params: Any, ctx: ChannelContext) -> LinkSnapshot:
|
|
143
|
+
"""Rotate the active model and reply with a snapshot. Probes for the
|
|
144
|
+
conductor's optional ``cycle_model`` (TS ``cycleModel?.()``)."""
|
|
145
|
+
cycle = getattr(ctx.conductor, "cycle_model", None)
|
|
146
|
+
if callable(cycle):
|
|
147
|
+
cycle(params["modelId"])
|
|
148
|
+
return project_snapshot(ctx.conductor.snapshot())
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
#: The frozen link op set: every operation a driver can invoke, each
|
|
152
|
+
#: delegating to the conductor on the context.
|
|
153
|
+
#:
|
|
154
|
+
#: - ``submit`` — run a user turn to settlement and reply with a snapshot.
|
|
155
|
+
#: - ``abort`` — cancel the in-flight turn and reply with a snapshot.
|
|
156
|
+
#: - ``snapshot`` — read the current state, projected to a snapshot.
|
|
157
|
+
#: - ``resume`` — restore a persisted session and reply with a snapshot.
|
|
158
|
+
#: - ``listModels`` — list the model bound to the session (the active entry).
|
|
159
|
+
#: - ``cycleModel`` — rotate the active model and reply with a snapshot.
|
|
160
|
+
#:
|
|
161
|
+
#: The map is consumed verbatim by the server (data-driven dispatch) and by
|
|
162
|
+
#: the generated link client (its method set is exactly these keys).
|
|
163
|
+
SESSION_OPS: OpRegistry = define_ops(
|
|
164
|
+
{
|
|
165
|
+
"submit": Op(method="submit", handle=_submit),
|
|
166
|
+
"abort": Op(method="abort", handle=_abort),
|
|
167
|
+
"snapshot": Op(method="snapshot", handle=_snapshot),
|
|
168
|
+
"resume": Op(method="resume", handle=_resume),
|
|
169
|
+
"listModels": Op(method="listModels", handle=_list_models),
|
|
170
|
+
"cycleModel": Op(method="cycleModel", handle=_cycle_model),
|
|
171
|
+
}
|
|
172
|
+
)
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"""Conductor — the product-level session orchestration layer (public barrel).
|
|
2
|
+
|
|
3
|
+
The framework ``Agent`` (:mod:`indusagi.agent`) is a raw LLM conversation
|
|
4
|
+
loop; the conductor wraps exactly one such agent and turns it into a
|
|
5
|
+
*coding-agent session*: a stable product signal stream
|
|
6
|
+
(:data:`SessionSignal`), typed faults (:class:`ConductorFault`), an
|
|
7
|
+
immutable state snapshot (:class:`ConductorState`) maintained by the pure
|
|
8
|
+
:func:`reduce_state` reducer, a branchable on-disk transcript vocabulary
|
|
9
|
+
(:class:`TranscriptEntry` / :class:`SessionHead` /
|
|
10
|
+
:data:`TRANSCRIPT_SCHEMA`), and the :class:`SessionConductor` Protocol the
|
|
11
|
+
interactive console, oneshot/print mode, and JSON-RPC link all drive.
|
|
12
|
+
|
|
13
|
+
M2 wave-1 surface (this barrel today):
|
|
14
|
+
|
|
15
|
+
- :mod:`.contract` — the FROZEN type seam: signals, faults, transcript
|
|
16
|
+
schema, catalog refs/queries, state + reducer, queue/stats/bash shapes,
|
|
17
|
+
and the :class:`SessionConductor` / :class:`AgentLike` /
|
|
18
|
+
:class:`CondenseFn` / :class:`RetryPolicy` seams.
|
|
19
|
+
- :mod:`.signal_hub` — the :class:`SignalHub` fan-out bus plus the
|
|
20
|
+
framework-event → product-signal projector
|
|
21
|
+
(:func:`translate_agent_event` / :data:`TRANSLATOR_TABLE`).
|
|
22
|
+
- :mod:`.skill_parse` — the re-derived ``<skill …>body</skill>`` block
|
|
23
|
+
scanner (:func:`parse_skill_invocation`).
|
|
24
|
+
- :mod:`.catalog` / :mod:`.matcher` — the normalized model catalog over the
|
|
25
|
+
framework registry and the scored-candidate matcher
|
|
26
|
+
(:class:`ModelCatalog` / :class:`ModelMatcher` / :func:`canonical_id` /
|
|
27
|
+
:func:`to_card_ref`).
|
|
28
|
+
- :mod:`.transcript_store` / :mod:`.serialize` — the branchable transcript
|
|
29
|
+
tree store, NDJSON envelope + the one app-wide message⇄dict codec, and the
|
|
30
|
+
legacy framework-session import (:class:`TranscriptStore` /
|
|
31
|
+
:func:`memory_backend` / :func:`fs_backend` / :func:`replay` /
|
|
32
|
+
:func:`message_to_dict` / :func:`message_from_dict`).
|
|
33
|
+
|
|
34
|
+
M2 wave-2 surface (landed):
|
|
35
|
+
|
|
36
|
+
- :mod:`.conductor` — the :class:`SessionConductorImpl` turn loop +
|
|
37
|
+
:func:`create_session_conductor` factory (queue drain, transient-fault
|
|
38
|
+
retry with injectable sleep, per-message persist tail, condense seam,
|
|
39
|
+
fork/navigate, ``execute_bash`` on asyncio subprocess, thinking ladder,
|
|
40
|
+
:func:`noop_condense`, :class:`ConductorDeps`, :data:`DEFAULT_RETRY`, and
|
|
41
|
+
the lazy live-agent assembly :class:`LazyAgent`).
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
from __future__ import annotations
|
|
45
|
+
|
|
46
|
+
from .contract import (
|
|
47
|
+
FAULT_KINDS,
|
|
48
|
+
QUEUE_MODES,
|
|
49
|
+
SIGNAL_KINDS,
|
|
50
|
+
TRANSCRIPT_ROLES,
|
|
51
|
+
TRANSCRIPT_SCHEMA,
|
|
52
|
+
AgentLike,
|
|
53
|
+
AgentMessage,
|
|
54
|
+
AgentStateLike,
|
|
55
|
+
AgentTool,
|
|
56
|
+
BashOutcome,
|
|
57
|
+
CompactedSignal,
|
|
58
|
+
CondenseFn,
|
|
59
|
+
ConductorFault,
|
|
60
|
+
ConductorPhase,
|
|
61
|
+
ConductorState,
|
|
62
|
+
ExecuteBashOptions,
|
|
63
|
+
FaultAction,
|
|
64
|
+
FaultKind,
|
|
65
|
+
FaultSignal,
|
|
66
|
+
HeadAction,
|
|
67
|
+
IdleSignal,
|
|
68
|
+
KnownProvider,
|
|
69
|
+
MatchQuery,
|
|
70
|
+
Model,
|
|
71
|
+
ModelAction,
|
|
72
|
+
ModelCardRef,
|
|
73
|
+
PersistedSignal,
|
|
74
|
+
PhaseAction,
|
|
75
|
+
PromptSignal,
|
|
76
|
+
QueuedInput,
|
|
77
|
+
QueueMode,
|
|
78
|
+
QueueSignal,
|
|
79
|
+
RetryPolicy,
|
|
80
|
+
SessionConductor,
|
|
81
|
+
SessionConductorOptions,
|
|
82
|
+
SessionHead,
|
|
83
|
+
SessionSignal,
|
|
84
|
+
SessionStats,
|
|
85
|
+
SettledAction,
|
|
86
|
+
SignalHandler,
|
|
87
|
+
SignalKind,
|
|
88
|
+
StateAction,
|
|
89
|
+
TextSignal,
|
|
90
|
+
ThinkingLevel,
|
|
91
|
+
ThinkingSignal,
|
|
92
|
+
TokenTally,
|
|
93
|
+
ToolEndSignal,
|
|
94
|
+
ToolStartSignal,
|
|
95
|
+
TranscriptEntry,
|
|
96
|
+
TranscriptRole,
|
|
97
|
+
TranscriptSchema,
|
|
98
|
+
TurnEndSignal,
|
|
99
|
+
Usage,
|
|
100
|
+
UsageAction,
|
|
101
|
+
conductor_fault,
|
|
102
|
+
reduce_state,
|
|
103
|
+
)
|
|
104
|
+
from .catalog import (
|
|
105
|
+
CatalogCard,
|
|
106
|
+
CatalogSource,
|
|
107
|
+
ModelCatalog,
|
|
108
|
+
canonical_id,
|
|
109
|
+
to_card_ref,
|
|
110
|
+
)
|
|
111
|
+
from .conductor import (
|
|
112
|
+
DEFAULT_RETRY,
|
|
113
|
+
ConductorDeps,
|
|
114
|
+
LazyAgent,
|
|
115
|
+
SessionConductorImpl,
|
|
116
|
+
create_session_conductor,
|
|
117
|
+
noop_condense,
|
|
118
|
+
)
|
|
119
|
+
from .matcher import ModelMatcher, ResolveInput
|
|
120
|
+
from .serialize import (
|
|
121
|
+
ParsedSessionFile,
|
|
122
|
+
branch_to_llm_messages,
|
|
123
|
+
branch_to_messages,
|
|
124
|
+
encode_entry,
|
|
125
|
+
encode_head,
|
|
126
|
+
import_legacy_file,
|
|
127
|
+
import_legacy_text,
|
|
128
|
+
message_from_dict,
|
|
129
|
+
message_to_dict,
|
|
130
|
+
parse_session_text,
|
|
131
|
+
resolve_legacy_messages,
|
|
132
|
+
role_for_message,
|
|
133
|
+
)
|
|
134
|
+
from .signal_hub import TRANSLATOR_TABLE, SignalHub, translate_agent_event
|
|
135
|
+
from .skill_parse import SkillInvocation, parse_skill_invocation
|
|
136
|
+
from .transcript_store import (
|
|
137
|
+
TranscriptBackend,
|
|
138
|
+
TranscriptClock,
|
|
139
|
+
TranscriptState,
|
|
140
|
+
TranscriptStore,
|
|
141
|
+
fs_backend,
|
|
142
|
+
memory_backend,
|
|
143
|
+
replay,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
__all__ = [
|
|
147
|
+
"AgentLike",
|
|
148
|
+
"AgentMessage",
|
|
149
|
+
"AgentStateLike",
|
|
150
|
+
"AgentTool",
|
|
151
|
+
"BashOutcome",
|
|
152
|
+
"CatalogCard",
|
|
153
|
+
"CatalogSource",
|
|
154
|
+
"CompactedSignal",
|
|
155
|
+
"CondenseFn",
|
|
156
|
+
"ConductorDeps",
|
|
157
|
+
"ConductorFault",
|
|
158
|
+
"ConductorPhase",
|
|
159
|
+
"ConductorState",
|
|
160
|
+
"DEFAULT_RETRY",
|
|
161
|
+
"ExecuteBashOptions",
|
|
162
|
+
"FAULT_KINDS",
|
|
163
|
+
"FaultAction",
|
|
164
|
+
"FaultKind",
|
|
165
|
+
"FaultSignal",
|
|
166
|
+
"HeadAction",
|
|
167
|
+
"IdleSignal",
|
|
168
|
+
"KnownProvider",
|
|
169
|
+
"LazyAgent",
|
|
170
|
+
"MatchQuery",
|
|
171
|
+
"Model",
|
|
172
|
+
"ModelAction",
|
|
173
|
+
"ModelCardRef",
|
|
174
|
+
"ModelCatalog",
|
|
175
|
+
"ModelMatcher",
|
|
176
|
+
"ParsedSessionFile",
|
|
177
|
+
"PersistedSignal",
|
|
178
|
+
"PhaseAction",
|
|
179
|
+
"PromptSignal",
|
|
180
|
+
"QUEUE_MODES",
|
|
181
|
+
"QueueMode",
|
|
182
|
+
"QueueSignal",
|
|
183
|
+
"QueuedInput",
|
|
184
|
+
"ResolveInput",
|
|
185
|
+
"RetryPolicy",
|
|
186
|
+
"SIGNAL_KINDS",
|
|
187
|
+
"SessionConductor",
|
|
188
|
+
"SessionConductorImpl",
|
|
189
|
+
"SessionConductorOptions",
|
|
190
|
+
"SessionHead",
|
|
191
|
+
"SessionSignal",
|
|
192
|
+
"SessionStats",
|
|
193
|
+
"SettledAction",
|
|
194
|
+
"SignalHandler",
|
|
195
|
+
"SignalHub",
|
|
196
|
+
"SignalKind",
|
|
197
|
+
"SkillInvocation",
|
|
198
|
+
"StateAction",
|
|
199
|
+
"TRANSCRIPT_ROLES",
|
|
200
|
+
"TRANSCRIPT_SCHEMA",
|
|
201
|
+
"TRANSLATOR_TABLE",
|
|
202
|
+
"TextSignal",
|
|
203
|
+
"ThinkingLevel",
|
|
204
|
+
"ThinkingSignal",
|
|
205
|
+
"TokenTally",
|
|
206
|
+
"ToolEndSignal",
|
|
207
|
+
"ToolStartSignal",
|
|
208
|
+
"TranscriptBackend",
|
|
209
|
+
"TranscriptClock",
|
|
210
|
+
"TranscriptEntry",
|
|
211
|
+
"TranscriptRole",
|
|
212
|
+
"TranscriptSchema",
|
|
213
|
+
"TranscriptState",
|
|
214
|
+
"TranscriptStore",
|
|
215
|
+
"TurnEndSignal",
|
|
216
|
+
"Usage",
|
|
217
|
+
"UsageAction",
|
|
218
|
+
"branch_to_llm_messages",
|
|
219
|
+
"branch_to_messages",
|
|
220
|
+
"canonical_id",
|
|
221
|
+
"conductor_fault",
|
|
222
|
+
"create_session_conductor",
|
|
223
|
+
"encode_entry",
|
|
224
|
+
"encode_head",
|
|
225
|
+
"fs_backend",
|
|
226
|
+
"import_legacy_file",
|
|
227
|
+
"import_legacy_text",
|
|
228
|
+
"memory_backend",
|
|
229
|
+
"message_from_dict",
|
|
230
|
+
"message_to_dict",
|
|
231
|
+
"noop_condense",
|
|
232
|
+
"parse_session_text",
|
|
233
|
+
"parse_skill_invocation",
|
|
234
|
+
"reduce_state",
|
|
235
|
+
"replay",
|
|
236
|
+
"resolve_legacy_messages",
|
|
237
|
+
"role_for_message",
|
|
238
|
+
"to_card_ref",
|
|
239
|
+
"translate_agent_event",
|
|
240
|
+
]
|