From 162e6e4b013b75aaacc43b2209a0a6dbcccfcd50 Mon Sep 17 00:00:00 2001 From: Tony Holdstock-Brown Date: Tue, 3 Dec 2024 16:23:13 -0800 Subject: [PATCH 01/15] Add anthropic as a provider This depends on https://github.com/inngest/inngest-js/pull/764, which exposes model options in Inngest's model provider. This makes types happy. --- src/adapters/anthropic.ts | 1 - src/model.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/adapters/anthropic.ts b/src/adapters/anthropic.ts index ac6a248..640bd80 100644 --- a/src/adapters/anthropic.ts +++ b/src/adapters/anthropic.ts @@ -3,7 +3,6 @@ * * @module */ - import { type AnthropicAiAdapter, type AiAdapter, diff --git a/src/model.ts b/src/model.ts index 6981edb..ac5740e 100644 --- a/src/model.ts +++ b/src/model.ts @@ -36,7 +36,7 @@ export class AgenticModel { } export namespace AgenticModel { - export type Any = AgenticModel; + export type Any = AgenticModel; /** * InferenceResponse is the response from a model for an inference request. From c489a0010d633071fac9ccda215033dcc19338af Mon Sep 17 00:00:00 2001 From: Charly POLY Date: Wed, 4 Dec 2024 11:28:29 +0100 Subject: [PATCH 02/15] fix(adapters): `tool_choice = "auto"` + safely parse JSON generated by OpenAI --- src/adapters/openai.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/adapters/openai.ts b/src/adapters/openai.ts index 606b25b..2d73d60 100644 --- a/src/adapters/openai.ts +++ b/src/adapters/openai.ts @@ -9,6 +9,33 @@ import { zodToJsonSchema } from "openai-zod-to-json-schema"; import { type AgenticModel } from "../model"; import { type InternalNetworkMessage, type ToolMessage } from "../state"; +// Helper to parse JSON that may contain backticks: +// Example: +// "{\n \"files\": [\n {\n \"filename\": \"fibo.ts\",\n \"content\": `\nfunction fibonacci(n: number): number {\n if (n < 2) {\n return n;\n } else {\n return fibonacci(n - 1) + fibonacci(n - 2);\n }\n}\n\nexport default fibonacci;\n`\n }\n ]\n}" +const safeParseOpenAIJson = (str: string): unknown => { + // Remove any leading/trailing quotes if present + const trimmed = str.replace(/^["']|["']$/g, ''); + + try { + // First try direct JSON parse + return JSON.parse(trimmed); + } catch { + try { + // Replace backtick strings with regular JSON strings + // Match content between backticks, preserving newlines + const withQuotes = trimmed.replace( + /`([\s\S]*?)`/g, + (_, content) => JSON.stringify(content) + ); + return JSON.parse(withQuotes); + } catch (e) { + throw new Error(`Failed to parse JSON with backticks: ${e}`); + } + } +}; + + + /** * Parse a request from internal network messages to an OpenAI input. */ @@ -27,6 +54,7 @@ export const requestParser: AgenticModel.RequestParser = ( }; if (tools?.length) { + request.tool_choice = "auto"; request.tools = tools.map((t) => { return { type: "function", From bca099ca80ec3a25d1bae88788f303bf38ff071e Mon Sep 17 00:00:00 2001 From: Charly POLY Date: Wed, 4 Dec 2024 18:08:28 +0100 Subject: [PATCH 03/15] fix(agent): implement tool calling loop in `Agent()` --- demo/inngest.ts | 54 +- package.json | 9 +- pnpm-lock.yaml | 1098 +++++++++++++++++++++++++++++++++++----- src/adapters/openai.ts | 52 +- src/agent.ts | 55 +- src/state.ts | 6 +- tsconfig-demo.json | 24 + 7 files changed, 1122 insertions(+), 176 deletions(-) create mode 100644 tsconfig-demo.json diff --git a/demo/inngest.ts b/demo/inngest.ts index 68b2a75..2e4f604 100644 --- a/demo/inngest.ts +++ b/demo/inngest.ts @@ -5,6 +5,7 @@ import { createNetwork, createTypedTool, defaultRoutingAgent, + openai, } from "../src/index"; import { EventSchemas, Inngest } from "inngest"; import { z } from "zod"; @@ -24,7 +25,7 @@ export const fn = inngest.createFunction( { id: "agent" }, { event: "agent/run" }, async ({ event, step }) => { - const model = anthropic({ model: "claude-3-5-haiku-latest", max_tokens: 1024, step }); + const model = openai({ model: "gpt-4", step }); // 1. Single agents // @@ -33,36 +34,35 @@ export const fn = inngest.createFunction( model, }); - // 2. A network of agents that works together - - const network = createNetwork({ - agents: [ - codeWritingAgent.withModel(model), - executingAgent.withModel(model), - ], - defaultModel: model, - maxIter: 4, - }); - - // This uses the defaut agentic router to determine which agent to handle first. You can - // optionally specifiy the agent that should execute first, and provide your own logic for - // handling logic in between agent calls. - const result = await network.run(event.data.input, ({ network }) => { - if (network.state.kv.has("files")) { - // Okay, we have some files. Did an agent run tests? - return executingAgent; - } - - return defaultRoutingAgent.withModel(model); - }); - - return result; + // // 2. A network of agents that works together + + // const network = createNetwork({ + // agents: [ + // codeWritingAgent.withModel(model), + // executingAgent.withModel(model), + // ], + // defaultModel: model, + // maxIter: 4, + // }); + + // // This uses the defaut agentic router to determine which agent to handle first. You can + // // optionally specifiy the agent that should execute first, and provide your own logic for + // // handling logic in between agent calls. + // const result = await network.run(event.data.input, ({ network }) => { + // if (network.state.kv.has("files")) { + // // Okay, we have some files. Did an agent run tests? + // return executingAgent; + // } + + // return defaultRoutingAgent.withModel(model); + // }); + + return output; }, ); const systemPrompt = - "You are an expert TypeScript programmer. Given a set of asks, think step-by-step to plan clean, " + - "idiomatic TypeScript code, with comments and tests as necessary."; + "You are an expert TypeScript programmer."; const codeWritingAgent = createAgent({ name: "Code writer", diff --git a/package.json b/package.json index 6be21b0..a322cbc 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "build": "rm -rf dist && tsc", "lint": "eslint .", "release": "pnpm run build && changeset publish", - "prepare": "husky install" + "prepare": "husky install", + "dev": "nodemon --watch demo -e ts --exec \"ts-node -P tsconfig-demo.json demo/index.ts\"" }, "files": [ "dist" @@ -38,7 +39,8 @@ } }, "dependencies": { - "inngest": "3.27.1", + "inngest": "^3.27.4", + "express": "^4.21.1", "openai-zod-to-json-schema": "^1.0.3", "zod": "^3.23.8" }, @@ -46,6 +48,7 @@ "devDependencies": { "@changesets/cli": "^2.27.10", "@eslint/js": "^9.15.0", + "@types/express": "^5.0.0", "@types/node": "^22.9.1", "@typescript-eslint/eslint-plugin": "^8.15.0", "@typescript-eslint/parser": "^8.15.0", @@ -54,7 +57,9 @@ "eslint-plugin-prettier": "^5.2.1", "husky": ">=7", "lint-staged": ">=10", + "nodemon": "^3.0.2", "prettier": "^3.3.3", + "ts-node": "^10.9.2", "typescript": "^5.6.3", "typescript-eslint": "^8.15.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b22cdb..61a626b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,12 @@ importers: .: dependencies: + express: + specifier: ^4.21.1 + version: 4.21.1 inngest: - specifier: 3.27.1 - version: 3.27.1(typescript@5.6.3) + specifier: ^3.27.4 + version: 3.27.4(express@4.21.1)(typescript@5.7.2) openai-zod-to-json-schema: specifier: ^1.0.3 version: 1.0.3(zod@3.23.8) @@ -23,40 +26,49 @@ importers: version: 2.27.10 '@eslint/js': specifier: ^9.15.0 - version: 9.15.0 + version: 9.16.0 + '@types/express': + specifier: ^5.0.0 + version: 5.0.0 '@types/node': specifier: ^22.9.1 - version: 22.9.1 + version: 22.10.1 '@typescript-eslint/eslint-plugin': specifier: ^8.15.0 - version: 8.15.0(@typescript-eslint/parser@8.15.0)(eslint@9.15.0)(typescript@5.6.3) + version: 8.17.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0)(typescript@5.7.2))(eslint@9.16.0)(typescript@5.7.2) '@typescript-eslint/parser': specifier: ^8.15.0 - version: 8.15.0(eslint@9.15.0)(typescript@5.6.3) + version: 8.17.0(eslint@9.16.0)(typescript@5.7.2) eslint: specifier: ^9.15.0 - version: 9.15.0 + version: 9.16.0 eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@9.15.0) + version: 9.1.0(eslint@9.16.0) eslint-plugin-prettier: specifier: ^5.2.1 - version: 5.2.1(eslint-config-prettier@9.1.0)(eslint@9.15.0)(prettier@3.3.3) + version: 5.2.1(eslint-config-prettier@9.1.0(eslint@9.16.0))(eslint@9.16.0)(prettier@3.4.2) husky: specifier: '>=7' version: 9.1.7 lint-staged: specifier: '>=10' version: 15.2.10 + nodemon: + specifier: ^3.0.2 + version: 3.1.7 prettier: specifier: ^3.3.3 - version: 3.3.3 + version: 3.4.2 + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@22.10.1)(typescript@5.7.2) typescript: specifier: ^5.6.3 - version: 5.6.3 + version: 5.7.2 typescript-eslint: specifier: ^8.15.0 - version: 8.15.0(eslint@9.15.0)(typescript@5.6.3) + version: 8.17.0(eslint@9.16.0)(typescript@5.7.2) packages: @@ -119,6 +131,10 @@ packages: '@changesets/write@0.3.2': resolution: {integrity: sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==} + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + '@eslint-community/eslint-utils@4.4.1': resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -141,8 +157,8 @@ packages: resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.15.0': - resolution: {integrity: sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==} + '@eslint/js@9.16.0': + resolution: {integrity: sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.4': @@ -173,6 +189,16 @@ packages: resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} engines: {node: '>=18.18'} + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -195,26 +221,68 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/body-parser@1.19.5': + resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/express-serve-static-core@5.0.2': + resolution: {integrity: sha512-vluaspfvWEtE4vcSDlKRNer52DvOGrB2xv6diXy6UKyKW0lqZiWHGNApSyxOv+8DE5Z27IzVvE7hNkxg7EXIcg==} + + '@types/express@5.0.0': + resolution: {integrity: sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==} + + '@types/http-errors@2.0.4': + resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/mime@1.3.5': + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@22.9.1': - resolution: {integrity: sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==} + '@types/node@22.10.1': + resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==} + + '@types/qs@6.9.17': + resolution: {integrity: sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + + '@types/send@0.17.4': + resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} - '@typescript-eslint/eslint-plugin@8.15.0': - resolution: {integrity: sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg==} + '@types/serve-static@1.15.7': + resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} + + '@typescript-eslint/eslint-plugin@8.17.0': + resolution: {integrity: sha512-HU1KAdW3Tt8zQkdvNoIijfWDMvdSweFYm4hWh+KwhPstv+sCmWb89hCIP8msFm9N1R/ooh9honpSuvqKWlYy3w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 @@ -224,8 +292,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@8.15.0': - resolution: {integrity: sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==} + '@typescript-eslint/parser@8.17.0': + resolution: {integrity: sha512-Drp39TXuUlD49F7ilHHCG7TTg8IkA+hxCuULdmzWYICxGXvDXmDmWEjJYZQYgf6l/TFfYNE167m7isnc3xlIEg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -234,12 +302,12 @@ packages: typescript: optional: true - '@typescript-eslint/scope-manager@8.15.0': - resolution: {integrity: sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA==} + '@typescript-eslint/scope-manager@8.17.0': + resolution: {integrity: sha512-/ewp4XjvnxaREtqsZjF4Mfn078RD/9GmiEAtTeLQ7yFdKnqwTOgRMSvFz4et9U5RiJQ15WTGXPLj89zGusvxBg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.15.0': - resolution: {integrity: sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw==} + '@typescript-eslint/type-utils@8.17.0': + resolution: {integrity: sha512-q38llWJYPd63rRnJ6wY/ZQqIzPrBCkPdpIsaCfkR3Q4t3p6sb422zougfad4TFW9+ElIFLVDzWGiGAfbb/v2qw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -248,12 +316,12 @@ packages: typescript: optional: true - '@typescript-eslint/types@8.15.0': - resolution: {integrity: sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ==} + '@typescript-eslint/types@8.17.0': + resolution: {integrity: sha512-gY2TVzeve3z6crqh2Ic7Cr+CAv6pfb0Egee7J5UAVWCpVvDI/F71wNfolIim4FE6hT15EbpZFVUj9j5i38jYXA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.15.0': - resolution: {integrity: sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg==} + '@typescript-eslint/typescript-estree@8.17.0': + resolution: {integrity: sha512-JqkOopc1nRKZpX+opvKqnM3XUlM7LpFMD0lYxTqOTKQfCWAmxw45e3qlOCsEqEB2yuacujivudOFpCnqkBDNMw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -261,8 +329,8 @@ packages: typescript: optional: true - '@typescript-eslint/utils@8.15.0': - resolution: {integrity: sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ==} + '@typescript-eslint/utils@8.17.0': + resolution: {integrity: sha512-bQC8BnEkxqG8HBGKwG9wXlZqg37RKSMY7v/X8VEWD8JG2JuTHuNK0VFvMPMUKQcbk6B+tf05k+4AShAEtCtJ/w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -271,15 +339,23 @@ packages: typescript: optional: true - '@typescript-eslint/visitor-keys@8.15.0': - resolution: {integrity: sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q==} + '@typescript-eslint/visitor-keys@8.17.0': + resolution: {integrity: sha512-1Hm7THLpO6ww5QU6H/Qp+AusUUl+z/CAm3cNZZ0jQvon9yicgO7Rwd+/WWRpMKLYV6p2UvdbR27c86rzCPpreg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + acorn@8.14.0: resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} engines: {node: '>=0.4.0'} @@ -316,12 +392,22 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -333,6 +419,14 @@ packages: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -343,6 +437,14 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -361,6 +463,10 @@ packages: chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -390,6 +496,24 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + cookie-signature@1.0.6: + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + + cookie@0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + engines: {node: '>= 0.6'} + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + cross-fetch@4.0.0: resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} @@ -397,6 +521,14 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.3.7: resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} @@ -409,17 +541,44 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} @@ -428,6 +587,17 @@ packages: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} + es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -464,8 +634,8 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.15.0: - resolution: {integrity: sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==} + eslint@9.16.0: + resolution: {integrity: sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -499,6 +669,10 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} @@ -506,6 +680,10 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} + express@4.21.1: + resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==} + engines: {node: '>= 0.10.0'} + extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -540,6 +718,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + engines: {node: '>= 0.8'} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -555,6 +737,14 @@ packages: flatted@3.3.2: resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -563,10 +753,22 @@ packages: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + get-east-asian-width@1.3.0: resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} engines: {node: '>=18'} + get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + get-stream@8.0.1: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} @@ -587,19 +789,46 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} + gopd@1.1.0: + resolution: {integrity: sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.1.0: + resolution: {integrity: sha512-QLdzI9IIO1Jg7f9GT1gXpPpXArAn6cS31R1eEZqz08Gc+uQ8/XiqHWt17Fiw+2p6oTTIq5GXEpQkAlA88YRl/Q==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + hash.js@1.1.7: resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} @@ -616,6 +845,9 @@ packages: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} + ignore-by-default@1.0.1: + resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -631,8 +863,8 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - inngest@3.27.1: - resolution: {integrity: sha512-66JvDYD46cejv1gdCTNGgTTNpg6K6njpBxiZuOPkEDbod1By2M1gnfrOXpJrWkpzVvG+/dY+I3jnhzitwSYPuA==} + inngest@3.27.4: + resolution: {integrity: sha512-S71jJNxmfA9d4jmFKSxgi/u5d+tSmpsThAmTMHhjGieBTSrfGguwhHHskkPpFCtrMWI+Qdy8ek/rtQNxFkE9eQ==} engines: {node: '>=14'} peerDependencies: '@sveltejs/kit': '>=1.27.3' @@ -667,6 +899,14 @@ packages: typescript: optional: true + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -763,6 +1003,16 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -770,10 +1020,27 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + mimic-fn@4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} @@ -796,12 +1063,19 @@ packages: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -811,10 +1085,27 @@ packages: encoding: optional: true + nodemon@3.1.7: + resolution: {integrity: sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==} + engines: {node: '>=10'} + hasBin: true + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + npm-run-path@5.3.0: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + object-inspect@1.13.3: + resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} @@ -868,13 +1159,17 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - package-manager-detector@0.2.4: - resolution: {integrity: sha512-H/OUu9/zUfP89z1APcBf2X8Us0tt8dUK4lUmKqz12QNXif3DxAs1/YqjGtcutZi1zQqeNQRWr9C+EbQnnvSSFA==} + package-manager-detector@0.2.6: + resolution: {integrity: sha512-9vPH3qooBlYRJdmdYP00nvjZOulm40r5dhtal8st18ctf+6S1k7pi5yIHLvI4w5D70x0Y+xdVD9qITH0QO/A8A==} parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -887,6 +1182,9 @@ packages: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} engines: {node: '>=12'} + path-to-regexp@0.1.10: + resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -920,22 +1218,45 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - prettier@3.3.3: - resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + prettier@3.4.2: + resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} engines: {node: '>=14'} hasBin: true + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + pstree.remy@1.1.8: + resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + read-yaml-file@1.1.0: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -961,6 +1282,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -969,9 +1293,24 @@ packages: engines: {node: '>=10'} hasBin: true + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + engines: {node: '>= 0.8.0'} + serialize-error-cjs@0.1.3: resolution: {integrity: sha512-GXwbHkufrNZ87O7DUEvWhR8eBnOqiXtHsOXakkJliG7eLDmjh6gDlbJbMZFFbUx0J5sXKgwq4NFCs41dF5MhiA==} + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + engines: {node: '>= 0.8.0'} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -980,10 +1319,18 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-update-notifier@2.0.0: + resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} + engines: {node: '>=10'} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -1002,6 +1349,10 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -1034,6 +1385,10 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -1054,15 +1409,37 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + touch@3.1.1: + resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} + hasBin: true + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - ts-api-utils@1.4.0: - resolution: {integrity: sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==} + ts-api-utils@1.4.3: + resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -1070,8 +1447,12 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.15.0: - resolution: {integrity: sha512-wY4FRGl0ZI+ZU4Jo/yjdBu0lVTSML58pu6PgGtJmCufvzfV565pUF6iACQt092uFOd49iLOTX/sEVmHtbSrS+w==} + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + + typescript-eslint@8.17.0: + resolution: {integrity: sha512-409VXvFd/f1br1DCbuKNFqQpXICoTB+V51afcwG1pn1a3Cp92MqAUges3YjwEdQ0cMUoCIodjVDAYzyD8h3SYA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -1080,21 +1461,39 @@ packages: typescript: optional: true - typescript@5.6.3: - resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} engines: {node: '>=14.17'} hasBin: true - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undefsafe@2.0.5: + resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} + + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -1119,6 +1518,10 @@ packages: engines: {node: '>= 14'} hasBin: true + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -1188,7 +1591,7 @@ snapshots: fs-extra: 7.0.1 mri: 1.2.0 p-limit: 2.3.0 - package-manager-detector: 0.2.4 + package-manager-detector: 0.2.6 picocolors: 1.1.1 resolve-from: 5.0.0 semver: 7.6.3 @@ -1277,9 +1680,13 @@ snapshots: human-id: 1.0.2 prettier: 2.8.8 - '@eslint-community/eslint-utils@4.4.1(eslint@9.15.0)': + '@cspotcode/source-map-support@0.8.1': dependencies: - eslint: 9.15.0 + '@jridgewell/trace-mapping': 0.3.9 + + '@eslint-community/eslint-utils@4.4.1(eslint@9.16.0)': + dependencies: + eslint: 9.16.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -1287,7 +1694,7 @@ snapshots: '@eslint/config-array@0.19.0': dependencies: '@eslint/object-schema': 2.1.4 - debug: 4.3.7 + debug: 4.3.7(supports-color@5.5.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -1297,7 +1704,7 @@ snapshots: '@eslint/eslintrc@3.2.0': dependencies: ajv: 6.12.6 - debug: 4.3.7 + debug: 4.3.7(supports-color@5.5.0) espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -1308,7 +1715,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.15.0': {} + '@eslint/js@9.16.0': {} '@eslint/object-schema@2.1.4': {} @@ -1329,6 +1736,15 @@ snapshots: '@humanwhocodes/retry@0.4.1': {} + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + '@manypkg/find-root@1.1.0': dependencies: '@babel/runtime': 7.26.0 @@ -1359,103 +1775,167 @@ snapshots: '@pkgr/core@0.1.1': {} + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/body-parser@1.19.5': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 22.10.1 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 22.10.1 + '@types/debug@4.1.12': dependencies: '@types/ms': 0.7.34 '@types/estree@1.0.6': {} + '@types/express-serve-static-core@5.0.2': + dependencies: + '@types/node': 22.10.1 + '@types/qs': 6.9.17 + '@types/range-parser': 1.2.7 + '@types/send': 0.17.4 + + '@types/express@5.0.0': + dependencies: + '@types/body-parser': 1.19.5 + '@types/express-serve-static-core': 5.0.2 + '@types/qs': 6.9.17 + '@types/serve-static': 1.15.7 + + '@types/http-errors@2.0.4': {} + '@types/json-schema@7.0.15': {} + '@types/mime@1.3.5': {} + '@types/ms@0.7.34': {} '@types/node@12.20.55': {} - '@types/node@22.9.1': + '@types/node@22.10.1': + dependencies: + undici-types: 6.20.0 + + '@types/qs@6.9.17': {} + + '@types/range-parser@1.2.7': {} + + '@types/send@0.17.4': + dependencies: + '@types/mime': 1.3.5 + '@types/node': 22.10.1 + + '@types/serve-static@1.15.7': dependencies: - undici-types: 6.19.8 + '@types/http-errors': 2.0.4 + '@types/node': 22.10.1 + '@types/send': 0.17.4 - '@typescript-eslint/eslint-plugin@8.15.0(@typescript-eslint/parser@8.15.0)(eslint@9.15.0)(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@8.17.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0)(typescript@5.7.2))(eslint@9.16.0)(typescript@5.7.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.15.0(eslint@9.15.0)(typescript@5.6.3) - '@typescript-eslint/scope-manager': 8.15.0 - '@typescript-eslint/type-utils': 8.15.0(eslint@9.15.0)(typescript@5.6.3) - '@typescript-eslint/utils': 8.15.0(eslint@9.15.0)(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 8.15.0 - eslint: 9.15.0 + '@typescript-eslint/parser': 8.17.0(eslint@9.16.0)(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.17.0 + '@typescript-eslint/type-utils': 8.17.0(eslint@9.16.0)(typescript@5.7.2) + '@typescript-eslint/utils': 8.17.0(eslint@9.16.0)(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.17.0 + eslint: 9.16.0 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 1.4.0(typescript@5.6.3) - typescript: 5.6.3 + ts-api-utils: 1.4.3(typescript@5.7.2) + optionalDependencies: + typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.15.0(eslint@9.15.0)(typescript@5.6.3)': + '@typescript-eslint/parser@8.17.0(eslint@9.16.0)(typescript@5.7.2)': dependencies: - '@typescript-eslint/scope-manager': 8.15.0 - '@typescript-eslint/types': 8.15.0 - '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 8.15.0 - debug: 4.3.7 - eslint: 9.15.0 - typescript: 5.6.3 + '@typescript-eslint/scope-manager': 8.17.0 + '@typescript-eslint/types': 8.17.0 + '@typescript-eslint/typescript-estree': 8.17.0(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.17.0 + debug: 4.3.7(supports-color@5.5.0) + eslint: 9.16.0 + optionalDependencies: + typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.15.0': + '@typescript-eslint/scope-manager@8.17.0': dependencies: - '@typescript-eslint/types': 8.15.0 - '@typescript-eslint/visitor-keys': 8.15.0 + '@typescript-eslint/types': 8.17.0 + '@typescript-eslint/visitor-keys': 8.17.0 - '@typescript-eslint/type-utils@8.15.0(eslint@9.15.0)(typescript@5.6.3)': + '@typescript-eslint/type-utils@8.17.0(eslint@9.16.0)(typescript@5.7.2)': dependencies: - '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.6.3) - '@typescript-eslint/utils': 8.15.0(eslint@9.15.0)(typescript@5.6.3) - debug: 4.3.7 - eslint: 9.15.0 - ts-api-utils: 1.4.0(typescript@5.6.3) - typescript: 5.6.3 + '@typescript-eslint/typescript-estree': 8.17.0(typescript@5.7.2) + '@typescript-eslint/utils': 8.17.0(eslint@9.16.0)(typescript@5.7.2) + debug: 4.3.7(supports-color@5.5.0) + eslint: 9.16.0 + ts-api-utils: 1.4.3(typescript@5.7.2) + optionalDependencies: + typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.15.0': {} + '@typescript-eslint/types@8.17.0': {} - '@typescript-eslint/typescript-estree@8.15.0(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@8.17.0(typescript@5.7.2)': dependencies: - '@typescript-eslint/types': 8.15.0 - '@typescript-eslint/visitor-keys': 8.15.0 - debug: 4.3.7 + '@typescript-eslint/types': 8.17.0 + '@typescript-eslint/visitor-keys': 8.17.0 + debug: 4.3.7(supports-color@5.5.0) fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 1.4.0(typescript@5.6.3) - typescript: 5.6.3 + ts-api-utils: 1.4.3(typescript@5.7.2) + optionalDependencies: + typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.15.0(eslint@9.15.0)(typescript@5.6.3)': + '@typescript-eslint/utils@8.17.0(eslint@9.16.0)(typescript@5.7.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.15.0) - '@typescript-eslint/scope-manager': 8.15.0 - '@typescript-eslint/types': 8.15.0 - '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.6.3) - eslint: 9.15.0 - typescript: 5.6.3 + '@eslint-community/eslint-utils': 4.4.1(eslint@9.16.0) + '@typescript-eslint/scope-manager': 8.17.0 + '@typescript-eslint/types': 8.17.0 + '@typescript-eslint/typescript-estree': 8.17.0(typescript@5.7.2) + eslint: 9.16.0 + optionalDependencies: + typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.15.0': + '@typescript-eslint/visitor-keys@8.17.0': dependencies: - '@typescript-eslint/types': 8.15.0 + '@typescript-eslint/types': 8.17.0 eslint-visitor-keys: 4.2.0 + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: acorn: 8.14.0 + acorn-walk@8.3.4: + dependencies: + acorn: 8.14.0 + acorn@8.14.0: {} ajv@6.12.6: @@ -1483,12 +1963,21 @@ snapshots: ansi-styles@6.2.1: {} + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@4.1.3: {} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 argparse@2.0.1: {} + array-flatten@1.1.1: {} + array-union@2.1.0: {} balanced-match@1.0.2: {} @@ -1497,6 +1986,25 @@ snapshots: dependencies: is-windows: 1.0.2 + binary-extensions@2.3.0: {} + + body-parser@1.20.3: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.13.0 + raw-body: 2.5.2 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -1510,6 +2018,16 @@ snapshots: dependencies: fill-range: 7.1.1 + bytes@3.1.2: {} + + call-bind@1.0.7: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + callsites@3.1.0: {} canonicalize@1.0.8: {} @@ -1523,6 +2041,18 @@ snapshots: chardet@0.7.0: {} + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + ci-info@3.9.0: {} cli-cursor@5.0.0: @@ -1546,6 +2076,18 @@ snapshots: concat-map@0.0.1: {} + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + + cookie-signature@1.0.6: {} + + cookie@0.7.1: {} + + create-require@1.1.1: {} + cross-fetch@4.0.0: dependencies: node-fetch: 2.7.0 @@ -1558,20 +2100,44 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - debug@4.3.7: + debug@2.6.9: + dependencies: + ms: 2.0.0 + + debug@4.3.7(supports-color@5.5.0): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 5.5.0 deep-is@0.1.4: {} + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.1.0 + + depd@2.0.0: {} + + destroy@1.2.0: {} + detect-indent@6.1.0: {} + diff@4.0.2: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 + ee-first@1.1.1: {} + emoji-regex@10.4.0: {} + encodeurl@1.0.2: {} + + encodeurl@2.0.0: {} + enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 @@ -1579,19 +2145,28 @@ snapshots: environment@1.1.0: {} + es-define-property@1.0.0: + dependencies: + get-intrinsic: 1.2.4 + + es-errors@1.3.0: {} + + escape-html@1.0.3: {} + escape-string-regexp@4.0.0: {} - eslint-config-prettier@9.1.0(eslint@9.15.0): + eslint-config-prettier@9.1.0(eslint@9.16.0): dependencies: - eslint: 9.15.0 + eslint: 9.16.0 - eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0)(eslint@9.15.0)(prettier@3.3.3): + eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@9.16.0))(eslint@9.16.0)(prettier@3.4.2): dependencies: - eslint: 9.15.0 - eslint-config-prettier: 9.1.0(eslint@9.15.0) - prettier: 3.3.3 + eslint: 9.16.0 + prettier: 3.4.2 prettier-linter-helpers: 1.0.0 synckit: 0.9.2 + optionalDependencies: + eslint-config-prettier: 9.1.0(eslint@9.16.0) eslint-scope@8.2.0: dependencies: @@ -1602,14 +2177,14 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.15.0: + eslint@9.16.0: dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.15.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.16.0) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.19.0 '@eslint/core': 0.9.0 '@eslint/eslintrc': 3.2.0 - '@eslint/js': 9.15.0 + '@eslint/js': 9.16.0 '@eslint/plugin-kit': 0.2.3 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 @@ -1619,7 +2194,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.3.7 + debug: 4.3.7(supports-color@5.5.0) escape-string-regexp: 4.0.0 eslint-scope: 8.2.0 eslint-visitor-keys: 4.2.0 @@ -1661,6 +2236,8 @@ snapshots: esutils@2.0.3: {} + etag@1.8.1: {} + eventemitter3@5.0.1: {} execa@8.0.1: @@ -1675,6 +2252,42 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 + express@4.21.1: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.3 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.1 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.1 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.10 + proxy-addr: 2.0.7 + qs: 6.13.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.0 + serve-static: 1.16.2 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + extendable-error@0.1.7: {} external-editor@3.1.0: @@ -1711,6 +2324,18 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@1.3.1: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -1728,6 +2353,10 @@ snapshots: flatted@3.3.2: {} + forwarded@0.2.0: {} + + fresh@0.5.2: {} + fs-extra@7.0.1: dependencies: graceful-fs: 4.2.11 @@ -1740,8 +2369,21 @@ snapshots: jsonfile: 4.0.0 universalify: 0.1.2 + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + get-east-asian-width@1.3.0: {} + get-intrinsic@1.2.4: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.1.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + get-stream@8.0.1: {} glob-parent@5.1.2: @@ -1763,17 +2405,45 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + gopd@1.1.0: + dependencies: + get-intrinsic: 1.2.4 + graceful-fs@4.2.11: {} graphemer@1.4.0: {} + has-flag@3.0.0: {} + has-flag@4.0.0: {} + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.0 + + has-proto@1.1.0: + dependencies: + call-bind: 1.0.7 + + has-symbols@1.1.0: {} + hash.js@1.1.7: dependencies: inherits: 2.0.4 minimalistic-assert: 1.0.1 + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + human-id@1.0.2: {} human-signals@5.0.0: {} @@ -1784,6 +2454,8 @@ snapshots: dependencies: safer-buffer: 2.1.2 + ignore-by-default@1.0.1: {} + ignore@5.3.2: {} import-fresh@3.3.0: @@ -1795,24 +2467,32 @@ snapshots: inherits@2.0.4: {} - inngest@3.27.1(typescript@5.6.3): + inngest@3.27.4(express@4.21.1)(typescript@5.7.2): dependencies: '@types/debug': 4.1.12 canonicalize: 1.0.8 chalk: 4.1.2 cross-fetch: 4.0.0 - debug: 4.3.7 + debug: 4.3.7(supports-color@5.5.0) hash.js: 1.1.7 json-stringify-safe: 5.0.1 ms: 2.1.3 serialize-error-cjs: 0.1.3 strip-ansi: 5.2.0 - typescript: 5.6.3 zod: 3.22.5 + optionalDependencies: + express: 4.21.1 + typescript: 5.7.2 transitivePeerDependencies: - encoding - supports-color + ipaddr.js@1.9.1: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + is-extglob@2.1.1: {} is-fullwidth-code-point@4.0.0: {} @@ -1873,7 +2553,7 @@ snapshots: dependencies: chalk: 5.3.0 commander: 12.1.0 - debug: 4.3.7 + debug: 4.3.7(supports-color@5.5.0) execa: 8.0.1 lilconfig: 3.1.3 listr2: 8.2.5 @@ -1913,15 +2593,31 @@ snapshots: strip-ansi: 7.1.0 wrap-ansi: 9.0.0 + make-error@1.3.6: {} + + media-typer@0.3.0: {} + + merge-descriptors@1.0.3: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} + methods@1.1.2: {} + micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@1.6.0: {} + mimic-fn@4.0.0: {} mimic-function@5.0.1: {} @@ -1938,18 +2634,43 @@ snapshots: mri@1.2.0: {} + ms@2.0.0: {} + ms@2.1.3: {} natural-compare@1.4.0: {} + negotiator@0.6.3: {} + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 + nodemon@3.1.7: + dependencies: + chokidar: 3.6.0 + debug: 4.3.7(supports-color@5.5.0) + ignore-by-default: 1.0.1 + minimatch: 3.1.2 + pstree.remy: 1.1.8 + semver: 7.6.3 + simple-update-notifier: 2.0.0 + supports-color: 5.5.0 + touch: 3.1.1 + undefsafe: 2.0.5 + + normalize-path@3.0.0: {} + npm-run-path@5.3.0: dependencies: path-key: 4.0.0 + object-inspect@1.13.3: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + onetime@6.0.0: dependencies: mimic-fn: 4.0.0 @@ -1999,18 +2720,22 @@ snapshots: p-try@2.2.0: {} - package-manager-detector@0.2.4: {} + package-manager-detector@0.2.6: {} parent-module@1.0.1: dependencies: callsites: 3.1.0 + parseurl@1.3.3: {} + path-exists@4.0.0: {} path-key@3.1.1: {} path-key@4.0.0: {} + path-to-regexp@0.1.10: {} + path-type@4.0.0: {} picocolors@1.1.1: {} @@ -2029,12 +2754,32 @@ snapshots: prettier@2.8.8: {} - prettier@3.3.3: {} + prettier@3.4.2: {} + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + pstree.remy@1.1.8: {} punycode@2.3.1: {} + qs@6.13.0: + dependencies: + side-channel: 1.0.6 + queue-microtask@1.2.3: {} + range-parser@1.2.1: {} + + raw-body@2.5.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + read-yaml-file@1.1.0: dependencies: graceful-fs: 4.2.11 @@ -2042,6 +2787,10 @@ snapshots: pify: 4.0.1 strip-bom: 3.0.0 + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + regenerator-runtime@0.14.1: {} resolve-from@4.0.0: {} @@ -2061,20 +2810,71 @@ snapshots: dependencies: queue-microtask: 1.2.3 + safe-buffer@5.2.1: {} + safer-buffer@2.1.2: {} semver@7.6.3: {} + send@0.19.0: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + serialize-error-cjs@0.1.3: {} + serve-static@1.16.2: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.0 + transitivePeerDependencies: + - supports-color + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.1.0 + has-property-descriptors: 1.0.2 + + setprototypeof@1.2.0: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} + side-channel@1.0.6: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.3 + signal-exit@4.1.0: {} + simple-update-notifier@2.0.0: + dependencies: + semver: 7.6.3 + slash@3.0.0: {} slice-ansi@5.0.0: @@ -2094,6 +2894,8 @@ snapshots: sprintf-js@1.0.3: {} + statuses@2.0.1: {} + string-argv@0.3.2: {} string-width@7.2.0: @@ -2120,6 +2922,10 @@ snapshots: strip-json-comments@3.1.1: {} + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -2139,11 +2945,33 @@ snapshots: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + + touch@3.1.1: {} + tr46@0.0.3: {} - ts-api-utils@1.4.0(typescript@5.6.3): + ts-api-utils@1.4.3(typescript@5.7.2): dependencies: - typescript: 5.6.3 + typescript: 5.7.2 + + ts-node@10.9.2(@types/node@22.10.1)(typescript@5.7.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.10.1 + acorn: 8.14.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.7.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 tslib@2.8.1: {} @@ -2151,26 +2979,42 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.15.0(eslint@9.15.0)(typescript@5.6.3): + type-is@1.6.18: dependencies: - '@typescript-eslint/eslint-plugin': 8.15.0(@typescript-eslint/parser@8.15.0)(eslint@9.15.0)(typescript@5.6.3) - '@typescript-eslint/parser': 8.15.0(eslint@9.15.0)(typescript@5.6.3) - '@typescript-eslint/utils': 8.15.0(eslint@9.15.0)(typescript@5.6.3) - eslint: 9.15.0 - typescript: 5.6.3 + media-typer: 0.3.0 + mime-types: 2.1.35 + + typescript-eslint@8.17.0(eslint@9.16.0)(typescript@5.7.2): + dependencies: + '@typescript-eslint/eslint-plugin': 8.17.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0)(typescript@5.7.2))(eslint@9.16.0)(typescript@5.7.2) + '@typescript-eslint/parser': 8.17.0(eslint@9.16.0)(typescript@5.7.2) + '@typescript-eslint/utils': 8.17.0(eslint@9.16.0)(typescript@5.7.2) + eslint: 9.16.0 + optionalDependencies: + typescript: 5.7.2 transitivePeerDependencies: - supports-color - typescript@5.6.3: {} + typescript@5.7.2: {} - undici-types@6.19.8: {} + undefsafe@2.0.5: {} + + undici-types@6.20.0: {} universalify@0.1.2: {} + unpipe@1.0.0: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 + utils-merge@1.0.1: {} + + v8-compile-cache-lib@3.0.1: {} + + vary@1.1.2: {} + webidl-conversions@3.0.1: {} whatwg-url@5.0.0: @@ -2192,6 +3036,8 @@ snapshots: yaml@2.5.1: {} + yn@3.1.1: {} + yocto-queue@0.1.0: {} zod@3.22.5: {} diff --git a/src/adapters/openai.ts b/src/adapters/openai.ts index 2d73d60..ccb8cef 100644 --- a/src/adapters/openai.ts +++ b/src/adapters/openai.ts @@ -12,7 +12,7 @@ import { type InternalNetworkMessage, type ToolMessage } from "../state"; // Helper to parse JSON that may contain backticks: // Example: // "{\n \"files\": [\n {\n \"filename\": \"fibo.ts\",\n \"content\": `\nfunction fibonacci(n: number): number {\n if (n < 2) {\n return n;\n } else {\n return fibonacci(n - 1) + fibonacci(n - 2);\n }\n}\n\nexport default fibonacci;\n`\n }\n ]\n}" -const safeParseOpenAIJson = (str: string): unknown => { +const safeParseOpenAIJson = (str: string): any => { // Remove any leading/trailing quotes if present const trimmed = str.replace(/^["']|["']$/g, ''); @@ -34,6 +34,26 @@ const safeParseOpenAIJson = (str: string): unknown => { } }; +// TODO: move to another file? +const StateRoleToOpenAiRole = { + system: "system", + user: "user", + assistant: "assistant", + tool_result: "tool", +} as const; + +const StateStopReasonToOpenAiStopReason = { + tool: 'tool_calls', + stop: 'stop', +} as const; + +const OpenAiStopReasonToStateStopReason = { + tool_calls: 'tool', + stop: 'stop', + length: 'stop', + content_filter: 'stop', + function_call: 'tool', +} as const; /** @@ -46,15 +66,31 @@ export const requestParser: AgenticModel.RequestParser = ( ) => { const request: AiAdapter.Input = { messages: messages.map((m) => { + const role = StateRoleToOpenAiRole[m.role]; return { - role: m.role, + ...(m.stop_reason ? { finish_reason: StateStopReasonToOpenAiStopReason[m.stop_reason] } : {}), + role, content: m.content, + // NOTE: this is very ugly, we need to better handle different shape of messages + // TODO: refactor + unit tests + tool_call_id: role === 'tool' ? m.tools?.[0]?.id : undefined, + tool_calls: role === 'assistant' && !!m.tools ? m.tools?.map((tool) => ({ + id: tool.id, + type: "function", + function: { + name: tool.name, + arguments: JSON.stringify(tool.input), + }, + })) : undefined, }; }) as AiAdapter.Input["messages"], }; if (tools?.length) { request.tool_choice = "auto"; + // it is recommended to disable parallel tool calls with structured output + // https://platform.openai.com/docs/guides/function-calling#parallel-function-calling-and-structured-outputs + request.parallel_tool_calls = false; request.tools = tools.map((t) => { return { type: "function", @@ -88,14 +124,18 @@ export const responseParser: AgenticModel.ResponseParser = ( { role: choice.message.role, content: choice.message.content, + // NOTE: this is very ugly, we need to better handle different shape of messages + // TODO: refactor + unit tests + // @ts-expect-error TODO: patch `inngest` to support `finish_reason` + ...(choice.finish_reason ? { stop_reason: OpenAiStopReasonToStateStopReason[choice.finish_reason] } : {}), tools: (choice.message.tool_calls ?? []).map((tool) => { return { - type: "tool", + type: "function", id: tool.id, name: tool.function.name, - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - input: JSON.parse(tool.function.arguments || "{}"), - }; + function: tool.function.name, + input: safeParseOpenAIJson(tool.function.arguments || "{}"), + } as any; }), } as InternalNetworkMessage, ]; diff --git a/src/agent.ts b/src/agent.ts index 15acede..a597b4b 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -93,8 +93,9 @@ export class Agent { throw new Error("No step caller provided to agent"); } - let system = await this.agentPrompt(input, network); let history = network ? network.state.history : []; + let system = await this.agentPrompt(input, network); + let result: InferenceResult; if (this.lifecycles?.onStart) { const modified = await this.lifecycles.onStart({ @@ -108,6 +109,33 @@ export class Agent { history = modified.history; } + let hasMoreActions = true + + do { + const inference = await this.performInference(input, p, history, system, network); + + hasMoreActions = this.tools.size > 0 && (inference.output[inference.output.length - 1]!).stop_reason !== 'stop'; + result = inference; + history = [...inference.output]; + + } while (hasMoreActions) + + if (this.lifecycles?.onFinish) { + result = await this.lifecycles.onFinish({ agent: this, network, result }); + } + + return result; + } + + private async performInference( + input: string, + p: AgenticModel.Any, + history: InternalNetworkMessage[], + system: InternalNetworkMessage[], + network?: Network, + ): Promise { + + const { output, raw } = await p.infer( this.name, system.concat(history), @@ -134,12 +162,13 @@ export class Agent { } // And ensure we invoke any call from the agent - result.toolCalls = await this.invokeTools(result.output, p, network); - if (this.lifecycles?.onFinish) { - result = await this.lifecycles.onFinish({ agent: this, network, result }); + const toolCallOutput = await this.invokeTools(result.output, p, network) + // if a tool was called, we add it to the history/messages + if (toolCallOutput.length > 0) { + result.output = result.output.concat(toolCallOutput); } - return result; + return result } private async invokeTools( @@ -174,19 +203,17 @@ export class Agent { step: p.step, }); - if (result === undefined) { - // This had no result, so we don't wnat to save it to the state. - continue; - } + // TODO: handle error and send them back to the LLM output.push({ role: "tool_result", - content: { - type: "tool_result", + tools: [{ + type: "tool", id: tool.id, - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - content: result, // TODO: Properly type content. - }, + name: tool.name, + input: tool.input.arguments as any, + }], + content: !!result ? result : `${tool.name} successfully executed` }); } } diff --git a/src/state.ts b/src/state.ts index df8fac6..fac24d7 100644 --- a/src/state.ts +++ b/src/state.ts @@ -4,7 +4,11 @@ export interface InternalNetworkMessage { role: "system" | "user" | "assistant" | "tool_result"; content: string | Array | ToolResult; tools?: ToolMessage[]; - // TODO: Images and multi-modality. + // Anthropic: + // stop_reason: "end_turn" | "max_tokens" | "stop_sequence" | "tool_use" | null; + // OpenAI: + // finish_reason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'function_call' | null; + stop_reason?: 'tool' | 'stop'; } export interface TextMessage { diff --git a/tsconfig-demo.json b/tsconfig-demo.json new file mode 100644 index 0000000..4c4f242 --- /dev/null +++ b/tsconfig-demo.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "es2017", + "lib": ["ES2021", "DOM"], + "module": "commonjs", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "rootDir": "./", + "outDir": "./dist-demo", + "types": ["node"], + "moduleResolution": "node", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "noImplicitOverride": true, + "resolveJsonModule": true, + "noUncheckedIndexedAccess": true, + "strictNullChecks": true + }, + "include": ["./**/*.ts"], + "exclude": ["./demo/inngest_alt.ts", "./demo/mw.ts"] +} From d0a5228fbe8cdfdca2bf5775513160741b8521e9 Mon Sep 17 00:00:00 2001 From: Jack Williams <1736957+jpwilliams@users.noreply.github.com> Date: Wed, 4 Dec 2024 11:19:21 +0000 Subject: [PATCH 04/15] Fix linting, switch compile error --- src/model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model.ts b/src/model.ts index ac5740e..6981edb 100644 --- a/src/model.ts +++ b/src/model.ts @@ -36,7 +36,7 @@ export class AgenticModel { } export namespace AgenticModel { - export type Any = AgenticModel; + export type Any = AgenticModel; /** * InferenceResponse is the response from a model for an inference request. From a60d2f8d06fd40a856be7b43e44f59ddef516927 Mon Sep 17 00:00:00 2001 From: Jack Williams <1736957+jpwilliams@users.noreply.github.com> Date: Wed, 4 Dec 2024 17:35:58 +0000 Subject: [PATCH 05/15] Further fixes --- src/adapters/openai.ts | 72 ++++++++++++++++++++++++++---------------- src/agent.ts | 40 +++++++++++++---------- src/state.ts | 2 +- src/util.ts | 12 +++++++ 4 files changed, 81 insertions(+), 45 deletions(-) diff --git a/src/adapters/openai.ts b/src/adapters/openai.ts index ccb8cef..05a6ede 100644 --- a/src/adapters/openai.ts +++ b/src/adapters/openai.ts @@ -7,15 +7,16 @@ import { type AiAdapter, type OpenAi } from "inngest"; import { zodToJsonSchema } from "openai-zod-to-json-schema"; import { type AgenticModel } from "../model"; +import { stringifyError } from "../util"; import { type InternalNetworkMessage, type ToolMessage } from "../state"; // Helper to parse JSON that may contain backticks: // Example: // "{\n \"files\": [\n {\n \"filename\": \"fibo.ts\",\n \"content\": `\nfunction fibonacci(n: number): number {\n if (n < 2) {\n return n;\n } else {\n return fibonacci(n - 1) + fibonacci(n - 2);\n }\n}\n\nexport default fibonacci;\n`\n }\n ]\n}" -const safeParseOpenAIJson = (str: string): any => { +const safeParseOpenAIJson = (str: string): unknown => { // Remove any leading/trailing quotes if present - const trimmed = str.replace(/^["']|["']$/g, ''); - + const trimmed = str.replace(/^["']|["']$/g, ""); + try { // First try direct JSON parse return JSON.parse(trimmed); @@ -23,13 +24,14 @@ const safeParseOpenAIJson = (str: string): any => { try { // Replace backtick strings with regular JSON strings // Match content between backticks, preserving newlines - const withQuotes = trimmed.replace( - /`([\s\S]*?)`/g, - (_, content) => JSON.stringify(content) + const withQuotes = trimmed.replace(/`([\s\S]*?)`/g, (_, content) => + JSON.stringify(content), ); return JSON.parse(withQuotes); } catch (e) { - throw new Error(`Failed to parse JSON with backticks: ${e}`); + throw new Error( + `Failed to parse JSON with backticks: ${stringifyError(e)}`, + ); } } }; @@ -43,19 +45,18 @@ const StateRoleToOpenAiRole = { } as const; const StateStopReasonToOpenAiStopReason = { - tool: 'tool_calls', - stop: 'stop', + tool: "tool_calls", + stop: "stop", } as const; const OpenAiStopReasonToStateStopReason = { - tool_calls: 'tool', - stop: 'stop', - length: 'stop', - content_filter: 'stop', - function_call: 'tool', + tool_calls: "tool", + stop: "stop", + length: "stop", + content_filter: "stop", + function_call: "tool", } as const; - /** * Parse a request from internal network messages to an OpenAI input. */ @@ -68,20 +69,25 @@ export const requestParser: AgenticModel.RequestParser = ( messages: messages.map((m) => { const role = StateRoleToOpenAiRole[m.role]; return { - ...(m.stop_reason ? { finish_reason: StateStopReasonToOpenAiStopReason[m.stop_reason] } : {}), + ...(m.stop_reason + ? { finish_reason: StateStopReasonToOpenAiStopReason[m.stop_reason] } + : {}), role, content: m.content, // NOTE: this is very ugly, we need to better handle different shape of messages // TODO: refactor + unit tests - tool_call_id: role === 'tool' ? m.tools?.[0]?.id : undefined, - tool_calls: role === 'assistant' && !!m.tools ? m.tools?.map((tool) => ({ - id: tool.id, - type: "function", - function: { - name: tool.name, - arguments: JSON.stringify(tool.input), - }, - })) : undefined, + tool_call_id: role === "tool" ? m.tools?.[0]?.id : undefined, + tool_calls: + role === "assistant" && !!m.tools + ? m.tools?.map((tool) => ({ + id: tool.id, + type: "function", + function: { + name: tool.name, + arguments: JSON.stringify(tool.input), + }, + })) + : undefined, }; }) as AiAdapter.Input["messages"], }; @@ -119,6 +125,13 @@ export const responseParser: AgenticModel.ResponseParser = ( return acc; } + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access + const finishReason = (choice as any).finish_reason; + const stopReason = + OpenAiStopReasonToStateStopReason[ + finishReason as keyof typeof OpenAiStopReasonToStateStopReason + ]; + return [ ...acc, { @@ -126,8 +139,11 @@ export const responseParser: AgenticModel.ResponseParser = ( content: choice.message.content, // NOTE: this is very ugly, we need to better handle different shape of messages // TODO: refactor + unit tests - // @ts-expect-error TODO: patch `inngest` to support `finish_reason` - ...(choice.finish_reason ? { stop_reason: OpenAiStopReasonToStateStopReason[choice.finish_reason] } : {}), + ...(finishReason + ? { + stop_reason: stopReason, + } + : {}), tools: (choice.message.tool_calls ?? []).map((tool) => { return { type: "function", @@ -135,7 +151,7 @@ export const responseParser: AgenticModel.ResponseParser = ( name: tool.function.name, function: tool.function.name, input: safeParseOpenAIJson(tool.function.arguments || "{}"), - } as any; + } as unknown as ToolMessage; // :( }), } as InternalNetworkMessage, ]; diff --git a/src/agent.ts b/src/agent.ts index a597b4b..c718c7b 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -109,16 +109,23 @@ export class Agent { history = modified.history; } - let hasMoreActions = true + let hasMoreActions = true; do { - const inference = await this.performInference(input, p, history, system, network); + const inference = await this.performInference( + input, + p, + history, + system, + network, + ); - hasMoreActions = this.tools.size > 0 && (inference.output[inference.output.length - 1]!).stop_reason !== 'stop'; + hasMoreActions = + this.tools.size > 0 && + inference.output[inference.output.length - 1]!.stop_reason !== "stop"; result = inference; history = [...inference.output]; - - } while (hasMoreActions) + } while (hasMoreActions); if (this.lifecycles?.onFinish) { result = await this.lifecycles.onFinish({ agent: this, network, result }); @@ -134,8 +141,6 @@ export class Agent { system: InternalNetworkMessage[], network?: Network, ): Promise { - - const { output, raw } = await p.infer( this.name, system.concat(history), @@ -162,13 +167,13 @@ export class Agent { } // And ensure we invoke any call from the agent - const toolCallOutput = await this.invokeTools(result.output, p, network) + const toolCallOutput = await this.invokeTools(result.output, p, network); // if a tool was called, we add it to the history/messages if (toolCallOutput.length > 0) { result.output = result.output.concat(toolCallOutput); } - return result + return result; } private async invokeTools( @@ -207,13 +212,16 @@ export class Agent { output.push({ role: "tool_result", - tools: [{ - type: "tool", - id: tool.id, - name: tool.name, - input: tool.input.arguments as any, - }], - content: !!result ? result : `${tool.name} successfully executed` + tools: [ + { + type: "tool", + id: tool.id, + name: tool.name, + input: tool.input.arguments as Record, + }, + ], + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + content: result ? result : `${tool.name} successfully executed`, }); } } diff --git a/src/state.ts b/src/state.ts index fac24d7..e1c1327 100644 --- a/src/state.ts +++ b/src/state.ts @@ -8,7 +8,7 @@ export interface InternalNetworkMessage { // stop_reason: "end_turn" | "max_tokens" | "stop_sequence" | "tool_use" | null; // OpenAI: // finish_reason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'function_call' | null; - stop_reason?: 'tool' | 'stop'; + stop_reason?: "tool" | "stop"; } export interface TextMessage { diff --git a/src/util.ts b/src/util.ts index 2e5a870..e1f9b56 100644 --- a/src/util.ts +++ b/src/util.ts @@ -14,3 +14,15 @@ export type MaybePromise = T | Promise; */ // eslint-disable-next-line @typescript-eslint/no-explicit-any export type AnyZodType = ZodType; + +/** + * Given an unknown value, return a string representation of the error if it is + * an error, otherwise return the stringified value. + */ +export const stringifyError = (e: unknown): string => { + if (e instanceof Error) { + return e.message; + } + + return String(e); +}; From 0b83ca0e75112746760b7b6b4910d5734b665fae Mon Sep 17 00:00:00 2001 From: Jack Williams <1736957+jpwilliams@users.noreply.github.com> Date: Thu, 5 Dec 2024 12:45:13 +0000 Subject: [PATCH 06/15] Fix up parsing to be a touch safer --- .husky/pre-commit | 3 -- src/adapters/openai.ts | 92 ++++++++++++++++++++++-------------------- 2 files changed, 48 insertions(+), 47 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 36af219..2312dc5 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - npx lint-staged diff --git a/src/adapters/openai.ts b/src/adapters/openai.ts index 05a6ede..b3f1228 100644 --- a/src/adapters/openai.ts +++ b/src/adapters/openai.ts @@ -10,9 +10,15 @@ import { type AgenticModel } from "../model"; import { stringifyError } from "../util"; import { type InternalNetworkMessage, type ToolMessage } from "../state"; -// Helper to parse JSON that may contain backticks: -// Example: -// "{\n \"files\": [\n {\n \"filename\": \"fibo.ts\",\n \"content\": `\nfunction fibonacci(n: number): number {\n if (n < 2) {\n return n;\n } else {\n return fibonacci(n - 1) + fibonacci(n - 2);\n }\n}\n\nexport default fibonacci;\n`\n }\n ]\n}" +/** + * Parse the given `str` `string` as JSON, also handling backticks, a common + * OpenAI quirk. + * + * @example Input + * ``` + * "{\n \"files\": [\n {\n \"filename\": \"fibo.ts\",\n \"content\": `\nfunction fibonacci(n: number): number {\n if (n < 2) {\n return n;\n } else {\n return fibonacci(n - 1) + fibonacci(n - 2);\n }\n}\n\nexport default fibonacci;\n`\n }\n ]\n}" + * ``` + */ const safeParseOpenAIJson = (str: string): unknown => { // Remove any leading/trailing quotes if present const trimmed = str.replace(/^["']|["']$/g, ""); @@ -36,26 +42,45 @@ const safeParseOpenAIJson = (str: string): unknown => { } }; -// TODO: move to another file? -const StateRoleToOpenAiRole = { - system: "system", - user: "user", - assistant: "assistant", - tool_result: "tool", -} as const; - -const StateStopReasonToOpenAiStopReason = { +const StateStopReasonToOpenAiStopReason: Record = { tool: "tool_calls", stop: "stop", -} as const; +}; -const OpenAiStopReasonToStateStopReason = { +const OpenAiStopReasonToStateStopReason: Record = { tool_calls: "tool", stop: "stop", length: "stop", content_filter: "stop", function_call: "tool", -} as const; +}; + +const reqMsgRoleHandlers: Record< + InternalNetworkMessage["role"], + ( + internalMessage: InternalNetworkMessage, + ) => Partial["messages"][number]> +> = { + system: () => ({ role: "system" }), + user: () => ({ role: "user" }), + assistant: (m) => ({ + role: "assistant", + tool_calls: m.tools + ? m.tools?.map((tool) => ({ + id: tool.id, + type: "function", + function: { + name: tool.name, + arguments: JSON.stringify(tool.input), + }, + })) + : undefined, + }), + tool_result: (m) => ({ + role: "tool", + tool_call_id: m.tools?.[0]?.id, + }), +}; /** * Parse a request from internal network messages to an OpenAI input. @@ -67,27 +92,16 @@ export const requestParser: AgenticModel.RequestParser = ( ) => { const request: AiAdapter.Input = { messages: messages.map((m) => { - const role = StateRoleToOpenAiRole[m.role]; - return { + const baseMsg = { ...(m.stop_reason ? { finish_reason: StateStopReasonToOpenAiStopReason[m.stop_reason] } : {}), - role, content: m.content, - // NOTE: this is very ugly, we need to better handle different shape of messages - // TODO: refactor + unit tests - tool_call_id: role === "tool" ? m.tools?.[0]?.id : undefined, - tool_calls: - role === "assistant" && !!m.tools - ? m.tools?.map((tool) => ({ - id: tool.id, - type: "function", - function: { - name: tool.name, - arguments: JSON.stringify(tool.input), - }, - })) - : undefined, + }; + + return { + ...baseMsg, + ...reqMsgRoleHandlers[m.role](m), }; }) as AiAdapter.Input["messages"], }; @@ -125,25 +139,15 @@ export const responseParser: AgenticModel.ResponseParser = ( return acc; } - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access - const finishReason = (choice as any).finish_reason; const stopReason = - OpenAiStopReasonToStateStopReason[ - finishReason as keyof typeof OpenAiStopReasonToStateStopReason - ]; + OpenAiStopReasonToStateStopReason[choice.finish_reason ?? ""]; return [ ...acc, { role: choice.message.role, content: choice.message.content, - // NOTE: this is very ugly, we need to better handle different shape of messages - // TODO: refactor + unit tests - ...(finishReason - ? { - stop_reason: stopReason, - } - : {}), + ...(stopReason ? { stop_reason: stopReason } : {}), tools: (choice.message.tool_calls ?? []).map((tool) => { return { type: "function", From e6cf806e4bae946fba0cc6075caeb240b1948d90 Mon Sep 17 00:00:00 2001 From: Charly POLY Date: Thu, 5 Dec 2024 17:22:56 +0100 Subject: [PATCH 07/15] fix(network): `select_agent` fix + disable iterations on Agent when ran with a network --- src/agent.ts | 12 +++++++++--- src/network.ts | 24 +++++++++++++----------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/agent.ts b/src/agent.ts index c718c7b..d06135d 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -86,7 +86,11 @@ export class Agent { */ async run( input: string, - { model, network }: Agent.RunOptions | undefined = {}, + { + model, + network, + maxIter = this.tools.size + 1, + }: Agent.RunOptions | undefined = {}, ): Promise { const p = model || this.model || network?.defaultModel; if (!p) { @@ -110,7 +114,7 @@ export class Agent { } let hasMoreActions = true; - + let iter = 0; do { const inference = await this.performInference( input, @@ -125,7 +129,8 @@ export class Agent { inference.output[inference.output.length - 1]!.stop_reason !== "stop"; result = inference; history = [...inference.output]; - } while (hasMoreActions); + iter++; + } while (hasMoreActions && iter < maxIter); if (this.lifecycles?.onFinish) { result = await this.lifecycles.onFinish({ agent: this, network, result }); @@ -273,6 +278,7 @@ export namespace Agent { export interface RunOptions { model?: AgenticModel.Any; network?: Network; + maxIter?: number; } export interface Lifecycle { diff --git a/src/network.ts b/src/network.ts index 6a226e4..e7d2661 100644 --- a/src/network.ts +++ b/src/network.ts @@ -132,7 +132,9 @@ export class Network { return this; } - const call = await agent.run(input, { network: this }); + // We force Agent to emit structured output in case of the use of tools by + // setting maxIter to 0. + const call = await agent.run(input, { network: this, maxIter: 0 }); this._counter += 1; // Ensure that we store the call network history. @@ -233,23 +235,23 @@ export const defaultRoutingAgent = new Agent({ .describe("The name of the agent that should handle the request"), }) .strict(), - handler: (input, { agent, network }) => { + handler: ({ name }, { network }) => { if (!network) { throw new Error( "The routing agent can only be used within a network of agents", ); } - // if (typeof name !== "string") { - // throw new Error("The routing agent requested an invalid agent"); - // } + if (typeof name !== "string") { + throw new Error("The routing agent requested an invalid agent"); + } - // const agent = network.agents.get(name); - // if (agent === undefined) { - // throw new Error( - // `The routing agent requested an agent that doesn't exist: ${name}`, - // ); - // } + const agent = network.agents.get(name); + if (agent === undefined) { + throw new Error( + `The routing agent requested an agent that doesn't exist: ${name}`, + ); + } // Schedule another agent. network.schedule(agent.name); From 65c86db371fafe9ea481a4555f02cdd7aec0c0db Mon Sep 17 00:00:00 2001 From: Charly POLY Date: Thu, 5 Dec 2024 17:23:52 +0100 Subject: [PATCH 08/15] feat(demo): restore demo, working demo --- demo/inngest.ts | 63 ++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/demo/inngest.ts b/demo/inngest.ts index 2e4f604..8cd2373 100644 --- a/demo/inngest.ts +++ b/demo/inngest.ts @@ -25,44 +25,43 @@ export const fn = inngest.createFunction( { id: "agent" }, { event: "agent/run" }, async ({ event, step }) => { - const model = openai({ model: "gpt-4", step }); + const model = openai({ model: "gpt-4", step }) as any; - // 1. Single agents - // + // 1. Single agent + // Run a single agent as a prompt without a network. - const { output, raw } = await codeWritingAgent.run(event.data.input, { + await codeWritingAgent.run(event.data.input, { model, }); - // // 2. A network of agents that works together - - // const network = createNetwork({ - // agents: [ - // codeWritingAgent.withModel(model), - // executingAgent.withModel(model), - // ], - // defaultModel: model, - // maxIter: 4, - // }); - - // // This uses the defaut agentic router to determine which agent to handle first. You can - // // optionally specifiy the agent that should execute first, and provide your own logic for - // // handling logic in between agent calls. - // const result = await network.run(event.data.input, ({ network }) => { - // if (network.state.kv.has("files")) { - // // Okay, we have some files. Did an agent run tests? - // return executingAgent; - // } - - // return defaultRoutingAgent.withModel(model); - // }); - - return output; + // 2. A network of agents that works together + const network = createNetwork({ + agents: [ + codeWritingAgent.withModel(model), + executingAgent.withModel(model), + ], + defaultModel: model, + maxIter: 4, + }); + + // This uses the defaut agentic router to determine which agent to handle first. You can + // optionally specifiy the agent that should execute first, and provide your own logic for + // handling logic in between agent calls. + const result = await network.run(event.data.input, ({ network }) => { + if (network.state.kv.has("files")) { + // Okay, we have some files. Did an agent run tests? + return executingAgent; + } + + return defaultRoutingAgent.withModel(model); + }); + + return result; }, ); const systemPrompt = - "You are an expert TypeScript programmer."; + "You are an expert TypeScript programmer. You can create files with idiomatic TypeScript code, with comments and associated tests."; const codeWritingAgent = createAgent({ name: "Code writer", @@ -100,8 +99,8 @@ const codeWritingAgent = createAgent({ // "- If you would like to write code, add all code within the following tags (replace $filename and $contents appropriately):" + // " $contents"; createTypedTool({ - name: "write_files", - description: "Write code with the given filenames", + name: "create_files", + description: "Create files with the given filenames and contents", parameters: z .object({ files: z.array( @@ -141,7 +140,7 @@ const executingAgent = createAgent({ }, }, - system: `You are an export TypeScript engineer that can execute commands, run tests, debug the output, and make modifications to code. + system: `You are an expert TypeScript engineer that can execute commands, run tests, debug the output, and make modifications to code. Think carefully about the request that the user is asking for. Do not respond with anything else other than the following XML tags: From 8e9ed82b5b9463e0ed8350f27fc42440a1e98891 Mon Sep 17 00:00:00 2001 From: Jack Williams <1736957+jpwilliams@users.noreply.github.com> Date: Fri, 6 Dec 2024 12:17:47 +0000 Subject: [PATCH 09/15] Fix invalid `step` typing being too specific Also fixes this not being compatible with prev/next versions. --- demo/inngest.ts | 2 +- src/models/openai.ts | 10 +++------- src/types.ts | 19 ++++++++++++++++++- src/util.ts | 42 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/demo/inngest.ts b/demo/inngest.ts index 8cd2373..5ed2f76 100644 --- a/demo/inngest.ts +++ b/demo/inngest.ts @@ -25,7 +25,7 @@ export const fn = inngest.createFunction( { id: "agent" }, { event: "agent/run" }, async ({ event, step }) => { - const model = openai({ model: "gpt-4", step }) as any; + const model = openai({ model: "gpt-4", step }); // 1. Single agent diff --git a/src/models/openai.ts b/src/models/openai.ts index 426b1f7..a01c715 100644 --- a/src/models/openai.ts +++ b/src/models/openai.ts @@ -1,11 +1,7 @@ -import { - openai as iopenai, - type GetStepTools, - type Inngest, - type OpenAi, -} from "inngest"; +import { openai as iopenai, type OpenAi } from "inngest"; import { requestParser, responseParser } from "../adapters/openai"; import { AgenticModel } from "../model"; +import { type AnyStepTools } from "../types"; export namespace AgenticOpenAiModel { export interface Options @@ -18,7 +14,7 @@ export namespace AgenticOpenAiModel { /** * The step tools to use internally within this model. */ - step: GetStepTools; + step: AnyStepTools; } } diff --git a/src/types.ts b/src/types.ts index 4d56eec..5a4c74c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -3,7 +3,12 @@ import { type output as ZodOutput } from "zod"; import { type Agent } from "./agent"; import { type Network } from "./network"; import { type InferenceResult, type InternalNetworkMessage } from "./state"; -import { type AnyZodType, type MaybePromise } from "./util"; +import { + type GenericizeFunctionsInObject, + type AnyZodType, + type MaybePromise, + type SimplifyDeep, +} from "./util"; export type Tool = { name: string; @@ -46,3 +51,15 @@ export interface BeforeLifecycleArgs extends BaseLifecycleArgs { system: InternalNetworkMessage[]; history?: InternalNetworkMessage[]; } + +/** + * Represents step tooling from an Inngest client, purposefully genericized to + * allow for more flexible usage. + * + * Prefer use of `GetStepTools` in most cases, especially when you have access + * to a client. + */ +export type AnyStepTools = SimplifyDeep< + GenericizeFunctionsInObject> +> & + Record; diff --git a/src/util.ts b/src/util.ts index e1f9b56..1a6dd35 100644 --- a/src/util.ts +++ b/src/util.ts @@ -26,3 +26,45 @@ export const stringifyError = (e: unknown): string => { return String(e); }; + +/** + * Given an object `T`, return a new object where all keys with function types + * as values are genericized. If the value is an object, recursively apply this + * transformation. + */ +export type GenericizeFunctionsInObject = { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [K in keyof T]: T[K] extends (...args: any[]) => any + ? // eslint-disable-next-line @typescript-eslint/no-explicit-any + (...args: any[]) => any + : // eslint-disable-next-line @typescript-eslint/no-explicit-any + T[K] extends Record + ? // Allow every object to also contain arbitrary additional properties. + GenericizeFunctionsInObject & Record + : T[K]; +}; + +export type Simplify = { [KeyType in keyof T]: T[KeyType] } & {}; + +export type ConditionalSimplifyDeep< + Type, + ExcludeType = never, + IncludeType = unknown, +> = Type extends ExcludeType + ? Type + : Type extends IncludeType + ? { + [TypeKey in keyof Type]: ConditionalSimplifyDeep< + Type[TypeKey], + ExcludeType, + IncludeType + >; + } + : Type; + +export type SimplifyDeep = ConditionalSimplifyDeep< + Type, + // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type + Function | Iterable, + object +>; From abdcc189d97853c1a6b0a5454ecd6fa2443e6e50 Mon Sep 17 00:00:00 2001 From: Jack Williams <1736957+jpwilliams@users.noreply.github.com> Date: Fri, 6 Dec 2024 13:38:32 +0000 Subject: [PATCH 10/15] Use `AiAdapter.Any` for easier subtype checking --- src/model.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/model.ts b/src/model.ts index 6981edb..dd5198b 100644 --- a/src/model.ts +++ b/src/model.ts @@ -2,7 +2,7 @@ import { type AiAdapter, type GetStepTools, type Inngest } from "inngest"; import { type InternalNetworkMessage } from "./state"; import { type Tool } from "./types"; -export class AgenticModel { +export class AgenticModel { #model: TAiAdapter; step: GetStepTools; @@ -36,7 +36,7 @@ export class AgenticModel { } export namespace AgenticModel { - export type Any = AgenticModel; + export type Any = AgenticModel; /** * InferenceResponse is the response from a model for an inference request. @@ -48,20 +48,20 @@ export namespace AgenticModel { raw: T; }; - export interface Constructor { + export interface Constructor { model: TAiAdapter; step: GetStepTools; requestParser: RequestParser; responseParser: ResponseParser; } - export type RequestParser = ( + export type RequestParser = ( model: TAiAdapter, state: InternalNetworkMessage[], tools: Tool.Any[], ) => AiAdapter.Input; - export type ResponseParser = ( + export type ResponseParser = ( output: AiAdapter.Output, ) => InternalNetworkMessage[]; } From 81c01bd0db757837106b8d12d4501c9fedab9b9b Mon Sep 17 00:00:00 2001 From: Jack Williams <1736957+jpwilliams@users.noreply.github.com> Date: Fri, 6 Dec 2024 14:42:15 +0000 Subject: [PATCH 11/15] Shift back to stable `inngest` version --- demo/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/package.json b/demo/package.json index 6235009..62e5aa7 100644 --- a/demo/package.json +++ b/demo/package.json @@ -11,7 +11,7 @@ "dependencies": { "@inngest/agent-kit": "~0.0.1", "express": "^4.21.1", - "inngest": "^3.26.2" + "inngest": "^3.27.3" }, "devDependencies": { "@types/express": "^5.0.0", From 5ca44f079a071d2fe8d6d1639b98d72d933c9cb6 Mon Sep 17 00:00:00 2001 From: Tony Holdstock-Brown Date: Fri, 6 Dec 2024 12:15:13 -0800 Subject: [PATCH 12/15] Update agent, state, and tool types --- demo/inngest.ts | 4 +-- src/agent.ts | 70 +++++++++++++++++++++++++++---------------------- src/network.ts | 4 +-- src/state.ts | 43 +++++++++++++++++++----------- src/types.ts | 8 +++++- 5 files changed, 76 insertions(+), 53 deletions(-) diff --git a/demo/inngest.ts b/demo/inngest.ts index 5ed2f76..7e5940e 100644 --- a/demo/inngest.ts +++ b/demo/inngest.ts @@ -3,7 +3,7 @@ import { anthropic, createAgent, createNetwork, - createTypedTool, + createTool, defaultRoutingAgent, openai, } from "../src/index"; @@ -98,7 +98,7 @@ const codeWritingAgent = createAgent({ // "Do not respond with anything else other than the following XML tags:" + // "- If you would like to write code, add all code within the following tags (replace $filename and $contents appropriately):" + // " $contents"; - createTypedTool({ + createTool({ name: "create_files", description: "Create files with the given filenames and contents", parameters: z diff --git a/src/agent.ts b/src/agent.ts index d06135d..3769222 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -13,7 +13,7 @@ import { type AnyZodType, type MaybePromise } from "./util"; * createTool is a helper that properly types the input argument for a handler * based off of the Zod parameter types. */ -export const createTypedTool = (t: Tool): Tool => t; +export const createTool = (t: Tool): Tool => t; /** * Agent represents a single agent, responsible for a set of tasks. @@ -86,47 +86,51 @@ export class Agent { */ async run( input: string, - { - model, - network, - maxIter = this.tools.size + 1, - }: Agent.RunOptions | undefined = {}, + { model, network, maxIter = 0 }: Agent.RunOptions | undefined = {}, ): Promise { const p = model || this.model || network?.defaultModel; if (!p) { throw new Error("No step caller provided to agent"); } - let history = network ? network.state.history : []; - let system = await this.agentPrompt(input, network); - let result: InferenceResult; - - if (this.lifecycles?.onStart) { - const modified = await this.lifecycles.onStart({ - agent: this, - network, - input, - system, - history, - }); - system = modified.system; - history = modified.history; - } - + let history = network ? network.state.format() : []; + let prompt = await this.agentPrompt(input, network); + let result = new InferenceResult(this, input, prompt, history, [], [], ""); let hasMoreActions = true; let iter = 0; + do { + // Call lifecycles each time we perform inference. + if (this.lifecycles?.onStart) { + const modified = await this.lifecycles.onStart({ + agent: this, + network, + input, + prompt, + history, + }); + + if (modified.stop) { + // We allow users to prevent calling the LLM directly here. + return result; + } + + prompt = modified.prompt; + history = modified.history; + } + const inference = await this.performInference( input, p, + prompt, history, - system, network, ); hasMoreActions = this.tools.size > 0 && inference.output[inference.output.length - 1]!.stop_reason !== "stop"; + result = inference; history = [...inference.output]; iter++; @@ -142,13 +146,13 @@ export class Agent { private async performInference( input: string, p: AgenticModel.Any, + prompt: InternalNetworkMessage[], history: InternalNetworkMessage[], - system: InternalNetworkMessage[], network?: Network, ): Promise { const { output, raw } = await p.infer( this.name, - system.concat(history), + prompt.concat(history), Array.from(this.tools.values()), ); @@ -157,8 +161,8 @@ export class Agent { let result = new InferenceResult( this, input, - system, - system.concat(history), + prompt, + history, output, [], typeof raw === "string" ? raw : JSON.stringify(raw), @@ -173,9 +177,8 @@ export class Agent { // And ensure we invoke any call from the agent const toolCallOutput = await this.invokeTools(result.output, p, network); - // if a tool was called, we add it to the history/messages if (toolCallOutput.length > 0) { - result.output = result.output.concat(toolCallOutput); + result.toolCalls = result.toolCalls.concat(toolCallOutput); } return result; @@ -203,8 +206,9 @@ export class Agent { // Call this tool. // - // TODO: This should be wrapped in a step, but then `network.schedule` - // breaks, as `step.run` memoizes so agents aren't scheduled on their + // XXX: You might expect this to be wrapped in a step, but each tool can + // com + // `network.schedule` breaks, as `step.run` memoizes so agents aren't scheduled on their // next loop. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const result = await found.handler(tool.input, { @@ -299,8 +303,10 @@ export namespace Agent { * */ onStart?: (args: BeforeLifecycleArgs) => MaybePromise<{ - system: InternalNetworkMessage[]; + prompt: InternalNetworkMessage[]; history: InternalNetworkMessage[]; + // stop, if true, will prevent calling the agent + stop: boolean; }>; /** diff --git a/src/network.ts b/src/network.ts index e7d2661..1c13afb 100644 --- a/src/network.ts +++ b/src/network.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { Agent, createTypedTool } from "./agent"; +import { Agent, createTool } from "./agent"; import { type AgenticModel } from "./model"; import { type InferenceResult, State } from "./state"; import { type MaybePromise } from "./util"; @@ -224,7 +224,7 @@ export const defaultRoutingAgent = new Agent({ tools: [ // This tool does nothing but ensure that the model responds with the // agent name as valid JSON. - createTypedTool({ + createTool({ name: "select_agent", description: "select an agent to handle the input, based off of the current conversation", diff --git a/src/state.ts b/src/state.ts index e1c1327..d0ab2bd 100644 --- a/src/state.ts +++ b/src/state.ts @@ -73,7 +73,7 @@ export class State { } /** - * Results retursn a new array containing all past inference results in the + * Results returns a new array containing all past inference results in the * network. This array is safe to modify. */ get results() { @@ -81,12 +81,15 @@ export class State { } /** - * history returns the memory used for agentic calls based off of prior + * format returns the memory used for agentic calls based off of prior * agentic calls. * + * This is used to format the current State as a conversation log when + * calling an individual agent. + * */ - get history(): InternalNetworkMessage[] { - return this._history.map((call) => call.history()).flat(); + format(): InternalNetworkMessage[] { + return this._history.map((call) => call.format()).flat(); } append(call: InferenceResult) { @@ -96,7 +99,7 @@ export class State { /** * InferenceResult represents a single agentic call as part of the network - * state. + * state. This stores every input and ouput for a call. * */ export class InferenceResult { @@ -117,15 +120,17 @@ export class InferenceResult { // input represents the input passed into the agent's run method. public input: string, - // system represents the input instructions - without any additional history - // - as created by the agent. - public system: InternalNetworkMessage[], - - // prompt represents the entire prompt sent to the inference call. This - // includes instructions and history from the current network state. + // prompt represents the input instructions - without any additional history + // - as created by the agent. This includes the system prompt, the user input, + // and any initial agent assistant message. public prompt: InternalNetworkMessage[], - // output represents the parsed output. + // history represents the history sent to the inference call, appended to the + // prompt to form a complete conversation log + public history: InternalNetworkMessage[], + + // output represents the parsed output from the inference call. This may be blank + // if the agent responds with tool calls only. public output: InternalNetworkMessage[], // toolCalls represents output from any tools called by the agent. @@ -140,23 +145,29 @@ export class InferenceResult { this._historyFormatter = f; } - history(): InternalNetworkMessage[] { + // format + format(): InternalNetworkMessage[] { if (this._historyFormatter) { return this._historyFormatter(this); } + if (this.raw === "") { + // There is no call to the agent, so ignore this. + return []; + } + // Return the default format, which turns all system prompts into assistant // prompts. const agent = this.agent; - const history: InternalNetworkMessage[] = this.system.map(function (msg) { + const messages: InternalNetworkMessage[] = this.prompt.map(function (msg) { let content: string; if (typeof msg.content === "string") { content = msg.content; } else if (Array.isArray(msg.content)) { content = msg.content.map((m) => m.text).join("\n"); } else { - // TODO `anyany` + // XXX: Type checking here. content = msg.content.content as string; } @@ -168,6 +179,6 @@ export class InferenceResult { }; }); - return history.concat(this.output).concat(this.toolCalls); + return messages.concat(this.output).concat(this.toolCalls); } } diff --git a/src/types.ts b/src/types.ts index 5a4c74c..4b310e5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -48,7 +48,13 @@ export interface ResultLifecycleArgs extends BaseLifecycleArgs { export interface BeforeLifecycleArgs extends BaseLifecycleArgs { // input is the user request for the entire agentic operation. input?: string; - system: InternalNetworkMessage[]; + + // prompt is the system, user, and any assistant prompt as generated + // by the Agent. This does not include any past history. + prompt: InternalNetworkMessage[]; + + // history is the past history as generated via State. Ths will be added + // after the prompt to form a single conversation log. history?: InternalNetworkMessage[]; } From 030127064a4e47e1a6d8843f74f417b3fdfc89d1 Mon Sep 17 00:00:00 2001 From: Tony Holdstock-Brown Date: Fri, 6 Dec 2024 12:25:21 -0800 Subject: [PATCH 13/15] Allow passing state into `agent.run()` and `new Network()` --- src/agent.ts | 24 +++++++++++++++++++++--- src/network.ts | 12 ++++++++++-- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/agent.ts b/src/agent.ts index 3769222..486ffce 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -1,6 +1,10 @@ import { type AgenticModel } from "./model"; import { type Network } from "./network"; -import { InferenceResult, type InternalNetworkMessage } from "./state"; +import { + type State, + InferenceResult, + type InternalNetworkMessage, +} from "./state"; import { type BaseLifecycleArgs, type BeforeLifecycleArgs, @@ -86,14 +90,22 @@ export class Agent { */ async run( input: string, - { model, network, maxIter = 0 }: Agent.RunOptions | undefined = {}, + { + model, + network, + state: inputState, + maxIter = 0, + }: Agent.RunOptions | undefined = {}, ): Promise { const p = model || this.model || network?.defaultModel; if (!p) { throw new Error("No step caller provided to agent"); } - let history = network ? network.state.format() : []; + // input state always overrides the network state. + const state = inputState || network?.state; + + let history = state ? state.format() : []; let prompt = await this.agentPrompt(input, network); let result = new InferenceResult(this, input, prompt, history, [], [], ""); let hasMoreActions = true; @@ -282,6 +294,12 @@ export namespace Agent { export interface RunOptions { model?: AgenticModel.Any; network?: Network; + /** + * State allows you to pass custom state into a single agent run call. This should only + * be provided if you are running agents outside of a network. Networks automatically + * supply their own state. + */ + state?: State; maxIter?: number; } diff --git a/src/network.ts b/src/network.ts index 1c13afb..19e1e46 100644 --- a/src/network.ts +++ b/src/network.ts @@ -47,10 +47,15 @@ export class Network { // agents referenced in the router here. private _agents: Map; - constructor({ agents, defaultModel, maxIter }: Network.Constructor) { + constructor({ + agents, + defaultModel, + maxIter, + state = new State(), + }: Network.Constructor) { this.agents = new Map(); this._agents = new Map(); - this.state = new State(); + this.state = state; this.defaultModel = defaultModel; this.maxIter = maxIter || 0; this._stack = []; @@ -304,6 +309,9 @@ export namespace Network { agents: Agent[]; defaultModel?: AgenticModel.Any; maxIter?: number; + // state is any pre-existing network state to use in this Network instance. By + // default, new state is created without any history for every Network. + state?: State; }; /** From b5de2cfb2f1bac849f270beccdb56ce9f1d34e28 Mon Sep 17 00:00:00 2001 From: Tony Holdstock-Brown Date: Fri, 6 Dec 2024 12:27:25 -0800 Subject: [PATCH 14/15] comments --- src/agent.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/agent.ts b/src/agent.ts index 486ffce..f82011d 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -219,9 +219,9 @@ export class Agent { // Call this tool. // // XXX: You might expect this to be wrapped in a step, but each tool can - // com - // `network.schedule` breaks, as `step.run` memoizes so agents aren't scheduled on their - // next loop. + // use multiple step tools, eg. `step.run`, then `step.waitForEvent` for + // human in the loop tasks. + // // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const result = await found.handler(tool.input, { agent: this, From 1914a3af1e7b3a163398d7a30843d2322b30d995 Mon Sep 17 00:00:00 2001 From: Tony Holdstock-Brown Date: Fri, 6 Dec 2024 12:29:59 -0800 Subject: [PATCH 15/15] Comments --- src/agent.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/agent.ts b/src/agent.ts index f82011d..b984386 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -311,14 +311,15 @@ export namespace Agent { enabled?: (args: BaseLifecycleArgs) => MaybePromise; /** - * onStart allows you to intercept and modify the input prompt for a given - * agent, or prevent the agent from being called altogether by throwing an - * error. + * onStart is called just before an agent starts an inference call. * * This receives the full agent prompt. If this is a networked agent, the * agent will also receive the network's history which will be concatenated * to the end of the prompt when making the inference request. * + * The return values can be used to adjust the prompt, history, or to stop + * the agent from making the call altogether. + * */ onStart?: (args: BeforeLifecycleArgs) => MaybePromise<{ prompt: InternalNetworkMessage[];