Documentation
¶
Overview ¶
Package core defines protocol-level types shared across Whale subsystems.
Keep this package limited to stable data structures and pure helpers with no filesystem, network, UI, or agent runtime side effects. Business flow belongs in agent/app/tools/tui packages instead of here.
Index ¶
- Constants
- func ApplyDisplayToolNames(text string) string
- func AsAnySlice(v any) []any
- func AsString(v any) string
- func BoundedTruncationPayload(text string, originalChars int, code, archivePath string) map[string]any
- func CanonicalToolName(modelName string) string
- func CanonicalizeToolPayload(env ToolEnvelope) map[string]any
- func ContainsArg(argv []string, want string) bool
- func DisplayToolName(internal string) string
- func FirstLine(s string) string
- func FirstNonEmpty(values ...string) string
- func FlattenSchemaForModel(parameters map[string]any) map[string]any
- func IsReadOnlyToolCall(spec ToolSpec, call ToolCall) bool
- func IsSessionJSONLName(name string) bool
- func LastShellCommandSegment(command string) string
- func MarshalToolEnvelope(env ToolEnvelope) (string, error)
- func MarshalToolJSON(v any) ([]byte, error)
- func MessagePartsPlainText(parts []MessagePart) string
- func MessagePlainText(msg Message) string
- func PathInside(path, parent string) (bool, error)
- func ProviderToolPayload(tool Tool) map[string]any
- func RenderToolResultText(name string, outcome ToolOutcome, code string, payload map[string]any) string
- func RenderTruncatedToolText(text string, maxChars int, archivePath string) string
- func RenestFlatInputForSpec(spec ToolSpec, raw string) (string, bool)
- func SanitizeSessionID(v string) string
- func ShellExitMeansNoMatches(command string, exitCode int, stdout, stderr string) bool
- func ShellExitMessage(command string, exitCode int, stdout, stderr string) string
- func ShellSegmentBaseCommand(segment string) string
- func ShouldFlattenSchema(parameters map[string]any) bool
- func SkillNameDisabled(name string, disabled []string) bool
- func ToolInputRecoveryHint(toolName, msg string) (string, bool)
- func ToolResultModelText(r ToolResult) string
- func WithToolResultArchive(ctx context.Context, dir, sessionID string) context.Context
- type AttachmentKind
- type AttachmentRef
- type FinishReason
- type Message
- type MessagePart
- type MessagePartType
- type MessageUsage
- type ProviderToolPayloadProvider
- type ProviderToolSchemaCache
- type Role
- type SubagentStep
- type Tool
- type ToolApprovalHint
- type ToolCall
- type ToolCapabilities
- type ToolDescriber
- type ToolEnvelope
- type ToolInputRepair
- type ToolOutcome
- type ToolParamSpec
- type ToolPreviewer
- type ToolProgress
- type ToolProgressRunner
- type ToolReadOnly
- type ToolReadOnlyCheck
- type ToolRegistry
- func (r *ToolRegistry) Dispatch(ctx context.Context, call ToolCall) (ToolResult, error)
- func (r *ToolRegistry) DispatchWithProgress(ctx context.Context, call ToolCall, progress func(ToolProgress)) (ToolResult, error)
- func (r *ToolRegistry) Get(name string) Tool
- func (r *ToolRegistry) ReplaceTools(tools []Tool) error
- func (r *ToolRegistry) SetMaxResultChars(limit int)
- func (r *ToolRegistry) Snapshot() *ToolRegistry
- func (r *ToolRegistry) Spec(name string) (ToolSpec, bool)
- func (r *ToolRegistry) Specs() []ToolSpec
- func (r *ToolRegistry) Tools() []Tool
- type ToolResult
- func FinalizeToolResultChannels(res ToolResult) ToolResult
- func NewToolResultError(call ToolCall, code, msg string, data map[string]any) ToolResult
- func NewToolResultFromEnvelope(call ToolCall, env ToolEnvelope, metadata map[string]any) ToolResult
- func NewToolResultSuccess(call ToolCall, data map[string]any, metadata map[string]any) ToolResult
- type ToolSpec
- type ToolSupportsParallel
- type UserInputAnswer
- type UserInputOption
- type UserInputQuestion
- type UserInputRequest
- type UserInputResponse
Constants ¶
const ( // ToolInputEventsSuffix is the filename suffix for tool input event logs. ToolInputEventsSuffix = ".tool_input_events.jsonl" // ApprovalEventsSuffix is the filename suffix for approval event logs. ApprovalEventsSuffix = ".approval_events.jsonl" )
const ( ToolInputRepairNullOptionalOmitted = "null_optional_omitted" ToolInputRepairStringifiedArray = "stringified_array" ToolInputRepairBareStringToArray = "bare_string_to_array" ToolInputRepairEmptyObjectToArray = "empty_object_to_array" ToolInputRepairMarkdownAutolinkPath = "markdown_autolink_path" ToolInputRepairSemanticBoolean = "semantic_boolean_string" ToolInputRepairSemanticInteger = "semantic_integer_string" )
const DefaultMaxToolResultChars = 32 * 1024
Variables ¶
This section is empty.
Functions ¶
func ApplyDisplayToolNames ¶ added in v0.1.50
ApplyDisplayToolNames rewrites internal tool names to their model-facing display names within free-form text (tool descriptions, guidance prose) so authored copy stays consistent with the schema without every string having to call DisplayToolName itself. Only snake_case names are rewritten, with word boundaries, so ordinary prose (and capability literals such as "workspace.write") is never corrupted. This is cosmetic: even if a name slips through, the model-supplied name still resolves because the tool remains registered under its internal name.
func AsAnySlice ¶ added in v0.1.24
AsAnySlice extracts a []any value, returning nil on mismatch or nil input.
func AsString ¶ added in v0.1.24
AsString extracts a string value from any type, returning empty string on mismatch.
func BoundedTruncationPayload ¶ added in v0.1.48
func BoundedTruncationPayload(text string, originalChars int, code, archivePath string) map[string]any
BoundedTruncationPayload replaces the full canonical payload when the rendered text was truncated, so large results are not persisted twice.
func CanonicalToolName ¶ added in v0.1.50
CanonicalToolName normalizes a model-supplied tool name to whale's internal name, accepting the conventional display name and known aliases case-insensitively. Unrecognized names pass through unchanged (trimmed), so genuinely unknown tools still surface as "tool not found" downstream.
func CanonicalizeToolPayload ¶ added in v0.1.48
func CanonicalizeToolPayload(env ToolEnvelope) map[string]any
CanonicalizeToolPayload converts envelope data into the canonical payload form: a JSON-typed map (strings, float64, bool, nested maps/slices) that is byte- and type-identical whether read before persistence or after a save/load cycle. Envelope fields without a struct home travel as reserved keys ("message", "summary", "truncated").
func ContainsArg ¶ added in v0.1.24
ContainsArg reports whether want is present in argv.
func DisplayToolName ¶ added in v0.1.50
DisplayToolName returns the model-facing name for an internal tool name. Names without a mapping pass through unchanged.
func FirstLine ¶ added in v0.1.24
FirstLine returns the first line of s (up to the first newline), trimmed. Returns the full trimmed input if there is no newline.
func FirstNonEmpty ¶ added in v0.1.24
FirstNonEmpty returns the first non-empty (after trimming whitespace) variadic string argument. Returns "" if all values are empty.
func FlattenSchemaForModel ¶
FlattenSchemaForModel flattens nested object properties into dotted keys (for example: payload.path) to reduce nested JSON generation errors.
func IsReadOnlyToolCall ¶
func IsSessionJSONLName ¶ added in v0.1.24
IsSessionJSONLName reports whether name is a session JSONL file (not tool input or approval events).
func LastShellCommandSegment ¶ added in v0.1.47
LastShellCommandSegment returns the final command in a pipe/&&/; chain, skipping separators inside quotes. The last segment determines the chain's exit code.
func MarshalToolEnvelope ¶
func MarshalToolEnvelope(env ToolEnvelope) (string, error)
MarshalToolEnvelope serializes the model-facing tool result. HTML escaping must stay off: the model reads this text and copies payload fragments (file content, shell commands) back into edit/write inputs, so & < > have to survive byte-for-byte. Session 019ead56 documents the failure mode.
func MarshalToolJSON ¶ added in v0.1.47
MarshalToolJSON serializes any model-visible tool JSON without HTML escaping. Use this instead of json.Marshal whenever the output becomes ToolResult.ModelText: the model reads that text raw, so json.Marshal's HTML escaping would corrupt every payload containing & < >.
func MessagePartsPlainText ¶ added in v0.1.39
func MessagePartsPlainText(parts []MessagePart) string
func MessagePlainText ¶ added in v0.1.39
func PathInside ¶ added in v0.1.24
PathInside reports whether path is inside parent (or equal to parent), resolving symlinks through the nearest existing ancestor for accurate boundary checking even when the final path does not exist yet.
func ProviderToolPayload ¶ added in v0.1.38
func RenderToolResultText ¶ added in v0.1.48
func RenderToolResultText(name string, outcome ToolOutcome, code string, payload map[string]any) string
RenderToolResultText renders the model-visible text of a tool result from its canonical payload. This is the phase-2 replacement for serializing the JSON envelope: a compact status header, the content verbatim (never re-escaped), and prefixed trailing lines (note:/warning:/diagnosis:/ recovery:/data:). Deterministic: map rendering goes through MarshalToolJSON (sorted keys), no timestamps.
func RenderTruncatedToolText ¶ added in v0.1.48
RenderTruncatedToolText bounds rendered text to maxChars with a head/tail split and an omission marker; archivePath (optional) points at the full text archived on disk.
func RenestFlatInputForSpec ¶
RenestFlatInputForSpec turns dotted keys back into nested objects when the tool schema is flattened for model interaction.
func SanitizeSessionID ¶ added in v0.1.24
SanitizeSessionID sanitizes a session ID for use in filenames. Non-alphanumeric characters (except - and _) are replaced with _.
func ShellExitMeansNoMatches ¶ added in v0.1.47
ShellExitMeansNoMatches reports whether a finished command's exit status conveys "no matches / no results" rather than failure. It keys on the last command segment because that is what determines the exit code. Commands frequently merge streams with 2>&1, so the rules must not assume error text stays on stderr — each command gets the strongest signal its actual behavior allows.
func ShellExitMessage ¶ added in v0.1.55
ShellExitMessage returns a human-readable interpretation of a non-zero exit code for the final command in a pipe/&&/; chain. It keys on the last command segment because that is what determines the exit code.
Commands already classified by ShellExitMeansNoMatches (grep, rg, git grep, where, findstr, dir) are excluded here — their exit-1 semantics are handled by the no-match rendering path. This function covers commands whose non-zero exit codes have well-documented meanings beyond "no matches".
Returns "" when no specific interpretation exists.
func ShellSegmentBaseCommand ¶ added in v0.1.47
ShellSegmentBaseCommand extracts the command word a segment's exit-code semantics are keyed on ("git grep" is kept as a unit).
func ShouldFlattenSchema ¶
ShouldFlattenSchema reports whether a tool schema is deep/wide enough to benefit from flattened argument keys for model-side tool calling.
func SkillNameDisabled ¶ added in v0.1.24
SkillNameDisabled reports whether name is in the disabled list. Comparison is case-insensitive with whitespace trimmed.
func ToolInputRecoveryHint ¶ added in v0.1.35
func ToolResultModelText ¶ added in v0.1.48
func ToolResultModelText(r ToolResult) string
ToolResultModelText returns the model-visible text of a result.
Types ¶
type AttachmentKind ¶ added in v0.1.39
type AttachmentKind string
const ( AttachmentKindImage AttachmentKind = "image" AttachmentKindPDF AttachmentKind = "pdf" AttachmentKindAudio AttachmentKind = "audio" AttachmentKindFile AttachmentKind = "file" )
type AttachmentRef ¶ added in v0.1.39
type AttachmentRef struct {
Kind AttachmentKind `json:"kind"`
Path string `json:"path,omitempty"`
OriginalPath string `json:"original_path,omitempty"`
MIME string `json:"mime,omitempty"`
Filename string `json:"filename,omitempty"`
SizeBytes int64 `json:"size_bytes,omitempty"`
SHA256 string `json:"sha256,omitempty"`
DisplayName string `json:"display_name,omitempty"`
}
type FinishReason ¶
type FinishReason string
const ( FinishReasonEndTurn FinishReason = "end_turn" FinishReasonToolUse FinishReason = "tool_use" FinishReasonCanceled FinishReason = "canceled" FinishReasonError FinishReason = "error" )
type Message ¶
type Message struct {
ID string
SessionID string
Role Role
Text string
Parts []MessagePart `json:"parts,omitempty"`
Hidden bool
Reasoning string
ToolCalls []ToolCall
ToolResults []ToolResult
FinishReason FinishReason
CreatedAt time.Time
UpdatedAt time.Time
// Usage carries the provider-reported token accounting for assistant
// turns; ErrorDetail preserves the failure reason for turns that end
// with FinishReasonError (session analysis was previously impossible:
// error turns persisted with empty text and no cause).
Usage *MessageUsage `json:"Usage,omitempty"`
ErrorDetail string `json:"ErrorDetail,omitempty"`
}
func NormalizeMessageContent ¶ added in v0.1.39
func TextMessage ¶ added in v0.1.39
func UserMessageFromParts ¶ added in v0.1.39
func UserMessageFromParts(sessionID string, parts []MessagePart, hidden bool) Message
type MessagePart ¶ added in v0.1.39
type MessagePart struct {
Type MessagePartType `json:"type"`
Text string `json:"text,omitempty"`
Attachment *AttachmentRef `json:"attachment,omitempty"`
}
type MessagePartType ¶ added in v0.1.39
type MessagePartType string
const ( MessagePartText MessagePartType = "text" MessagePartAttachment MessagePartType = "attachment" MessagePartPlan MessagePartType = "plan" )
type MessageUsage ¶ added in v0.1.48
type MessageUsage struct {
PromptTokens int `json:"prompt_tokens,omitempty"`
CompletionTokens int `json:"completion_tokens,omitempty"`
PromptCacheHitTokens int `json:"prompt_cache_hit_tokens,omitempty"`
PromptCacheMissTokens int `json:"prompt_cache_miss_tokens,omitempty"`
}
MessageUsage is the per-turn token accounting persisted with assistant messages, sourced from the provider's usage response.
type ProviderToolPayloadProvider ¶ added in v0.1.38
type ProviderToolSchemaCache ¶ added in v0.1.38
type ProviderToolSchemaCache struct {
// contains filtered or unexported fields
}
func NewProviderToolSchemaCache ¶ added in v0.1.38
func NewProviderToolSchemaCache() *ProviderToolSchemaCache
type SubagentStep ¶ added in v0.1.24
type ToolApprovalHint ¶
type ToolApprovalHint interface {
ApprovalHint() string
}
type ToolCapabilities ¶
type ToolCapabilities interface {
Capabilities() []string
}
type ToolDescriber ¶
type ToolDescriber interface {
Description() string
}
type ToolEnvelope ¶
type ToolEnvelope struct {
OK bool `json:"ok"`
Success bool `json:"success"`
Error string `json:"error,omitempty"`
Message string `json:"message,omitempty"`
Code string `json:"code,omitempty"`
Summary string `json:"summary,omitempty"`
Data map[string]any `json:"data,omitempty"`
Truncated bool `json:"truncated,omitempty"`
Meta map[string]any `json:"meta,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
func NewToolErrorEnvelope ¶
func NewToolErrorEnvelope(code, message string) ToolEnvelope
func NewToolSuccessEnvelope ¶
func NewToolSuccessEnvelope(data map[string]any) ToolEnvelope
func ParseToolEnvelope ¶
func ParseToolEnvelope(raw string) (ToolEnvelope, bool)
func ToolEnvelopeView ¶ added in v0.1.48
func ToolEnvelopeView(res ToolResult) (ToolEnvelope, bool)
ToolEnvelopeView rebuilds the legacy envelope view from the structured channel so existing envelope-shaped consumers keep working; text parsing remains only for results that predate the channel separation.
type ToolInputRepair ¶ added in v0.1.10
func RepairToolInputForSpec ¶ added in v0.1.10
func RepairToolInputForSpec(spec ToolSpec, raw string) (string, []ToolInputRepair)
RepairToolInputForSpec applies narrowly scoped, schema-guided repairs to common tool-call argument shape mistakes. Valid inputs are returned unchanged.
type ToolOutcome ¶ added in v0.1.48
type ToolOutcome string
ToolOutcome is the protocol-level disposition of a tool result. It is the single source for "is this an error" across the agent loop, the TUI, and telemetry; OutcomeNoResult exists so "searched fine, found nothing" stops being conflated with failure.
const ( OutcomeSuccess ToolOutcome = "success" OutcomeNoResult ToolOutcome = "no_result" OutcomeFailure ToolOutcome = "failure" OutcomeTimeout ToolOutcome = "timeout" OutcomeCancelled ToolOutcome = "cancelled" OutcomeBlocked ToolOutcome = "blocked" )
func OutcomeForErrorCode ¶ added in v0.1.48
func OutcomeForErrorCode(code string) ToolOutcome
OutcomeForErrorCode maps a machine-readable error code to its outcome so every error producer classifies uniformly.
func ToolResultOutcome ¶ added in v0.1.48
func ToolResultOutcome(r ToolResult) ToolOutcome
ToolResultOutcome returns the protocol outcome, deriving it for results whose producer has not classified them yet (raw envelope in ModelText).
type ToolParamSpec ¶
type ToolPreviewer ¶ added in v0.1.2
type ToolProgress ¶ added in v0.1.5
type ToolProgressRunner ¶ added in v0.1.5
type ToolProgressRunner interface {
RunWithProgress(ctx context.Context, call ToolCall, progress func(ToolProgress)) (ToolResult, error)
}
type ToolReadOnly ¶
type ToolReadOnly interface {
ReadOnly() bool
}
type ToolReadOnlyCheck ¶
type ToolRegistry ¶
type ToolRegistry struct {
// contains filtered or unexported fields
}
func NewToolRegistry ¶
func NewToolRegistry(tools []Tool) *ToolRegistry
func NewToolRegistryChecked ¶
func NewToolRegistryChecked(tools []Tool) (*ToolRegistry, error)
func (*ToolRegistry) Dispatch ¶
func (r *ToolRegistry) Dispatch(ctx context.Context, call ToolCall) (ToolResult, error)
func (*ToolRegistry) DispatchWithProgress ¶ added in v0.1.5
func (r *ToolRegistry) DispatchWithProgress(ctx context.Context, call ToolCall, progress func(ToolProgress)) (ToolResult, error)
func (*ToolRegistry) Get ¶
func (r *ToolRegistry) Get(name string) Tool
func (*ToolRegistry) ReplaceTools ¶ added in v0.1.6
func (r *ToolRegistry) ReplaceTools(tools []Tool) error
func (*ToolRegistry) SetMaxResultChars ¶
func (r *ToolRegistry) SetMaxResultChars(limit int)
func (*ToolRegistry) Snapshot ¶ added in v0.1.23
func (r *ToolRegistry) Snapshot() *ToolRegistry
func (*ToolRegistry) Specs ¶
func (r *ToolRegistry) Specs() []ToolSpec
func (*ToolRegistry) Tools ¶
func (r *ToolRegistry) Tools() []Tool
type ToolResult ¶
type ToolResult struct {
ToolCallID string
Name string
Metadata map[string]any `json:"metadata,omitempty"`
Outcome ToolOutcome `json:"Outcome,omitempty"`
Code string `json:"Code,omitempty"`
Payload any `json:"Payload,omitempty"`
ModelText string `json:"ModelText,omitempty"`
}
ToolResult is channel-separated: Outcome/Code/Payload are the structured channel for the TUI, recovery, and evals; ModelText is the only text the model sees, rendered once at creation and never re-rendered. Tools that still produce a legacy envelope put it in ModelText; the dispatch funnel re-derives and re-renders it. Error-ness is derived from Outcome via IsError().
func FinalizeToolResultChannels ¶ added in v0.1.48
func FinalizeToolResultChannels(res ToolResult) ToolResult
FinalizeToolResultChannels backfills the channel-separated fields on a result produced outside the dispatch funnel (agent special tools, blocked markers, recovery wrappers, abort-skip placeholders). ModelText takes the Content bytes verbatim; Outcome/Code/Payload are derived exactly the way the legacy session decoder derives them, so a result finalized live and the same result reloaded from an old session file classify identically. Idempotent: results that already carry ModelText pass through unchanged.
func NewToolResultError ¶ added in v0.1.48
func NewToolResultError(call ToolCall, code, msg string, data map[string]any) ToolResult
NewToolResultError wraps an error code/message (with optional data) in the standard error envelope.
func NewToolResultFromEnvelope ¶ added in v0.1.48
func NewToolResultFromEnvelope(call ToolCall, env ToolEnvelope, metadata map[string]any) ToolResult
NewToolResultFromEnvelope is the sanctioned producer for tool results. ModelText is rendered exactly once here; phase 1 renders it with the legacy envelope serializer so model-visible bytes are unchanged, phase 2 swaps the renderer for plain text.
func NewToolResultSuccess ¶ added in v0.1.48
NewToolResultSuccess wraps map data in the standard success envelope.
func (ToolResult) IsError ¶
func (r ToolResult) IsError() bool
IsError reports whether the result is a failure-class outcome. OutcomeNoResult ("searched fine, found nothing") is not an error. Unclassified results (raw envelope in ModelText, pre-funnel) derive their outcome on the fly so the answer never depends on which side of the dispatch funnel the caller sits.
func (ToolResult) MarshalJSON ¶ added in v0.1.48
func (r ToolResult) MarshalJSON() ([]byte, error)
func (*ToolResult) UnmarshalJSON ¶ added in v0.1.48
func (r *ToolResult) UnmarshalJSON(b []byte) error
type ToolSpec ¶
type ToolSpec struct {
Name string
Description string
Parameters map[string]any
ReadOnly bool
ReadOnlyCheck func(args map[string]any) bool
Capabilities []string
ApprovalHint string
SupportsParallel bool
}
func DescribeTool ¶
type ToolSupportsParallel ¶
type ToolSupportsParallel interface {
SupportsParallel() bool
}
type UserInputAnswer ¶
type UserInputOption ¶
type UserInputQuestion ¶
type UserInputQuestion struct {
Header string `json:"header"`
ID string `json:"id"`
Question string `json:"question"`
Options []UserInputOption `json:"options"`
}
type UserInputRequest ¶
type UserInputRequest struct {
Questions []UserInputQuestion `json:"questions"`
}
type UserInputResponse ¶
type UserInputResponse struct {
Answers []UserInputAnswer `json:"answers"`
}