How Large Responses Are Handled and Summarized in Craft-Agents-OSS

Craft-Agents-OSS automatically routes oversized tool outputs through a specialized pipeline that detects binary data, extracts embedded assets, persists payloads to disk, and optionally generates LLM summaries to prevent context window overflow.

When building agentic systems with the lukilabs/craft-agents-oss repository, tool calls often return massive payloads—API results, HTML pages, or base64-encoded media. The framework's large-response utility in packages/shared/src/utils/large-response.ts intercepts these results, ensuring the main agent context remains within token limits while preserving full data accessibility.

The Large-Response Processing Pipeline

The system uses a multi-stage decision tree to classify and handle responses. The entry point is guardLargeResult (lines 58–70), which branches based on content type, size, and structure.

Binary Detection and Safe Storage

Before any text processing occurs, the raw bytes are scanned for binary signatures via looksLikeBinary. If detected, the utility immediately saves the data to disk using saveBinaryResponse and returns a concise placeholder message to the agent.

This prevents binary garbage from polluting the LLM context while ensuring the asset remains available for downstream tools.

Structured JSON Asset Extraction

When the response is JSON, the system walks the object tree to find embedded base64-encoded assets. The extractAssetsFromStructuredJson function (lines 200–267) decodes these blobs, writes them to separate files, and rewrites the JSON pointers to reference the saved paths.

The formatStructuredMediaExtractionMessage function (lines 281–296) then generates a summary message listing the extracted files, allowing the agent to understand what media was retrieved without receiving the full base64 strings.

Inline Base64 and Data URL Handling

For plain-text responses containing data URLs or raw base64 blobs, the system detects these patterns at line 84 within guardLargeResult. The encoded data is decoded, persisted to the long_responses/ directory, and replaced with a short confirmation message indicating the binary content was saved externally.

Token-Based Thresholds and Persistence

The utility enforces strict size limits to protect the context window.

Size Estimation and Limits

The estimateTokens function (lines 40–45) calculates the approximate token count of the response text. The system compares this against TOKEN_LIMIT (15,000 tokens, approximately 60 KB).

If the response is below this threshold, the original result is returned unchanged, minimizing overhead for typical payloads.

Saving Oversized Responses

When the payload exceeds TOKEN_LIMIT, the saveLargeResponse function (lines 68–88) writes the full content to the session’s long_responses/ folder. This directory is defined in packages/shared/src/sessions/storage.ts.

The file path is preserved so that later tool calls—such as Read, Grep, or transform_data—can access the specific data without reloading the entire payload into the agent's context.

Optional LLM Summarization

For payloads that are large but not enormous, the system can generate a condensed summary to give the agent immediate context.

Summarization Triggers

If a summarization callback is provided (typically the agent’s runMiniCompletion method) and the payload is under MAX_SUMMARIZATION_INPUT (100,000 tokens, approximately 400 KB), the system proceeds to summarize.

The buildSummarizationPrompt function (lines 123–168) constructs a specialized prompt that includes the tool name, endpoint, parameters, and a truncated excerpt of the response, instructing the mini-model to extract key information.

Summary Formatting

The formatLargeResponseMessage function (lines 90–107) assembles the final message presented to the main agent. If summarization succeeded, the message includes:


[Large response (~<tokens> tokens) summarized]

Full data saved to: /path/to/file.txt
- Use Read/Grep to access specific content
- Use transform_data with inputFiles: ["long_responses/..."] for data analysis

<summary>

If no summary is available, a preview of the first 2 KB is included instead.

Implementation Examples

Direct Usage of the Guard Function

To process a tool output before sending it to the model:

import { guardLargeResult } from '@/utils/large-response.ts';

const result = await guardLargeResult(toolOutput, {
  sessionPath: '/tmp/session/123',
  toolName: 'gmail',
  input: { query: 'in:inbox' },
  intent: 'summarize',
  summarize: agent.runMiniCompletion.bind(agent),
});

if (result) {
  console.log(result);
}

Relevant source: guardLargeResult (lines 48–98) in packages/shared/src/utils/large-response.ts.

Registering a Summarization Callback

Agents register their summarization capability via:

class ClaudeAgent {
  private summarizeCallback?: (prompt: string) => Promise<string | null>;

  setSummarizeCallback(fn: (prompt: string) => Promise<string | null>) {
    this.summarizeCallback = fn;
  }
}

// When building an API tool:
const apiTool = createApiTool(config, cred, sessionPath, this.summarizeCallback);

Relevant source: setSummarizeCallback method in McpClientPool (lines 124–140) in packages/shared/src/mcp/mcp-pool.ts.

Building a Summarization Prompt

const prompt = buildSummarizationPrompt(veryLongText, {
  toolName: 'github',
  path: '/repos/lukilabs/craft-agents-oss',
  input: { repo: 'craft-agents-oss' },
  intent: 'Summarize recent PR changes',
});

Source: buildSummarizationPrompt (lines 123–168) in packages/shared/src/utils/large-response.ts.

Summary

  • Binary detection occurs first via looksLikeBinary in guardLargeResult, saving non-text data immediately to prevent context pollution.
  • Asset extraction from JSON and plain text removes base64 blobs, replaces them with file references, and generates inventory messages.
  • Token thresholds (TOKEN_LIMIT ≈ 15k tokens) determine whether a response passes through unchanged or gets persisted to the long_responses/ directory.
  • Optional summarization uses buildSummarizationPrompt and runMiniCompletion for payloads under 100k tokens, producing condensed context for the agent.
  • Reference formatting via formatLargeResponseMessage ensures the agent receives file paths, access instructions, and either a summary or preview snippet.

Frequently Asked Questions

What happens if a tool returns a binary file like a PDF or image?

The guardLargeResult function detects binary signatures using looksLikeBinary (lines 58–70) and immediately saves the data via saveBinaryResponse. The agent receives a short message like "Binary saved to: /path/to/file.pdf" instead of the raw bytes, keeping the context window clean.

How does the system decide whether to summarize a response?

The utility checks two conditions: the response must exceed the TOKEN_LIMIT (15,000 tokens), and it must be smaller than MAX_SUMMARIZATION_INPUT (100,000 tokens). If both conditions are met and a summarization callback was provided (typically runMiniCompletion), the system calls buildSummarizationPrompt and generates a summary.

Where are large responses stored on disk?

All oversized responses are written to the long_responses/ subdirectory within the session folder, as defined in packages/shared/src/sessions/storage.ts. The saveLargeResponse function (lines 68–88) handles the file I/O, and the resulting path is passed back to the agent for later access via Read, Grep, or transform_data tools.

Can the agent access the full response after it has been summarized?

Yes. When a response is summarized, the formatLargeResponseMessage function (lines 90–107) includes the full file path in the return message. The agent can then use tools like Read or Grep to access specific portions of the saved file, or use transform_data with inputFiles: ["long_responses/..."] to perform data analysis on the complete payload.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →