import { PersonaTools } from 'src/protocol'; import { ReactNode } from 'react'; import type { ToolInstance } from './tools'; import type { PersonaLogger } from './logging'; import type { SessionStorage } from './storage'; export type { PersonaLogger, SessionStorage }; export type ReadonlyJSONObject = { readonly [key: string]: string | number | boolean | null | ReadonlyJSONObject | ReadonlyArray; }; export type FunctionCall = { id?: string; name: string; args: ReadonlyJSONObject; }; export type FunctionResponse = { name: string; result?: ToolResultItem | ToolResultItem[] | null; functionCallId?: string; }; export type PersonaFile = { name: string; url?: string; base64?: string; contentType: string; }; export type PersonaSession = { id: string; code: string; projectId: string; agentId: string; currentAgentId: string; userId: string; status: 'active' | 'finished'; type: 'realtime' | 'async'; createdAt: string; finishedAt: string | null; }; export type PersonaProjectSubscription = { id: string; projectId?: string | null; owner?: string | null; planType: 'free' | 'baby' | 'junior' | 'pro' | 'mentor'; status: 'creating' | 'active' | 'inactive' | 'cancelled'; startDate?: string | null; planCredits: number; extraCredits: number; keepCreditsOnRenew: boolean; endDate?: string | null; createdAt?: string | null; updatedAt?: string | null; stripeCustomerId?: string | null; stripeSubscriptionId?: string | null; }; export type PersonaAgentContext = { data: Record; files?: PersonaFile[]; session?: PersonaSession; }; export type PersonaTransaction = { id: string; projectId: string; sessionId: string; status: 'pending' | 'completed' | 'failed'; error: string | null; functionCall: FunctionCall | null; context: PersonaAgentContext; }; export type PersonaReasoning = { thought: string; imageUrl?: string; }; export type PersonaImage = { content: string; contentType: string; }; /** * Allegato di un messaggio utente mostrato in chat (eco locale dell'invio): * immagine o file, così com'erano nel composer. */ export type PersonaMessageAttachment = { image?: PersonaImage; file?: PersonaFile; }; export type ToolResultItem = string | PersonaFile | PersonaImage | ReadonlyJSONObject; export type PersonaSourceChunk = { start: number; end: number; }; export type PersonaSource = { type: 'web' | 'document'; url?: string; documentId?: string; pageId?: string; pageNumber?: number; chunks?: PersonaSourceChunk[]; mostRelevant?: boolean; }; export type PersonaCommand = { command: 'get_mcp_assets' | 'set_initial_context' | 'set_local_tools' | 'cancel' | 'steer' | 'get_agent_state'; arguments: Record; }; export type PersonaRequest = PersonaMessage | Array | string; export type PersonaPacketPayload = PersonaRequest | PersonaCommand | PersonaReasoning | PersonaTransaction | AgentStartPayload | AgentEndPayload | TurnStartPayload | TurnEndPayload | ToolExecutionStartPayload | ToolExecutionUpdatePayload | ToolExecutionEndPayload | SteerAcceptedPayload | SteerProcessedPayload | Record; export type PersonaPacket = { type: 'request' | 'message' | 'command' | 'reasoning' | 'mcp_assets' | 'transaction' | 'agent_start' | 'agent_end' | 'turn_start' | 'turn_end' | 'tool_execution_start' | 'tool_execution_update' | 'tool_execution_end' | 'steer_accepted' | 'steer_processed'; payload?: PersonaPacketPayload; }; export type PersonaMessage = { id?: string | null; protocol?: string; thought?: string; text: string; image?: PersonaImage; attachments?: PersonaMessageAttachment[]; type: 'reasoning' | 'text' | 'transaction' | 'command'; role: 'user' | 'assistant' | 'function'; /** Chi ha scritto il messaggio: per quelli dell'agente è il suo nome. */ sender?: string | null; file?: PersonaFile; sources?: PersonaSource[]; sessionId?: string; finishReason?: 'stop' | 'function_call'; functionCalls?: FunctionCall[]; functionResponse?: FunctionResponse; status?: { type: 'running' | 'complete' | 'incomplete' }; // ThreadMessageLike compatible fields createdAt?: Date; metadata?: { /** * `custom.notice` marca i messaggi di servizio prodotti dal runtime e non * dall'agente (turno interrotto, errore): il client li può rendere come * avviso invece che come risposta in chat. */ custom?: { notice?: MessageNotice } & Record; [key: string]: unknown; }; }; /** Tipo di avviso di servizio: vedi `PersonaMessage.metadata.custom.notice`. */ export type MessageNotice = 'cancelled' | 'error'; // ─── Nuovi tipi per il lifecycle dell'agente ───────────────────────── export type AgentState = 'idle' | 'running' | 'cancelling'; export type AgentStartPayload = { sessionId: string; agentId: string; timestamp: string; }; export type AgentEndPayload = { sessionId: string; stopReason: 'completed' | 'cancelled' | 'error' | 'max_turns' | 'steered_completion'; totalTurns: number; totalCredits?: number; errorMessage?: string; }; export type TurnStartPayload = { turnNumber: number; timestamp: string; }; export type TurnEndPayload = { turnNumber: number; messageCount: number; toolResults: Array<{ toolCallId: string; toolName: string; result: string }>; }; export type ToolExecutionStartPayload = { toolCallId: string; toolName: string; args: Record; timestamp: string; }; export type ToolExecutionUpdatePayload = { toolCallId: string; partialResult: unknown; }; export type ToolExecutionEndPayload = { toolCallId: string; result: unknown; durationMs?: number; error?: string; }; export type SteerAcceptedPayload = { steerId: string; text: string; acceptedAt: string; willProcessAfterTurn: number | null; }; export type SteerProcessedPayload = { steerId: string; processedAtTurn: number; }; export type ModelResponse = { messages: PersonaMessage[]; }; export type PersonaResponse = { sessionId: string; response: ModelResponse; }; export type PersonaBaseConfig = { logger?: PersonaLogger; }; export type PersonaWebRTCConfig = PersonaBaseConfig & { webrtcUrl: string; iceServers?: RTCIceServer[]; onDataMessage?: (msg: MessageEvent) => void; }; export type Session = string | null | undefined; export type TransformMessages = (messages: PersonaMessage[]) => PersonaMessage[]; export type ThreadData = { threadId: string; title?: string; status: 'regular' | 'archived'; }; export type MessageListenerCallback = (message: PersonaPacket) => void; export type StatusChangeCallback = (status: ProtocolStatus) => void; export type ProtocolStatus = 'disconnected' | 'connecting' | 'connected'; export type PersonaProtocolBaseConfig = { logger?: PersonaLogger; apiKey: string; agentId: string; userId?: string; }; export interface PersonaProtocol { status: ProtocolStatus; autostart: boolean; getName: () => string; getPriority: () => number; connect: (session?: Session) => Promise; disconnect: () => Promise; onTransaction: (transaction: PersonaTransaction) => void; setSession: (session: Session) => Promise; sendPacket: (packet: PersonaPacket) => Promise; setAgentContext: (context: PersonaAgentContext) => Promise; clearListeners: () => void; addStatusChangeListener: (callback: StatusChangeCallback) => void; addPacketListener: (callback: MessageListenerCallback) => void; } export type PersonaConfig = PersonaBaseConfig & PersonaProtocolBaseConfig & { /** * In 'dev' mode the endpoint is set to localhost:8000, * use it only for development purposes. */ dev?: boolean; /** * The base URL of the API. * @default 'persona.applica.guru/api' */ baseUrl?: string; session?: Session; children: ReactNode; context?: PersonaAgentContext; protocols: | PersonaProtocol[] | { rest?: PersonaProtocolBaseConfig | boolean; webrtc?: PersonaProtocolBaseConfig | boolean; websocket?: PersonaProtocolBaseConfig | boolean; }; /** * Tools can be provided as an object (legacy) or as an array of { schema, implementation } (recommended) */ tools?: PersonaTools | ToolInstance[]; /** * Optional message transform function that processes messages before they are displayed */ transformMessages?: TransformMessages; /** * Fold each agent turn (reasoning, tool calls, text) into a single assistant * message, as assistant-ui components expect: consecutive tool calls group as * "N tool calls" and the action bar appears once per answer. User messages and * runtime notices stay separate. Disables branch switching. * @default false */ groupTurns?: boolean; /** * Enable thread management support */ threads?: boolean; /** * Session storage implementation * If not provided, defaults to PersonaSessionStorage */ sessionStorage?: SessionStorage; /** * Initial thread list (if thread management is enabled) */ initialThreads?: ThreadData[]; /** * Callback when a new thread is created */ onThreadCreate?: (threadId: string) => void; /** * Callback when switching to a thread */ onThreadSwitch?: (threadId: string) => void; /** * Callback when a thread is renamed */ onThreadRename?: (threadId: string, newTitle: string) => void; /** * Callback when a thread is archived */ onThreadArchive?: (threadId: string) => void; /** * Callback when a thread is unarchived */ onThreadUnarchive?: (threadId: string) => void; /** * Callback when a thread is deleted */ onThreadDelete?: (threadId: string) => void; /** * Enable file attachments (images, PDFs, text files) in the composer */ enableAttachments?: boolean; /** * Enable steer commands during agent execution. * When true, the user can send steer instructions while the agent is running. */ enableSteer?: boolean; /** * Callback when a steer command is accepted by the server. */ onSteerAccepted?: (payload: SteerAcceptedPayload) => void; /** * Callback when a steer command is processed (injected into the agent context). */ onSteerProcessed?: (payload: SteerProcessedPayload) => void; };