BREAKING CHANGE(api): Migrate public API to ai-sdk v6 and refactor core agent architecture: replace class-based DualAgent/Driver/Guardian with a single runAgent function; introduce ts_tools factories for tools, a compactMessages compaction subpath, and truncateOutput utility; simplify ToolRegistry to return ToolSet and remove legacy BaseToolWrapper/tool classes; update package exports and dependencies and bump major version.
This commit is contained in:
@@ -1,366 +1,54 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import type { ToolSet, ModelMessage, LanguageModelV3 } from './plugins.js';
|
||||
|
||||
// ================================
|
||||
// Tool Visibility & Registry Types
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* Tool visibility mode
|
||||
* - 'initial': Conveyed to model in system prompt AND discoverable via search
|
||||
* - 'on-demand': Only discoverable via search, must be activated before use
|
||||
*/
|
||||
export type TToolVisibility = 'initial' | 'on-demand';
|
||||
|
||||
/**
|
||||
* Tool metadata for discovery and management
|
||||
*/
|
||||
export interface IToolMetadata {
|
||||
name: string;
|
||||
description: string;
|
||||
actions: IToolAction[];
|
||||
visibility: TToolVisibility;
|
||||
isActivated: boolean;
|
||||
isInitialized: boolean;
|
||||
tags?: string[];
|
||||
category?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options when registering a tool
|
||||
*/
|
||||
export interface IToolRegistrationOptions {
|
||||
visibility?: TToolVisibility;
|
||||
tags?: string[];
|
||||
category?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for creating an Expert (SubAgent)
|
||||
*/
|
||||
export interface IExpertConfig {
|
||||
/** Unique name for the expert */
|
||||
name: string;
|
||||
/** Description of the expert's capabilities */
|
||||
description: string;
|
||||
/** System message defining expert behavior */
|
||||
systemMessage: string;
|
||||
/** Guardian policy for the expert's inner agent */
|
||||
guardianPolicy: string;
|
||||
/** AI provider (defaults to parent's provider) */
|
||||
provider?: plugins.smartai.TProvider;
|
||||
/** Tools available to this expert */
|
||||
tools?: IAgentToolWrapper[];
|
||||
/** Max iterations for expert tasks (default: 10) */
|
||||
maxIterations?: number;
|
||||
/** Visibility mode (default: 'initial') */
|
||||
visibility?: TToolVisibility;
|
||||
/** Searchable tags */
|
||||
tags?: string[];
|
||||
/** Category for grouping */
|
||||
category?: string;
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Task Run Options
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* Options for running a task with the DualAgentOrchestrator
|
||||
*/
|
||||
export interface ITaskRunOptions {
|
||||
/** Base64-encoded images to include with the task (for vision-capable models) */
|
||||
images?: string[];
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Agent Configuration Interfaces
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* Configuration options for the DualAgentOrchestrator
|
||||
*/
|
||||
export interface IDualAgentOptions extends plugins.smartai.ISmartAiOptions {
|
||||
/** Existing SmartAi instance to reuse (avoids creating duplicate providers) */
|
||||
smartAiInstance?: plugins.smartai.SmartAi;
|
||||
/** Name of the agent system */
|
||||
name?: string;
|
||||
/** Default AI provider for both Driver and Guardian */
|
||||
defaultProvider?: plugins.smartai.TProvider;
|
||||
/** Optional separate provider for Guardian (for cost optimization) */
|
||||
guardianProvider?: plugins.smartai.TProvider;
|
||||
/** System message for the Driver agent */
|
||||
driverSystemMessage?: string;
|
||||
/** Policy prompt for the Guardian agent - REQUIRED */
|
||||
guardianPolicyPrompt: string;
|
||||
/** Maximum iterations for task completion (default: 20) */
|
||||
maxIterations?: number;
|
||||
/** Maximum consecutive rejections before aborting (default: 3) */
|
||||
maxConsecutiveRejections?: number;
|
||||
/** Enable verbose logging */
|
||||
verbose?: boolean;
|
||||
/** Maximum characters for tool result output before truncation (default: 15000). Set to 0 to disable. */
|
||||
maxResultChars?: number;
|
||||
/** Maximum history messages to pass to API (default: 20). Set to 0 for unlimited. */
|
||||
maxHistoryMessages?: number;
|
||||
/** Optional callback for live progress updates during execution */
|
||||
onProgress?: (event: IProgressEvent) => void;
|
||||
/** Prefix for log messages (e.g., "[README]", "[Commit]"). Default: empty */
|
||||
logPrefix?: string;
|
||||
/** Callback fired for each token during LLM generation (streaming mode) */
|
||||
onToken?: (token: string, source: 'driver' | 'guardian') => void;
|
||||
export interface IAgentRunOptions {
|
||||
/** The LanguageModelV3 to use — from smartai.getModel() */
|
||||
model: LanguageModelV3;
|
||||
/** Initial user message or task description */
|
||||
prompt: string;
|
||||
/** System prompt override */
|
||||
system?: string;
|
||||
/** Tools available to the agent */
|
||||
tools?: ToolSet;
|
||||
/**
|
||||
* Enable native tool calling mode (default: false)
|
||||
* When enabled, uses Ollama's native tool calling API instead of XML parsing
|
||||
* This is more efficient for models that support it (e.g., GPT-OSS with Harmony format)
|
||||
* Maximum number of LLM↔tool round trips.
|
||||
* Each step may execute multiple tools in parallel.
|
||||
* Default: 20
|
||||
*/
|
||||
useNativeToolCalling?: boolean;
|
||||
maxSteps?: number;
|
||||
/** Prior conversation messages to include */
|
||||
messages?: ModelMessage[];
|
||||
/** Called for each streamed text delta */
|
||||
onToken?: (delta: string) => void;
|
||||
/** Called when a tool call starts */
|
||||
onToolCall?: (toolName: string, input: unknown) => void;
|
||||
/** Called when a tool call completes */
|
||||
onToolResult?: (toolName: string, result: unknown) => void;
|
||||
/**
|
||||
* Called when total token usage approaches the model's context limit.
|
||||
* Receives the full message history and must return a compacted replacement.
|
||||
* If not provided, runAgent throws a ContextOverflowError instead.
|
||||
*/
|
||||
onContextOverflow?: (messages: ModelMessage[]) => Promise<ModelMessage[]>;
|
||||
/** AbortSignal to cancel the run mid-flight */
|
||||
abort?: AbortSignal;
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Message Interfaces
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* Represents a message in the agent's conversation history
|
||||
*/
|
||||
export interface IAgentMessage {
|
||||
role: 'system' | 'user' | 'assistant' | 'tool' | 'guardian';
|
||||
content: string;
|
||||
toolName?: string;
|
||||
toolResult?: unknown;
|
||||
toolCall?: IToolCallProposal;
|
||||
guardianDecision?: IGuardianDecision;
|
||||
timestamp?: Date;
|
||||
export interface IAgentRunResult {
|
||||
/** Final text output from the model */
|
||||
text: string;
|
||||
/** All messages in the completed conversation */
|
||||
messages: ModelMessage[];
|
||||
/** Total steps taken */
|
||||
steps: number;
|
||||
/** Finish reason from the final step */
|
||||
finishReason: string;
|
||||
/** Accumulated token usage across all steps */
|
||||
usage: { inputTokens: number; outputTokens: number; totalTokens: number };
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Tool Interfaces
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* Represents an action that a tool can perform
|
||||
*/
|
||||
export interface IToolAction {
|
||||
/** Action name (e.g., 'read', 'write', 'delete') */
|
||||
name: string;
|
||||
/** Description of what this action does */
|
||||
description: string;
|
||||
/** JSON schema for action parameters */
|
||||
parameters: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Native tool call from provider (matches Ollama's tool calling format)
|
||||
* Format: function name is "toolName_actionName" (e.g., "json_validate")
|
||||
*/
|
||||
export interface INativeToolCall {
|
||||
function: {
|
||||
name: string; // Format: "toolName_actionName"
|
||||
arguments: Record<string, unknown>;
|
||||
index?: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Proposed tool call from the Driver
|
||||
*/
|
||||
export interface IToolCallProposal {
|
||||
/** Unique ID for this proposal */
|
||||
proposalId: string;
|
||||
/** Name of the tool */
|
||||
toolName: string;
|
||||
/** Specific action to perform */
|
||||
action: string;
|
||||
/** Parameters for the action */
|
||||
params: Record<string, unknown>;
|
||||
/** Driver's reasoning for this call */
|
||||
reasoning?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of tool execution
|
||||
*/
|
||||
export interface IToolExecutionResult {
|
||||
success: boolean;
|
||||
result?: unknown;
|
||||
error?: string;
|
||||
/** Optional human-readable summary for history (if provided, used instead of full result) */
|
||||
summary?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base interface for wrapped tools
|
||||
*/
|
||||
export interface IAgentToolWrapper {
|
||||
/** Tool name */
|
||||
name: string;
|
||||
/** Tool description */
|
||||
description: string;
|
||||
/** Available actions */
|
||||
actions: IToolAction[];
|
||||
/** Initialize the tool */
|
||||
initialize(): Promise<void>;
|
||||
/** Cleanup resources */
|
||||
cleanup(): Promise<void>;
|
||||
/** Execute an action */
|
||||
execute(action: string, params: Record<string, unknown>): Promise<IToolExecutionResult>;
|
||||
/** Get a summary for Guardian review */
|
||||
getCallSummary(action: string, params: Record<string, unknown>): string;
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Guardian Interfaces
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* Request for Guardian evaluation
|
||||
*/
|
||||
export interface IGuardianEvaluationRequest {
|
||||
/** The proposed tool call */
|
||||
proposal: IToolCallProposal;
|
||||
/** Current task context */
|
||||
taskContext: string;
|
||||
/** Recent conversation history (last N messages) */
|
||||
recentHistory: IAgentMessage[];
|
||||
/** Summary of what the tool call will do */
|
||||
callSummary: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Guardian's decision
|
||||
*/
|
||||
export interface IGuardianDecision {
|
||||
/** Approve or reject */
|
||||
decision: 'approve' | 'reject';
|
||||
/** Explanation of the decision */
|
||||
reason: string;
|
||||
/** Specific concerns if rejected */
|
||||
concerns?: string[];
|
||||
/** Suggestions for the Driver if rejected */
|
||||
suggestions?: string;
|
||||
/** Confidence level (0-1) */
|
||||
confidence?: number;
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Result Interfaces
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* Log entry for tool executions
|
||||
*/
|
||||
export interface IToolExecutionLog {
|
||||
timestamp: Date;
|
||||
toolName: string;
|
||||
action: string;
|
||||
params: Record<string, unknown>;
|
||||
guardianDecision: 'approved' | 'rejected';
|
||||
guardianReason: string;
|
||||
executionResult?: unknown;
|
||||
executionError?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status of a dual-agent run
|
||||
*/
|
||||
export type TDualAgentRunStatus =
|
||||
| 'completed'
|
||||
| 'in_progress'
|
||||
| 'max_iterations_reached'
|
||||
| 'max_rejections_reached'
|
||||
| 'clarification_needed'
|
||||
| 'error';
|
||||
|
||||
/**
|
||||
* Result of a dual-agent run
|
||||
*/
|
||||
export interface IDualAgentRunResult {
|
||||
/** Whether the task was successful */
|
||||
success: boolean;
|
||||
/** Whether the task is completed */
|
||||
completed: boolean;
|
||||
/** Final result or response */
|
||||
result: string;
|
||||
/** Total iterations taken */
|
||||
iterations: number;
|
||||
/** Full conversation history */
|
||||
history: IAgentMessage[];
|
||||
/** Current status */
|
||||
status: TDualAgentRunStatus;
|
||||
/** Number of tool calls made */
|
||||
toolCallCount?: number;
|
||||
/** Number of Guardian rejections */
|
||||
rejectionCount?: number;
|
||||
/** Tool execution log */
|
||||
toolLog?: IToolExecutionLog[];
|
||||
/** Error message if status is 'error' */
|
||||
error?: string;
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Progress Event Interfaces
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* Progress event types for live feedback during agent execution
|
||||
*/
|
||||
export type TProgressEventType =
|
||||
| 'task_started'
|
||||
| 'iteration_started'
|
||||
| 'tool_proposed'
|
||||
| 'guardian_evaluating'
|
||||
| 'tool_approved'
|
||||
| 'tool_rejected'
|
||||
| 'tool_executing'
|
||||
| 'tool_completed'
|
||||
| 'task_completed'
|
||||
| 'clarification_needed'
|
||||
| 'max_iterations'
|
||||
| 'max_rejections';
|
||||
|
||||
/**
|
||||
* Log level for progress events
|
||||
*/
|
||||
export type TLogLevel = 'info' | 'warn' | 'error' | 'success';
|
||||
|
||||
/**
|
||||
* Progress event for live feedback during agent execution
|
||||
*/
|
||||
export interface IProgressEvent {
|
||||
/** Type of progress event */
|
||||
type: TProgressEventType;
|
||||
/** Current iteration number */
|
||||
iteration?: number;
|
||||
/** Maximum iterations configured */
|
||||
maxIterations?: number;
|
||||
/** Name of the tool being used */
|
||||
toolName?: string;
|
||||
/** Action being performed */
|
||||
action?: string;
|
||||
/** Reason for rejection or other explanation */
|
||||
reason?: string;
|
||||
/** Human-readable message about the event */
|
||||
message?: string;
|
||||
/** Timestamp of the event */
|
||||
timestamp: Date;
|
||||
/** Log level for this event (info, warn, error, success) */
|
||||
logLevel: TLogLevel;
|
||||
/** Pre-formatted log message ready for output */
|
||||
logMessage: string;
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Utility Types
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* Available tool names
|
||||
*/
|
||||
export type TToolName = 'filesystem' | 'http' | 'browser' | 'shell';
|
||||
|
||||
/**
|
||||
* Generate a unique proposal ID
|
||||
*/
|
||||
export function generateProposalId(): string {
|
||||
return `proposal_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
||||
export class ContextOverflowError extends Error {
|
||||
constructor(message = 'Agent context limit reached and no onContextOverflow handler provided') {
|
||||
super(message);
|
||||
this.name = 'ContextOverflowError';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user