refactor: root-package imports (svc/runtime/interfaces) and fix PYTHONPATH

- Rename platform/ to svc/ to avoid shadowing stdlib platform.
- Replace from oclaw.* with from svc/runtime/interfaces; update -m CLI paths.
- tests/conftest: prepend repo root to sys.path (no parent-folder package name).
- CI: paths and offline_eval script under repo root.
- Ops scripts: PYTHONPATH must be repo root for python -m runtime.* (fixes gateway/WhatsApp sidecar startup).
- Fix default oclaw.json path in tabular/file attachment limits; stabilize attachment test config.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-05-13 14:51:17 +08:00
parent 7941b27f58
commit 420abac9f1
405 changed files with 1316 additions and 1345 deletions

View file

@ -9,9 +9,9 @@ from collections.abc import Callable
from dataclasses import dataclass
from typing import Any, Optional
from oclaw.runtime.tools.base import ToolRegistry
from oclaw.platform.persistence.sqlite_store import SqliteStore
from oclaw.platform.llm.chat_models import (
from runtime.tools.base import ToolRegistry
from svc.persistence.sqlite_store import SqliteStore
from svc.llm.chat_models import (
ChatModel,
LLMResponse,
LLMToolCall,
@ -22,8 +22,8 @@ from oclaw.platform.llm.chat_models import (
build_default_model,
gemini_openai_compat_client,
)
from oclaw.runtime.prompt_templates import render_prompt_for_lang
from oclaw.runtime.tools.tool_validation import validate_tool_arguments
from runtime.prompt_templates import render_prompt_for_lang
from runtime.tools.tool_validation import validate_tool_arguments
logger = logging.getLogger(__name__)
@ -81,13 +81,13 @@ class Agent:
def _format_ollama_failure_banner(self, exc: BaseException) -> str:
# Backward compat wrapper; implementation lives in `src.chat.agent_errors`.
from oclaw.runtime.chat.agent_errors import format_ollama_failure_banner
from runtime.chat.agent_errors import format_ollama_failure_banner
return format_ollama_failure_banner(lang=self.lang, exc=exc)
def _format_openai_transport_error(self, exc: BaseException) -> str:
# Backward compat wrapper; implementation lives in `src.chat.agent_errors`.
from oclaw.runtime.chat.agent_errors import format_openai_transport_error
from runtime.chat.agent_errors import format_openai_transport_error
return format_openai_transport_error(lang=self.lang, exc=exc)
@ -197,8 +197,8 @@ class Agent:
interaction_mode: str | None = None,
selected_specialist: str | None = None,
) -> str:
from oclaw.runtime.gateway import OclawGateway
from oclaw.runtime.types import StandardMessage
from runtime.gateway import OclawGateway
from runtime.types import StandardMessage
tenant_id = str(path_policy_tenant_id or "").strip()
user_id = str(path_policy_user_id or "").strip()
@ -256,7 +256,7 @@ class Agent:
return str(res.reply_text or "")
def _build_llm_messages(self, session_id: str) -> list[dict[str, Any]]:
from oclaw.runtime.chat.agent_messages import build_llm_messages
from 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()

View file

@ -6,7 +6,7 @@ from __future__ import annotations
"""
from typing import Any
from oclaw.runtime.prompt_templates import render_prompt
from runtime.prompt_templates import render_prompt
def format_ollama_failure_banner(*, lang: str, exc: BaseException) -> str:

View file

@ -13,12 +13,12 @@ import os
import re
from typing import Any
from oclaw.platform.llm.chat_models import _normalize_image_b64_payload, gemini_openai_compat_client, ChatModel
from oclaw.runtime.chat.media_redact import redact_embedded_image_blobs
from oclaw.runtime.chat.tool_runtime import tool_llm_message_max_chars, truncate_tool_result_for_llm_messages
from oclaw.runtime.prompt_templates import render_prompt
from oclaw.platform.files.attachment_assets import attachment_id_to_data_url
from oclaw.runtime.relay_pointer import parse_pointer_uri
from svc.llm.chat_models import _normalize_image_b64_payload, gemini_openai_compat_client, ChatModel
from runtime.chat.media_redact import redact_embedded_image_blobs
from runtime.chat.tool_runtime import tool_llm_message_max_chars, truncate_tool_result_for_llm_messages
from runtime.prompt_templates import render_prompt
from svc.files.attachment_assets import attachment_id_to_data_url
from 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)
@ -207,7 +207,7 @@ def build_llm_messages(
When ``active_turn_uuid`` matches a tool/user row ``turn_uuid``, that turn is treated as the
in-flight MCP turn: tool JSON is not stripped of nested image payloads here (see also
:func:`~oclaw.runtime.direct_loop._guard_tool_results_for_llm_context`). Omit or leave empty
:func:`~runtime.direct_loop._guard_tool_results_for_llm_context`). Omit or leave empty
to apply image-blob stripping for every tool row (safe default for callers without turn context).
Only the **last** user message may expand attachments into native multimodal ``input_image``

View file

@ -4,8 +4,8 @@ import json
from dataclasses import dataclass
from typing import Any
from oclaw.runtime.chat.media_redact import redact_embedded_image_blobs
from oclaw.runtime.direct_loop import (
from runtime.chat.media_redact import redact_embedded_image_blobs
from runtime.direct_loop import (
_OCLAW_TOOL_RESULT_HARD_CAP_CHARS,
_image_tool_result_replay_cap_chars,
_video_tool_result_replay_cap_chars,

View file

@ -7,7 +7,7 @@ from __future__ import annotations
import base64
import os
from typing import Any
from oclaw.platform.files.attachment_assets import AttachmentAssetStore
from svc.files.attachment_assets import AttachmentAssetStore
_IMAGE_CONTENT_TYPES = frozenset({"image", "input_image"})
_BASE64_PAYLOAD_KEYS = ("data", "image_base64", "base64", "content_base64", "body_base64")

View file

@ -17,16 +17,16 @@ from concurrent.futures import TimeoutError as FuturesTimeoutError
from dataclasses import dataclass
from typing import Any, Callable, Optional
from oclaw.platform.persistence.sqlite_store import SqliteStore
from oclaw.runtime.tools.base import ToolRegistry
from oclaw.platform.llm.chat_models import LLMToolCall
from oclaw.runtime.tools.tool_validation import validate_tool_arguments
from oclaw.runtime.chat.media_redact import ingest_embedded_image_blobs_as_refs
from oclaw.runtime.tools.path_guard import (
from svc.persistence.sqlite_store import SqliteStore
from runtime.tools.base import ToolRegistry
from svc.llm.chat_models import LLMToolCall
from runtime.tools.tool_validation import validate_tool_arguments
from runtime.chat.media_redact import ingest_embedded_image_blobs_as_refs
from runtime.tools.path_guard import (
workspace_path_access_scope,
workspace_write_namespace_scope,
)
from oclaw.runtime.chat.tool_invocation_context import tool_workspace_lane_scope
from runtime.chat.tool_invocation_context import tool_workspace_lane_scope
logger = logging.getLogger(__name__)
_tool_exec_log = logging.getLogger("oclaw.tool_exec")
@ -628,7 +628,7 @@ class ToolExecutor:
if not ctx.trace_id:
return
try:
from oclaw.runtime.orchestration.trace import new_span_id
from runtime.orchestration.trace import new_span_id
ctx.store.add_trace_event(
session_id=ctx.session_id,