Totoro 6177b07c06
fix(conversation): clarify reference semantics and keep reader pages inline (#5421)
Document that read permission expiry and source deletion do not erase
text already copied into the destination conversation, and that reads
follow the source's current visible history. Truncated results now tell
the agent to acknowledge the omission and ask for the missing material
before claiming every requirement is covered.

Pages were filled to 20,000 text characters by cutting the last message
that did not fit, and that suffix could never be paged back. They could
also exceed the default 12,000-character tool-output budget, which
externalized the page to a file. Pages are now sized by their serialized
length against the read_conversation tool-output budget; a message that
does not fit starts the next page intact, so only a message over 4,000
characters (or one whose escaped JSON alone exceeds the budget) is cut.

Co-authored-by: Totoro-qaq <279883115+Totoro-qaq@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 15:05:30 +08:00

73 lines
3.9 KiB
Python

"""Shared runtime protocol constants."""
DEFAULT_SKILLS_CONTAINER_PATH = "/mnt/skills"
# Host-only per-run capability. Keep this dependency-free: the runtime worker
# must not initialize the tool/subagent packages while importing this key.
CONVERSATION_READER_CONTEXT_KEY = "__conversation_reader"
CONVERSATION_TOOL_USE = "deerflow.tools.conversation:read_conversation"
# The Gateway sizes reader pages by this tool's tool-output budget entry.
CONVERSATION_TOOL_NAME = "read_conversation"
# Hidden subdirectory (under a thread's outputs dir) that holds the browser
# tools' per-step screenshots. These are transient live-progress frames, not
# deliverables, so the workspace-changes scanner excludes this directory. Both
# the browser tools (which write here) and the scanner (which ignores it) import
# this single source of truth so the name cannot drift between them.
BROWSER_FRAMES_DIRNAME = ".browser-frames"
# Default subdirectory (under a thread's outputs dir) where the tool-output
# budget middleware persists oversized tool outputs. These are process
# feedback the model reads back via ``read_file`` (the budget preview carries
# the reference), not deliverables, so the workspace-changes scanner excludes
# this directory and run delivery verification never counts it as a produced
# artifact. Both the budget middleware's default ``storage_subdir`` and the
# scanner import this single source of truth so the name cannot drift between
# them; a custom configured ``storage_subdir`` is threaded through the
# snapshot capture as an extra excluded dir name.
TOOL_RESULTS_DIRNAME = ".tool-results"
# Hidden directory under a thread workspace owned by stdio MCP runtimes. The
# default subprocess temp directory lives at ``.mcp/tmp``; these files are
# process-internal state rather than workspace deliverables, so the
# workspace-changes scanner excludes the whole reserved namespace. MCP launch
# paths and the scanner share this name so writes and filtering cannot drift.
MCP_INTERNAL_DIRNAME = ".mcp"
# Default subprocess temp subdirectory pinned into stdio MCP environments
# (``TMPDIR``/``TMP``/``TEMP``). Both stdio launch paths (persistent sessions
# and background task calls) import this instead of composing the suffix
# themselves. Pinning the process temp dir here (alongside its cwd) makes
# tools that write to ``os.tmpdir()`` / ``tempfile.gettempdir()`` land inside
# the mounted user-data tree, where their output is resolvable by the
# sandbox/artifact API — instead of on an unreachable host temp path.
MCP_TMP_SUBDIR = f"{MCP_INTERNAL_DIRNAME}/tmp"
# Default timeout (seconds) for MCP server bring-up: tool discovery (subprocess
# spawn + initialize + tools/list) and persistent-session initialization. A hung
# stdio server (e.g. npx blocked on a package download or a server that never
# answers initialize) would otherwise block agent construction forever — and on
# the Gateway event loop, the whole process. Per-server override is
# ``mcpServers.<name>.session_init_timeout``; ``None`` disables the timeout.
DEFAULT_MCP_SESSION_INIT_TIMEOUT = 60.0
# Durable MCP task storage/protocol limits. The runtime validators and ORM use
# the same constants so SQLite cannot accept values that PostgreSQL later
# rejects at its VARCHAR boundaries.
MCP_TASK_SERVER_NAME_MAX_LENGTH = 128
MCP_TASK_REMOTE_ID_MAX_LENGTH = 255
MCP_TASK_NAME_MAX_LENGTH = 255
MCP_TASK_RESULT_ARTIFACT_MAX_BYTES = 65_536
MCP_TASK_POLL_AFTER_MAX_SECONDS = 86_400
# Persisted run-event envelope limits. Runtime definitions and the ORM both
# import these from this dependency-free module so lower layers never need to
# initialize deerflow.runtime just to validate storage constraints.
RUN_EVENT_TYPE_MAX_LENGTH = 32
RUN_EVENT_CATEGORY_MAX_LENGTH = 16
# Workspace changes are produced below the runtime layer, so their persisted
# event identity also lives here rather than in the runtime event catalog.
WORKSPACE_CHANGES_EVENT_TYPE = "workspace_changes"
WORKSPACE_CHANGES_EVENT_CATEGORY = "workspace"