mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-09 03:30:48 +08:00
重构主控编排与运行时预热链路,统一工作区提示词/专家调度协议并补齐 wiki 记忆注入与写回闭环。
同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。 Made-with: Cursor
This commit is contained in:
parent
4a23b715a2
commit
dbbe3add6a
14438 changed files with 2693620 additions and 2546 deletions
|
|
@ -211,14 +211,6 @@ class Agent:
|
|||
tenant_id = tenant_id or str(owner.get("tenant_id") or "")
|
||||
user_id = user_id or str(owner.get("user_id") or "")
|
||||
|
||||
session = self.store.get_session(session_id)
|
||||
if session and session.title in ("新会话", "New Chat"):
|
||||
title = user_text.strip().replace("\n", " ")
|
||||
if not title and attachments:
|
||||
title = str(attachments[0].get("name") or "New Chat")
|
||||
if title:
|
||||
self.store.rename_session(session_id, title[:SESSION_TITLE_MAX_LEN])
|
||||
|
||||
self._emit_progress(
|
||||
on_progress,
|
||||
"Received. Working on your request…",
|
||||
|
|
@ -267,11 +259,14 @@ class Agent:
|
|||
from oclaw.runtime.chat.agent_messages import build_llm_messages
|
||||
|
||||
msgs = self.store.get_messages(session_id=session_id, limit=self.config.max_messages)
|
||||
trunc_raw = str(self.store.get_setting("AIA_TOOL_CONTEXT_TRUNCATE_ENABLED") or "").strip().lower()
|
||||
tool_context_truncate_enabled = trunc_raw not in ("0", "false", "no", "off")
|
||||
return build_llm_messages(
|
||||
store_messages=msgs,
|
||||
system_prompt=self._compose_system_prompt(),
|
||||
model=self.model,
|
||||
lang=self.lang,
|
||||
tool_context_truncate_enabled=tool_context_truncate_enabled,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ from oclaw.runtime.relay_pointer import parse_pointer_uri
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
_THINK_BLOCK_RE = re.compile(r"<think>\s*(.*?)\s*</think>\s*", flags=re.IGNORECASE | re.DOTALL)
|
||||
_TOOL_CONTEXT_RESULT_MAX_CHARS = 50
|
||||
|
||||
|
||||
def _replay_recent_tool_rounds() -> int:
|
||||
|
|
@ -175,12 +176,23 @@ def _summarize_unpaired_tool_content(raw: str, *, cap: int) -> str:
|
|||
return s
|
||||
|
||||
|
||||
def _truncate_tool_context(text: str, *, lang: str) -> str:
|
||||
s = str(text or "").strip()
|
||||
if not s:
|
||||
return s
|
||||
if len(s) <= _TOOL_CONTEXT_RESULT_MAX_CHARS:
|
||||
return s
|
||||
tip = "…(详情请重新阅读)" if not str(lang or "").startswith("en") else "... (details truncated, please re-read)"
|
||||
return s[:_TOOL_CONTEXT_RESULT_MAX_CHARS] + tip
|
||||
|
||||
|
||||
def build_llm_messages(
|
||||
*,
|
||||
store_messages: list[Any],
|
||||
system_prompt: str,
|
||||
model: ChatModel,
|
||||
lang: str,
|
||||
tool_context_truncate_enabled: bool = True,
|
||||
) -> list[dict[str, Any]]:
|
||||
"""把 DB 中的消息序列转换为 LLM messages。"""
|
||||
out: list[dict[str, Any]] = [{"role": "system", "content": (system_prompt or "").strip()}]
|
||||
|
|
@ -427,6 +439,8 @@ def build_llm_messages(
|
|||
r0 = getattr(m, "content", "") or ""
|
||||
cap0 = tool_llm_message_max_chars()
|
||||
pretty = _summarize_unpaired_tool_content(r0, cap=cap0)
|
||||
if tool_context_truncate_enabled:
|
||||
pretty = _truncate_tool_context(pretty, lang=lang)
|
||||
out.append(
|
||||
{
|
||||
"role": "assistant",
|
||||
|
|
@ -457,6 +471,10 @@ def build_llm_messages(
|
|||
tool_content_out = raw_tc_content[: max(1, cap - 80)] + "\n...<truncated>"
|
||||
except Exception:
|
||||
tool_content_out = raw_tc_content[: max(1, cap - 80)] + "\n...<truncated>"
|
||||
if tool_context_truncate_enabled:
|
||||
# Preserve explicit guard markers from upstream context guards.
|
||||
if "_tool_result_guarded" not in str(tool_content_out or ""):
|
||||
tool_content_out = _truncate_tool_context(tool_content_out, lang=lang)
|
||||
tool_row: dict[str, Any] = {
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call_id,
|
||||
|
|
@ -476,6 +494,8 @@ def build_llm_messages(
|
|||
r = getattr(m, "content", "") or ""
|
||||
cap2 = tool_llm_message_max_chars()
|
||||
pretty2 = _summarize_unpaired_tool_content(r, cap=cap2)
|
||||
if tool_context_truncate_enabled:
|
||||
pretty2 = _truncate_tool_context(pretty2, lang=lang)
|
||||
out.append(
|
||||
{
|
||||
"role": "assistant",
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ from oclaw.runtime.tools.tool_validation import validate_tool_arguments
|
|||
from oclaw.runtime.tools.experts.workspace.workspace_base import workspace_path_access_scope
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
_tool_exec_log = logging.getLogger("oclaw.tool_exec")
|
||||
|
||||
_TOOL_ERROR_MAP = {
|
||||
"tool_timeout_or_failed": "tool_timeout_or_failed",
|
||||
|
|
@ -275,13 +276,43 @@ class ToolExecutor:
|
|||
ex.shutdown(wait=False)
|
||||
else:
|
||||
result = _call()
|
||||
return normalize_tool_result(result), int((time.perf_counter() - t0) * 1000)
|
||||
out = normalize_tool_result(result)
|
||||
dur_ms = int((time.perf_counter() - t0) * 1000)
|
||||
try:
|
||||
_tool_exec_log.info(
|
||||
"tool_exec name=%s ok=%s dur_ms=%s session=%s specialist=%s tool_call_id=%s error_code=%s",
|
||||
str(tc.name or ""),
|
||||
str(bool(out.get("ok"))),
|
||||
str(dur_ms),
|
||||
str(ctx.session_id or ""),
|
||||
str(ctx.specialist or ""),
|
||||
str(getattr(tc, "id", "") or ""),
|
||||
str(out.get("error_code") or ""),
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
return out, dur_ms
|
||||
except Exception as e:
|
||||
if ctx.lang.startswith("en"):
|
||||
err = {"ok": False, "error_code": "tool_execution_error", "error": f"Tool execution error: {type(e).__name__}: {e}"}
|
||||
else:
|
||||
err = {"ok": False, "error_code": "tool_execution_error", "error": f"工具执行异常: {type(e).__name__}: {e}"}
|
||||
return normalize_tool_result(err), int((time.perf_counter() - t0) * 1000)
|
||||
out = normalize_tool_result(err)
|
||||
dur_ms = int((time.perf_counter() - t0) * 1000)
|
||||
try:
|
||||
_tool_exec_log.info(
|
||||
"tool_exec name=%s ok=%s dur_ms=%s session=%s specialist=%s tool_call_id=%s error_code=%s",
|
||||
str(tc.name or ""),
|
||||
str(bool(out.get("ok"))),
|
||||
str(dur_ms),
|
||||
str(ctx.session_id or ""),
|
||||
str(ctx.specialist or ""),
|
||||
str(getattr(tc, "id", "") or ""),
|
||||
str(out.get("error_code") or ""),
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
return out, dur_ms
|
||||
|
||||
@staticmethod
|
||||
def _json_dumps_safe(obj: Any) -> str:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue