tools

package
v0.0.0-...-1c90dee Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 27, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package tools registers the eight MCP tools hearsay exposes. Each tool bakes the peer's --name into its description at registration time so auto-routing works ("Ivan reported X" → Ivan's server). The ambiguity contract on get_current_session is also spelled out in the description so a consuming Claude doesn't need an external CLAUDE.md block to behave correctly on multi-live-session peers.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Register

func Register(s *mcp.Server, ctx Context)

Register wires the always-on Phase-1 tools onto an already- constructed mcp.Server, plus any Phase-2 tools whose dependencies are present in ctx.

Types

type AskPeerClaudeInput

type AskPeerClaudeInput struct {
	Prompt         string `json:"prompt" jsonschema:"the question or instruction to send to the peer's Claude"`
	Project        string `json:"project,omitempty" jsonschema:"working directory the agent's tools see (default: hearsay's cwd)"`
	MaxTokens      int    `json:"max_tokens,omitempty"`
	MaxToolCalls   int    `json:"max_tool_calls,omitempty"`
	TimeoutSeconds int    `json:"timeout_seconds,omitempty"`
}

AskPeerClaudeInput is the wire shape the calling Claude sees. All budget fields are optional and cascade through call → server defaults.

type AskPeerClaudeOutput

type AskPeerClaudeOutput struct {
	Body          string `json:"body,omitempty"`
	TurnCount     int    `json:"turnCount,omitempty"`
	ToolCallCount int    `json:"toolCallCount,omitempty"`
	StopReason    string `json:"stopReason,omitempty"`
	ElapsedMs     int64  `json:"elapsedMs,omitempty"`
	ErrorSummary  string `json:"errorSummary,omitempty"`
}

AskPeerClaudeOutput carries the model's response body alongside the per-call metadata.

The body lives in StructuredContent (this struct) AND in Content as a fallback. Why both: PR #14 made StructuredContent empty on the theory that consumers would fall back to Content — but Claude Code-class clients render StructuredContent when present (even `{}`), silently dropping Content. Putting the body into the structured channel makes the response visible regardless of which channel the consumer prefers.

type Context

type Context struct {
	PeerName    string
	PeerVersion string
	DataDir     string
	LiveWindow  time.Duration
	Log         func(tool, status string, dur time.Duration)

	// Agent is non-nil only when --enable-agent was passed; nil
	// keeps Phase-1 behavior (the 8 read-only tools, no ask_peer_claude).
	Agent agent.Agent
}

Context bundles the settings every tool handler needs. It's built once in main.go and passed into Register.

type EffectiveBudgetOutput

type EffectiveBudgetOutput struct {
	MaxTokens      int   `json:"maxTokens"`
	MaxToolCalls   int   `json:"maxToolCalls"`
	TimeoutSeconds int64 `json:"timeoutSeconds"`
}

EffectiveBudgetOutput echoes the resolved budget back so callers know what they're inheriting before deciding to override per turn.

type EndPeerConversationInput

type EndPeerConversationInput struct {
	ConvID string `json:"convId"`
}

type EndPeerConversationOutput

type EndPeerConversationOutput struct {
	Ended        bool   `json:"ended"`
	AlreadyEnded bool   `json:"alreadyEnded"`
	TotalTurns   int    `json:"totalTurns"`
	EndedReason  string `json:"endedReason"`
}

type GetCurrentSessionInput

type GetCurrentSessionInput struct {
	Project string `json:"project,omitempty" jsonschema:"optional project filter (same semantics as list_sessions.project)"`
}

type GetCurrentSessionOutput

type GetCurrentSessionOutput struct {
	Ambiguous  bool                        `json:"ambiguous"`
	Session    *transcript.SessionSummary  `json:"session"`
	Candidates []transcript.SessionSummary `json:"candidates,omitempty"`
}

GetCurrentSessionOutput honors the ambiguity contract from the plan:

  • exactly one live session: {ambiguous: false, session: <it>}
  • no live session: {ambiguous: false, session: null}
  • multiple live sessions: {ambiguous: true, candidates: [...]}

