Add assistant-ui data agent frontend
This commit is contained in:
+48
-7
@@ -99,6 +99,20 @@ class PromptPreflightResult:
|
||||
reason: str | None = None
|
||||
|
||||
|
||||
def _prepend_runtime_context(prompt: str, runtime_context: str | None) -> str:
|
||||
"""把仅模型可见的运行上下文附加到本轮 prompt 前,不污染用户历史消息。"""
|
||||
if not runtime_context or not runtime_context.strip():
|
||||
return prompt
|
||||
return '\n\n'.join(
|
||||
[
|
||||
'<system-reminder>',
|
||||
runtime_context.strip(),
|
||||
'</system-reminder>',
|
||||
prompt,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class LocalCodingAgent:
|
||||
model_config: ModelConfig
|
||||
@@ -355,12 +369,18 @@ class LocalCodingAgent:
|
||||
),
|
||||
)
|
||||
|
||||
def run(self, prompt: str) -> AgentRunResult:
|
||||
def run(
|
||||
self,
|
||||
prompt: str,
|
||||
session_id: str | None = None,
|
||||
*,
|
||||
runtime_context: str | None = None,
|
||||
) -> AgentRunResult:
|
||||
self.managed_agent_id = None
|
||||
self.resume_source_session_id = None
|
||||
if self.plugin_runtime is not None:
|
||||
self.plugin_runtime.restore_session_state({})
|
||||
session_id = uuid4().hex
|
||||
session_id = session_id or uuid4().hex
|
||||
scratchpad_directory = self._ensure_scratchpad_directory(session_id)
|
||||
result = self._run_prompt(
|
||||
prompt,
|
||||
@@ -368,12 +388,19 @@ class LocalCodingAgent:
|
||||
session_id=session_id,
|
||||
scratchpad_directory=scratchpad_directory,
|
||||
existing_file_history=(),
|
||||
runtime_context=runtime_context,
|
||||
)
|
||||
self._accumulate_usage(result)
|
||||
self._finalize_managed_agent(result)
|
||||
return result
|
||||
|
||||
def resume(self, prompt: str, stored_session: StoredAgentSession) -> AgentRunResult:
|
||||
def resume(
|
||||
self,
|
||||
prompt: str,
|
||||
stored_session: StoredAgentSession,
|
||||
*,
|
||||
runtime_context: str | None = None,
|
||||
) -> AgentRunResult:
|
||||
self.managed_agent_id = None
|
||||
self.resume_source_session_id = stored_session.session_id
|
||||
session = AgentSessionState.from_persisted(
|
||||
@@ -390,7 +417,9 @@ class LocalCodingAgent:
|
||||
self.active_session_id = stored_session.session_id
|
||||
self.last_session = session
|
||||
self.last_session_path = str(
|
||||
self.runtime_config.session_directory / f'{stored_session.session_id}.json'
|
||||
self.runtime_config.session_directory
|
||||
/ stored_session.session_id
|
||||
/ 'session.json'
|
||||
)
|
||||
if self.plugin_runtime is not None:
|
||||
self.plugin_runtime.restore_session_state(stored_session.plugin_state)
|
||||
@@ -405,6 +434,7 @@ class LocalCodingAgent:
|
||||
session_id=stored_session.session_id,
|
||||
scratchpad_directory=scratchpad_directory,
|
||||
existing_file_history=stored_session.file_history,
|
||||
runtime_context=runtime_context,
|
||||
)
|
||||
self._accumulate_usage(result)
|
||||
self._finalize_managed_agent(result)
|
||||
@@ -418,6 +448,7 @@ class LocalCodingAgent:
|
||||
session_id: str,
|
||||
scratchpad_directory: Path | None,
|
||||
existing_file_history: tuple[dict[str, object], ...],
|
||||
runtime_context: str | None = None,
|
||||
) -> AgentRunResult:
|
||||
slash_result = preprocess_slash_command(self, prompt)
|
||||
if slash_result.handled and not slash_result.should_query:
|
||||
@@ -457,7 +488,11 @@ class LocalCodingAgent:
|
||||
scratchpad_directory=scratchpad_directory,
|
||||
)
|
||||
)
|
||||
session.append_user(effective_prompt)
|
||||
model_prompt = _prepend_runtime_context(
|
||||
effective_prompt,
|
||||
runtime_context,
|
||||
)
|
||||
session.append_user(effective_prompt, model_content=model_prompt)
|
||||
self.last_session = session
|
||||
self.active_session_id = session_id
|
||||
tool_specs = [tool.to_openai_tool() for tool in self.tool_registry.values()]
|
||||
@@ -3042,7 +3077,9 @@ class LocalCodingAgent:
|
||||
return normalized[: limit - 3] + '...'
|
||||
|
||||
def _ensure_scratchpad_directory(self, session_id: str) -> Path:
|
||||
scratchpad_directory = (self.runtime_config.scratchpad_root / session_id).resolve()
|
||||
scratchpad_directory = (
|
||||
self.runtime_config.scratchpad_root / session_id / 'scratchpad'
|
||||
).resolve()
|
||||
scratchpad_directory.mkdir(parents=True, exist_ok=True)
|
||||
return scratchpad_directory
|
||||
|
||||
@@ -3430,7 +3467,11 @@ class LocalCodingAgent:
|
||||
previous_turns = 0
|
||||
previous_tool_calls = 0
|
||||
previous_budget_state: dict[str, object] = {}
|
||||
existing_path = self.runtime_config.session_directory / f'{result.session_id}.json'
|
||||
existing_path = (
|
||||
self.runtime_config.session_directory / result.session_id / 'session.json'
|
||||
)
|
||||
if not existing_path.exists():
|
||||
existing_path = self.runtime_config.session_directory / f'{result.session_id}.json'
|
||||
if existing_path.exists():
|
||||
try:
|
||||
previous = load_agent_session(
|
||||
|
||||
+14
-2
@@ -13,6 +13,7 @@ MAX_MUTATION_HISTORY = 8
|
||||
class AgentMessage:
|
||||
role: str
|
||||
content: str
|
||||
model_content: str | None = None
|
||||
name: str | None = None
|
||||
tool_call_id: str | None = None
|
||||
tool_calls: tuple[JSONDict, ...] = ()
|
||||
@@ -26,7 +27,7 @@ class AgentMessage:
|
||||
def to_openai_message(self) -> JSONDict:
|
||||
payload: JSONDict = {
|
||||
'role': self.role,
|
||||
'content': self.content,
|
||||
'content': self.model_content if self.model_content is not None else self.content,
|
||||
}
|
||||
if self.name is not None:
|
||||
payload['name'] = self.name
|
||||
@@ -37,7 +38,16 @@ class AgentMessage:
|
||||
return payload
|
||||
|
||||
def to_transcript_entry(self) -> JSONDict:
|
||||
payload = self.to_openai_message()
|
||||
payload: JSONDict = {
|
||||
'role': self.role,
|
||||
'content': self.content,
|
||||
}
|
||||
if self.name is not None:
|
||||
payload['name'] = self.name
|
||||
if self.tool_call_id is not None:
|
||||
payload['tool_call_id'] = self.tool_call_id
|
||||
if self.tool_calls:
|
||||
payload['tool_calls'] = list(self.tool_calls)
|
||||
blocks = self.blocks or _derive_blocks(self)
|
||||
if blocks:
|
||||
payload['blocks'] = [dict(block) for block in blocks]
|
||||
@@ -288,6 +298,7 @@ class AgentSessionState:
|
||||
self,
|
||||
content: str,
|
||||
*,
|
||||
model_content: str | None = None,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
message_id: str | None = None,
|
||||
) -> None:
|
||||
@@ -295,6 +306,7 @@ class AgentSessionState:
|
||||
AgentMessage(
|
||||
role='user',
|
||||
content=content,
|
||||
model_content=model_content,
|
||||
blocks=_text_blocks(content),
|
||||
metadata=_initialize_message_metadata(
|
||||
role='user',
|
||||
|
||||
+6
-3
@@ -28,15 +28,18 @@ def main() -> None:
|
||||
)
|
||||
parser.add_argument(
|
||||
'--model',
|
||||
default=os.environ.get('OPENAI_MODEL', 'Qwen/Qwen3-Coder-30B-A3B-Instruct'),
|
||||
default=os.environ.get('OPENAI_MODEL', 'xiaomi/mimo-v2-flash'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--base-url',
|
||||
default=os.environ.get('OPENAI_BASE_URL', 'http://127.0.0.1:8000/v1'),
|
||||
default=os.environ.get('OPENAI_BASE_URL', 'http://model.mify.ai.srv/v1'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--api-key',
|
||||
default=os.environ.get('OPENAI_API_KEY', 'local-token'),
|
||||
default=os.environ.get(
|
||||
'OPENAI_API_KEY',
|
||||
'sk-Jxoh5lf1jWg6HQZYYyfyagXudGxUXNAgkZklxMnnXHn7pFmU',
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--session-dir',
|
||||
|
||||
@@ -72,14 +72,19 @@ class StoredAgentSession:
|
||||
def save_agent_session(session: StoredAgentSession, directory: Path | None = None) -> Path:
|
||||
target_dir = directory or DEFAULT_AGENT_SESSION_DIR
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
path = target_dir / f'{session.session_id}.json'
|
||||
session_dir = target_dir / session.session_id
|
||||
session_dir.mkdir(parents=True, exist_ok=True)
|
||||
path = session_dir / 'session.json'
|
||||
path.write_text(json.dumps(asdict(session), indent=2), encoding='utf-8')
|
||||
return path
|
||||
|
||||
|
||||
def load_agent_session(session_id: str, directory: Path | None = None) -> StoredAgentSession:
|
||||
target_dir = directory or DEFAULT_AGENT_SESSION_DIR
|
||||
data = json.loads((target_dir / f'{session_id}.json').read_text(encoding='utf-8'))
|
||||
path = target_dir / session_id / 'session.json'
|
||||
if not path.exists():
|
||||
path = target_dir / f'{session_id}.json'
|
||||
data = json.loads(path.read_text(encoding='utf-8'))
|
||||
return StoredAgentSession(
|
||||
session_id=data['session_id'],
|
||||
model_config=dict(data['model_config']),
|
||||
|
||||
Reference in New Issue
Block a user