diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 67476071d..f11a72775 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,25 +1,25 @@ -// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at: -// https://github.com/microsoft/vscode-dev-containers/tree/v0.134.0/containers/javascript-node { - "name": "Node.js", - "build": { - "dockerfile": "Dockerfile", - "args": { - "VARIANT": "16" - } - }, - // Add the IDs of extensions you want installed when the container is created. + "image": "mcr.microsoft.com/devcontainers/javascript-node:20", "customizations": { "vscode": { "extensions": [ - "dbaeumer.vscode-eslint", + "GitHub.copilot-chat", "esbenp.prettier-vscode", + "dbaeumer.vscode-eslint", + "bierner.markdown-mermaid", + "yoavbls.pretty-ts-errors", + "file-icons.file-icons", + "GitHub.vscode-pull-request-github", + "johnpapa.vscode-peacock", + "usernamehw.errorlens", "genaiscript.genaiscript-vscode" ] } }, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - "forwardPorts": [8080, 8000], - // Comment out the next line to run as root instead. - "remoteUser": "node" -} + "features": { + "ghcr.io/ghcr.io/devcontainers/features/github-cli:1.0.13": {}, + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + "ghcr.io/devcontainers/features/azure-cli:1.2.5": {}, + "ghcr.io/devcontainers/features/python:1.6.3": {} + } +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index f8106d4f0..8167deae1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -19,5 +19,8 @@ "**/yotta_modules": true, "**/yotta_targets": true, "**/pxt_modules": true + }, + "genaiscript.languageChatModels": { + "openai:gpt-4o": "gpt-4o" } } \ No newline at end of file diff --git a/button/_locales/de/jacdac-button-jsdoc-strings.json b/button/_locales/de/jacdac-button-jsdoc-strings.json new file mode 100644 index 000000000..32bd0859d --- /dev/null +++ b/button/_locales/de/jacdac-button-jsdoc-strings.json @@ -0,0 +1,24 @@ +{ + "jacdac.ButtonEvent.Down": "Ausgelöst, wenn die Taste von inaktiv zu aktiv wechselt.", + "jacdac.ButtonEvent.Hold": "Argument: time ms uint32_t. Ausgelöst, wenn die Drückzeit größer als 500ms ist und dann mindestens alle 500ms, solange die Taste gedrückt bleibt. Der 'time'-Parameter zeichnet die Zeit auf, die die Taste gehalten wurde (seit dem Down-Ereignis).\n* ```\nconst [time] = jdunpack<[number]>(buf, \"u32\")\n```", + "jacdac.ButtonEvent.Up": "Argument: time ms uint32_t. Ausgelöst, wenn die Taste von aktiv zu inaktiv wechselt. Der 'time'-Parameter zeichnet die Zeit zwischen den Down- und Up-Ereignissen auf.\n* ```\nconst [time] = jdunpack<[number]>(buf, \"u32\")\n```", + "jacdac.ButtonEventPack.Hold": "Paketformat für 'hold'-Daten.", + "jacdac.ButtonEventPack.Up": "Paketformat für 'up'-Daten.", + "jacdac.ButtonReg.Analog": "Konstantes boolesches (uint8_t). Gibt an, ob die Taste analoge `Druck`-Messwerte liefert.\n* ```\nconst [analog] = jdunpack<[number]>(buf, \"u8\")\n```", + "jacdac.ButtonReg.Pressed": "Schreibgeschütztes boolesches (uint8_t). Bestimmt, ob die Taste derzeit gedrückt wird.", + "jacdac.ButtonReg.Pressure": "Schreibgeschütztes Verhältnis u0.16 (uint16_t). Gibt den Druckzustand der Taste an, wobei `0` offen ist.\n* ```\nconst [pressure] = jdunpack<[number]>(buf, \"u0.16\")\n```", + "jacdac.ButtonRegPack.Analog": "Paketformat für 'analog'-Daten.", + "jacdac.ButtonRegPack.Pressed": "Paketformat für 'pressed'-Daten.", + "jacdac.ButtonRegPack.Pressure": "Paketformat für 'pressure'-Daten.", + "modules": "Jacdac-Module", + "modules.ButtonClient": "Ein Druckknopf, der in die inaktive Position zurückkehrt, wenn er nicht mehr betätigt wird.", + "modules.ButtonClient.analog": "Gibt an, ob die Taste analoge ``Druck``-Messwerte liefert.", + "modules.ButtonClient.holdDuration": "Die zuletzt gemeldete Haltezeit, wenn die Taste gedrückt ist.\n* Die `down`- und `hold`-Ereignisse melden auch die gesamte Haltezeit in Millisekunden.\nDer Wert ist die letzte Haltezeit, während die Taste oben ist.", + "modules.ButtonClient.onDown": "Ausgelöst, wenn die Taste von inaktiv zu aktiv wechselt.", + "modules.ButtonClient.onEvent": "Registriere Code, der ausgeführt wird, wenn ein Ereignis ausgelöst wird", + "modules.ButtonClient.onHold": "Ausgelöst, wenn die Drückzeit größer als 500ms ist und dann mindestens alle 500ms, solange die Taste gedrückt bleibt. Der 'time'-Parameter zeichnet die Zeit auf, die die Taste gehalten wurde (seit dem Down-Ereignis).", + "modules.ButtonClient.onPressureChangedBy": "Code ausführen, wenn sich der Druck um den angegebenen Schwellenwert ändert.", + "modules.ButtonClient.onUp": "Ausgelöst, wenn die Taste von aktiv zu inaktiv wechselt. Der 'time'-Parameter zeichnet die Zeit zwischen den Down- und Up-Ereignissen auf.", + "modules.ButtonClient.pressed": "Bestimmt, ob die Taste derzeit gedrückt wird.\n* Wenn das Ereignis ``down`` beobachtet wird, ist ``pressed`` wahr; wenn ``up`` oder ``hold`` beobachtet werden, ist ``pressed`` falsch.\nZur Initialisierung warten Sie auf ein beliebiges Ereignis oder eine Zeitüberschreitung, damit ``pressed`` nach 750ms (1,5x Haltezeit) wahr ist.", + "modules.ButtonClient.pressure": "Gibt den Druckzustand der Taste an, wobei ``0`` offen ist." +} \ No newline at end of file diff --git a/button/_locales/fr/jacdac-button-jsdoc-strings.json b/button/_locales/fr/jacdac-button-jsdoc-strings.json new file mode 100644 index 000000000..0ee4564b5 --- /dev/null +++ b/button/_locales/fr/jacdac-button-jsdoc-strings.json @@ -0,0 +1,24 @@ +{ + "jacdac.ButtonEvent.Down": "Émis lorsque le bouton passe de l'état inactif à actif.", + "jacdac.ButtonEvent.Hold": "Argument : temps ms uint32_t. Émis lorsque le temps d'appui est supérieur à 500ms, puis au moins toutes les 500ms\ntant que le bouton reste enfoncé. Le paramètre 'temps' enregistre la durée pendant laquelle\nle bouton a été maintenu (depuis l'événement d'appui).\n* ```\nconst [time] = jdunpack<[number]>(buf, \"u32\")\n```", + "jacdac.ButtonEvent.Up": "Argument : temps ms uint32_t. Émis lorsque le bouton passe de l'état actif à inactif. Le paramètre 'temps'\nenregistre la durée entre les événements d'appui et de relâchement.\n* ```\nconst [time] = jdunpack<[number]>(buf, \"u32\")\n```", + "jacdac.ButtonEventPack.Hold": "Format de paquet pour les données 'hold'.", + "jacdac.ButtonEventPack.Up": "Format de paquet pour les données 'up'.", + "jacdac.ButtonReg.Analog": "Constante bool (uint8_t). Indique si le bouton fournit des lectures analogiques de `pression`.\n* ```\nconst [analog] = jdunpack<[number]>(buf, \"u8\")\n```", + "jacdac.ButtonReg.Pressed": "Booléen en lecture seule (uint8_t). Détermine si le bouton est actuellement enfoncé.", + "jacdac.ButtonReg.Pressure": "Ratio en lecture seule u0.16 (uint16_t). Indique l'état de pression du bouton, où `0` est ouvert.\n* ```\nconst [pressure] = jdunpack<[number]>(buf, \"u0.16\")\n```", + "jacdac.ButtonRegPack.Analog": "Format de paquet pour les données 'analog'.", + "jacdac.ButtonRegPack.Pressed": "Format de paquet pour les données 'pressed'.", + "jacdac.ButtonRegPack.Pressure": "Format de paquet pour les données 'pressure'.", + "modules": "Modules Jacdac", + "modules.ButtonClient": "Un bouton-poussoir, qui revient à la position inactive lorsqu'il n'est plus actionné.", + "modules.ButtonClient.analog": "Indique si le bouton fournit des lectures analogiques de ``pression``.", + "modules.ButtonClient.holdDuration": "La dernière durée d'appui signalée lorsque le bouton est enfoncé.\n* Les événements `down` et `hold` rapportent également la durée totale d'appui en millisecondes.\nLa valeur est la dernière durée d'appui lorsque le bouton est relâché.", + "modules.ButtonClient.onDown": "Émis lorsque le bouton passe de l'état inactif à actif.", + "modules.ButtonClient.onEvent": "Enregistrer le code à exécuter lorsqu'un événement est déclenché", + "modules.ButtonClient.onHold": "Émis lorsque le temps d'appui est supérieur à 500ms, puis au moins toutes les 500ms\ntant que le bouton reste enfoncé. Le paramètre 'temps' enregistre la durée pendant laquelle\nle bouton a été maintenu (depuis l'événement d'appui).", + "modules.ButtonClient.onPressureChangedBy": "Exécuter le code lorsque la pression change d'une valeur seuil donnée.", + "modules.ButtonClient.onUp": "Émis lorsque le bouton passe de l'état actif à inactif. Le paramètre 'temps'\nenregistre la durée entre les événements d'appui et de relâchement.", + "modules.ButtonClient.pressed": "Détermine si le bouton est actuellement enfoncé.\n* Si l'événement ``down`` est observé, ``pressed`` est vrai; si ``up`` ou ``hold`` sont observés, ``pressed`` est faux.\nPour initialiser, attendez n'importe quel événement ou timeout pour que ``pressed`` soit vrai après 750ms (1.5x temps d'appui).", + "modules.ButtonClient.pressure": "Indique l'état de pression du bouton, où ``0`` est ouvert." +} \ No newline at end of file diff --git a/button/_locales/fr/jacdac-button-strings.json b/button/_locales/fr/jacdac-button-strings.json new file mode 100644 index 000000000..ccfcbdf8b --- /dev/null +++ b/button/_locales/fr/jacdac-button-strings.json @@ -0,0 +1,22 @@ +{ + "jacdac.ButtonEvent.Down": "Émis lorsque le bouton passe de l'état inactif à actif.", + "jacdac.ButtonEvent.Down|block": "bas", + "jacdac.ButtonEvent.Hold": "Argument : temps ms uint32_t. Émis lorsque le temps de pression est supérieur à 500 ms, puis au moins toutes les 500 ms\ntant que le bouton reste enfoncé. Le paramètre 'time' enregistre la durée pendant laquelle\nle bouton a été maintenu (depuis l'événement bas).\n* ```\nconst [time] = jdunpack<[number]>(buf, \"u32\")\n```", + "jacdac.ButtonEvent.Hold|block": "maintenir", + "jacdac.ButtonEvent.Up": "Argument : temps ms uint32_t. Émis lorsque le bouton passe de l'état actif à inactif. Le paramètre 'time'\nenregistre la durée entre les événements bas et haut.\n* ```\nconst [time] = jdunpack<[number]>(buf, \"u32\")\n```", + "jacdac.ButtonEvent.Up|block": "haut", + "jacdac.ButtonReg.Analog": "Constant bool (uint8_t). Indique si le bouton fournit des lectures `pressure` analogiques.\n* ```\nconst [analog] = jdunpack<[number]>(buf, \"u8\")\n```", + "jacdac.ButtonReg.Pressed": "Lecture seule bool (uint8_t). Détermine si le bouton est actuellement pressé.", + "jacdac.ButtonReg.Pressure": "Lecture seule ratio u0.16 (uint16_t). Indique l'état de pression du bouton, où `0` est ouvert.\n* ```\nconst [pressure] = jdunpack<[number]>(buf, \"u0.16\")\n```", + "modules.ButtonClient.holdDuration|block": "%button durée de maintien (ms)", + "modules.ButtonClient.onEvent|block": "on %button %event", + "modules.ButtonClient.pressed|block": "%button pressé", + "modules.button1|block": "bouton1", + "modules.button2|block": "bouton2", + "modules.button3|block": "bouton3", + "modules.button4|block": "bouton4", + "modules|block": "modules", + "{id:category}Jacdac": "Jacdac", + "{id:category}Modules": "Modules", + "{id:group}Button": "Bouton" +} \ No newline at end of file diff --git a/dot-matrix/_locales/de/jacdac-dot-matrix-jsdoc-strings.json b/dot-matrix/_locales/de/jacdac-dot-matrix-jsdoc-strings.json new file mode 100644 index 000000000..9d729bd00 --- /dev/null +++ b/dot-matrix/_locales/de/jacdac-dot-matrix-jsdoc-strings.json @@ -0,0 +1,22 @@ +{ + "jacdac.DotMatrixReg.Brightness": "Lese-Schreib-Verhältnis u0.8 (uint8_t). Liest die allgemeine Helligkeit des Displays, Helligkeit für LEDs. `0`, wenn der Bildschirm aus ist.\n* ```\nconst [brightness] = jdunpack<[number]>(buf, \"u0.8\")\n```", + "jacdac.DotMatrixReg.Columns": "Konstante # uint16_t. Anzahl der Spalten auf dem Bildschirm\n* ```\nconst [columns] = jdunpack<[number]>(buf, \"u16\")\n```", + "jacdac.DotMatrixReg.Dots": "Lese-Schreib-Bytes. Der Zustand des Bildschirms, bei dem der Punkt Ein/Aus-Zustand ist, wird als Bit gespeichert, Spalte für Spalte. Die Spalte sollte Byte-ausgerichtet sein.\n* ```\nconst [dots] = jdunpack<[Buffer]>(buf, \"b\")\n```", + "jacdac.DotMatrixReg.Rows": "Konstante # uint16_t. Anzahl der Reihen auf dem Bildschirm\n* ```\nconst [rows] = jdunpack<[number]>(buf, \"u16\")\n```", + "jacdac.DotMatrixReg.Variant": "Konstante Variante (uint8_t). Beschreibt den Typ der verwendeten Matrix.\n* ```\nconst [variant] = jdunpack<[jacdac.DotMatrixVariant]>(buf, \"u8\")\n```", + "jacdac.DotMatrixRegPack.Brightness": "Paketformat für 'brightness'-Daten.", + "jacdac.DotMatrixRegPack.Columns": "Paketformat für 'columns'-Daten.", + "jacdac.DotMatrixRegPack.Dots": "Paketformat für 'dots'-Daten.", + "jacdac.DotMatrixRegPack.Rows": "Paketformat für 'rows'-Daten.", + "jacdac.DotMatrixRegPack.Variant": "Paketformat für 'variant'-Daten.", + "modules": "Jacdac-Module", + "modules.DotMatrixClient": "Ein rechteckiges Punktmatrix-Display, bestehend aus monochromen LEDs oder Braille-Stiften.", + "modules.DotMatrixClient.brightness": "Liest die allgemeine Helligkeit des Displays, Helligkeit für LEDs. `0`, wenn der Bildschirm aus ist.", + "modules.DotMatrixClient.clearDots": "Alle Punkte löschen\n//% \n//% \n//% \n//%", + "modules.DotMatrixClient.columns": "Anzahl der Spalten auf dem Bildschirm", + "modules.DotMatrixClient.rows": "Anzahl der Reihen auf dem Bildschirm", + "modules.DotMatrixClient.setBrightness": "Liest die allgemeine Helligkeit des Displays, Helligkeit für LEDs. `0`, wenn der Bildschirm aus ist.", + "modules.DotMatrixClient.setDot": "Setzt einen Punkteintrag auf einen bestimmten Wert\n//% \n//% \n//% \n//%", + "modules.DotMatrixClient.toggleDot": "Einen Punkt umschalten\n//% \n//% \n//% \n//%", + "modules.DotMatrixClient.variant": "Beschreibt den Typ der verwendeten Matrix." +} \ No newline at end of file diff --git a/e-co2/_locales/de/jacdac-e-co2-strings.json b/e-co2/_locales/de/jacdac-e-co2-strings.json index 2525b10e5..717cf9d28 100644 --- a/e-co2/_locales/de/jacdac-e-co2-strings.json +++ b/e-co2/_locales/de/jacdac-e-co2-strings.json @@ -1,16 +1,16 @@ { - "jacdac.ECO2Reg.ECO2": "Nur-Lesen ppm u22.", - "jacdac.ECO2Reg.ECO2Error": "Nur-Lesen ppm u22.", - "jacdac.ECO2Reg.MaxECO2": "Konstante ppm u22.", - "jacdac.ECO2Reg.MinECO2": "Konstante ppm u22.", - "jacdac.ECO2Reg.Variant": "Konstante Variante (uint8_t).", + "jacdac.ECO2Reg.ECO2": "Schreibgeschützt ppm u22.10 (uint32_t). Äquivalente CO₂ (eCO₂)-Messwerte.\n* ```\nconst [eCO2] = jdunpack<[number]>(buf, \"u22.10\")\n```", + "jacdac.ECO2Reg.ECO2Error": "Schreibgeschützt ppm u22.10 (uint32_t). Fehler beim Messwert.\n* ```\nconst [eCO2Error] = jdunpack<[number]>(buf, \"u22.10\")\n```", + "jacdac.ECO2Reg.MaxECO2": "Konstante ppm u22.10 (uint32_t). Minimal messbarer Wert\n* ```\nconst [maxECO2] = jdunpack<[number]>(buf, \"u22.10\")\n```", + "jacdac.ECO2Reg.MinECO2": "Konstante ppm u22.10 (uint32_t). Minimal messbarer Wert\n* ```\nconst [minECO2] = jdunpack<[number]>(buf, \"u22.10\")\n```", + "jacdac.ECO2Reg.Variant": "Konstante Variante (uint8_t). Typ des physikalischen Sensors und Fähigkeiten.\n* ```\nconst [variant] = jdunpack<[jacdac.ECO2Variant]>(buf, \"u8\")\n```", "jacdac.ECO2Variant.NDIR|block": "ndir", "jacdac.ECO2Variant.VOC|block": "voc", "modules.ECO2Client.eCO2|block": "%eco2 e CO2 (ppm)", - "modules.ECO2Client.onECO2ChangedBy|block": "wenn %eco2 e CO2 sich um %threshold (ppm) ändert", + "modules.ECO2Client.onECO2ChangedBy|block": "on %eco2 e CO2 geändert um %threshold (ppm)", "modules.eCO21|block": "e co21", "modules|block": "module", "{id:category}Jacdac": "Jacdac", "{id:category}Modules": "Module", - "{id:group}Environment": "Umwelt" + "{id:group}Environment": "Umgebung" } \ No newline at end of file diff --git a/genaisrc/gcm.genai.mts b/genaisrc/gcm.genai.mts new file mode 100644 index 000000000..e1ebd1197 --- /dev/null +++ b/genaisrc/gcm.genai.mts @@ -0,0 +1,87 @@ +/** + * git commit flow with auto-generated commit message + */ +script({ + title: "git commit message", + description: "Generate a commit message for all staged changes", +}) + +// TODO: update this diff command to match your workspace +const diffCmd = "git diff --cached -- . :!**/genaiscript.d.ts" + +// Check for staged changes and stage all changes if none are staged +let diff = await host.exec(diffCmd) +if (!diff.stdout) { + /** + * Ask user to stage all changes if none are staged + */ + const stage = await host.confirm("No staged changes. Stage all changes?", { + default: true, + }) + if (stage) { + // Stage all changes and recompute diff + await host.exec("git add .") + diff = await host.exec(diffCmd) + } + if (!diff.stdout) cancel("no staged changes") +} + +// show diff in the console +console.log(diff.stdout) + +let choice +let message +do { + // Generate commit message + const res = await runPrompt( + (_) => { + _.def("GIT_DIFF", diff, { maxTokens: 20000 }) + _.$`GIT_DIFF is a diff of all staged changes, coming from the command: +\`\`\` +git diff --cached +\`\`\` +Please generate a concise, one-line commit message for these changes. +- do NOT add quotes +` // TODO: add a better prompt + }, + { cache: false, temperature: 0.8 } + ) + if (res.error) throw res.error + + message = res.text + if (!message) { + console.log("No message generated, did you configure the LLM model?") + break + } + + // Prompt user for commit message + choice = await host.select(message, [ + { + value: "commit", + description: "accept message and commit", + }, + { + value: "edit", + description: "edit message and commit", + }, + { + value: "regenerate", + description: "regenerate message", + }, + ]) + + // Handle user choice + if (choice === "edit") { + message = await host.input("Edit commit message", { + required: true, + }) + choice = "commit" + } + // Regenerate message + if (choice === "commit" && message) { + console.log((await host.exec("git", ["commit", "-m", message])).stdout) + if (await host.confirm("Push changes?", { default: true })) + console.log((await host.exec("git push")).stdout) + break + } +} while (choice !== "commit") diff --git a/genaisrc/genaiscript.d.ts b/genaisrc/genaiscript.d.ts index 6671ae0ad..df355fd9f 100644 --- a/genaisrc/genaiscript.d.ts +++ b/genaisrc/genaiscript.d.ts @@ -1,3 +1,7 @@ +type OptionsOrString = (string & {}) | TOptions + +type ElementOrArray = T | T[] + interface PromptGenerationConsole { log(...data: any[]): void warn(...data: any[]): void @@ -65,9 +69,42 @@ interface PromptLike extends PromptDefinition { text?: string } -type SystemPromptId = "system" | "system.annotations" | "system.changelog" | "system.diff" | "system.explanations" | "system.files" | "system.files_schema" | "system.fs_find_files" | "system.fs_read_file" | "system.fs_read_summary" | "system.functions" | "system.math" | "system.python" | "system.retrieval_fuzz_search" | "system.retrieval_vector_search" | "system.retrieval_web_search" | "system.schema" | "system.tasks" | "system.technical" | "system.typescript" | "system.zero_shot_cot" +type SystemPromptId = OptionsOrString< + | "system" + | "system.annotations" + | "system.changelog" + | "system.diagrams" + | "system.diff" + | "system.explanations" + | "system.files" + | "system.files_schema" + | "system.fs_find_files" + | "system.fs_read_file" + | "system.math" + | "system.md_frontmatter" + | "system.python" + | "system.python_code_interpreter" + | "system.retrieval_fuzz_search" + | "system.retrieval_vector_search" + | "system.retrieval_web_search" + | "system.schema" + | "system.tasks" + | "system.technical" + | "system.tools" + | "system.typescript" + | "system.zero_shot_cot" +> -type SystemToolId = "fs_find_files" | "fs_read_file" | "fs_read_summary" | "math_eval" | "retrieval_fuzz_search" | "retrieval_vector_search" | "retrieval_web_search" +type SystemToolId = OptionsOrString< + | "fs_find_files" + | "fs_read_file" + | "math_eval" + | "md_read_frontmatter" + | "python_code_interpreter" + | "retrieval_fuzz_search" + | "retrieval_vector_search" + | "retrieval_web_search" +> type FileMergeHandler = ( filename: string, @@ -99,24 +136,28 @@ type PromptOutputProcessorHandler = ( | Promise | undefined | Promise + | void + | Promise -type PromptTemplateResponseType = "json_object" | undefined +type PromptTemplateResponseType = "json_object" | "json_schema" | undefined interface ModelConnectionOptions { /** * Which LLM model to use. * * @default gpt-4 - * @example gpt-4 gpt-4-32k gpt-3.5-turbo ollama:phi3 ollama:llama3 ollama:mixtral aici:mixtral + * @example gpt-4 */ - model?: + model?: OptionsOrString< + | "openai:gpt-4o" + | "openai:gpt-4o-mini" | "openai:gpt-4" - | "openai:gpt-4-32k" + | "openai:gpt-4-turbo" | "openai:gpt-3.5-turbo" | "ollama:phi3" | "ollama:llama3" | "ollama:mixtral" - | string + > } interface ModelOptions extends ModelConnectionOptions { @@ -129,15 +170,17 @@ interface ModelOptions extends ModelConnectionOptions { temperature?: number /** - * Specifies the type of output. Default is `markdown`. Use `responseSchema` to - * specify an output schema. + * Specifies the type of output. Default is plain text. + * - `json_object` enables JSON mode + * - `json_schema` enables structured outputs + * Use `responseSchema` to specify an output schema. */ responseType?: PromptTemplateResponseType /** - * JSON object schema for the output. Enables the `JSON` output mode. + * JSON object schema for the output. Enables the `JSON` output mode by default. */ - responseSchema?: JSONSchemaObject + responseSchema?: PromptParametersSchema | JSONSchemaObject /** * “Top_p” or nucleus sampling is a setting that decides how many possible words to consider. @@ -168,71 +211,51 @@ interface ModelOptions extends ModelConnectionOptions { seed?: number /** - * If true, the prompt will be cached. If false, the LLM chat is never cached. - * Leave empty to use the default behavior. + * By default, LLM queries are not cached. If true, the LLM request will be cached. Use a string to override the default cache name */ - cache?: boolean + 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 } interface EmbeddingsModelConnectionOptions { /** * LLM model to use for embeddings. */ - embeddingsModel?: "openai:text-embedding-ada-002" | string + embeddingsModel?: OptionsOrString< + "openai:text-embedding-3-small", + "openai:text-embedding-3-large", + "openai:text-embedding-ada-002", + "github:text-embedding-3-small", + "github:text-embedding-3-large", + "ollama:nomic-embed-text" + > } interface EmbeddingsModelOptions extends EmbeddingsModelConnectionOptions {} -interface ScriptRuntimeOptions { +interface PromptSystemOptions { /** * List of system script ids used by the prompt. */ -/** -* System prompt identifiers ([reference](https://microsoft.github.io/genaiscript/reference/scripts/system/)) -* - `system`: Base system prompt -* - `system.annotations`: Emits annotations compatible with GitHub Actions -* - `system.changelog`: Generate changelog formatter edits -* - `system.diff`: Generates concise file diffs. -* - `system.explanations`: Explain your answers -* - `system.files`: File generation -* - `system.files_schema`: Apply JSON schemas to generated data. -* - `system.fs_find_files`: File Find Files -* - `system.fs_read_file`: File Read File -* - `system.fs_read_summary`: File Read Summary -* - `system.functions`: use functions -* - `system.math`: Math expression evaluator -* - `system.python`: Expert at generating and understanding Python code. -* - `system.retrieval_fuzz_search`: Full Text Fuzzy Search -* - `system.retrieval_vector_search`: Embeddings Vector Search -* - `system.retrieval_web_search`: Web Search -* - `system.schema`: JSON Schema support -* - `system.tasks`: Generates tasks -* - `system.technical`: Technical Writer -* - `system.typescript`: Export TypeScript Developer -* - `system.zero_shot_cot`: Zero-shot Chain Of Though -**/ - system?: SystemPromptId[] + system?: SystemPromptId | SystemPromptId[] /** * List of tools used by the prompt. */ -/** -* System tool identifiers ([reference](https://microsoft.github.io/genaiscript/reference/scripts/tools/)) -* - `fs_find_files`: Finds file matching a glob pattern. -* - `fs_read_file`: Reads a file as text from the file system. -* - `fs_read_summary`: Reads a summary of a file from the file system. -* - `math_eval`: Evaluates a math expression -* - `retrieval_fuzz_search`: Search for keywords using the full text of files and a fuzzy distance. -* - `retrieval_vector_search`: Search files using embeddings and similarity distance. -* - `retrieval_web_search`: Search the web for a user query using Bing Search. -**/ - tools?: SystemToolId[] + tools?: SystemToolId | SystemToolId[] +} +interface ScriptRuntimeOptions { /** * Secrets required by the prompt */ @@ -248,11 +271,15 @@ type PromptParameterType = | string | number | boolean + | object | JSONSchemaNumber | JSONSchemaString | JSONSchemaBoolean -type PromptParametersSchema = Record -type PromptParameters = Record +type PromptParametersSchema = Record< + string, + PromptParameterType | PromptParameterType[] +> +type PromptParameters = Record type PromptAssertion = { // How heavily to weigh the assertion. Defaults to 1.0 @@ -308,6 +335,10 @@ type PromptAssertion = { ) interface PromptTest { + /** + * Short name of the test + */ + name?: string /** * Description of the test. */ @@ -319,7 +350,7 @@ interface PromptTest { /** * Extra set of variables for this scenario */ - vars?: PromptParameters + vars?: Record /** * LLM output matches a given rubric, using a Language Model to grade output. */ @@ -345,6 +376,7 @@ interface PromptTest { interface PromptScript extends PromptLike, ModelOptions, + PromptSystemOptions, EmbeddingsModelOptions, ScriptRuntimeOptions { /** @@ -385,7 +417,7 @@ interface PromptScript } /** - * Represent a file linked from a `.gpsec.md` document. + * Represent a workspace file and optional content. */ interface WorkspaceFile { /** @@ -492,7 +524,39 @@ interface ToolCallContent { edits?: Edits[] } -type ToolCallOutput = string | ToolCallContent | ShellOutput +type ToolCallOutput = + | string + | number + | boolean + | ToolCallContent + | ShellOutput + | WorkspaceFile + | RunPromptResult + | undefined + +interface WorkspaceFileCache { + /** + * Gets the value associated with the key, or undefined if there is none. + * @param key + */ + get(key: K): Promise + /** + * Sets the value associated with the key. + * @param key + * @param value + */ + set(key: K, value: V): Promise + + /** + * List of keys + */ + keys(): Promise + + /** + * List the values in the cache. + */ + values(): Promise +} interface WorkspaceFileSystem { /** @@ -517,20 +581,31 @@ interface WorkspaceFileSystem { */ grep( query: string | RegExp, - globs: string | string[] + globs: string | string[], + options?: { + /** + * Set to false to skip read text content. True by default + */ + readText?: boolean + } ): Promise<{ files: WorkspaceFile[] }> /** * Reads the content of a file as text * @param path */ - readText(path: string | WorkspaceFile): Promise + readText(path: string | Awaitable): Promise /** * Reads the content of a file and parses to JSON, using the JSON5 parser. - * @param path + * @param path + */ + readJSON(path: string | Awaitable): Promise + + /** + * Reads the content of a file and parses to XML, using the XML parser. */ - readJSON(path: string | WorkspaceFile): Promise + readXML(path: string | Awaitable): Promise /** * Writes a file as text to the file system @@ -538,6 +613,15 @@ interface WorkspaceFileSystem { * @param content */ writeText(path: string, content: string): Promise + + /** + * Opens a 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 + */ + cache( + cacheName: string + ): Promise> } interface ToolCallContext { @@ -545,10 +629,20 @@ interface ToolCallContext { } interface ToolCallback { - definition: ToolDefinition - fn: ( + spec: ToolDefinition + impl: ( args: { context: ToolCallContext } & Record - ) => ToolCallOutput | Promise + ) => Awaitable +} + +type AgenticToolCallback = Omit & { + spec: Omit & { + parameters: Record + } +} + +interface AgenticToolProviderCallback { + functions: Iterable } type ChatParticipantHandler = ( @@ -587,7 +681,7 @@ interface ExpansionVariables { /** * User defined variables */ - vars: PromptParameters + vars?: Record /** * List of secrets used by the prompt, must be registered in `genaiscript`. @@ -613,6 +707,7 @@ type PromptSystemArgs = Omit< | "maxTokens" | "seed" | "tests" + | "responseLanguage" | "responseType" | "responseSchema" | "files" @@ -647,11 +742,20 @@ interface FenceOptions { } interface ContextExpansionOptions { - priority?: number /** - * Specifies an maximum of estimated tokesn for this entry; after which it will be truncated. + * 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 } interface DefOptions extends FenceOptions, ContextExpansionOptions, DataFilter { @@ -673,6 +777,18 @@ interface DefOptions extends FenceOptions, ContextExpansionOptions, DataFilter { interface DefImagesOptions { detail?: "high" | "low" + /** + * Maximum width of the image + */ + maxWidth?: number + /** + * Maximum height of the image + */ + maxHeight?: number + /** + * Auto cropping same color on the edges of the image + */ + autoCrop?: boolean } interface ChatTaskOptions { @@ -869,6 +985,8 @@ interface ParseZipOptions { glob?: string } +type TokenEncoder = (text: string) => number[] + interface Parsers { /** * Parses text as a JSON5 payload @@ -885,7 +1003,7 @@ interface Parsers { JSONL(content: string | WorkspaceFile): any[] | undefined /** - * Parses text as a YAML paylaod + * Parses text as a YAML payload */ YAML( content: string | WorkspaceFile, @@ -980,6 +1098,13 @@ interface Parsers { options?: HTMLToTextOptions ): string + /** + * Convert HTML to markdown + * @param content html string or file + * @param options + */ + HTMLToMarkdown(content: string | WorkspaceFile): string + /** * Extracts the contents of a zip archive file * @param file @@ -1018,7 +1143,7 @@ interface Parsers { * Parses and evaluates a math expression * @param expression math expression compatible with mathjs */ - math(expression: string): string | number | undefined + math(expression: string): Promise /** * Using the JSON schema, validates the content @@ -1026,6 +1151,17 @@ interface Parsers { * @param content object to validate */ validateJSON(schema: JSONSchema, content: any): JSONSchemaValidation + + /** + * Renders a mustache template + * @param text template text + * @param data data to render + */ + mustache(text: string | WorkspaceFile, data: Record): str + /** + * Renders a jinja template + */ + jinja(text: string | WorkspaceFile, data: Record): string } interface AICIGenOptions { @@ -1099,7 +1235,71 @@ interface XML { * Parses an XML payload to an object * @param text */ - parse(text: string): any + parse(text: string, options?: XMLParseOptions): any +} + +interface HTMLTableToJSONOptions { + useFirstRowForHeadings?: boolean + headers?: HeaderRows + stripHtmlFromHeadings?: boolean + stripHtmlFromCells?: boolean + stripHtml?: boolean | null + forceIndexAsNumber?: boolean + countDuplicateHeadings?: boolean + ignoreColumns?: number[] | null + onlyColumns?: number[] | null + ignoreHiddenRows?: boolean + id?: string[] | null + headings?: string[] | null + containsClasses?: string[] | null + limitrows?: number | null +} + +interface HTML { + /** + * Converts all HTML tables to JSON. + * @param html + * @param options + */ + convertTablesToJSON( + html: string, + options?: HTMLTableToJSONOptions + ): object[][] + /** + * Converts HTML markup to plain text + * @param html + */ + convertToText(html: string): string + /** + * Converts HTML markup to markdown + * @param html + */ + convertToMarkdown(html: string): string +} + +interface MD { + /** + * Parses front matter from markdown + * @param text + */ + frontmatter(text: string, format?: "yaml" | "json" | "toml" | "text"): any + + /** + * Removes the front matter from the markdown text + */ + content(text: string): string + + /** + * Merges frontmatter with the existing text + * @param text + * @param frontmatter + * @param format + */ + updateFrontmatter( + text: string, + frontmatter: any, + format?: "yaml" | "json" + ): string } interface JSONL { @@ -1272,7 +1472,7 @@ interface DefDataOptions extends Omit, DataFilter { /** - * Output format in the prompt. Defaults to markdownified CSV + * Output format in the prompt. Defaults to Markdown table rendering. */ format?: "json" | "yaml" | "csv" } @@ -1286,7 +1486,7 @@ interface DefSchemaOptions { type ChatFunctionHandler = ( args: { context: ToolCallContext } & Record -) => ToolCallOutput | Promise +) => Awaitable interface WriteTextOptions extends ContextExpansionOptions { /** @@ -1295,9 +1495,9 @@ interface WriteTextOptions extends ContextExpansionOptions { assistant?: boolean } -type PromptGenerator = (ctx: ChatGenerationContext) => Awaitable +type PromptGenerator = (ctx: ChatGenerationContext) => Awaitable -interface PromptGeneratorOptions extends ModelOptions { +interface PromptGeneratorOptions extends ModelOptions, PromptSystemOptions { /** * Label for trace */ @@ -1313,15 +1513,56 @@ interface FileOutputOptions { interface FileOutput { pattern: string - description: string + description?: string options?: FileOutputOptions } +interface ImportTemplateOptions {} + +interface PromptTemplateString { + /** + * Set a priority similar to CSS z-index + * to control the trimming of the prompt when the context is full + * @param priority + */ + priority(value: number): PromptTemplateString + /** + * Sets the context layout flex weight + */ + flex(value: number): PromptTemplateString + /** + * Applies jinja template to the string lazily + * @param data jinja data + */ + jinja(data: Record): PromptTemplateString + /** + * Applies mustache template to the string lazily + * @param data mustache data + */ + mustache(data: Record): PromptTemplateString + /** + * Sets the max tokens for this string + * @param tokens + */ + maxTokens(tokens: number): PromptTemplateString +} + interface ChatTurnGenerationContext { + importTemplate( + files: string | string[], + arguments?: Record< + string | number | boolean | (() => string | number | boolean) + >, + options?: ImportTemplateOptions + ): void writeText(body: Awaitable, options?: WriteTextOptions): void - $(strings: TemplateStringsArray, ...args: any[]): void + $(strings: TemplateStringsArray, ...args: any[]): PromptTemplateString fence(body: StringLike, options?: FenceOptions): void - def(name: string, body: StringLike, options?: DefOptions): string + def( + name: string, + body: string | WorkspaceFile | WorkspaceFile[] | ShellOutput | Fenced, + options?: DefOptions + ): string defData( name: string, data: object[] | object, @@ -1336,13 +1577,23 @@ interface FileUpdate { validation?: JSONSchemaValidation } +interface RunPromptResultPromiseWithOptions extends Promise { + options(values?: PromptGeneratorOptions): RunPromptResultPromiseWithOptions +} + interface ChatGenerationContext extends ChatTurnGenerationContext { defSchema( name: string, schema: JSONSchema, options?: DefSchemaOptions ): string - defImages(files: StringLike, options?: DefImagesOptions): void + defImages( + files: ElementOrArray, + options?: DefImagesOptions + ): void + defTool( + tool: ToolCallback | AgenticToolCallback | AgenticToolProviderCallback + ): void defTool( name: string, description: string, @@ -1355,9 +1606,17 @@ interface ChatGenerationContext extends ChatTurnGenerationContext { ): void defFileOutput( pattern: string, - description: string, + description?: string, options?: FileOutputOptions ): void + runPrompt( + generator: string | PromptGenerator, + options?: PromptGeneratorOptions + ): Promise + prompt( + strings: TemplateStringsArray, + ...args: any[] + ): RunPromptResultPromiseWithOptions } interface GenerationOutput { @@ -1527,17 +1786,477 @@ interface ShellOptions { interface ShellOutput { stdout?: string stderr?: string - output?: string exitCode: number failed: boolean } +interface BrowserOptions { + /** + * Browser engine for this page. Defaults to chromium + * + */ + browser?: "chromium" | "firefox" | "webkit" + + /** + * If specified, accepted downloads are downloaded into this directory. Otherwise, temporary directory is created and is deleted when browser is closed. In either case, the downloads are deleted when the browser context they were created in is closed. + */ + downloadsPath?: string + + /** + * Whether to run browser in headless mode. More details for Chromium and Firefox. Defaults to true unless the devtools option is true. + */ + headless?: boolean + + /** + * Specify environment variables that will be visible to the browser. Defaults to process.env. + */ + env?: Record +} + +interface BrowseSessionOptions extends BrowserOptions, TimeoutOptions { + /** + * Creates a new context for the browser session + */ + incognito?: boolean + + /** + * Base url to use for relative urls + * @link https://playwright.dev/docs/api/class-browser#browser-new-context-option-base-url + */ + baseUrl?: string + + /** + * Toggles bypassing page's Content-Security-Policy. Defaults to false. + * @link https://playwright.dev/docs/api/class-browser#browser-new-context-option-bypass-csp + */ + bypassCSP?: boolean + + /** + * Whether to ignore HTTPS errors when sending network requests. Defaults to false. + * @link https://playwright.dev/docs/api/class-browser#browser-new-context-option-ignore-https-errors + */ + ignoreHTTPSErrors?: boolean + + /** + * Whether or not to enable JavaScript in the context. Defaults to true. + * @link https://playwright.dev/docs/api/class-browser#browser-new-context-option-java-script-enabled + */ + javaScriptEnabled?: boolean +} + +interface TimeoutOptions { + /** + * Maximum time in milliseconds. Default to no timeout + */ + timeout?: number +} + +interface ScreenshotOptions extends TimeoutOptions { + quality?: number + scale?: "css" | "device" + type?: "png" | "jpeg" + style?: string +} + +interface PageScreenshotOptions extends ScreenshotOptions { + fullPage?: boolean + omitBackground?: boolean + clip?: { + x: number + y: number + width: number + height: number + } +} + +interface BrowserLocatorSelector { + /** + * Allows locating elements by their ARIA role, ARIA attributes and accessible name. + * @param role + * @param options + */ + getByRole( + role: + | "alert" + | "alertdialog" + | "application" + | "article" + | "banner" + | "blockquote" + | "button" + | "caption" + | "cell" + | "checkbox" + | "code" + | "columnheader" + | "combobox" + | "complementary" + | "contentinfo" + | "definition" + | "deletion" + | "dialog" + | "directory" + | "document" + | "emphasis" + | "feed" + | "figure" + | "form" + | "generic" + | "grid" + | "gridcell" + | "group" + | "heading" + | "img" + | "insertion" + | "link" + | "list" + | "listbox" + | "listitem" + | "log" + | "main" + | "marquee" + | "math" + | "meter" + | "menu" + | "menubar" + | "menuitem" + | "menuitemcheckbox" + | "menuitemradio" + | "navigation" + | "none" + | "note" + | "option" + | "paragraph" + | "presentation" + | "progressbar" + | "radio" + | "radiogroup" + | "region" + | "row" + | "rowgroup" + | "rowheader" + | "scrollbar" + | "search" + | "searchbox" + | "separator" + | "slider" + | "spinbutton" + | "status" + | "strong" + | "subscript" + | "superscript" + | "switch" + | "tab" + | "table" + | "tablist" + | "tabpanel" + | "term" + | "textbox" + | "time" + | "timer" + | "toolbar" + | "tooltip" + | "tree" + | "treegrid" + | "treeitem", + options?: { + checked?: boolean + disabled?: boolean + exact?: boolean + expanded?: boolean + name?: string + selected?: boolean + } & TimeoutOptions + ): Locator + + /** + * Allows locating input elements by the text of the associated