The calling Claude is instructed (via the tool description) to ASK the user when ambiguous=true rather than silently pick one.

type GetPeerInfoInput

type GetPeerInfoInput struct{}

type GetPeerInfoOutput

type GetPeerInfoOutput struct {
	Name               string `json:"name"`
	Version            string `json:"version"`
	SessionCount       int    `json:"sessionCount"`
	ActiveSessionCount int    `json:"activeSessionCount"`
}

type GetSessionSummaryInput

type GetSessionSummaryInput struct {
	SessionID string `json:"sessionId"`
}

type GetSessionSummaryOutput

type GetSessionSummaryOutput struct {
	SessionID         string          `json:"sessionId"`
	FirstUserMessage  string          `json:"firstUserMessage,omitempty"`
	ToolCallCount     int             `json:"toolCallCount"`
	UniqueToolNames   []string        `json:"uniqueToolNames"`
	Subagents         []SubagentEntry `json:"subagents"`
	LastAssistantText string          `json:"lastAssistantText,omitempty"`
}

type ListPeerConversationsInput

type ListPeerConversationsInput struct{}

type ListPeerConversationsOutput

type ListPeerConversationsOutput struct {
	Conversations []PeerConversationSummary `json:"conversations"`
}

type ListSessionsInput

type ListSessionsInput struct {
	Project string `json:"project,omitempty" jsonschema:"short project name (substring match on the decoded cwd) or full path"`
	Since   string `json:"since,omitempty" jsonschema:"ISO8601 — only return sessions with lastActivityAt >= since"`
	Limit   int    `json:"limit,omitempty" jsonschema:"max results (default 20)"`
}

ListSessionsInput is the tool argument type. Struct tags drive both the JSON schema presented to MCP clients and the jsonschema-inferred docs.

type ListSessionsOutput

type ListSessionsOutput struct {
	Sessions []transcript.SessionSummary `json:"sessions"`
}

type PeerConversationSummary

type PeerConversationSummary struct {
	ConvID         string    `json:"convId"`
	StartedAt      time.Time `json:"startedAt"`
	LastActivityAt time.Time `json:"lastActivityAt"`
	TurnCount      int       `json:"turnCount"`
	Preview        string    `json:"preview"`
}

type ReadSessionInput

type ReadSessionInput struct {
	SessionID string `json:"sessionId" jsonschema:"session UUID from list_sessions or get_current_session"`
	FromTurn  int    `json:"fromTurn,omitempty" jsonschema:"inclusive start turn (default 0)"`
	ToTurn    int    `json:"toTurn,omitempty" jsonschema:"exclusive end turn (0 means end)"`
	Format    string `json:"format,omitempty" jsonschema:"'full' (default) returns markdown + JSON metadata; 'json' returns metadata only"`
}

type ReadSessionOutput

type ReadSessionOutput struct {
	// Body holds the rendered markdown for format="full" (the default);
	// it is omitted for format="json".  See the AskPeerClaudeOutput
	// docstring for why the body lives in StructuredContent rather than
	// only in Content — Claude Code-class clients render the structured
	// channel and silently drop the Content channel when both exist.
	Body            string `json:"body,omitempty"`
	SessionID       string `json:"sessionId"`
	TotalTurns      int    `json:"totalTurns"`
	RenderedTurns   int    `json:"renderedTurns"`
	NextCursor      *int   `json:"nextCursor,omitempty"`
	PartialLastLine bool   `json:"partialLastLine"`
}

type ReadSubagentInput

type ReadSubagentInput struct {
	SessionID string `json:"sessionId"`
	AgentUUID string `json:"agentUuid" jsonschema:"the tool_use.id of an Agent-tool call shown in read_session output"`
	FromTurn  int    `json:"fromTurn,omitempty"`
	ToTurn    int    `json:"toTurn,omitempty"`
}

