UNPKG

graphlit-client

Version:
245 lines (244 loc) 8.76 kB
import { ConversationMessage, ConversationMessageInput, ConversationToolCall, EntityReferenceInput, ContentCriteriaInput, ToolDefinitionInput, Specification, ToolExecutionStatus } from "../generated/graphql-types.js"; import type { AgentStreamEvent } from "./ui-events.js"; export interface ArtifactCollector { addPending(promise: Promise<{ id: string; } | undefined>): void; resolve(): Promise<{ id: string; }[]>; } export type ToolHandler = (args: any, artifacts?: ArtifactCollector, abortSignal?: AbortSignal) => Promise<any>; export interface ContextStrategy { /** Max tokens for any single tool result. Results exceeding this are truncated. Default: 8192 */ toolResultTokenLimit?: number; /** Max tool call/response rounds to keep in context. Older rounds are dropped FIFO. Default: 10 */ toolRoundLimit?: number; /** Fraction of token budget (0.0-1.0) at which client-side windowing is triggered. Default: 0.75 */ rebudgetThreshold?: number; } export interface AgentOptions { maxToolRounds?: number; timeout?: number; contextStrategy?: ContextStrategy; } export interface AgentMetrics { totalTime: number; llmTime?: number; toolTime?: number; ttft?: number; tokensPerSecond?: number; toolExecutions?: number; rounds?: number; } export interface ContextWindowUsage { usedTokens: number; maxTokens: number; percentage: number; remainingTokens: number; } export type ContextManagementAction = { type: "truncated_tool_result"; toolName: string; originalTokens: number; truncatedTokens: number; } | { type: "windowed_tool_rounds"; droppedRounds: number; keptRounds: number; }; export interface AgentResult { message: string; conversationId: string; conversationMessage?: ConversationMessage; toolCalls?: ConversationToolCall[]; toolResults?: ToolCallResult[]; metrics?: AgentMetrics; usage?: UsageInfo; contextWindow?: ContextWindowUsage; contextActions?: ContextManagementAction[]; error?: AgentError; } export interface StreamAgentOptions { maxToolRounds?: number; abortSignal?: AbortSignal; smoothingEnabled?: boolean; chunkingStrategy?: "character" | "word" | "sentence"; smoothingDelay?: number; contextStrategy?: ContextStrategy; /** Default eligible OpenAI GPT-5.4+ models to Responses; false forces legacy Chat Completions. */ useResponsesApi?: boolean; /** Harness-injected instructions appended to the formatted conversation (e.g. wind-down, stuck intervention). */ instructions?: string; /** Harness-injected scratchpad text, merged with conversation scratchpad. Placed right before user-prompt. */ scratchpad?: string; /** Skill references to inject into the agent's context window. Retrieved via querySkills, passed by reference. */ skills?: EntityReferenceInput[]; /** Stable, caller-supplied system-channel content to append after the specification system prompt. */ additionalSystemInstructions?: string; /** Ordered fallback specifications to try for native streaming after retryable provider failures. */ fallbacks?: EntityReferenceInput[]; } export interface ToolCallResult { id: string; name: string; arguments: any; result?: any; error?: string; startedAt?: string; completedAt?: string; durationMs?: number; failedAt?: string; status?: ToolExecutionStatus; /** @deprecated Use durationMs instead. */ duration?: number; } export interface UsageInfo { promptTokens: number; completionTokens: number; totalTokens: number; cost?: number; model?: string; /** Provider-reported cached input tokens, when available. */ cachedInputTokens?: number; /** Anthropic cache-write tokens, when available. */ cacheCreationInputTokens?: number; /** Anthropic cache-read tokens, when available. */ cacheReadInputTokens?: number; /** Provider-specific usage details. */ metadata?: Record<string, unknown>; } export interface AgentError { message: string; code?: string; recoverable: boolean; details?: Record<string, unknown>; } /** Terminal status of a runAgent execution. */ export type HarnessStatus = "completed" | "budget_exhausted" | "stuck" | "error" | "cancelled"; /** Per-turn data captured by the harness. */ export interface TurnResult { turnNumber: number; prompt: string; responseText: string; toolCalls: string[]; toolCallCount: number; durationMs: number; taskComplete?: boolean; contextWindowUsage?: ContextWindowUsage; contextActions?: ContextManagementAction[]; errors?: string[]; /** Token usage for this turn (from native LLM provider). */ usage?: UsageInfo; } /** Budget snapshot passed to the onBudgetWarning callback. */ export interface BudgetSnapshot { turnsUsed: number; turnsRemaining: number; toolCallsUsed: number; toolCallsRemaining: number; wallClockMs: number; wallClockMsRemaining: number; contextWindowPercent?: number; } /** Result of stuck-pattern evaluation for a single turn. */ export interface StuckEvaluation { stuck: boolean; pattern?: string; firstOccurrence?: boolean; } /** Options for the runAgent multi-turn harness. */ export interface RunAgentOptions { conversationId?: string; tools?: ToolDefinitionInput[]; toolHandlers?: Record<string, ToolHandler>; persona?: EntityReferenceInput; augmentedFilter?: ContentCriteriaInput; maxTurns?: number; maxWallClockMs?: number; maxToolCalls?: number; windDownTurns?: number; onTurnComplete?: (turn: TurnResult) => void; onBudgetWarning?: (snapshot: BudgetSnapshot) => void; onStreamEvent?: (event: AgentStreamEvent) => void; abortSignal?: AbortSignal; contextStrategy?: ContextStrategy; instructions?: string; correlationId?: string; qualityAssessment?: boolean; qualityAssessmentSpecification?: EntityReferenceInput; smoothingEnabled?: boolean; chunkingStrategy?: "character" | "word" | "sentence"; smoothingDelay?: number; useResponsesApi?: boolean; /** Skill references to inject into the agent's context window. Retrieved via querySkills, passed by reference. */ skills?: EntityReferenceInput[]; /** Stable, caller-supplied system-channel content to append after the specification system prompt. */ additionalSystemInstructions?: string; } /** Quality assessment scores from LLM-as-judge post-run evaluation. */ export interface QualityAssessment { completeness: number; quality: number; efficiency: number; overall: number; issues: string[]; } /** Full result returned by runAgent. */ export interface RunAgentResult { agentId: string; conversationId: string; status: HarnessStatus; finalMessage: string; turns: number; totalToolCalls: number; wallClockMs: number; contextWindowAtEnd?: ContextWindowUsage; turnResults: TurnResult[]; error?: string; stuckPattern?: string; qualityAssessment?: QualityAssessment; /** Accumulated token usage across all turns (from native LLM provider). */ usage?: UsageInfo; } import type { ReasoningMetadata } from "./ui-events.js"; import type { TokenBudgetTracker } from "../helpers/context-management.js"; import type { UIEventAdapter } from "../streaming/ui-event-adapter.js"; /** Configuration passed to the extracted executeStreamingLoop. */ export interface StreamingLoopConfig { conversationId: string; specification: Specification; messages: ConversationMessage[]; tools: ToolDefinitionInput[] | undefined; toolHandlers: Record<string, ToolHandler> | undefined; uiAdapter: UIEventAdapter; budgetTracker: TokenBudgetTracker | undefined; contextStrategy: { toolResultTokenLimit: number; toolRoundLimit: number; rebudgetThreshold: number; }; maxRounds: number; abortSignal: AbortSignal | undefined; useResponsesApi?: boolean; correlationId?: string; persona?: EntityReferenceInput; mimeType?: string; data?: string; additionalSystemInstructions?: string; fallbackSpecifications?: Specification[]; } /** Result returned from executeStreamingLoop. */ export interface StreamingLoopResult { fullMessage: string; finalAssistantMessage: string; toolCallCount: number; toolCallNames: string[]; errors: string[]; contextWindow?: ContextWindowUsage; contextActions: ContextManagementAction[]; reasoning?: ReasoningMetadata; intermediateMessages: ConversationMessageInput[]; lastRoundReasoning?: ReasoningMetadata; usedSpecification?: Specification; }