UNPKG

@iyio/convo-lang

Version:

A conversational language.

687 lines (686 loc) 22 kB
import { CodeParsingResult, JsonScheme, MarkdownLine } from '@iyio/common'; import type { ZodObject, ZodType } from 'zod'; import type { Conversation } from "./Conversation"; import type { ConvoExecutionContext } from './ConvoExecutionContext'; export type ConvoMessageType = 'text' | 'function'; export declare const convoValueConstants: readonly ["true", "false", "null", "undefined"]; export type ConvoValueConstant = (typeof convoValueConstants)[number]; export declare const convoNonFuncKeywords: readonly ["in"]; export type ConvoNonFuncKeyword = (typeof convoNonFuncKeywords)[number]; export declare const convoReservedRoles: readonly ["call", "do", "result", "define", "debug", "end"]; export type ConvoReservedRole = (typeof convoReservedRoles)[number]; export declare const convoObjFlag = "**convo**"; export interface ConvoTag { name: string; value?: string; } export type ConvoErrorType = ('invalid-return-value-type' | 'function-call-parse-count' | 'function-call-args-suspended' | 'unexpected-base-type' | 'invalid-args' | 'proxy-call-not-supported' | 'function-not-defined' | 'function-return-type-not-defined' | 'function-args-type-not-defined' | 'function-args-type-not-an-object' | 'suspended-scheme-statements-not-supported' | 'zod-object-expected' | 'scope-waiting' | 'suspension-parent-not-found' | 'variable-ref-required' | 'max-type-conversion-depth-reached' | 'unknown-json-scheme-type' | 'invalid-scheme-type' | 'invalid-variable-name' | 'invalid-function-name' | 'invalid-type-name' | 'invalid-register-only-function' | 'invalid-role' | 'use-of-reserved-role-not-allowed' | 'invalid-message-response-scheme' | 'missing-defaults'); export interface ConvoErrorReferences { message?: ConvoMessage; fn?: ConvoFunction; statement?: ConvoStatement; statements?: ConvoStatement[]; completion?: ConvoCompletionMessage; baseType?: ConvoBaseType; } export declare const allConvoCapabilityAry: readonly ["vision"]; export type ConvoCapability = typeof allConvoCapabilityAry[number]; export declare const isConvoCapability: (value: any) => value is ConvoCapability; /** * Can be a text message or function definition */ export interface ConvoMessage { role?: string; content?: string; description?: string; statement?: ConvoStatement; fn?: ConvoFunction; tags?: ConvoTag[]; markdown?: MarkdownLine[]; /** * The target render area of the message. */ renderTarget?: string; /** * A variable to assign the content or jsonValue of the message to */ assignTo?: string; /** * The value of the message parsed as json */ jsonValue?: any; /** * If the message has the `@component` tag the message will be marked as a component. If component * equals true then the component is an unnamed component. Components are by default cause the * message to be renderOnly */ component?: string | boolean; /** * If true the message should be rendered but not sent to LLMs */ renderOnly?: boolean; sourceUrl?: string; sourceId?: string; sourceName?: string; /** * If true the message should be clickable and when clicked the content of the message should be * added to the conversation. */ isSuggestion?: boolean; /** * Thread Id. Conversations can be divided into threads and during evaluation threads can be * used to control which messages are included. */ tid?: string; } export interface ConvoMessagePart { id?: string; content?: string; hidden?: boolean; } export interface ConvoStatement { /** * Raw value */ value?: any; /** * name of function to invoke */ fn?: string; /** * Dot path used with fn */ fnPath?: string[]; /** * Args to pass to fn if defined */ params?: ConvoStatement[]; /** * Name of a variable to set the function call result or value to. */ set?: string; /** * Dot path used with set */ setPath?: string[]; /** * Name of a referenced variable */ ref?: string; /** * Dot path used with ref */ refPath?: string[]; /** * Label optional - If true the statement is option. Used in com */ opt?: boolean; /** * Statement label */ label?: string; /** * Name of a non function keyword */ keyword?: string; comment?: string; tags?: ConvoTag[]; /** * If true the statement has the shared tag and assignment of variables will be stored in the * shared variable scope. */ shared?: boolean; /** * Source index start */ s: number; /** * Source index end. The index is non-inclusive. */ e: number; /** * Source index close. Only used with function calls. The index is non-inclusive. */ c?: number; /** * If true the statement is a match case. Match cases are used with switch statements. Match * case functions include (case, test and default) */ mc?: boolean; /** * If the statement has child match case statements. */ hmc?: boolean; /** * Used to start the source code of a statement. Source is most commonly used by message templates. */ source?: string; /** * If true the statement in font of the current pipe statement will be piped to the statement * behind the current pipe statement. Pipe statements are converted to calls to the pipe function * when a convo script is parsed and will to be present in a fully parsed syntax tree */ _pipe?: boolean; /** * If true the statement has pipe statements in it's args. */ _hasPipes?: boolean; } export interface ConvoMessageAndOptStatement { message: ConvoMessage; statement?: ConvoStatement; } export interface ConvoFunction { name: string; modifiers: string[]; /** * Name of a type variable that the function returns. If undefined the function * can return any type. */ returnType?: string; /** * If true the function is a local statement that should only be called by other functions in the * current convo script */ local: boolean; /** * If true it has been requested that the function be called. */ call: boolean; /** * If true the function is a collection of top level statements */ topLevel: boolean; /** * If true the function only defines types */ definitionBlock?: boolean; description?: string; /** * The body statements of the function. If a function does not have a body then it is either * a function interface or a call or called statement. */ body?: ConvoStatement[]; params: ConvoStatement[]; paramType?: string; } /** * Filters what messages are included in a conversation based on the rules of the filter. * Exclusive rules take priority over inclusive rules. */ export interface ConvoThreadFilter { /** * Ids of threads to include. If defined only messages with a thread id that is included in * includeThreads will be included in the evaluation of a conversation. Messages without a * threadId will be included if includeNonThreaded is true. */ includeThreads?: string[]; /** * If true and a message does not have a thread id the message is included. */ includeNonThreaded?: boolean; /** * Ids of threads to excluded. If defined any messages with a thread id that is included in * excludeThreads will be excluded from the evaluation of a conversation. Messages without a * threadId will be excluded if excludeNonThreaded is true. */ excludeThreads?: string[]; /** * If true and a message does not have a thread id the message is excluded. */ excludeNonThreaded?: boolean; } export type ConvoParsingResult = CodeParsingResult<ConvoMessage[]>; export interface ConvoScopeError { message: string; error?: any; statement?: ConvoStatement; } export interface OptionalConvoValue<T = any> { [convoObjFlag]: 'optional'; value?: T; } export declare const isOptionalConvoValue: (value: any) => value is OptionalConvoValue; export interface ConvoFlowControllerDataRef { ctrlData?: any; childCtrlData?: Record<string, ConvoFlowControllerDataRef>; } export declare const convoFlowControllerKey: unique symbol; export interface ConvoFlowController { /** * If true only the last param value is stored in the scopes param value array */ discardParams?: boolean; usesLabels?: boolean; /** * If true return control flow should be caught */ catchReturn?: boolean; /** * If true break control flow should be caught */ catchBreak?: boolean; sourceFn?: ConvoFunction; /** * If true the ctrl data will be stored by the parent scope of the ctrl * This is useful for ctrls that manage loops or iterators. */ keepData?: boolean; startParam?(scope: ConvoScope, parentScope: ConvoScope | undefined, ctx: ConvoExecutionContext): number | false; nextParam?(scope: ConvoScope, parentScope: ConvoScope | undefined, paramStatement: ConvoStatement, ctx: ConvoExecutionContext): number | false; shouldExecute?(scope: ConvoScope, parentScope: ConvoScope | undefined, ctx: ConvoExecutionContext): boolean; transformResult?(value: any, scope: ConvoScope, parentScope: ConvoScope | undefined, ctx: ConvoExecutionContext): any; } export type ConvoScopeFunction = (scope: ConvoScope, ctx: ConvoExecutionContext) => any; export declare const convoScopeFnKey: unique symbol; export declare const convoScopeParentKey: unique symbol; export interface ConvoScope { /** * suspension id */ si?: string; onComplete?: ((value: any) => void)[]; onError?: ((error: any) => void)[]; /** * value */ v?: any; /** * If true the control flow should return from the current function */ r?: boolean; /** * If true the control flow should break the current loop */ bl?: boolean; /** * If defined li tells control flow that the statement at the given index is the body of a * loop statement */ li?: number; /** * index */ i: number; s: ConvoStatement; /** * Wait id. Id of another scope to wait for before resuming */ wi?: string; /** * Parent suspension id */ pi?: string; /** * Suspension Finished */ fi?: boolean; [convoScopeFnKey]?: ConvoScopeFunction; /** * Param values used with function statements */ paramValues?: any[]; /** * Maps label names to param indexes */ labels?: Record<string, number | OptionalConvoValue<number>>; error?: ConvoScopeError; /** * If true the scope is defining a type */ td?: boolean; ctrlData?: any; /** * Similar to ctrlData but can be used by child statement controls to store data between * statements executions. Used by the (in) function to store iterator position. */ childCtrlData?: Record<string, any>; fromIndex?: number; gotoIndex?: number; /** * When this index is reached flow control should break. The statement at the index will not be executed. * breakIndex (bi) does not effect the scopes parent. */ bi?: number; it?: ConvoIterator; /** * Variable scope for the scope. When a function is executed all scopes generated will share the * same vars scope object. This is important to remember when serializing scope objects. */ vars: Record<string, any>; /** * If true metadata should be captured. Metadata capturing is implemented in ConvoFlowControllers. */ cm?: boolean; /** * Stores the current switch value */ sv?: any; /** * If true the scope is used as the default scope object. This property is used for internal * optimization and should be ignored */ _d?: boolean; } export interface ConvoIterator { /** * Index of current iteration item */ i: number; /** * Keys of item currently being iterated. Used when iterating over objects */ keys?: string[]; } export interface ConvoKeyValuePair { key: string; value: any; } export declare const convoBaseTypes: readonly ["string", "number", "int", "boolean", "time", "void", "any", "map", "array"]; export type ConvoBaseType = (typeof convoBaseTypes)[number]; export declare const isConvoBaseType: (value: any) => value is ConvoBaseType; export interface ConvoType { [convoObjFlag]: 'type'; type: string; enumValues?: any[]; } export declare const isConvoType: (value: any) => value is ConvoType; export interface ConvoMarkdownLine { [convoObjFlag]: 'md'; line: MarkdownLine; } export declare const isConvoMarkdownLine: (value: any) => value is ConvoMarkdownLine; export interface FlatConvoMessage { role: string; isUser?: boolean; content?: string; /** * A function that can be called */ fn?: ConvoFunction; /** * Params type of the function that can be called */ fnParams?: ZodObject<any>; /** * The target render area of the message. */ renderTarget?: string; /** * A function that was called */ called?: ConvoFunction; /** * The parameters that where passed to the function */ calledParams?: any; /** * The value the called function returned */ calledReturn?: any; /** * If true message was generated at the edge of the conversation, meaning the template expressions * where evaluated with the latest variables. */ edge?: boolean; /** * Used with messages that set variables such as define and result messages. */ setVars?: Record<string, any>; tags?: Record<string, string | undefined>; /** * The model the message has been requested to be completed with. */ responseModel?: string; responseEndpoint?: string; responseFormat?: string; responseFormatTypeName?: string; responseFormatIsArray?: boolean; responseAssignTo?: string; task?: string; /** * If the message has the `@component` tag the message will be marked as a component. If component * equals true then the component is an unnamed component. */ component?: string | boolean; /** * If true the message should be rendered but not sent to LLMs */ renderOnly?: boolean; markdown?: MarkdownLine[]; sourceUrl?: string; sourceId?: string; sourceName?: string; /** * If true the message should be clickable and when clicked the content of the message should be * added to the conversation. */ isSuggestion?: boolean; /** * Thread Id. Conversations can be divided into threads and during evaluation threads can be * used to control which messages are included. */ tid?: string; } export interface ConvoCompletionMessage extends Partial<ConvoTokenUsage> { role?: string; content?: string; callFn?: string; callParams?: any; tags?: Record<string, string | undefined>; model?: string; format?: string; formatTypeName?: string; formatIsArray?: boolean; assignTo?: string; endpoint?: string; } export interface ConvoCompletionService { completeConvoAsync(flat: FlatConvoConversation): Promise<ConvoCompletionMessage[]>; } export type ConvoCompletionStatus = 'complete' | 'busy' | 'error' | 'disposed'; export type ConvoRagMode = boolean | number; export declare const isConvoRagMode: (value: any) => value is ConvoRagMode; export interface ConvoFnCallInfo { name: string; message: ConvoMessage; fn: ConvoFunction; returnValue: any; } export interface ConvoCompletion { status: ConvoCompletionStatus; message?: ConvoCompletionMessage; messages: ConvoCompletionMessage[]; error?: any; exe?: ConvoExecutionContext; lastFnCall?: ConvoFnCallInfo; returnValues?: any[]; task: string; } export interface FlatConvoConversation { exe: ConvoExecutionContext; vars: Record<string, any>; messages: FlatConvoMessage[]; conversation: Conversation; capabilities: ConvoCapability[]; task: string; /** * Maps task triggers to tasks. * triggerName -> task array */ taskTriggers?: Record<string, string[]>; templates?: ConvoMessageTemplate[]; markdownVars: Record<string, ConvoMarkdownLine | string>; /** * If defined the debug function should be written to with debug info. */ debug?: (...args: any[]) => void; ragMode?: ConvoRagMode; ragPrefix?: string; ragSuffix?: string; } export interface ConvoExecuteResult { scope: ConvoScope; value?: any; valuePromise?: Promise<any>; } /** * A function that prints the args it is passed and returns the last arg. */ export type ConvoPrintFunction = (...args: any[]) => any; export interface ConvoMetadata { name?: string; comment?: string; tags?: ConvoTag[]; properties?: Record<string, ConvoMetadata>; } export interface ConvoPipeTarget { convoPipeSink(value: any): Promise<any> | any; } export declare const isConvoPipeTarget: (value: any) => value is ConvoPipeTarget; export interface ConvoGlobal extends ConvoPipeTarget { conversation?: Conversation; exe?: ConvoExecutionContext; } export interface ConvoTypeDef<T = any> { name: string; type: ZodType<T> | JsonScheme; } export interface ConvoVarDef<T = any> { name: string; value: T; } export interface ConvoFunctionDef<P = any, R = any> { description?: string; name: string; local?: boolean; paramsType?: ZodType<P>; paramsJsonScheme?: JsonScheme; returnTypeName?: string; returnScheme?: ConvoTypeDef<P>; /** * Convo function body code */ body?: string; callback?: (params: P) => R; scopeCallback?: ConvoScopeFunction; disableAutoComplete?: boolean; /** * If true the function will only be registered and will not be added the to conversation code. * This is useful for defining library functions or functions that don't need to be tracked as * part of a conversation. Setting registerOnly will for the function to be local. */ registerOnly?: boolean; } export interface ConvoDefItem<T = any, R = any> { type?: ConvoTypeDef<T>; var?: ConvoVarDef<T>; fn?: ConvoFunctionDef<T, R>; /** * If true the item will be registered but its code will not be added to the conversation. */ hidden?: boolean; types?: Record<string, ConvoTypeDef['type']>; vars?: Record<string, ConvoVarDef['value']>; fns?: Record<string, Omit<ConvoFunctionDef, 'name'> | ((params?: any) => any)>; } export interface ConvoAppend { text: string; messages: ConvoMessage[]; } /** * Completes a flattened conversation. Flatten conversations are conversation where all template * variables have been applied and the conversation is ready to be passed to an LLM or other * service that will use the flatten view of the conversation. */ export type ConvoFlatCompletionCallback = (flat: FlatConvoConversation) => Promise<ConvoCompletionMessage[]> | ConvoCompletionMessage[]; export interface ConvoTokenUsage { inputTokens: number; outputTokens: number; tokenPrice: number; } export interface ConvoMessagePrefixOptions { includeTokenUsage?: boolean; msg?: ConvoCompletionMessage; } export interface FlattenConvoOptions { /** * If true the flatten view of the conversation will be set as the current flatten version * @default task === "default" */ setCurrent?: boolean; /** * The name of the current task being executed. * @default "default" */ task?: string; discardTemplates?: boolean; threadFilter?: ConvoThreadFilter; } export interface ConvoSubTask { name: string; promise: Promise<ConvoCompletion>; } export interface ConvoCompletionOptions { task?: string; append?: string; /** * If true completion should stop and return just before a function is to be called */ returnOnCall?: boolean; /** * If true completion should stop and return after a function is called before sending a response * to the LLM */ returnOnCalled?: boolean; threadFilter?: ConvoThreadFilter; /** * If defined the token usage will be added to the defined usage. */ usage?: ConvoTokenUsage; debug?: boolean; } export interface ConvoMessageTemplate { message: ConvoMessage; name?: string; watchPath?: string; matchValue?: string; startValue?: any; } export interface CloneConversationOptions { systemOnly?: boolean; noFunctions?: boolean; } export interface ConvoDocumentReference { content: string; sourceId?: string; sourceName?: string; sourceUrl?: string; } export interface ConvoRagContext { params: Record<string, any>; tolerance: number; lastMessage: FlatConvoMessage; flat: FlatConvoConversation; conversation: Conversation; } export type ConvoRagCallback = (ragContext: ConvoRagContext) => ConvoDocumentReference | null | Promise<ConvoDocumentReference | null>; export interface AppendConvoMessageObjOptions { disableAutoFlatten?: boolean; appendCode?: boolean; } export interface ConvoImport { name: string; } export interface ConvoImportResult { name: string; /** * Convo to be inserted before the import */ convo?: string; /** * A type or set of types that will be converted to a convo type and imported */ type?: ConvoTypeDef | ConvoTypeDef[]; } export type ConvoImportHandler = (_import: ConvoImport) => ConvoImportResult | null | undefined | Promise<ConvoImportResult | null | undefined>;