Add assistant-ui data agent frontend

This commit is contained in:
武阳
2026-05-06 16:18:32 +08:00
parent d6a2359dc1
commit 7d4ae3e7ba
119 changed files with 14330 additions and 14420 deletions
+48 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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',
+7 -2
View File
@@ -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']),