MCPcopy Create free account
hub / github.com/agentforce314/clawcodex / ToolContext

Class ToolContext

src/tool_system/context.py:67–376  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

65
66@dataclass
67class ToolContext:
68 workspace_root: Path
69 permission_context: ToolPermissionContext = field(
70 default_factory=lambda: ToolPermissionContext(mode="bypassPermissions")
71 )
72 cwd: Path | None = None
73 read_file_fingerprints: dict[Path, tuple[int, int] | tuple[int, int, bool]] = field(default_factory=dict)
74 task_manager: TaskManager = field(default_factory=TaskManager)
75 mcp_clients: dict[str, Any] = field(default_factory=dict)
76 lsp_client: Any | None = None
77 todos: list[dict[str, Any]] = field(default_factory=list)
78 tasks: dict[str, dict[str, Any]] = field(default_factory=dict)
79 # Chapter-10 / Chunk B / WI-1.3 — typed runtime-task registry. Houses
80 # ``LocalShellTaskState`` / ``LocalAgentTaskState`` / etc. as
81 # ``TaskStateBase`` subclasses. Replaces the un-typed
82 # ``background_bash_tasks`` and ``_internal=True`` agent entries that
83 # used to live on ``tasks``. ``runtime_tasks`` is the source of truth
84 # for the chapter-10 task state machine; ``tasks`` continues to host
85 # ``tasks_v2``/todo entries for the unrelated TaskCreate system.
86 runtime_tasks: RuntimeTaskRegistry = field(default_factory=RuntimeTaskRegistry)
87 # WI-5.1: per-message tool-result aggregate counter. The execution
88 # pipeline (Step 11) reads + increments this each time a tool result
89 # is mapped to its API form; when the running total exceeds
90 # ``MAX_TOOL_RESULTS_PER_MESSAGE_CHARS`` (default 200K) the next
91 # result is persisted to disk regardless of its individual size.
92 # Reset to 0 between messages by the turn-loop dispatcher.
93 #
94 # ``_aggregate_lock`` synchronizes the read-decide-write across
95 # concurrent tool dispatches (critic B6). The query loop's concurrent dispatch
96 # uses ``asyncio.to_thread`` to fan out concurrency-safe tools (Read,
97 # Grep, Glob) — without this lock, N threads would all read 0, all
98 # decide their block is under the cap, and the per-message budget
99 # would be silently bypassed. The full read+decide+write runs
100 # serialized so the persistence decision uses the LIVE counter and
101 # the cap is strictly enforced. Cost: the rare persist-to-disk path
102 # serializes against the lock, but persists are O(1) per turn in
103 # typical workloads (the common case under-threshold returns the
104 # block without I/O).
105 tool_result_chars_so_far: int = 0
106 _aggregate_lock: threading.Lock = field(default_factory=threading.Lock)
107 # Session-cumulative tokens spent on client-side advisor calls.
108 # ``src/tool_system/tools/advisor.py`` accumulates here on every
109 # consultation; the status surface reads them to display
110 # ``advisor: <in>/<out>`` next to the worker's
111 # token counts. Distinct from ``tool_result_chars_so_far`` (which
112 # is a per-message budget tied to API-result persistence) — these
113 # are per-session totals for UI display.
114 advisor_input_tokens: int = 0
115 advisor_output_tokens: int = 0
116 # Chapter-10 / Chunk F / WI-6.1 — agent-name registry. Maps the
117 # human-readable ``name`` (passed via Agent({name: "researcher"}))
118 # to the random ``agent_id`` returned by the spawn. SendMessage
119 # consults this registry first when resolving a ``to:`` field;
120 # falling back to "treat ``to`` as a raw agent_id" when the name
121 # isn't registered preserves the legacy code path.
122 #
123 # Per Chunk-F-Phase-6 critic concern C1 (Phase-7 fix): the registry
124 # is a typed ``AgentNameRegistry`` (not a bare dict) so the

Calls 1