Turn helpers are utilities in src/core/orchestrator/turn-helpers.ts that manage text screening, attachment loading, connector skill filtering, and egress policy—enabling QM to validate content safety, resource budgets, and network access during agent execution. The module provides helpers for constructing output (stripping boilerplate, acks, and retrieving channel labels) and resolving permissions—determining which scopes a skill can write to and which hosts an agent may reach. The Slack integration extracts forwarded message payloads and includes them in the turn context passed to the agent, enabling agents to read content from messages forwarded into conversations. turn-handler.ts and conversation-view.ts in src/slack/ are the primary owners of assembling forwarded message content into turn input. The ambient reply path in src/api/app-ambient.ts fetches and injects the conversation roster via the directory store, giving agents knowledge of conversation participants during reply assembly.
MAX_AUTO_ATTACHMENT_SCREEN_BYTES in src/core/orchestrator/turn-helpers.ts is set to 12_000 bytes, capping the size of attachments that are automatically screened as text.[1] isScreenableTextAttachment treats a MIME type as screenable text if it starts with text/ or is one of application/json, application/xml, application/javascript, application/yaml, or application/x-yaml; only the portion before the first ; is considered.[1] headLooksLikeText classifies a buffer as binary if it contains a null byte, and as suspiciously binary if more than 10% of its UTF-8 characters are replacement characters (U+FFFD) or non-printable control characters (excluding tab, LF, and CR).[1]
loadTapeImage returns the sentinel value "over-budget" — rather than null — when the artifact's sizeBytes exceeds MAX_VISION_IMAGE_BYTES or the caller-supplied remainingBytes, letting callers distinguish a budget exhaustion from an authorization or availability failure.[1] Before reading any bytes, loadTapeImage validates the opened stream against the stored artifact metadata (size, sha256, mimetype) and destroys the stream, returning null, if any field mismatches — preventing use of corrupted or swapped file content.[1]
CONNECTOR_SKILL_PROVIDERS is the static mapping from skill names to their required connector provider — for example, "google-workspace" → "google", "slack-drafts" → "slack", and "morning-digest" → "x".[1] filterConnectorSkills removes skill resolutions whose connector provider is absent from the set of availableProviders; skills with no entry in CONNECTOR_SKILL_PROVIDERS always pass through.[1]
visibleSkillScopes computes which scopes a skill may write to: the writable memory scope, all read-only non-org layer scopes (team scopes), and the org scope.[1]
egressClaimAllowingControlPlane returns undefined — imposing no egress restriction — when allowedHosts and deniedHosts are both empty and denyPrivateNetworks is false, short-circuiting policy construction for unrestricted deployments.[1] When an allowlist is active, egressClaimAllowingControlPlane always strips the control-plane host (apiBaseUrl hostname) from deniedHosts and adds it to allowedHosts, ensuring agent-to-control-plane traffic is never accidentally blocked by egress policy.[1]
stripTurnBoilerplate removes paragraphs that start with [ — such as bracketed tool-result or metadata blocks — from assistant text before using it for display purposes such as title generation.[1] conversationLabelFor resolves a human-readable channel label (e.g., #general) by first using channelName if provided, then querying the DirectoryStore only for channel-kind scope IDs; it returns undefined for all other scope kinds or when no directory is available.[1] stripAckPrefix removes a leading acknowledgment token (e.g., a bot's @-mention ack) from the start of a message, trimming leading whitespace before and after the prefix; it is a no-op when either text or ack is falsy.[1]
Sources