@essentialai/cogent-bridge
Version:
Cogent Bridge — cross-agent comms for Claude Code, OpenAI Codex and Slack. Codex users: install with `curl -fsSL https://cogent.tools/install.sh | sh`, then start with `cogent-codex` for real-time peer wake.
108 lines • 5.42 kB
JavaScript
import { z } from "zod";
import { getBackend, isCloudDeferred } from "../backend/index.js";
import { getConfig } from "../config.js";
import { successResult, errorResult } from "../errors.js";
import { logger } from "../logger.js";
/**
* Maximum total character count for the tool response.
* Keeps the result safely below Claude Code's MCP result size limit.
* Older messages are dropped first when the budget is exceeded.
*/
const MAX_RESULT_CHARS = 50_000;
export function registerGetHistoryTool(server) {
server.registerTool("cogent_get_history", {
title: "Get Message History",
description: "Retrieve the message history for the bridge. " +
"Optionally filter by a specific peer ID. " +
"Returns the most recent messages that fit within a 50,000-character response budget — " +
"older messages are omitted when AI responses are large (code blocks, long explanations). " +
"Use peerId to filter to a specific conversation thread for focused context. " +
"Returns messages in chronological order, most recent last.",
inputSchema: {
peerId: z
.string()
.optional()
.describe("Optional peer ID to filter history for"),
limit: z
.number()
.optional()
.default(30)
.describe("Maximum number of messages to fetch. Defaults to 30. " +
"Increase if you need more history context."),
includeRelayEchoes: z
.boolean()
.optional()
.default(false)
.describe("Include auto-relay echo records that mirror the recipient's reply. " +
"Off by default to keep history readable; turn on for debugging the " +
"relay pipeline (260511-o3p, requires server 3.1.6+)."),
metadataOnly: z.boolean()
.optional()
.default(false)
.describe("Return records as metadata only — keys limited to " +
"{id, fromPeerId, toPeerId, timestamp, durationMs, isRelayEcho, success, " +
"attachmentCount}. " +
"message and response bodies are omitted entirely. " +
"Target: ≥90% payload reduction for cheap \"did head move?\" polling. " +
"Added in 3.2 (HIST-02); attachmentCount added by Cogent Mail M2.5."),
dedupInferredEchoes: z.boolean()
.optional()
.default(false)
.describe("Suppress untagged auto-relay echo records via content-and-direction " +
"heuristic: drop M[i] when M[i].message === M[i-1].response AND " +
"fromPeerId/toPeerId are swapped AND Δt < 120s. Catches the ~13% of " +
"echoes that bypass the isRelayEcho tag (peer-driven re-broadcasts). " +
"Requires server 3.2.1+; older servers ignore the param. " +
"Added in 3.2.1 (FIX-INFERRED-ECHO, Phase 18 light)."),
},
annotations: {
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: false,
},
}, async ({ peerId, limit, includeRelayEchoes, metadataOnly, dedupInferredEchoes }) => {
try {
// SECURITY: a cloud-configured agent that has not joined a channel yet
// runs on the local FileBackend placeholder over the host-global
// ~/.cogent/cogent-state.json, which can hold OTHER agents' local
// history. It belongs to no channel, so return empty rather than
// disclose another channel's content. See backend/isCloudDeferred.
if (isCloudDeferred(getConfig().COGENT_ENDPOINT)) {
return successResult({
messages: [],
count: 0,
truncated: false,
totalAvailable: 0,
notJoined: true,
hint: "Not connected to a channel yet — call cogent_join_session (or cogent_register_peer) first. Local history is withheld to prevent cross-channel disclosure.",
});
}
const backend = getBackend();
const messages = await backend.getHistory(peerId, limit, includeRelayEchoes, metadataOnly, dedupInferredEchoes);
// Apply response budget: keep the newest messages that fit within
// MAX_RESULT_CHARS to avoid exceeding Claude Code's MCP result size limit.
const trimmed = [];
let chars = 0;
for (let i = messages.length - 1; i >= 0; i--) {
const size = JSON.stringify(messages[i]).length;
if (chars + size > MAX_RESULT_CHARS)
break;
trimmed.unshift(messages[i]);
chars += size;
}
const truncated = trimmed.length < messages.length;
return successResult({
messages: trimmed,
count: trimmed.length,
truncated,
totalAvailable: messages.length,
});
}
catch (err) {
logger.error("get-history failed", { error: err });
return errorResult(err);
}
});
}
//# sourceMappingURL=get-history.js.map