type ReadSubagentOutput

type ReadSubagentOutput struct {
	SessionID       string `json:"sessionId"`
	AgentID         string `json:"agentId"`
	AgentType       string `json:"agentType,omitempty"`
	Description     string `json:"description,omitempty"`
	TotalTurns      int    `json:"totalTurns"`
	RenderedTurns   int    `json:"renderedTurns"`
	NextCursor      *int   `json:"nextCursor,omitempty"`
	PartialLastLine bool   `json:"partialLastLine"`
}

type ReadToolResultInput

type ReadToolResultInput struct {
	SessionID string `json:"sessionId"`
	ToolUseID string `json:"toolUseId"`
	MaxBytes  int    `json:"maxBytes,omitempty" jsonschema:"default 65536"`
}

type ReadToolResultOutput

type ReadToolResultOutput struct{}

ReadToolResultOutput is intentionally empty in PR 0.

Phase 1 returned the body in a TextContent block AND a populated StructuredContent block ({source, truncated, bytes}). Some MCP consumers surfaced only the structured channel back to the calling model, which experienced as "metadata-only" reads against large sidecars. To make the body the unconditional source of truth, the metadata is now inlined as a leading line in the body text:

[source=sidecar, bytes=12345, truncated=false]

<actual content...>

The other Phase-1 tools keep markdown + StructuredContent metadata — this is a targeted exception, not a deprecation of the convention.

type SearchMatch

type SearchMatch struct {
	TurnIndex        int              `json:"turnIndex"`
	MatchedText      string           `json:"matchedText"`
	SurroundingTurns []map[string]any `json:"surroundingTurns"`
}

type SearchSessionInput

type SearchSessionInput struct {
	SessionID    string `json:"sessionId"`
	Query        string `json:"query" jsonschema:"literal substring (case-insensitive)"`
	ContextTurns int    `json:"contextTurns,omitempty" jsonschema:"context turns on each side (default 3)"`
}

type SearchSessionOutput

type SearchSessionOutput struct {
	Query        string        `json:"query"`
	TotalMatches int           `json:"totalMatches"`
	Matches      []SearchMatch `json:"matches"`
}

type SendPeerMessageInput

type SendPeerMessageInput struct {
	ConvID         string `json:"convId" jsonschema:"the conversation handle returned by start_peer_conversation"`
	Prompt         string `json:"prompt" jsonschema:"the next user message in the conversation"`
	MaxTokens      int    `json:"max_tokens,omitempty"`
	MaxToolCalls   int    `json:"max_tool_calls,omitempty"`
	TimeoutSeconds int    `json:"timeout_seconds,omitempty"`
}

type SendPeerMessageOutput

type SendPeerMessageOutput = AskPeerClaudeOutput

SendPeerMessageOutput mirrors AskPeerClaudeOutput: per-turn body + metadata in StructuredContent, body duplicated into Content as a fallback. See the AskPeerClaudeOutput doc for the rationale.

type StartPeerConversationInput

type StartPeerConversationInput struct {
	SystemPrompt   string `json:"system_prompt,omitempty" jsonschema:"optional system prompt seeded on the conversation"`
	Project        string `json:"project,omitempty" jsonschema:"working directory for the agent's tools (default: hearsay's cwd)"`
	MaxTokens      int    `json:"max_tokens,omitempty"`
	MaxToolCalls   int    `json:"max_tool_calls,omitempty"`
	TimeoutSeconds int    `json:"timeout_seconds,omitempty"`
}

type StartPeerConversationOutput

type StartPeerConversationOutput struct {
	ConvID          string                `json:"convId"`
	StartedAt       time.Time             `json:"startedAt"`
	EffectiveBudget EffectiveBudgetOutput `json:"effectiveBudget"`
}

type SubagentEntry

type SubagentEntry struct {
	AgentID     string `json:"agentId"`
	AgentType   string `json:"agentType,omitempty"`
	Description string `json:"description,omitempty"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL