| 107 | return selected[:limit] |
| 108 | |
| 109 | def bootstrap_session(self, prompt: str, limit: int = 5) -> RuntimeSession: |
| 110 | context = build_port_context() |
| 111 | setup_report = run_setup(trusted=True) |
| 112 | setup = setup_report.setup |
| 113 | history = HistoryLog() |
| 114 | engine = QueryEnginePort.from_workspace() |
| 115 | history.add('context', f'python_files={context.python_file_count}, archive_available={context.archive_available}') |
| 116 | history.add('registry', f'commands={len(PORTED_COMMANDS)}, tools={len(PORTED_TOOLS)}') |
| 117 | matches = self.route_prompt(prompt, limit=limit) |
| 118 | registry = build_execution_registry() |
| 119 | command_execs = tuple(registry.command(match.name).execute(prompt) for match in matches if match.kind == 'command' and registry.command(match.name)) |
| 120 | tool_execs = tuple(registry.tool(match.name).execute(prompt) for match in matches if match.kind == 'tool' and registry.tool(match.name)) |
| 121 | denials = tuple(self._infer_permission_denials(matches)) |
| 122 | stream_events = tuple(engine.stream_submit_message( |
| 123 | prompt, |
| 124 | matched_commands=tuple(match.name for match in matches if match.kind == 'command'), |
| 125 | matched_tools=tuple(match.name for match in matches if match.kind == 'tool'), |
| 126 | denied_tools=denials, |
| 127 | )) |
| 128 | turn_result = engine.submit_message( |
| 129 | prompt, |
| 130 | matched_commands=tuple(match.name for match in matches if match.kind == 'command'), |
| 131 | matched_tools=tuple(match.name for match in matches if match.kind == 'tool'), |
| 132 | denied_tools=denials, |
| 133 | ) |
| 134 | persisted_session_path = engine.persist_session() |
| 135 | history.add('routing', f'matches={len(matches)} for prompt={prompt!r}') |
| 136 | history.add('execution', f'command_execs={len(command_execs)} tool_execs={len(tool_execs)}') |
| 137 | history.add('turn', f'commands={len(turn_result.matched_commands)} tools={len(turn_result.matched_tools)} denials={len(turn_result.permission_denials)} stop={turn_result.stop_reason}') |
| 138 | history.add('session_store', persisted_session_path) |
| 139 | return RuntimeSession( |
| 140 | prompt=prompt, |
| 141 | context=context, |
| 142 | setup=setup, |
| 143 | setup_report=setup_report, |
| 144 | system_init_message=build_system_init_message(trusted=True), |
| 145 | history=history, |
| 146 | routed_matches=matches, |
| 147 | turn_result=turn_result, |
| 148 | command_execution_messages=command_execs, |
| 149 | tool_execution_messages=tool_execs, |
| 150 | stream_events=stream_events, |
| 151 | persisted_session_path=persisted_session_path, |
| 152 | ) |
| 153 | |
| 154 | def run_turn_loop(self, prompt: str, limit: int = 5, max_turns: int = 3, structured_output: bool = False) -> list[TurnResult]: |
| 155 | engine = QueryEnginePort.from_workspace() |