Repository navigation
Refactor/scenario provider #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,9 +2,13 @@ | |
|
|
||
| import argparse | ||
| import asyncio | ||
| from pyexpat.errors import messages | ||
|
|
||
| from httpx import stream | ||
|
|
||
| from mitocode.backend.agent.agent_orchestrator import AgentOrchestrator | ||
| from mitocode.backend.chat_provider.scenario_provider import ScenarioProvider | ||
| from mitocode.backend.chat_provider.chat_provider_openai import ChatProviderOpenAI | ||
| from mitocode.backend.tool.tool_manager import ToolManager | ||
| from mitocode.tui.ui_main import VibeFrontend | ||
|
|
||
|
|
@@ -65,7 +69,28 @@ def main(): | |
| tool_manager = ToolManager() | ||
| _register_tools(tool_manager) | ||
|
|
||
| provider = ScenarioProvider(delay=args.speed) | ||
| provider = asyncio.run(ChatProviderOpenAI.factory( | ||
| default_model= "nvidia/nemotron-3.5-lightning:free", | ||
| default_model_list= None, | ||
|
Comment on lines
+72
to
+74
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1. Cli requires live model discovery The CLI now constructs ChatProviderOpenAI with no fallback model list, whose factory performs a live model-list request and raises when that request fails. A network outage, unreachable OpenRouter endpoint, or authentication failure therefore prevents the TUI from launching instead of retaining the previous offline scenario behavior. Agent Prompt
|
||
| default_messages= None, | ||
| default_tools= None, | ||
| stream= True, | ||
| settings={ | ||
| "api_key": "sk-别看了这次我不会再把key提交到仓库了!", | ||
| "base_url": "https://openrouter.ai/api/v1", | ||
| "timeout": 60, | ||
| }) | ||
| ) | ||
|
|
||
| # print(asyncio.run(provider.chat( | ||
| # model ="nvidia/nemotron-3.5-lightning:free", | ||
| # tools =None, | ||
| # messages = [ | ||
| # {"role": "system", "content": "You are a helpful assistant."}, | ||
| # {"role": "user", "content": "Hello!"} | ||
| # ], | ||
| # stream = False | ||
| # ))) | ||
|
|
||
| orchestrator = AgentOrchestrator( | ||
| tool_manager=tool_manager, default_provider=provider | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,3 @@ | ||
| """旧实现,与现有ABC不符,已弃用,请勿参考!""" | ||
|
|
||
| """Scripted mock provider replaying a fixed multi-turn tool-call demo. | ||
|
|
||
| Used for offline demos and TUI development: each ``chat`` call plays back | ||
|
|
@@ -9,7 +7,10 @@ | |
| import asyncio | ||
| import json | ||
| from types import SimpleNamespace | ||
| from typing import Any, Dict, List, Optional | ||
| from typing import Any, Dict, List, Optional, AsyncGenerator | ||
|
|
||
| from mitocode.backend.chat_provider.sample_chat_provider import _SampleChatProvider | ||
|
|
||
|
|
||
|
|
||
| def _make_chunk( | ||
|
|
@@ -139,52 +140,84 @@ def _chunk_tool_call( | |
| return chunks | ||
|
|
||
|
|
||
| class ScenarioProvider: | ||
| class ScenarioProvider(_SampleChatProvider): | ||
| """Mock provider that plays back a multi-turn tool-call scenario. | ||
|
|
||
| Each call to :meth:`chat` advances an internal turn counter and returns | ||
| the next pre-recorded stream: markdown text, bash, write_file, read_file | ||
| the next pre-recorded stream: markdown text, bash / write_file / read_file | ||
| tool calls with bubble sort code. | ||
| """ | ||
|
|
||
| def __init__(self, delay: float = 0.03): | ||
| def __init__( | ||
| self, | ||
| default_model: str = "scenario-model", | ||
| default_model_list: Optional[List[str]] = None, | ||
| default_messages: Optional[List[Dict]] = None, | ||
| default_tools: Optional[List[Dict]] = None, | ||
| stream: bool = True, | ||
| settings: Optional[Dict[str, Any]] = None, | ||
| delay: float = 0.03, | ||
| ): | ||
| """Initialize the provider with an inter-chunk streaming delay. | ||
|
|
||
| Args: | ||
| delay: Seconds to sleep between yielded chunks (default 0.03). | ||
| """ | ||
| if default_model_list is None: | ||
| default_model_list = ["scenario-model"] | ||
| super().__init__( | ||
| default_model=default_model, | ||
| default_model_list=default_model_list, | ||
| default_messages=default_messages, | ||
| default_tools=default_tools, | ||
| stream=stream, | ||
| settings=settings, | ||
| ) | ||
| self.turn = 0 | ||
| self._delay = delay | ||
|
|
||
| @staticmethod | ||
| def get_model_list(): | ||
| """Return the model identifiers accepted by this provider.""" | ||
| return ["scenario-model"] | ||
| @classmethod | ||
| async def factory(cls, *args, **kwargs) -> "ScenarioProvider": | ||
| """Create and initialize a provider instance asynchronously.""" | ||
| ins = cls(*args, **kwargs) | ||
| await ins.init() | ||
| return ins | ||
|
|
||
| @classmethod | ||
| def get_settings_schema(cls): | ||
| def get_settings_schema(cls) -> Dict[str, Any]: | ||
| """Return the JSON Schema describing accepted settings.""" | ||
| return { | ||
| "type": "object", | ||
| "properties": {}, | ||
| "properties": { | ||
| "delay": {"type": "number", "minimum": 0, "default": 0.03}, | ||
| }, | ||
| "additionalProperties": True, | ||
| } | ||
|
|
||
| @staticmethod | ||
| def check_settings_schema(settings): | ||
| """Validate that *settings* is a dict; any keys are allowed.""" | ||
| return isinstance(settings, dict) | ||
| @classmethod | ||
| def check_settings_schema(cls, settings: Any) -> bool: | ||
| """Validate that *settings* is a dict with optional delay.""" | ||
| if not isinstance(settings, dict): | ||
| return False | ||
| delay = settings.get("delay", 0.03) | ||
| return isinstance(delay, (int, float)) and delay >= 0 | ||
|
|
||
| async def get_model_list(self) -> List[str]: | ||
| """Return the model identifiers accepted by this provider.""" | ||
| return ["scenario-model"] | ||
|
|
||
| def init(self): | ||
| async def init(self) -> None: | ||
| """No-op initialization hook kept for provider interface parity.""" | ||
| pass | ||
| delay = self.settings.get("delay", 0.03) if self.settings else 0.03 | ||
| self._delay = delay | ||
|
Comment on lines
+209
to
+212
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 3. Factory discards delay argument ScenarioProvider.factory(delay=x) stores x in the constructor and then init immediately overwrites it with settings.delay or 0.03. Callers using the provider's standard factory lifecycle therefore cannot configure the stream delay through the explicit delay parameter. Agent Prompt
|
||
|
|
||
| async def chat( | ||
| self, | ||
| tools: Optional[list] = None, | ||
| messages: Optional[List[Dict[str, Any]]] = None, | ||
| **kwargs, | ||
| ): | ||
| model: str = "", | ||
| tools: Optional[List[Dict]] = None, | ||
| messages: Optional[List[Dict]] = None, | ||
| stream: bool = True, | ||
| ) -> AsyncGenerator | Dict: | ||
| """Return an async stream playing back the next scripted turn. | ||
|
|
||
| Each invocation advances the internal turn counter: turns 0-2 emit | ||
|
|
@@ -231,4 +264,23 @@ async def _stream(): | |
| yield c | ||
| await asyncio.sleep(self._delay) | ||
|
|
||
| return _stream() | ||
| if stream: | ||
| return _stream() | ||
|
|
||
| full_content = "" | ||
| for c in chunks: | ||
| if c.choices[0].delta.content: | ||
| full_content += c.choices[0].delta.content | ||
|
Comment on lines
+270
to
+273
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 4. Non-streaming drops tool calls For scripted turns 0–2, the new non-streaming branch copies only delta.content, omits message.tool_calls, and hardcodes finish_reason to stop. Consumers requesting stream=False receive a false normal completion and cannot execute the scenario's bash, write_file, or read_file calls. Agent Prompt
|
||
| return { | ||
| "choices": [ | ||
| { | ||
| "message": { | ||
| "role": "assistant", | ||
| "content": full_content, | ||
| }, | ||
| "finish_reason": "stop", | ||
| "index": 0, | ||
| } | ||
| ], | ||
| "model": model or self.default_model, | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2. Speed option is ignored
🐞 Bug≡ CorrectnessAgent Prompt
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools