diff --git a/genaisrc/codecomplete.genai.mts b/genaisrc/codecomplete.genai.mts new file mode 100644 index 000000000..a1217cfe6 --- /dev/null +++ b/genaisrc/codecomplete.genai.mts @@ -0,0 +1,149 @@ + +script({ + title: "Invoke LLM completion for code snippets", +}) + + +import * as fs from 'fs'; +import * as path from 'path'; + + +async function runCodePrompt(role, message, code) { + const answer = await runPrompt( + (_) => { + _.def("ROLE", role); + _.def("REQUEST", message); + _.def("CODE", code); + _.$`Your role is . + The request is given by + original code snippet: + .` + } + ) + console.log(answer.text); + return answer.text; +} + +async function invokeLLMCompletion(code, prefix) { + + let role = `You are a highly experienced compiler engineer with over 20 years of expertise, + specializing in C and C++ programming. Your deep knowledge of best coding practices + and software engineering principles enables you to produce robust, efficient, and + maintainable code in any scenario.`; + + let userMessage = `Please complete the provided C/C++ code to ensure it is compilable and executable. + Return only the fully modified code while preserving the original logic. + Add any necessary stubs, infer data types, and make essential changes to enable + successful compilation and execution. Avoid unnecessary code additions. + Ensure the final code is robust, secure, and adheres to best practices.`; + + return runCodePrompt(role, userMessage, code); +} + +async function invokeLLMAnalyzer(code, inputFilename, funcName) { + // Define the llm role + let role = + `You are a highly experienced compiler engineer with over 20 years of expertise, + specializing in C and C++ programming. Your deep knowledge of best coding practices + and software engineering principles enables you to produce robust, efficient, and + maintainable code in any scenario.`; + + // Define the message to send + let userMessage = + `Please analyze the provided C/C++ code and identify any potential issues, bugs, or opportunities for performance improvement. For each observation: + + - Clearly describe the issue or inefficiency. + - Explain the reasoning behind the problem or performance bottleneck. + - Suggest specific code changes or optimizations, including code examples where applicable. + - Ensure recommendations follow best practices for efficiency, maintainability, and correctness. + + At the end of the analysis, provide a detailed report in **Markdown format** summarizing: + + 1. **Identified Issues and Their Impact:** + - Description of each issue and its potential consequences. + + 2. **Suggested Fixes (with Code Examples):** + - Detailed code snippets showing the recommended improvements. + + 3. **Performance Improvement Recommendations:** + - Explanation of optimizations and their expected benefits. + + 4. **Additional Insights or Best Practices:** + - Suggestions to further enhance the code's quality and maintainability.`; + + return runCodePrompt(role, userMessage, code); + } + +async function createGitUpdateRequest(src_directory : string, filename : string, modifiedCode : string) { + // extract relative path from filename after slice_directory, extract function and source file name. + // Relative path: code_slices\ast\sls\orig_sls_smt_solver.cpp_updt_params.cpp file name: orig_sls_smt.cpp + const regex = /code_slices\\(.*)\\([^_]*)_(.*)\.cpp_(.*)\.cpp/; + const match = filename.match(regex); + if (!match) { + console.log(`Filename does not match expected pattern: ${filename}`); + return ""; + } + const [_, relative_path, prefix, fileName, funcName] = match; + + console.log(`Relative path: ${relative_path} file name: ${fileName}.cpp`); + + const srcFilePath = path.join(src_directory, relative_path, fileName + ".cpp"); + const srcFileContent = await workspace.readText(srcFilePath); + + let role = + `You are a highly experienced compiler engineer with over 20 years of expertise, + specializing in C and C++ programming. Your deep knowledge of best coding practices + and software engineering principles enables you to produce robust, efficient, and + maintainable code in any scenario.`; + + const answer = await runPrompt( + (_) => { + _.def("ROLE", role); + _.def("SOURCE", srcFileContent); + _.def("REVIEW", modifiedCode); + _.def("FUNCTION", funcName); + _.$`Your role is . + Please create a well-formed git patch based on the source code given in + + A code analysis is for the method or function . + The analysis is he following: + ` + } + ) + console.log(answer.text); + return answer.text; +} + +const input_directory = "code_slices"; +const output_directory = "code_slices_analyzed"; +const src_directory = "src"; +const code_slice_files = await workspace.findFiles("code_slices/**/*.cpp"); + +let count = 0; +for (const file of code_slice_files) { + if (path.extname(file.filename) === '.cpp') { + console.log(`Processing file: ${file.filename}`); + + const regex = /(.*)_(.*)\.cpp_(.*)\.cpp/; + const match = file.filename.match(regex); + + if (!match) { + console.log(`Filename does not match expected pattern: ${file.filename}`); + continue; + } + const [_, prefix, fileName, funcName] = match; + + const content = file.content; + const answer1 = await invokeLLMCompletion(content, fileName); + const answer2 = await invokeLLMAnalyzer(answer1, fileName, funcName); + const outputFilePath = path.join(output_directory, fileName + "_" + funcName + ".md"); + await workspace.writeText(outputFilePath, answer2); + const answer3 = await createGitUpdateRequest(src_directory, file.filename, answer2); + const outputFilePath2 = path.join(output_directory, fileName + "_" + funcName + ".patch"); + await workspace.writeText(outputFilePath2, answer3); + ++count; + if (count > 3) + break; + } +} + diff --git a/genaisrc/genaiscript.d.ts b/genaisrc/genaiscript.d.ts index e11a3edd7..94df8d9ef 100644 --- a/genaisrc/genaiscript.d.ts +++ b/genaisrc/genaiscript.d.ts @@ -49,79 +49,140 @@ interface PromptDefinition { * Longer description of the prompt. Shows in UI grayed-out. */ description?: string + + /** + * Groups template in UI + */ + group?: string + + /** + * List of tools defined in the script + */ + defTools?: { id: string; description: string; kind: "tool" | "agent" }[] } -interface PromptLike extends PromptDefinition { +interface PromptLike extends PromptDefinition, PromptToolsDefinition { /** * File where the prompt comes from (if any). */ filename?: string - /** - * The text of the prompt JS source code. - */ - jsSource: string - /** * The actual text of the prompt template. * Only used for system prompts. */ text?: string + + /** + * The text of the prompt JS source code. + */ + jsSource?: string + + /** + * Resolved system ids + */ + resolvedSystem?: string[] + + /** + * Infered input schema for parameters + */ + inputSchema?: JSONSchemaObject } type SystemPromptId = OptionsOrString< | "system" + | "system.agent_data" + | "system.agent_docs" | "system.agent_fs" | "system.agent_git" | "system.agent_github" | "system.agent_interpreter" + | "system.agent_planner" | "system.agent_user_input" + | "system.agent_video" + | "system.agent_web" | "system.annotations" + | "system.assistant" | "system.changelog" | "system.diagrams" | "system.diff" + | "system.english" | "system.explanations" | "system.files" | "system.files_schema" + | "system.fs_ask_file" + | "system.fs_data_query" | "system.fs_diff_files" | "system.fs_find_files" | "system.fs_read_file" | "system.git" + | "system.git_diff" + | "system.git_info" | "system.github_actions" | "system.github_files" | "system.github_info" | "system.github_issues" | "system.github_pulls" | "system.math" + | "system.md_find_files" | "system.md_frontmatter" + | "system.meta_prompt" + | "system.meta_schema" + | "system.node_info" + | "system.node_test" + | "system.output_ini" + | "system.output_json" + | "system.output_markdown" + | "system.output_plaintext" + | "system.output_yaml" + | "system.planner" | "system.python" | "system.python_code_interpreter" + | "system.python_types" | "system.retrieval_fuzz_search" | "system.retrieval_vector_search" | "system.retrieval_web_search" + | "system.safety_canary_word" + | "system.safety_harmful_content" + | "system.safety_jailbreak" + | "system.safety_protected_material" + | "system.safety_ungrounded_content_summarization" + | "system.safety_validate_harmful_content" | "system.schema" | "system.tasks" | "system.technical" + | "system.tool_calls" | "system.tools" + | "system.transcribe" | "system.typescript" | "system.user_input" + | "system.video" + | "system.vision_ask_images" | "system.zero_shot_cot" > type SystemToolId = OptionsOrString< + | "agent_data" + | "agent_docs" | "agent_fs" | "agent_git" | "agent_github" | "agent_interpreter" + | "agent_planner" | "agent_user_input" + | "agent_video" + | "agent_web" + | "fs_ask_file" + | "fs_data_query" | "fs_diff_files" | "fs_find_files" | "fs_read_file" | "git_branch_current" + | "git_branch_default" | "git_branch_list" | "git_diff" | "git_last_tag" - | "git_log" + | "git_list_commits" | "git_status" | "github_actions_job_logs_diff" | "github_actions_job_logs_get" @@ -136,15 +197,26 @@ type SystemToolId = OptionsOrString< | "github_pulls_list" | "github_pulls_review_comments_list" | "math_eval" + | "md_find_files" | "md_read_frontmatter" - | "python_code_interpreter_copy_files" + | "meta_prompt" + | "meta_schema" + | "node_test" + | "python_code_interpreter_copy_files_to_container" + | "python_code_interpreter_read_file" | "python_code_interpreter_run" | "retrieval_fuzz_search" | "retrieval_vector_search" | "retrieval_web_search" + | "transcribe" | "user_input_confirm" | "user_input_select" | "user_input_text" + | "video_extract_audio" + | "video_extract_clip" + | "video_extract_frames" + | "video_probe" + | "vision_ask_images" > type FileMergeHandler = ( @@ -180,28 +252,152 @@ type PromptOutputProcessorHandler = ( | void | Promise -type PromptTemplateResponseType = "json_object" | "json_schema" | undefined +type PromptTemplateResponseType = + | "text" + | "json" + | "yaml" + | "markdown" + | "json_object" + | "json_schema" + | undefined + +type ModelType = OptionsOrString< + | "large" + | "small" + | "long" + | "vision" + | "vision_small" + | "reasoning" + | "reasoning_small" + | "openai:gpt-4o" + | "openai:gpt-4o-mini" + | "openai:gpt-3.5-turbo" + | "openai:o1" + | "openai:o1-mini" + | "openai:o1-preview" + | "github:o3-mini" + | "github:gpt-4o" + | "github:gpt-4o-mini" + | "github:o1" + | "github:o1-mini" + | "github:o1-preview" + | "github:o3-mini" + | "github:AI21-Jamba-1.5-Large" + | "github:AI21-Jamba-1-5-Mini" + | "github:DeepSeek-R1" + | "github:Phi-4" + | "azure:gpt-4o" + | "azure:gpt-4o-mini" + | "azure:o1" + | "azure:o1-mini" + | "azure:o1-preview" + | "azure:o3-mini" + | "ollama:marco-o1" + | "ollama:tulu3" + | "ollama:athene-v2" + | "ollama:opencoder" + | "ollama:qwen2.5-coder" + | "ollama:llama3.2-vision" + | "ollama:llama3.2" + | "ollama:phi4" + | "ollama:phi3.5" + | "ollama:deepseek-r1:1.5b" + | "ollama:deepseek-r1:7b" + | "ollama:olmo2:7b" + | "ollama:command-r7b:7b" + | "anthropic:claude-3-5-sonnet-20240620" + | "anthropic:claude-3-opus-20240229" + | "anthropic:claude-3-sonnet-20240229" + | "anthropic:claude-3-haiku-20240307" + | "anthropic:claude-2.1" + | "anthropic:claude-instant-1.2" + | "anthropic_bedrock:anthropic.claude-3-opus-20240229-v1:0" + | "anthropic_bedrock:anthropic.claude-3-sonnet-20240229-v1:0" + | "anthropic_bedrock:anthropic.claude-3-haiku-20240307-v1:0" + | "huggingface:microsoft/Phi-3-mini-4k-instruct" + | "jan:llama3.2-3b-instruct" + | "google:gemini-2.0-flash-exp" + | "google:gemini-2.0-flash-thinking-exp-1219" + | "google:gemini-1.5-flash" + | "google:gemini-1.5-flash-latest" + | "google:gemini-1.5-flash-8b" + | "google:gemini-1.5-flash-8b-latest" + | "google:gemini-1.5-pro" + | "google:gemini-1.5-pro-latest" + | "mistral:mistral-large-latest" + | "mistral:mistral-small-latest" + | "mistral:pixtral-large-latest" + | "mistral:codestral-latest" + | "mistral:nemo" + | "alibaba:qwen-turbo" + | "alibaba:qwen-max" + | "alibaba:qwen-plus" + | "alibaba:qwen2-72b-instruct" + | "alibaba:qwen2-57b-a14b-instruct" + | "deepseek:deepseek-chat" + | "transformers:onnx-community/Qwen2.5-0.5B-Instruct:q4" + | "transformers:HuggingFaceTB/SmolLM2-1.7B-Instruct:q4f16" +> + +type ModelSmallType = OptionsOrString< + | "openai:gpt-4o-mini" + | "github:gpt-4o-mini" + | "azure:gpt-4o-mini" + | "openai:gpt-3.5-turbo" + | "github:Phi-3-5-mini-instruct" + | "github:AI21-Jamba-1-5-Mini" +> + +type ModelVisionType = OptionsOrString< + "openai:gpt-4o" | "github:gpt-4o" | "azure:gpt-4o" | "azure:gpt-4o-mini" +> + +type ModelTranscriptionType = OptionsOrString< + "openai:whisper-1" | "whisperasr:default" +> + +type ModelProviderType = OptionsOrString< + | "openai" + | "azure" + | "azure_serverless" + | "azure_serverless_models" + | "anthropic" + | "anthropic_bedrock" + | "google" + | "huggingface" + | "mistral" + | "alibaba" + | "github" + | "transformers" + | "ollama" + | "lmstudio" + | "jan" + | "llamafile" + | "litellm" + | "github_copilot_chat" + | "deepseek" +> interface ModelConnectionOptions { /** - * Which LLM model to use. - * - * @default gpt-4 - * @example gpt-4 + * Which LLM model by default or for the `large` alias. */ - model?: OptionsOrString< - | "openai:gpt-4o" - | "openai:gpt-4o-mini" - | "openai:gpt-4" - | "openai:gpt-4-turbo" - | "openai:gpt-3.5-turbo" - | "ollama:phi3" - | "ollama:llama3" - | "ollama:mixtral" - > + model?: ModelType } -interface ModelOptions extends ModelConnectionOptions { +interface ModelAliasesOptions { + /** + * Configure the `small` model alias. + */ + smallModel?: ModelSmallType + + /** + * Configure the `vision` model alias. + */ + visionModel?: ModelVisionType +} + +interface ModelOptions extends ModelConnectionOptions, ModelTemplateOptions { /** * Temperature to use. Higher temperature means more hallucination/creativity. * Range 0.0-2.0. @@ -210,18 +406,43 @@ interface ModelOptions extends ModelConnectionOptions { */ temperature?: number + /** + * Some reasoning model support a reasoning effort parameter. + */ + reasoningEffort?: "high" | "medium" | "low" + + /** + * A list of keywords that should be found in the output. + */ + choices?: ElementOrArray< + string | { token: string | number; weight?: number } + > + + /** + * Returns the log probabilities of the each tokens. Not supported in all models. + */ + logprobs?: boolean + + /** + * Number of alternate token logprobs to generate, up to 5. Enables logprobs. + */ + topLogprobs?: number + /** * Specifies the type of output. Default is plain text. - * - `json_object` enables JSON mode - * - `json_schema` enables structured outputs + * - `text` enables plain text mode (through system prompts) + * - `json` enables JSON mode (through system prompts) + * - `yaml` enables YAML mode (through system prompts) + * - `json_object` enables JSON mode (native) + * - `json_schema` enables structured outputs (native) * Use `responseSchema` to specify an output schema. */ responseType?: PromptTemplateResponseType /** - * JSON object schema for the output. Enables the `JSON` output mode by default. + * JSON object schema for the output. Enables the `json_object` output mode by default. */ - responseSchema?: PromptParametersSchema | JSONSchemaObject + responseSchema?: PromptParametersSchema | JSONSchema /** * “Top_p” or nucleus sampling is a setting that decides how many possible words to consider. @@ -231,7 +452,7 @@ interface ModelOptions extends ModelConnectionOptions { topP?: number /** - * When to stop producing output. + * Maximum number of completion tokens * */ maxTokens?: number @@ -256,17 +477,6 @@ interface ModelOptions extends ModelConnectionOptions { */ cache?: boolean | string - /** - * Custom cache name. If not set, the default cache is used. - * @deprecated Use `cache` instead with a string - */ - cacheName?: string - - /** - * Budget of tokens to apply the prompt flex renderer. - */ - flexTokens?: number - /** * A list of model ids and their maximum number of concurrent requests. */ @@ -293,37 +503,39 @@ interface PromptSystemOptions { /** * List of system script ids used by the prompt. */ - system?: SystemPromptId | SystemPromptId[] + system?: ElementOrArray /** * List of tools used by the prompt. */ - tools?: SystemToolId | SystemToolId[] + tools?: ElementOrArray + + /** + * List of system to exclude from the prompt. + */ + excludedSystem?: ElementOrArray } -interface ScriptRuntimeOptions { +interface ScriptRuntimeOptions extends LineNumberingOptions { /** * Secrets required by the prompt */ secrets?: string[] - - /** - * Default value for emitting line numbers in fenced code blocks. - */ - lineNumbers?: boolean } +type PromptJSONParameterType = T & { required?: boolean } + type PromptParameterType = | string | number | boolean | object - | JSONSchemaNumber - | JSONSchemaString - | JSONSchemaBoolean + | PromptJSONParameterType + | PromptJSONParameterType + | PromptJSONParameterType type PromptParametersSchema = Record< string, - PromptParameterType | PromptParameterType[] + PromptParameterType | [PromptParameterType] > type PromptParameters = Record @@ -393,6 +605,10 @@ interface PromptTest { * List of files to apply the test to. */ files?: string | string[] + /** + * List of in-memory files to apply the test to. + */ + workspaceFiles?: WorkspaceFile | WorkspaceFile[] /** * Extra set of variables for this scenario */ @@ -417,18 +633,153 @@ interface PromptTest { * Additional deterministic assertions. */ asserts?: PromptAssertion | PromptAssertion[] + + /** + * Determines what kind of output is sent back to the test engine. Default is "text". + */ + format?: "text" | "json" +} + +/** + * Configure promptfoo redteam plugins + */ +interface PromptRedteam { + /** + * The `purpose` property is used to guide the attack generation process. It should be as clear and specific as possible. + * Include the following information: + * - Who the user is and their relationship to the company + * - What data the user has access to + * - What data the user does not have access to + * - What actions the user can perform + * - What actions the user cannot perform + * - What systems the agent has access to + * @link https://www.promptfoo.dev/docs/red-team/troubleshooting/attack-generation/ + */ + purpose: string + + /** + * Redteam identifer used for reporting purposes + */ + label?: string + + /** + * Default number of inputs to generate for each plugin. + * The total number of tests will be `(numTests * plugins.length * (1 + strategies.length) * languages.length)` + * Languages.length is 1 by default, but is added when the multilingual strategy is used. + */ + numTests?: number + + /** + * List of languages to target. Default is English. + */ + language?: string + + /** + * Red team plugin list + * @link https://www.promptfoo.dev/docs/red-team/owasp-llm-top-10/ + */ + plugins?: ElementOrArray< + OptionsOrString< + | "default" + | "nist:ai:measure" + | "owasp:llm" + | "owasp:api" + | "mitre:atlas" + | "owasp:llm:01" + | "owasp:llm:02" + | "owasp:llm:04" + | "owasp:llm:06" + | "owasp:llm:09" + | "contracts" + | "divergent-repetition" + | "excessive-agency" + | "hallucination" + | "harmful:chemical-biological-weapons" + | "harmful:child-exploitation" + | "harmful:copyright-violations" + | "harmful:cybercrime" + | "harmful:cybercrime:malicious-code" + | "harmful:graphic-content" + | "harmful:harassment-bullying" + | "harmful:hate" + | "harmful:illegal-activities" + | "harmful:illegal-drugs" + | "harmful:illegal-drugs:meth" + | "harmful:indiscriminate-weapons" + | "harmful:insults" + | "harmful:intellectual-property" + | "harmful:misinformation-disinformation" + | "harmful:non-violent-crime" + | "harmful:privacy" + | "harmful:profanity" + | "harmful:radicalization" + | "harmful:self-harm" + | "harmful:sex-crime" + | "harmful:sexual-content" + | "harmful:specialized-advice" + | "harmful:unsafe-practices" + | "harmful:violent-crime" + | "harmful:weapons:ied" + | "hijacking" + | "pii:api-db" + | "pii:direct" + | "pii:session" + | "pii:social" + | "politics" + > + > + + /** + * Adversary prompt generation strategies + */ + strategies?: ElementOrArray< + OptionsOrString< + | "default" + | "basic" + | "jailbreak" + | "jailbreak:composite" + | "base64" + | "jailbreak" + | "prompt-injection" + > + > +} + +interface ContentSafetyOptions { + contentSafety?: ContentSafetyProvider +} + +/** + * Different ways to render a fence block. + */ +type FenceFormat = "markdown" | "xml" | "none" + +interface FenceFormatOptions { + /** + * Formatting of code sections + */ + fenceFormat?: FenceFormat +} + +interface ModelTemplateOptions extends FenceFormatOptions { + /** + * Budget of tokens to apply the prompt flex renderer. + */ + flexTokens?: number } interface PromptScript extends PromptLike, ModelOptions, + ModelAliasesOptions, PromptSystemOptions, EmbeddingsModelOptions, + ContentSafetyOptions, ScriptRuntimeOptions { /** - * Groups template in UI + * Which provider to prefer when picking a model. */ - group?: string + provider?: ModelProviderType /** * Additional template parameters that will populate `env.vars` @@ -439,7 +790,12 @@ interface PromptScript * A file path or list of file paths or globs. * The content of these files will be by the files selected in the UI by the user or the cli arguments. */ - files?: string | string[] + files?: ElementOrArray + + /** + * A comma separated list of file extensions to accept. + */ + accept?: string /** * Extra variable values that can be used to configure system prompts. @@ -449,7 +805,12 @@ interface PromptScript /** * Tests to validate this script. */ - tests?: PromptTest | PromptTest[] + tests?: ElementOrArray + + /** + * LLM vulnerability checks + */ + redteam?: PromptRedteam /** * Don't show it to the user in lists. Template `system.*` are automatically unlisted. @@ -460,13 +821,7 @@ interface PromptScript * Set if this is a system prompt. */ isSystem?: boolean - - /** - * List of tools defined in the script - */ - defTools?: { id: string, description: string }[] } - /** * Represent a workspace file and optional content. */ @@ -476,10 +831,25 @@ interface WorkspaceFile { */ filename: string + /** + * Content mime-type if known + */ + type?: string + + /** + * Encoding of the content + */ + encoding?: "base64" + /** * Content of the file. */ content?: string + + /** + * Size in bytes if known + */ + size?: number } interface WorkspaceFileWithScore extends WorkspaceFile { @@ -514,11 +884,167 @@ interface ToolDefinition { parameters?: JSONSchema } +/** + * Interface representing an output trace with various logging and tracing methods. + * Extends the `ToolCallTrace` interface. + */ +interface OutputTrace extends ToolCallTrace { + /** + * Logs a heading message at the specified level. + * @param level - The level of the heading. + * @param message - The heading message. + */ + heading(level: number, message: string): void + + /** + * Logs an image with an optional caption. + * @param url - The URL of the image. + * @param caption - The optional caption for the image. + */ + image(url: string, caption?: string): void + + /** + * Logs a markdown table + * @param rows + */ + table(rows: object[]): void + + /** + * Logs a result item with a boolean value and a message. + * @param value - The boolean value of the result item. + * @param message - The message for the result item. + */ + resultItem(value: boolean, message: string): void + + /** + * Starts a trace with details in markdown format. + * @param title - The title of the trace. + * @param options - Optional settings for the trace. + * @returns A `MarkdownTrace` instance. + */ + startTraceDetails( + title: string, + options?: { expanded?: boolean } + ): MarkdownTrace + + /** + * Appends content to the trace. + * @param value - The content to append. + */ + appendContent(value: string): void + + /** + * Starts a details section in the trace. + * @param title - The title of the details section. + * @param options - Optional settings for the details section. + */ + startDetails( + title: string, + options?: { success?: boolean; expanded?: boolean } + ): void + + /** + * Ends the current details section in the trace. + */ + endDetails(): void + + /** + * Logs a video with a name, file path, and optional alt text. + * @param name - The name of the video. + * @param filepath - The file path of the video. + * @param alt - The optional alt text for the video. + */ + video(name: string, filepath: string, alt?: string): void + + /** + * Logs an audio file + * @param name + * @param filepath + * @param alt + */ + audio(name: string, filepath: string, alt?: string): void + + /** + * Logs a details section with a title and body. + * @param title - The title of the details section. + * @param body - The body content of the details section, can be a string or an object. + * @param options - Optional settings for the details section. + */ + details( + title: string, + body: string | object, + options?: { success?: boolean; expanded?: boolean } + ): void + + /** + * Logs a fenced details section with a title, body, and optional content type. + * @param title - The title of the details section. + * @param body - The body content of the details section, can be a string or an object. + * @param contentType - The optional content type of the body. + * @param options - Optional settings for the details section. + */ + detailsFenced( + title: string, + body: string | object, + contentType?: string, + options?: { expanded?: boolean } + ): void + + /** + * Logs an item with a name, value, and optional unit. + * @param name - The name of the item. + * @param value - The value of the item. + * @param unit - The optional unit of the value. + */ + itemValue(name: string, value: any, unit?: string): void + + /** + * Logs a warning message. + * @param msg - The warning message to log. + */ + warn(msg: string): void + + /** + * Logs a caution message. + * @param msg - The caution message to log. + */ + caution(msg: string): void + + /** + * Logs a note message. + * @param msg - The note message to log. + */ + note(msg: string): void +} + +/** + * Interface representing a tool call trace for logging various types of messages. + */ interface ToolCallTrace { + /** + * Logs a general message. + * @param message - The message to log. + */ log(message: string): void + + /** + * Logs an item message. + * @param message - The item message to log. + */ item(message: string): void + + /** + * Logs a tip message. + * @param message - The tip message to log. + */ tip(message: string): void - fence(message: string, contentType?: string): void + + /** + * Logs a fenced message, optionally specifying the content type. + * @param message - The fenced message to log. + * @param contentType - The optional content type of the message. + */ + fence(message: string | unknown, contentType?: string): void } /** @@ -583,6 +1109,7 @@ type ToolCallOutput = | ShellOutput | WorkspaceFile | RunPromptResult + | SerializedError | undefined interface WorkspaceFileCache { @@ -609,6 +1136,47 @@ interface WorkspaceFileCache { values(): Promise } +interface WorkspaceGrepOptions { + /** + * List of paths to + */ + path?: ElementOrArray + /** + * list of filename globs to search. !-prefixed globs are excluded. ** are not supported. + */ + glob?: ElementOrArray + /** + * Set to false to skip read text content. True by default + */ + readText?: boolean +} + +interface WorkspaceGrepResult { + files: WorkspaceFile[] + matches: WorkspaceFile[] +} + +interface INIParseOptions { + defaultValue?: any +} + +interface FindFilesOptions { + /** Glob patterns to ignore */ + ignore?: ElementOrArray + /** + * Set to false to skip read text content. True by default + */ + readText?: boolean +} + +interface FileStats { + /** + * Size of the file in bytes + */ + size: number + mode: number +} + interface WorkspaceFileSystem { /** * Searches for files using the glob pattern and returns a list of files. @@ -617,12 +1185,7 @@ interface WorkspaceFileSystem { */ findFiles( glob: string, - options?: { - /** - * Set to false to skip read text content. True by default - */ - readText?: boolean - } + options?: FindFilesOptions ): Promise /** @@ -632,14 +1195,19 @@ interface WorkspaceFileSystem { */ grep( query: string | RegExp, - globs: string | string[], - options?: { - /** - * Set to false to skip read text content. True by default - */ - readText?: boolean - } - ): Promise<{ files: WorkspaceFile[] }> + options?: WorkspaceGrepOptions + ): Promise + grep( + query: string | RegExp, + glob: string, + options?: Omit + ): Promise + + /** + * Reads metadata information about the file. Returns undefined if the file does not exist. + * @param filename + */ + stat(filename: string): Promise /** * Reads the content of a file as text @@ -662,7 +1230,10 @@ interface WorkspaceFileSystem { /** * Reads the content of a file and parses to XML, using the XML parser. */ - readXML(path: string | Awaitable, options?: XMLParseOptions): Promise + readXML( + path: string | Awaitable, + options?: XMLParseOptions + ): Promise /** * Reads the content of a CSV file. @@ -673,6 +1244,24 @@ interface WorkspaceFileSystem { options?: CSVParseOptions ): Promise + /** + * Reads the content of a file and parses to INI + */ + readINI( + path: string | Awaitable, + options?: INIParseOptions + ): Promise + + /** + * Reads the content of a file and attempts to parse it as data. + * @param path + * @param options + */ + readData( + path: string | Awaitable, + options?: CSVParseOptions & INIParseOptions & XMLParseOptions + ): Promise + /** * Writes a file as text to the file system * @param path @@ -681,7 +1270,23 @@ interface WorkspaceFileSystem { writeText(path: string, content: string): Promise /** - * Opens a key-value cache for the given cache name. + * Caches a buffer to file and returns the unique file name + * @param bytes + */ + writeCached( + bytes: BufferLike, + options?: { scope?: "workspace" | "run" } + ): Promise + + /** + * Copies a file between two paths + * @param source + * @param destination + */ + copyFile(source: string, destination: string): Promise + + /** + * Opens a file-backed key-value cache for the given cache name. * The cache is persisted across runs of the script. Entries are dropped when the cache grows too large. * @param cacheName */ @@ -692,11 +1297,13 @@ interface WorkspaceFileSystem { interface ToolCallContext { log(message: string): void + debug(message: string): void trace: ToolCallTrace } interface ToolCallback { spec: ToolDefinition + options?: DefToolOptions impl: ( args: { context: ToolCallContext } & Record ) => Awaitable @@ -715,7 +1322,7 @@ interface AgenticToolProviderCallback { type ChatParticipantHandler = ( context: ChatTurnGenerationContext, messages: ChatCompletionMessageParam[] -) => Awaitable +) => Awaitable<{ messages?: ChatCompletionMessageParam[] } | undefined | void> interface ChatParticipantOptions { label?: string @@ -735,35 +1342,69 @@ interface ExpansionVariables { */ dir: string + /** + * Directory where output files (trace, output) are created + */ + runDir: string + /** * List of linked files parsed in context */ files: WorkspaceFile[] - /** - * current prompt template - */ - template: PromptDefinition - /** * User defined variables */ - vars?: Record + vars: Record & { + /** + * When running in GitHub Copilot Chat, the current user prompt + */ + question?: string + /** + * When running in GitHub Copilot Chat, the current chat history + */ + "copilot.history"?: (HistoryMessageUser | HistoryMessageAssistant)[] + /** + * When running in GitHub Copilot Chat, the current editor content + */ + "copilot.editor"?: string + /** + * When running in GitHub Copilot Chat, the current selection + */ + "copilot.selection"?: string + /** + * When running in GitHub Copilot Chat, the current terminal content + */ + "copilot.terminalSelection"?: string + } /** * List of secrets used by the prompt, must be registered in `genaiscript`. */ - secrets?: Record + secrets: Record /** * Root prompt generation context */ generator: ChatGenerationContext + + /** + * Output trace builder + */ + output: OutputTrace + + /** + * Resolved metadata + */ + meta: PromptDefinition & ModelConnectionOptions } type MakeOptional = Partial> & Omit -type PromptArgs = Omit +type PromptArgs = Omit< + PromptScript, + "text" | "id" | "jsSource" | "defTools" | "resolvedSystem" +> type PromptSystemArgs = Omit< PromptArgs, @@ -779,7 +1420,7 @@ type PromptSystemArgs = Omit< | "responseSchema" | "files" | "modelConcurrency" - | "parameters" + | "redteam" > type StringLike = string | WorkspaceFile | WorkspaceFile[] @@ -791,7 +1432,7 @@ interface LineNumberingOptions { lineNumbers?: boolean } -interface FenceOptions extends LineNumberingOptions { +interface FenceOptions extends LineNumberingOptions, FenceFormatOptions { /** * Language of the fenced code block. Defaults to "markdown". */ @@ -812,28 +1453,44 @@ interface FenceOptions extends LineNumberingOptions { schema?: string } +type PromptCacheControlType = "ephemeral" + interface ContextExpansionOptions { /** * Specifies an maximum of estimated tokens for this entry; after which it will be truncated. */ maxTokens?: number + /* * Value that is conceptually similar to a zIndex (higher number == higher priority). * If a rendered prompt has more message tokens than can fit into the available context window, the prompt renderer prunes messages with the lowest priority from the ChatMessages result, preserving the order in which they were declared. This means your extension code can safely declare TSX components for potentially large pieces of context like conversation history and codebase context. */ priority?: number + /** * Controls the proportion of tokens allocated from the container's budget to this element. * It defaults to 1 on all elements. */ flex?: number + /** - * This text is likely to change and will probably break the prefix cache. + * Caching policy for this text. `ephemeral` means the prefix can be cached for a short amount of time. */ - ephemeral?: boolean + cacheControl?: PromptCacheControlType } -interface DefOptions extends FenceOptions, ContextExpansionOptions, DataFilter { +interface RangeOptions { + /** + * The inclusive start of the line range, with a 1-based index + */ + lineStart?: number + /** + * The inclusive end of the line range, with a 1-based index + */ + lineEnd?: number +} + +interface FileFilterOptions { /** * Filename filter based on file suffix. Case insensitive. */ @@ -843,11 +1500,44 @@ interface DefOptions extends FenceOptions, ContextExpansionOptions, DataFilter { * Filename filter using glob syntax. */ glob?: ElementOrArray +} +interface ContentSafetyOptions { + /** + * Runs the default content safety validator + * to prevent prompt injection. + */ + detectPromptInjection?: "always" | "available" | boolean + + /** + * Policy to inject builtin system prompts. See to `false` prevent automatically injecting. + */ + systemSafety?: "default" | boolean + + /** + * Policy to disable secret scanning when communicating with the LLM. + * Set to `false` to disable. + */ + secretScanning?: boolean +} + +interface DefOptions + extends FenceOptions, + ContextExpansionOptions, + DataFilter, + RangeOptions, + FileFilterOptions, + ContentSafetyOptions { /** * By default, throws an error if the value in def is empty. */ ignoreEmpty?: boolean + + /** + * The content of the def is a predicted output. + * This setting disables line numbers. + */ + prediction?: boolean } /** @@ -855,29 +1545,67 @@ interface DefOptions extends FenceOptions, ContextExpansionOptions, DataFilter { */ interface DefDiffOptions extends ContextExpansionOptions, + FenceFormatOptions, LineNumberingOptions {} interface DefImagesOptions { + /** + * A "low" detail image is always downsampled to 512x512 pixels. + */ detail?: "high" | "low" /** - * Maximum width of the image + * Crops the image to the specified region. */ - maxWidth?: number - /** - * Maximum height of the image - */ - maxHeight?: number + crop?: { x?: number; y?: number; w?: number; h?: number } /** * Auto cropping same color on the edges of the image */ autoCrop?: boolean -} + /** + * Applies a scaling factor to the image after cropping. + */ + scale?: number + /** + * Rotates the image by the specified number of degrees. + */ + rotate?: number + /** + * Maximum width of the image. Applied after rotation. + */ + maxWidth?: number + /** + * Maximum height of the image. Applied after rotation. + */ + maxHeight?: number + /** + * Removes colour from the image using ITU Rec 709 luminance values + */ + greyscale?: boolean + /** + * Flips the image horizontally and/or vertically. + */ + flip?: { horizontal?: boolean; vertical?: boolean } + /** + * Selects the first N elements from the data + */ + sliceHead?: number + /** + * Selects the last N elements from the data + */ + sliceTail?: number + /** + * Selects the a random sample of N items in the collection. + */ + sliceSample?: number + /** + * Renders all images in a single tiled image + */ + tiled?: boolean -interface ChatTaskOptions { - command: string - cwd?: string - env?: Record - args?: string[] + /** + * By default, throws an error if no images are passed. + */ + ignoreEmpty?: boolean } type JSONSchemaTypeName = @@ -889,24 +1617,40 @@ type JSONSchemaTypeName = | "array" | "null" -type JSONSchemaType = +type JSONSchemaSimpleType = | JSONSchemaString | JSONSchemaNumber | JSONSchemaBoolean | JSONSchemaObject | JSONSchemaArray - | null -interface JSONSchemaString { - type: "string" - enum?: string[] - description?: string - default?: string +type JSONSchemaType = JSONSchemaSimpleType | JSONSchemaAnyOf | null + +interface JSONSchemaAnyOf { + anyOf: JSONSchemaType[] } -interface JSONSchemaNumber { - type: "number" | "integer" +interface JSONSchemaDescripted { + /** + * A short description of the property + */ + title?: string + /** + * A clear description of the property. + */ description?: string +} + +interface JSONSchemaString extends JSONSchemaDescripted { + type: "string" + uiType?: "textarea" + enum?: string[] + default?: string + pattern?: string +} + +interface JSONSchemaNumber extends JSONSchemaDescripted { + type: "number" | "integer" default?: number minimum?: number exclusiveMinimum?: number @@ -914,46 +1658,81 @@ interface JSONSchemaNumber { exclusiveMaximum?: number } -interface JSONSchemaBoolean { +interface JSONSchemaBoolean extends JSONSchemaDescripted { type: "boolean" - description?: string default?: boolean } -interface JSONSchemaObject { +interface JSONSchemaObject extends JSONSchemaDescripted { $schema?: string type: "object" - description?: string properties?: { [key: string]: JSONSchemaType } required?: string[] additionalProperties?: boolean + + default?: object } -interface JSONSchemaArray { +interface JSONSchemaArray extends JSONSchemaDescripted { $schema?: string type: "array" - description?: string items?: JSONSchemaType + + default?: any[] } type JSONSchema = JSONSchemaObject | JSONSchemaArray -interface JSONSchemaValidation { +interface FileEditValidation { + /** + * JSON schema + */ schema?: JSONSchema - valid: boolean - error?: string + /** + * Error while validating the JSON schema + */ + schemaError?: string + /** + * The path was validated with a file output (defFileOutput) + */ + pathValid?: boolean } interface DataFrame { schema?: string data: unknown - validation?: JSONSchemaValidation + validation?: FileEditValidation +} + +interface Logprob { + /** + * Token text + */ + token: string + /** + * Log probably of the generated token + */ + logprob: number + /** + * Logprob value converted to % + */ + probPercent?: number + /** + * Normalized entropy + */ + entropy?: number + /** + * Other top tokens considered by the LLM + */ + topLogprobs?: { token: string; logprob: number }[] } interface RunPromptResult { + messages: ChatCompletionMessageParam[] text: string + reasoning?: string annotations?: Diagnostic[] fences?: Fenced[] frames?: DataFrame[] @@ -969,6 +1748,14 @@ interface RunPromptResult { | "cancel" | "fail" usages?: ChatCompletionUsages + fileEdits?: Record + edits?: Edits[] + changelogs?: ChangeLog[] + model?: ModelType + choices?: LogProb[] + logprobs?: Logprob[] + perplexity?: number + uncertainty?: number } /** @@ -1027,7 +1814,7 @@ interface Fenced { content: string args?: { schema?: string } & Record - validation?: JSONSchemaValidation + validation?: FileEditValidation } interface XMLParseOptions { @@ -1041,7 +1828,22 @@ interface XMLParseOptions { } interface ParsePDFOptions { - filter?: (pageIndex: number, text?: string) => boolean + /** + * Disable removing trailing spaces in text + */ + disableCleanup?: boolean + /** + * Render each page as an image + */ + renderAsImage?: boolean + /** + * Zoom scaling with rendering pages and figures + */ + scale?: number + /** + * Disable caching with cache: false + */ + cache?: boolean } interface HTMLToTextOptions { @@ -1070,10 +1872,226 @@ interface ParseZipOptions { } type TokenEncoder = (text: string) => number[] +type TokenDecoder = (lines: Iterable) => string + +interface Tokenizer { + model: string + /** + * Number of tokens + */ + size?: number + encode: TokenEncoder + decode: TokenDecoder +} interface CSVParseOptions { delimiter?: string headers?: string[] + repair?: boolean +} + +interface TextChunk extends WorkspaceFile { + lineStart: number + lineEnd: number +} + +interface TextChunkerConfig extends LineNumberingOptions { + model?: ModelType + chunkSize?: number + chunkOverlap?: number + docType?: OptionsOrString< + | "cpp" + | "python" + | "py" + | "java" + | "go" + | "c#" + | "c" + | "cs" + | "ts" + | "js" + | "tsx" + | "typescript" + | "js" + | "jsx" + | "javascript" + | "php" + | "md" + | "mdx" + | "markdown" + | "rst" + | "rust" + > +} + +interface Tokenizers { + /** + * Estimates the number of tokens in the content. May not be accurate + * @param model + * @param text + */ + count(text: string, options?: { model?: ModelType }): Promise + + /** + * Truncates the text to a given number of tokens, approximation. + * @param model + * @param text + * @param maxTokens + * @param options + */ + truncate( + text: string, + maxTokens: number, + options?: { model?: ModelType; last?: boolean } + ): Promise + + /** + * Tries to resolve a tokenizer for a given model. Defaults to gpt-4o if not found. + * @param model + */ + resolve(model?: ModelType): Promise + + /** + * Chunk the text into smaller pieces based on a token limit and chunking strategy. + * @param text + * @param options + */ + chunk( + file: Awaitable, + options?: TextChunkerConfig + ): Promise +} + +interface HashOptions { + /** + * Algorithm used for hashing + */ + algorithm?: "sha-256" + /** + * Trim hash to this number of character + */ + length?: number + /** + * Include genaiscript version in the hash + */ + version?: boolean + /** + * Optional salting of the hash + */ + salt?: string + /** + * Read the content of workspace files object into the hash + */ + readWorkspaceFiles?: boolean +} + +interface VideoProbeResult { + streams: { + index: number + codec_name: string + codec_long_name: string + profile: string + codec_type: string + codec_tag_string: string + codec_tag: string + width?: number + height?: number + coded_width?: number + coded_height?: number + closed_captions?: number + film_grain?: number + has_b_frames?: number + sample_aspect_ratio?: string + display_aspect_ratio?: string + pix_fmt?: string + level?: number + color_range?: string + color_space?: string + color_transfer?: string + color_primaries?: string + chroma_location?: string + field_order?: string + refs?: number + is_avc?: string + nal_length_size?: number + id: string + r_frame_rate: string + avg_frame_rate: string + time_base: string + start_pts: number + start_time: number + duration_ts: number + duration: number + bit_rate: number + max_bit_rate: string + bits_per_raw_sample: number | string + nb_frames: number | string + nb_read_frames?: string + nb_read_packets?: string + extradata_size?: number + tags?: { + creation_time: string + language?: string + handler_name: string + vendor_id?: string + encoder?: string + } + disposition?: { + default: number + dub: number + original: number + comment: number + lyrics: number + karaoke: number + forced: number + hearing_impaired: number + visual_impaired: number + clean_effects: number + attached_pic: number + timed_thumbnails: number + captions: number + descriptions: number + metadata: number + dependent: number + still_image: number + } + sample_fmt?: string + sample_rate?: number + channels?: number + channel_layout?: string + bits_per_sample?: number | string + }[] + format: { + filename: string + nb_streams: number + nb_programs: number + format_name: string + format_long_name: string + start_time: number + duration: number + size: number + bit_rate: number + probe_score: number + tags: { + major_brand: string + minor_version: string + compatible_brands: string + creation_time: string + } + } +} + +interface PDFPageImage extends WorkspaceFile { + id: string + width: number + height: number +} + +interface PDFPage { + index: number + content: string + image?: string + figures?: PDFPageImage[] } interface Parsers { @@ -1085,6 +2103,12 @@ interface Parsers { options?: { defaultValue?: any } ): any | undefined + /** + * Parses text generated by an LLM as JSON payload + * @param content + */ + JSONLLM(content: string): any | undefined + /** * Parses text or file as a JSONL payload. Empty lines are ignore, and JSON5 is used for parsing. * @param content @@ -1125,14 +2149,36 @@ interface Parsers { PDF( content: string | WorkspaceFile, options?: ParsePDFOptions - ): Promise<{ file: WorkspaceFile; pages: string[] } | undefined> + ): Promise< + | { + /** + * Reconstructed text content from page content + */ + file: WorkspaceFile + /** + * Page text content + */ + pages: string[] + /** + * Rendered pages as images if `renderAsImage` is set + */ + images?: string[] + + /** + * Parse PDF content + */ + data: PDFPage[] + } + | undefined + > /** * Parses a .docx file * @param content */ DOCX( - content: string | WorkspaceFile + content: string | WorkspaceFile, + options?: { format: "markdown" | "text" | "html" } ): Promise<{ file: WorkspaceFile } | undefined> /** @@ -1165,7 +2211,7 @@ interface Parsers { */ INI( content: string | WorkspaceFile, - options?: { defaultValue?: any } + options?: INIParseOptions ): any | undefined /** @@ -1190,9 +2236,12 @@ interface Parsers { /** * Convert HTML to markdown * @param content html string or file - * @param options + * @param options rendering options */ - HTMLToMarkdown(content: string | WorkspaceFile): Promise + HTMLToMarkdown( + content: string | WorkspaceFile, + options?: HTMLToMarkdownOptions + ): Promise /** * Extracts the contents of a zip archive file @@ -1224,29 +2273,37 @@ interface Parsers { /** * Executes a tree-sitter query on a code file * @param file - * @param query tree sitter query; if missing, returns the entire tree + * @param query tree sitter query; if missing, returns the entire tree. `tags` return tags */ - code(file: WorkspaceFile, query?: string): Promise + code( + file: WorkspaceFile, + query?: OptionsOrString<"tags"> + ): Promise<{ captures: QueryCapture[] }> /** * Parses and evaluates a math expression * @param expression math expression compatible with mathjs + * @param scope object to read/write variables */ - math(expression: string): Promise + math( + expression: string, + scope?: object + ): Promise /** * Using the JSON schema, validates the content * @param schema JSON schema instance * @param content object to validate */ - validateJSON(schema: JSONSchema, content: any): JSONSchemaValidation + validateJSON(schema: JSONSchema, content: any): FileEditValidation /** * Renders a mustache template * @param text template text * @param data data to render */ - mustache(text: string | WorkspaceFile, data: Record): str + mustache(text: string | WorkspaceFile, data: Record): string + /** * Renders a jinja template */ @@ -1255,7 +2312,45 @@ interface Parsers { /** * Computes a diff between two files */ - diff(left: WorkspaceFile, right: WorkspaceFile, options?: DefDiffOptions): string + diff( + left: WorkspaceFile, + right: WorkspaceFile, + options?: DefDiffOptions + ): string + + /** + * Cleans up a dataset made of rows of data + * @param rows + * @param options + */ + tidyData(rows: object[], options?: DataFilter): object[] + + /** + * Applies a GROQ query to the data + * @param data data object to filter + * @param query query + * @see https://groq.dev/ + */ + GROQ(query: string, data: any): Promise + + /** + * Computes a sha1 that can be used for hashing purpose, not cryptographic. + * @param content content to hash + */ + hash(content: any, options?: HashOptions): Promise + + /** + * Optionally removes a code fence section around the text + * @param text + * @param language + */ + unfence(text: string, language: string): string + + /** + * Erase ... tags + * @param text + */ + unthink(text: string): string } interface AICIGenOptions { @@ -1321,7 +2416,7 @@ interface YAML { /** * Parses a YAML string to object */ - parse(text: string): any + parse(text: string | WorkspaceFile): any } interface XML { @@ -1329,7 +2424,22 @@ interface XML { * Parses an XML payload to an object * @param text */ - parse(text: string, options?: XMLParseOptions): any + parse(text: string | WorkspaceFile, options?: XMLParseOptions): any +} + +interface JSONSchemaUtilities { + /** + * Infers a JSON schema from an object + * @param obj + * @deprecated Use `fromParameters` instead + */ + infer(obj: any): Promise + + /** + * Converts a parameters schema to a JSON schema + * @param parameters + */ + fromParameters(parameters: PromptParametersSchema | undefined): JSONSchema } interface HTMLTableToJSONOptions { @@ -1349,6 +2459,10 @@ interface HTMLTableToJSONOptions { limitrows?: number | null } +interface HTMLToMarkdownOptions { + disableGfm?: boolean +} + interface HTML { /** * Converts all HTML tables to JSON. @@ -1368,15 +2482,24 @@ interface HTML { * Converts HTML markup to markdown * @param html */ - convertToMarkdown(html: string): Promise + convertToMarkdown( + html: string, + options?: HTMLToMarkdownOptions + ): Promise } interface GitCommit { sha: string + date: string message: string } interface Git { + /** + * Current working directory + */ + cwd: string + /** * Resolves the default branch for this repository */ @@ -1396,7 +2519,12 @@ interface Git { * Executes a git command in the repository and returns the stdout * @param cmd */ - exec(args: string[] | string, options?: { label?: string }): Promise + exec( + args: string[] | string, + options?: { + label?: string + } + ): Promise /** * Lists the branches in the git repository @@ -1436,6 +2564,9 @@ interface Git { paths?: ElementOrArray excludedPaths?: ElementOrArray unified?: number + algorithm?: "patience" | "minimal" | "histogram" | "myers" + ignoreSpaceChange?: boolean + extras?: string[] /** * Modifies the diff to be in a more LLM friendly format */ @@ -1448,11 +2579,187 @@ interface Git { log(options?: { base?: string head?: string + count?: number merges?: boolean + author?: string + until?: string + after?: string excludedGrep?: string | RegExp paths?: ElementOrArray excludedPaths?: ElementOrArray }): Promise + + /** + * Create a shallow git clone + * @param repository URL of the remote repository + * @param options various clone options + * @returns the path to the cloned repository + */ + shallowClone( + repository: string, + options?: { + /** + * Brnach to clone + */ + branch?: string + } + ): Promise + + /** + * Open a git client on a different directory + * @param cwd working directory + */ + client(cwd: string): Git +} + +/** + * A ffmpeg command builder. This instance is the 'native' fluent-ffmpeg command builder. + */ +interface FfmpegCommandBuilder { + seekInput(startTime: number | string): FfmpegCommandBuilder + duration(duration: number | string): FfmpegCommandBuilder + noVideo(): FfmpegCommandBuilder + noAudio(): FfmpegCommandBuilder + audioCodec(codec: string): FfmpegCommandBuilder + audioBitrate(bitrate: string | number): FfmpegCommandBuilder + audioChannels(channels: number): FfmpegCommandBuilder + audioFrequency(freq: number): FfmpegCommandBuilder + audioQuality(quality: number): FfmpegCommandBuilder + audioFilters( + filters: string | string[] | AudioVideoFilter[] + ): FfmpegCommandBuilder + toFormat(format: string): FfmpegCommandBuilder + + videoCodec(codec: string): FfmpegCommandBuilder + videoBitrate( + bitrate: string | number, + constant?: boolean + ): FfmpegCommandBuilder + videoFilters(filters: string | string[]): FfmpegCommandBuilder + outputFps(fps: number): FfmpegCommandBuilder + frames(frames: number): FfmpegCommandBuilder + keepDisplayAspectRatio(): FfmpegCommandBuilder + size(size: string): FfmpegCommandBuilder + aspectRatio(aspect: string | number): FfmpegCommandBuilder + autopad(pad?: boolean, color?: string): FfmpegCommandBuilder + + inputOptions(...options: string[]): FfmpegCommandBuilder + outputOptions(...options: string[]): FfmpegCommandBuilder +} + +interface FFmpegCommandOptions { + inputOptions?: ElementOrArray + outputOptions?: ElementOrArray + cache?: boolean | string + /** + * For video conversion, output size as `wxh` + */ + size?: string +} + +interface VideoExtractFramesOptions extends FFmpegCommandOptions { + /** + * A set of seconds or timestamps (`[[hh:]mm:]ss[.xxx]`) + */ + timestamps?: number[] | string[] + /** + * Number of frames to extract + */ + count?: number + /** + * Extract frames on the start of each transcript segment + */ + transcript?: TranscriptionResult | string + /** + * Extract Intra frames (keyframes). This is a efficient and fast decoding. + */ + keyframes?: boolean + /** + * Picks frames that exceed scene threshold (between 0 and 1), typically between 0.2, and 0.5. + * This is computationally intensive. + */ + sceneThreshold?: number + /** + * Output of the extracted frames + */ + format?: OptionsOrString<"jpeg" | "png"> +} + +interface VideoExtractClipOptions extends FFmpegCommandOptions { + /** + * Start time of the clip in seconds or timestamp (`[[hh:]mm:]ss[.xxx]`) + */ + start: number | string + /** + * Duration of the clip in seconds or timestamp (`[[hh:]mm:]ss[.xxx]`). + * You can also specify `end`. + */ + duration?: number | string + /** + * End time of the clip in seconds or timestamp (`[[hh:]mm:]ss[.xxx]`). + * You can also specify `duration`. + */ + end?: number | string +} + +interface VideoExtractAudioOptions extends FFmpegCommandOptions { + /** + * Optimize for speech-to-text transcription. Default is true. + */ + transcription?: boolean + + forceConversion?: boolean +} + +interface Ffmpeg { + /** + * Extracts metadata information from a video file using ffprobe + * @param filename + */ + probe( + file: string | WorkspaceFile, + options?: FFmpegCommandOptions + ): Promise + + /** + * Extracts frames from a video file + * @param options + */ + extractFrames( + file: string | WorkspaceFile, + options?: VideoExtractFramesOptions + ): Promise + + /** + * Extracts a clip from a video. Returns the generated video file path. + */ + extractClip( + file: string | WorkspaceFile, + options: VideoExtractClipOptions + ): Promise + + /** + * Extract the audio track from a video + * @param videoPath + */ + extractAudio( + file: string | WorkspaceFile, + options?: VideoExtractAudioOptions + ): Promise + + /** + * Runs a ffmpeg command and returns the list of generated file names + * @param input + * @param builder manipulates the ffmpeg command and returns the output name + */ + run( + input: string | WorkspaceFile, + builder: ( + cmd: FfmpegCommandBuilder, + options?: { input: string; dir: string } + ) => Awaitable, + options?: FFmpegCommandOptions + ): Promise } interface GitHubOptions { @@ -1462,6 +2769,7 @@ interface GitHubOptions { auth?: string ref?: string refName?: string + issueNumber?: number } type GitHubWorkflowRunStatus = @@ -1513,9 +2821,11 @@ interface GitHubIssue { number: number state: string state_reason?: "completed" | "reopened" | "not_planned" | null - html_url: string + html_url: string draft?: boolean reactions?: GitHubReactions + user: GitHubUser + assignee?: GitHubUser } interface GitHubReactions { @@ -1534,6 +2844,7 @@ interface GitHubReactions { interface GitHubComment { id: number body?: string + user: GitHubUser created_at: string updated_at: string html_url: string @@ -1541,6 +2852,12 @@ interface GitHubComment { } interface GitHubPullRequest extends GitHubIssue { + head: { + ref: string + } + base: { + ref: string + } } interface GitHubCodeSearchResult { @@ -1574,6 +2891,17 @@ interface GitHubUser { login: string } +interface GitHubRelease { + id: number + tag_name: string + name: string + draft?: boolean + prerelease?: boolean + html_url: string + published_at: string + body?: string +} + interface GitHub { /** * Gets connection information for octokit @@ -1632,23 +2960,36 @@ interface GitHub { labels?: string sort?: "created" | "updated" | "comments" direction?: "asc" | "desc" + creator?: string + assignee?: string + since?: string + mentioned?: string } & GitHubPaginationOptions ): Promise - /** * Gets the details of a GitHub issue - * @param number issue number (not the issue id!) + * @param issueNumber issue number (not the issue id!). If undefined, reads value from GITHUB_ISSUE environment variable. */ - async getIssue(number: number): Promise - + getIssue(issueNumber?: number | string): Promise + + /** + * Create a GitHub issue comment + * @param issueNumber issue number (not the issue id!). If undefined, reads value from GITHUB_ISSUE environment variable. + * @param body the body of the comment as Github Flavored markdown + */ + createIssueComment( + issueNumber: number | string, + body: string + ): Promise + /** * Lists comments for a given issue * @param issue_number * @param options */ listIssueComments( - issue_number: number, + issue_number: number | string, options?: GitHubPaginationOptions ): Promise @@ -1666,9 +3007,9 @@ interface GitHub { /** * Gets the details of a GitHub pull request - * @param pull_number pull request number (not the pull request id!) + * @param pull_number pull request number. Default resolves the pull request for the current branch. */ - getPullRequest(pull_number: number): Promise + getPullRequest(pull_number?: number | string): Promise /** * Lists comments for a given pull request @@ -1711,6 +3052,12 @@ interface GitHub { */ listRepositoryLanguages(): Promise> + /** + * List latest releases in a GitHub repository + * @param options + */ + listReleases(options?: GitHubPaginationOptions): Promise + /** * Lists tags in a GitHub repository */ @@ -1728,7 +3075,14 @@ interface GitHub { /** * Gets the underlying Octokit client */ - client(): Promise + api(): Promise + + /** + * Opens a client to a different repository + * @param owner + * @param repo + */ + client(owner: string, repo: string): GitHub } interface MD { @@ -1736,12 +3090,15 @@ interface MD { * Parses front matter from markdown * @param text */ - frontmatter(text: string, format?: "yaml" | "json" | "toml" | "text"): any + frontmatter( + text: string | WorkspaceFile, + format?: "yaml" | "json" | "toml" | "text" + ): any /** * Removes the front matter from the markdown text */ - content(text: string): string + content(text: string | WorkspaceFile): string /** * Merges frontmatter with the existing text @@ -1761,7 +3118,7 @@ interface JSONL { * Parses a JSONL string to an array of objects * @param text */ - parse(text: string): any[] + parse(text: string | WorkspaceFile): any[] /** * Converts objects to JSONL format * @param objs @@ -1774,7 +3131,7 @@ interface INI { * Parses a .ini file * @param text */ - parse(text: string): any + parse(text: string | WorkspaceFile): any /** * Converts an object to.ini string @@ -1783,6 +3140,20 @@ interface INI { stringify(value: any): string } +interface JSON5 { + /** + * Parses a JSON/YAML/XML string to an object + * @param text + */ + parse(text: string | WorkspaceFile): any + + /** + * Renders an object to a JSON5-LLM friendly string + * @param value + */ + stringify(value: any): string +} + interface CSVStringifyOptions { delimiter?: string header?: boolean @@ -1801,13 +3172,7 @@ interface CSV { * @param options.headers - An array of headers to use. If not provided, headers will be inferred from the first row. * @returns An array of objects representing the parsed CSV data. */ - parse( - text: string, - options?: { - delimiter?: string - headers?: string[] - } - ): object[] + parse(text: string | WorkspaceFile, options?: CSVParseOptions): object[] /** * Converts an array of objects to a CSV string. @@ -1828,16 +3193,51 @@ interface CSV { * @returns A markdown string representing the data table. */ markdownify(csv: object[], options?: { headers?: string[] }): string + + /** + * Splits the original array into chunks of the specified size. + * @param csv + * @param rows + */ + chunk( + csv: object[], + size: number + ): { chunkStartIndex: number; rows: object[] }[] +} + +/** + * Provide service for responsible. + */ +interface ContentSafety { + /** + * Scans text for the risk of a User input attack on a Large Language Model. + * If not supported, the method is not defined. + */ + detectPromptInjection?( + content: Awaitable< + ElementOrArray | ElementOrArray + > + ): Promise<{ attackDetected: boolean; filename?: string; chunk?: string }> + /** + * Analyzes text for harmful content. + * If not supported, the method is not defined. + * @param content + */ + detectHarmfulContent?( + content: Awaitable< + ElementOrArray | ElementOrArray + > + ): Promise<{ + harmfulContentDetected: boolean + filename?: string + chunk?: string + }> } interface HighlightOptions { maxLength?: number } -interface WebSearchResult { - webPages: WorkspaceFile[] -} - interface VectorSearchOptions extends EmbeddingsModelOptions { /** * Maximum number of embeddings to use @@ -1893,10 +3293,20 @@ interface FuzzSearchOptions { interface Retrieval { /** - * Executers a Bing web search. Requires to configure the BING_SEARCH_API_KEY secret. + * Executers a web search with Tavily or Bing Search. * @param query */ - webSearch(query: string): Promise + webSearch( + query: string, + options?: { + count?: number + provider?: "tavily" | "bing" + /** + * Return undefined when no web search providers are present + */ + ignoreMissingProvider?: boolean + } + ): Promise /** * Search using similarity distance on embeddings @@ -1920,14 +3330,7 @@ interface Retrieval { ): Promise } -type FetchTextOptions = Omit - -interface DataFilter { - /** - * The keys to select from the object. - * If a key is prefixed with -, it will be removed from the object. - */ - headers?: string[] +interface ArrayFilter { /** * Selects the first N elements from the data */ @@ -1940,20 +3343,39 @@ interface DataFilter { * Selects the a random sample of N items in the collection. */ sliceSample?: number +} +interface DataFilter extends ArrayFilter { + /** + * The keys to select from the object. + * If a key is prefixed with -, it will be removed from the object. + */ + headers?: ElementOrArray /** * Removes items with duplicate values for the specified keys. */ - distinct?: string[] + distinct?: ElementOrArray + /** + * Sorts the data by the specified key(s) + */ + sort?: ElementOrArray } interface DefDataOptions extends Omit, - DataFilter { + FenceFormatOptions, + DataFilter, + ContentSafetyOptions { /** * Output format in the prompt. Defaults to Markdown table rendering. */ format?: "json" | "yaml" | "csv" + + /** + * GROQ query to filter the data + * @see https://groq.dev/ + */ + query?: string } interface DefSchemaOptions { @@ -1963,24 +3385,53 @@ interface DefSchemaOptions { format?: "typescript" | "json" | "yaml" } -type ChatFunctionHandler = ( - args: { context: ToolCallContext } & Record -) => Awaitable +type ChatFunctionArgs = { context: ToolCallContext } & Record +type ChatFunctionHandler = (args: ChatFunctionArgs) => Awaitable +type ChatMessageRole = "user" | "assistant" | "system" + +interface HistoryMessageUser { + role: "user" + content: string +} + +interface HistoryMessageAssistant { + role: "assistant" + name?: string + content: string +} interface WriteTextOptions extends ContextExpansionOptions { /** - * Append text to the assistant response + * Append text to the assistant response. This feature is not supported by all models. + * @deprecated */ assistant?: boolean + /** + * Specifies the message role. Default is user + */ + role?: ChatMessageRole } type PromptGenerator = (ctx: ChatGenerationContext) => Awaitable -interface PromptGeneratorOptions extends ModelOptions, PromptSystemOptions { +interface PromptGeneratorOptions + extends ModelOptions, + PromptSystemOptions, + ContentSafetyOptions { /** * Label for trace */ label?: string + + /** + * Write file edits to the file system + */ + applyEdits?: boolean + + /** + * Throws if the generation is not successful + */ + throwOnError?: boolean } interface FileOutputOptions { @@ -1996,7 +3447,14 @@ interface FileOutput { options?: FileOutputOptions } -interface ImportTemplateOptions {} +interface ImportTemplateOptions { + /** + * Ignore unknown arguments + */ + allowExtraArguments?: boolean +} + +type PromptCacheControlType = "ephemeral" interface PromptTemplateString { /** @@ -2024,14 +3482,27 @@ interface PromptTemplateString { * @param tokens */ maxTokens(tokens: number): PromptTemplateString + + /** + * Updates the role of the message + */ + role(role: ChatMessageRole): PromptTemplateString + + /** + * Configure the cacheability of the prompt. + * @param value cache control type + */ + cacheControl(value: PromptCacheControlType): PromptTemplateString } +type ImportTemplateArgumentType = + | Awaitable + | (() => Awaitable) + interface ChatTurnGenerationContext { importTemplate( files: string | string[], - arguments?: Record< - string | number | boolean | (() => string | number | boolean) - >, + arguments?: Record, options?: ImportTemplateOptions ): void writeText(body: Awaitable, options?: WriteTextOptions): void @@ -2054,7 +3525,7 @@ interface ChatTurnGenerationContext { ): string defData( name: string, - data: object[] | object, + data: Awaitable, options?: DefDataOptions ): string defDiff( @@ -2069,31 +3540,208 @@ interface ChatTurnGenerationContext { interface FileUpdate { before: string after: string - validation?: JSONSchemaValidation + validation?: FileEditValidation } interface RunPromptResultPromiseWithOptions extends Promise { options(values?: PromptGeneratorOptions): RunPromptResultPromiseWithOptions } +interface DefToolOptions { + /** + * Maximum number of tokens per tool content response + */ + maxTokens?: number +} + +interface DefAgentOptions extends Omit { + /** + * Excludes agent conversation from agent memory + */ + disableMemory?: boolean + + /** + * Disable memory query on each query (let the agent call the tool) + */ + disableMemoryQuery?: boolean +} + +type ChatAgentHandler = ( + ctx: ChatGenerationContext, + args: ChatFunctionArgs +) => Awaitable + +interface McpServerConfig { + command: string + args: string[] + params?: string[] + version?: string + + id: string + options?: DefToolOptions +} + +type McpServersConfig = Record> + +type ZodTypeLike = { _def: any; safeParse: any; refine: any } + +type BufferLike = + | string + | WorkspaceFile + | Buffer + | Blob + | ArrayBuffer + | Uint8Array + | ReadableStream + +type TranscriptionModelType = OptionsOrString<"openai:whisper-1"> + +interface TranscriptionOptions { + /** + * Model to use for transcription. By default uses the `transcribe` alias. + */ + model?: TranscriptionModelType + + /** + * Translate to English. + */ + translate?: boolean + + /** + * Input language in iso-639-1 format. + * @see https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes + */ + language?: string + + /** + * The sampling temperature, between 0 and 1. + * Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. + */ + temperature?: number + + /** + * If true, the transcription will be cached. + */ + cache?: boolean | string +} + +interface TranscriptionResult { + /** + * Complete transcription text + */ + text: string + /** + * Error if any + */ + error?: SerializedError + + /** + * SubRip subtitle string from segments + */ + srt?: string + + /** + * WebVTT subtitle string from segments + */ + vtt?: string + + /** + * Individual segments + */ + segments?: { + /** + * The start time of the segment + */ + start: number + /** + * The transcribed text. + */ + text: string + /** + * Seek offset of the segment + */ + seek?: number + /** + * End time in seconds + */ + end?: number + /** + * Temperature used for the generation of the segment + */ + temperature?: number + }[] +} + +type SpeechModelType = OptionsOrString<"openai:tts-1-hd" | "openai:tts-1"> + +type SpeechVoiceType = OptionsOrString< + "alloy", + "ash", + "coral", + "echo", + "fable", + "onyx", + "nova", + "sage", + "shimmer" +> + +interface SpeechOptions { + /** + * Speech to text model + */ + model?: SpeechModelType + /** + * Voice to use (model-specific) + */ + voice?: SpeechVoiceType + /** + * If true, the transcription will be cached. + */ + cache?: boolean | string +} + +interface SpeechResult { + /** + * Generate audio-buffer file + */ + filename?: string + /** + * Error if any + */ + error?: SerializedError +} + interface ChatGenerationContext extends ChatTurnGenerationContext { defSchema( name: string, - schema: JSONSchema, + schema: JSONSchema | ZodTypeLike, options?: DefSchemaOptions ): string defImages( - files: ElementOrArray, + files: ElementOrArray, options?: DefImagesOptions ): void defTool( - tool: ToolCallback | AgenticToolCallback | AgenticToolProviderCallback + tool: + | ToolCallback + | AgenticToolCallback + | AgenticToolProviderCallback + | McpServersConfig, + options?: DefToolOptions ): void defTool( name: string, description: string, parameters: PromptParametersSchema | JSONSchema, - fn: ChatFunctionHandler + fn: ChatFunctionHandler, + options?: DefToolOptions + ): void + defAgent( + name: string, + description: string, + fn: string | ChatAgentHandler, + options?: DefAgentOptions ): void defChatParticipant( participant: ChatParticipantHandler, @@ -2101,7 +3749,7 @@ interface ChatGenerationContext extends ChatTurnGenerationContext { ): void defFileOutput( pattern: ElementOrArray, - description?: string, + description: string, options?: FileOutputOptions ): void runPrompt( @@ -2112,14 +3760,31 @@ interface ChatGenerationContext extends ChatTurnGenerationContext { strings: TemplateStringsArray, ...args: any[] ): RunPromptResultPromiseWithOptions + defFileMerge(fn: FileMergeHandler): void + defOutputProcessor(fn: PromptOutputProcessorHandler): void + transcribe( + audio: string | WorkspaceFile, + options?: TranscriptionOptions + ): Promise + speak(text: string, options?: SpeechOptions): Promise } interface GenerationOutput { + /** + * full chat history + */ + messages: ChatCompletionMessageParam[] + /** * LLM output. */ text: string + /** + * Reasoning produced by model + */ + reasoning?: string + /** * Parsed fence sections */ @@ -2337,6 +4002,16 @@ interface BrowseSessionOptions extends BrowserOptions, TimeoutOptions { * @link https://playwright.dev/docs/api/class-browser#browser-new-context-option-java-script-enabled */ javaScriptEnabled?: boolean + + /** + * Enable recording video for all pages. Implies incognito mode. + */ + recordVideo?: + | boolean + | { + width: number + height: number + } } interface TimeoutOptions { @@ -2493,6 +4168,11 @@ interface BrowserLocatorSelector { * @link https://playwright.dev/docs/api/class-locator */ interface BrowserLocator extends BrowserLocatorSelector { + /** + * When the locator points to a list of elements, this returns an array of locators, pointing to their respective elements. + * locator.all() does not wait for elements to match the locator, and instead immediately returns whatever is present in the page. + */ + all(): Promise /** * Click an element * @link https://playwright.dev/docs/api/class-locator#locator-click @@ -2613,6 +4293,13 @@ interface BrowseResponse { interface BrowserJSHandle {} +interface BrowserVideo { + /** + * Returns the video path once the page is closed. + */ + path(): Promise +} + /** * A playwright Page instance * @link https://playwright.dev/docs/api/class-page @@ -2662,7 +4349,8 @@ interface BrowserPage extends BrowserLocatorSelector { locator(selector: string): BrowserLocator /** - * Closes the browser page, context and other resources + * Closes the browser page, context and other resources. + * If video recording is enabled, the video will be saved at this time. */ close(): Promise @@ -2684,6 +4372,11 @@ interface BrowserPage extends BrowserLocatorSelector { selector: string, arg?: any ): Promise + + /** + * Video object associated with this page, if `recordVideo` option is enabled. + */ + video(): BrowserVideo | null } interface ShellSelectOptions {} @@ -2715,7 +4408,9 @@ interface ShellHost { args: string[], options?: ShellOptions ): Promise +} +interface UserInterfaceHost { /** * Starts a headless browser and navigates to the page. * Requires to [install playwright and dependencies](https://microsoft.github.io/genaiscript/reference/scripts/browser). @@ -2775,19 +4470,24 @@ interface ContainerOptions { env?: Record /** - * Assign the specified name to the container. Must match [a-zA-Z0-9_-]+ + * Assign the specified name to the container. Must match [a-zA-Z0-9_-]+. */ name?: string /** - * Disable automatic purge of container and volume directory + * Disable automatic purge of container and volume directory and potentially reuse with same name, configuration. */ - disablePurge?: boolean + persistent?: boolean /** * List of exposed TCP ports */ ports?: ElementOrArray + + /** + * Commands to executes after the container is created + */ + postCreateCommands?: ElementOrArray } interface PromiseQueue { @@ -2818,7 +4518,111 @@ interface PromiseQueue { ): Promise } -interface PromptHost extends ShellHost { +interface LanguageModelReference { + provider: string + model: string +} + +interface LanguageModelHost { + /** + * Resolve a language model alias to a provider and model based on the current configuration + * @param modelId + */ + resolveLanguageModel(modelId?: string): Promise +} + +type ContentSafetyProvider = "azure" + +interface ContentSafetyHost { + /** + * Resolve a content safety client + * @param id safety detection project + */ + contentSafety(id?: ContentSafetyProvider): Promise +} + +type FetchOptions = RequestInit & { + retryOn?: number[] // HTTP status codes to retry on + retries?: number // Number of retry attempts + retryDelay?: number // Initial delay between retries + maxDelay?: number // Maximum delay between retries +} + +type FetchTextOptions = Omit + +interface PythonRuntimeOptions { + cache?: string +} + +interface PythonRuntime { + /** + * Runs python code and returns the result + * @param code python code + */ + run(code: string): Promise + + /** + * Imports a package using micropip + * @param pkg name and version + */ + import(pkg: string): Promise + + /** + * Access to python global variables + */ + globals: PythonProxy +} + +interface PythonProxy { + /** + * Reads a value from the python object + * @param name + */ + get(name: string): T + /** + * Copyies a value into the python object + * @param name + * @param value + */ + set(name: string, value: T): void +} + +interface PromptHost + extends ShellHost, + UserInterfaceHost, + LanguageModelHost, + ContentSafetyHost { + /** + * A fetch wrapper with proxy, retry and timeout handling. + */ + fetch( + input: string | URL | globalThis.Request, + init?: FetchOptions + ): Promise + + /** + * A function that fetches text from a URL or a file + * @param url + * @param options + */ + fetchText( + url: string | WorkspaceFile, + options?: FetchTextOptions + ): Promise<{ + ok: boolean + status: number + text?: string + file?: WorkspaceFile + }> + + /** + * Opens a in-memory key-value cache for the given cache name. Entries are dropped when the cache grows too large. + * @param cacheName + */ + cache( + cacheName: string + ): Promise> + /** * Starts a container * @param options container creation options @@ -2829,6 +4633,50 @@ interface PromptHost extends ShellHost { * Create a new promise queue to run async functions with limited concurrency */ promiseQueue(concurrency: number): PromiseQueue + + /** + * Instantiates a python evaluation environment powered by pyodide (https://pyodide.org/) + */ + python(options?: PythonRuntimeOptions): Promise + + /** + * Gets a client to a Microsoft Teams channel from a share link URL; + * uses `GENAISCRIPT_TEAMS_CHANNEL_URL` environment variable if `shareUrl` is not provided. + * Uses Azure CLI login for authentication. + * @param url + */ + teamsChannel(shareUrl?: string): Promise +} + +interface WorkspaceFileWithDescription extends WorkspaceFile { + /** + * File description used for videos. + */ + description?: string +} + +/** + * A client to a messaging channel + */ +interface MessageChannelClient { + /** + * Posts a message with attachments to the channel + * @param message + * @param options + */ + postMessage( + message: string, + options?: { + /** + * File attachments that will be added in the channel folder + */ + files?: (string | WorkspaceFileWithDescription)[] + /** + * Sets to false to remove AI generated disclaimer + */ + disclaimer?: boolean | string + } + ): Promise } interface ContainerHost extends ShellHost { @@ -2837,21 +4685,21 @@ interface ContainerHost extends ShellHost { */ id: string + /** + * Name assigned to the container. For persistent containers, also contains the sha of the options + */ + name: string + /** * Disable automatic purge of container and volume directory */ - disablePurge: boolean + persistent: boolean /** * Path to the volume mounted in the host */ hostPath: string - /** - * Path to the volume mounted in the container - */ - containerPath: string - /** * Writes a file as text to the container file system * @param path @@ -2870,24 +4718,43 @@ interface ContainerHost extends ShellHost { * @param fromHost glob matching files * @param toContainer directory in the container */ - copyTo(fromHost: string | string[], toContainer: string): Promise + copyTo(fromHost: string | string[], toContainer: string): Promise + + /** + * List files in a directory in the container + * @param dir + */ + listFiles(dir: string): Promise /** * Stops and cleans out the container */ stop(): Promise + /** + * Pause container + */ + pause(): Promise + + /** + * Resume execution of the container + */ + resume(): Promise + /** * Force disconnect network */ disconnect(): Promise + + /** + * A promise queue of concurrency 1 to run serialized functions against the container + */ + scheduler: PromiseQueue } interface PromptContext extends ChatGenerationContext { script(options: PromptArgs): void system(options: PromptSystemArgs): void - defFileMerge(fn: FileMergeHandler): void - defOutputProcessor(fn: PromptOutputProcessorHandler): void env: ExpansionVariables path: Path parsers: Parsers @@ -2925,9 +4792,7 @@ declare function system(options: PromptSystemArgs): void */ declare function importTemplate( files: string | string[], - arguments?: Record< - string | number | boolean | (() => string | number | boolean) - >, + arguments?: Record, options?: ImportTemplateOptions ): void @@ -2940,6 +4805,14 @@ declare function writeText( options?: WriteTextOptions ): void +/** + * Append given string to the prompt as an assistant message. + */ +declare function assistant( + text: Awaitable, + options?: Omit +): void + /** * Append given string to the prompt. It automatically appends "\n". * `` $`foo` `` is the same as `text("foo")`. @@ -2997,13 +4870,33 @@ declare function defFileOutput( * @param fn callback invoked when the LLM requests to run this function */ declare function defTool( - tool: ToolCallback | AgenticToolCallback | AgenticToolProviderCallback + tool: + | ToolCallback + | AgenticToolCallback + | AgenticToolProviderCallback + | McpServersConfig, + options?: DefToolOptions ): void declare function defTool( name: string, description: string, parameters: PromptParametersSchema | JSONSchema, - fn: ChatFunctionHandler + fn: ChatFunctionHandler, + options?: DefToolOptions +): void + +/** + * Declares a LLM agent tool that can be called from the prompt. + * @param name name of the agent, do not prefix with agent + * @param description description of the agent, used by the model to choose when and how to call the agent + * @param fn prompt generation context + * @param options additional options for the agent LLM + */ +declare function defAgent( + name: string, + description: string, + fn: string | ChatAgentHandler, + options?: DefAgentOptions ): void /** @@ -3072,6 +4965,16 @@ declare var MD: MD */ declare var JSONL: JSONL +/** + * JSON5 parsing + */ +declare var JSON5: JSON5 + +/** + * JSON Schema utilities + */ +declare var JSONSchema: JSONSchemaUtilities + /** * AICI operations */ @@ -3093,8 +4996,17 @@ declare var github: GitHub declare var git: Git /** - * Fetches a given URL and returns the response. - * @param url + * Access to ffmpeg operations + */ +declare var ffmpeg: Ffmpeg + +/** + * Computation around tokens + */ +declare var tokenizers: Tokenizers + +/** + * @deprecated use `host.fetchText` instead */ declare function fetchText( url: string | WorkspaceFile, @@ -3109,7 +5021,7 @@ declare function fetchText( */ declare function defSchema( name: string, - schema: JSONSchema, + schema: JSONSchema | ZodTypeLike, options?: DefSchemaOptions ): string @@ -3119,7 +5031,7 @@ declare function defSchema( * @param options */ declare function defImages( - files: ElementOrArray, + files: ElementOrArray, options?: DefImagesOptions ): void @@ -3132,7 +5044,7 @@ declare function defImages( */ declare function defData( name: string, - data: object[] | object, + data: Awaitable, options?: DefDataOptions ): string @@ -3186,3 +5098,23 @@ declare function defChatParticipant( participant: ChatParticipantHandler, options?: ChatParticipantOptions ): void + +/** + * Transcribes audio to text. + * @param audio An audio file to transcribe. + * @param options + */ +declare function transcribe( + audio: string | WorkspaceFile, + options?: TranscriptionOptions +): Promise + +/** + * Converts text to speech. + * @param text + * @param options + */ +declare function speak( + text: string, + options?: SpeechOptions +): Promise diff --git a/genaisrc/mycop.genai.mts b/genaisrc/mycop.genai.mts new file mode 100644 index 000000000..5ab897313 --- /dev/null +++ b/genaisrc/mycop.genai.mts @@ -0,0 +1,76 @@ + +script({ + title: "Invoke LLM code update", +}) + + +async function runCodePrompt(role, message, code) { + const answer = await runPrompt( + (_) => { + _.def("ROLE", role); + _.def("REQUEST", message); + _.def("CODE", code); + _.$`Your role is . + The request is given by + original code: + .` + } + ) + console.log(answer.text); + return answer.text; +} + +async function invokeLLMUpdate(code, inputFile) { + + let role = `You are a highly experienced compiler engineer with over 20 years of expertise, + specializing in C and C++ programming. Your deep knowledge of best coding practices + and software engineering principles enables you to produce robust, efficient, and + maintainable code in any scenario.`; + + let userMessage = `Please modify the original code to ensure that it enforces the following: + - do not use pointer arithmetic. + - do not introduce uses of std::vector. + - only make replacements that are compatible with the ones listed below. + - add white space between operators: + For example: + i=0 + by + i = 0 + For example + a+b + by + a + b + - remove brackets around single statements: + For example: + { break; } + by + break; + - replaces uses of for loops using begin(), end() iterator patterns by C++21 style for loops + For example replace + for (auto it = x.begin(), end = x.end(); it != end; ++it) + by + for (auto & e : x) + + For example, replace + for (unsigned i = 0; i < a->get_num_args(); ++i) { + expr* arg = a->get_arg(i); + ... + } + by + for (auto arg : *a) { + ... + } + `; + + return runCodePrompt(role, userMessage, code); +} + + +const inputFile = env.files[0]; +const file = await workspace.readText(inputFile); +const answer = await invokeLLMUpdate(file.content, inputFile); +// Extract the code from the answer by removing ```cpp and ```: +let code = answer.replace(/```cpp/g, "").replace(/```/g, ""); +const outputFile = inputFile.filename + ".patch"; +await workspace.writeText(outputFile, code); +