From d384c1d79b235aeed6d06f13542535ca9fad6521 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Tue, 20 Jan 2026 00:39:36 +0000 Subject: [PATCH] feat(tests): integrate smartagent DualAgentOrchestrator with streaming support - Update test.invoices.nanonets.ts to use DualAgentOrchestrator for JSON extraction - Enable streaming token callback for real-time progress visibility - Add markdown caching to avoid re-running Nanonets OCR for cached files - Update test.bankstatements.minicpm.ts and test.invoices.minicpm.ts with streaming - Update dependencies to @push.rocks/smartai@0.11.1 and @push.rocks/smartagent@1.2.8 --- package.json | 4 +- pnpm-lock.yaml | 1134 +++++++++++++++++++++++++++ test/test.bankstatements.minicpm.ts | 144 ++-- test/test.invoices.minicpm.ts | 99 ++- test/test.invoices.nanonets.ts | 228 +++--- 5 files changed, 1405 insertions(+), 204 deletions(-) diff --git a/package.json b/package.json index 6eaf030..f27cdc1 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ }, "devDependencies": { "@git.zone/tsrun": "^2.0.1", - "@git.zone/tstest": "^3.1.5" + "@git.zone/tstest": "^3.1.5", + "@push.rocks/smartagent": "^1.2.8", + "@push.rocks/smartai": "^0.11.1" }, "repository": { "type": "git", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 19561b7..a3d55e7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,9 +18,24 @@ importers: '@git.zone/tstest': specifier: ^3.1.5 version: 3.1.5(socks@2.8.7)(typescript@5.9.3) + '@push.rocks/smartagent': + specifier: ^1.2.8 + version: 1.2.8(typescript@5.9.3)(ws@8.19.0)(zod@3.25.76) + '@push.rocks/smartai': + specifier: ^0.11.1 + version: 0.11.1(typescript@5.9.3)(ws@8.19.0)(zod@3.25.76) packages: + '@anthropic-ai/sdk@0.71.2': + resolution: {integrity: sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ==} + hasBin: true + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + '@api.global/typedrequest-interfaces@2.0.2': resolution: {integrity: sha512-D+mkr4IiUZ/eUgrdp5jXjBKOW/iuMcl0z2ZLQsLLypKX/psFGD3viZJ58FNRa+/1OSM38JS5wFyoWl8oPEFLrw==} @@ -415,6 +430,143 @@ packages: resolution: {integrity: sha512-mfOoUlIw8VBiJYPrl5RZfMzkXC/z7gbSpi2ecycrj/gRWLq2CMV+Q+0G+JPjeOmuNFgg0skEIzkVFzVYFP6URw==} engines: {node: '>=18.0.0'} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + '@inquirer/checkbox@3.0.1': resolution: {integrity: sha512-0hm2nrToWUdD6/UHnel/UKGdk1//ke5zGUpHIvk5ZWmaKezlGxZkOJXNSWsdxO/rEqTkbB3lNC2J6nBElV2aAQ==} engines: {node: '>=18'} @@ -483,6 +635,118 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@jimp/core@1.6.0': + resolution: {integrity: sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w==} + engines: {node: '>=18'} + + '@jimp/diff@1.6.0': + resolution: {integrity: sha512-+yUAQ5gvRC5D1WHYxjBHZI7JBRusGGSLf8AmPRPCenTzh4PA+wZ1xv2+cYqQwTfQHU5tXYOhA0xDytfHUf1Zyw==} + engines: {node: '>=18'} + + '@jimp/file-ops@1.6.0': + resolution: {integrity: sha512-Dx/bVDmgnRe1AlniRpCKrGRm5YvGmUwbDzt+MAkgmLGf+jvBT75hmMEZ003n9HQI/aPnm/YKnXjg/hOpzNCpHQ==} + engines: {node: '>=18'} + + '@jimp/js-bmp@1.6.0': + resolution: {integrity: sha512-FU6Q5PC/e3yzLyBDXupR3SnL3htU7S3KEs4e6rjDP6gNEOXRFsWs6YD3hXuXd50jd8ummy+q2WSwuGkr8wi+Gw==} + engines: {node: '>=18'} + + '@jimp/js-gif@1.6.0': + resolution: {integrity: sha512-N9CZPHOrJTsAUoWkWZstLPpwT5AwJ0wge+47+ix3++SdSL/H2QzyMqxbcDYNFe4MoI5MIhATfb0/dl/wmX221g==} + engines: {node: '>=18'} + + '@jimp/js-jpeg@1.6.0': + resolution: {integrity: sha512-6vgFDqeusblf5Pok6B2DUiMXplH8RhIKAryj1yn+007SIAQ0khM1Uptxmpku/0MfbClx2r7pnJv9gWpAEJdMVA==} + engines: {node: '>=18'} + + '@jimp/js-png@1.6.0': + resolution: {integrity: sha512-AbQHScy3hDDgMRNfG0tPjL88AV6qKAILGReIa3ATpW5QFjBKpisvUaOqhzJ7Reic1oawx3Riyv152gaPfqsBVg==} + engines: {node: '>=18'} + + '@jimp/js-tiff@1.6.0': + resolution: {integrity: sha512-zhReR8/7KO+adijj3h0ZQUOiun3mXUv79zYEAKvE0O+rP7EhgtKvWJOZfRzdZSNv0Pu1rKtgM72qgtwe2tFvyw==} + engines: {node: '>=18'} + + '@jimp/plugin-blit@1.6.0': + resolution: {integrity: sha512-M+uRWl1csi7qilnSK8uxK4RJMSuVeBiO1AY0+7APnfUbQNZm6hCe0CCFv1Iyw1D/Dhb8ph8fQgm5mwM0eSxgVA==} + engines: {node: '>=18'} + + '@jimp/plugin-blur@1.6.0': + resolution: {integrity: sha512-zrM7iic1OTwUCb0g/rN5y+UnmdEsT3IfuCXCJJNs8SZzP0MkZ1eTvuwK9ZidCuMo4+J3xkzCidRwYXB5CyGZTw==} + engines: {node: '>=18'} + + '@jimp/plugin-circle@1.6.0': + resolution: {integrity: sha512-xt1Gp+LtdMKAXfDp3HNaG30SPZW6AQ7dtAtTnoRKorRi+5yCJjKqXRgkewS5bvj8DEh87Ko1ydJfzqS3P2tdWw==} + engines: {node: '>=18'} + + '@jimp/plugin-color@1.6.0': + resolution: {integrity: sha512-J5q8IVCpkBsxIXM+45XOXTrsyfblyMZg3a9eAo0P7VPH4+CrvyNQwaYatbAIamSIN1YzxmO3DkIZXzRjFSz1SA==} + engines: {node: '>=18'} + + '@jimp/plugin-contain@1.6.0': + resolution: {integrity: sha512-oN/n+Vdq/Qg9bB4yOBOxtY9IPAtEfES8J1n9Ddx+XhGBYT1/QTU/JYkGaAkIGoPnyYvmLEDqMz2SGihqlpqfzQ==} + engines: {node: '>=18'} + + '@jimp/plugin-cover@1.6.0': + resolution: {integrity: sha512-Iow0h6yqSC269YUJ8HC3Q/MpCi2V55sMlbkkTTx4zPvd8mWZlC0ykrNDeAy9IJegrQ7v5E99rJwmQu25lygKLA==} + engines: {node: '>=18'} + + '@jimp/plugin-crop@1.6.0': + resolution: {integrity: sha512-KqZkEhvs+21USdySCUDI+GFa393eDIzbi1smBqkUPTE+pRwSWMAf01D5OC3ZWB+xZsNla93BDS9iCkLHA8wang==} + engines: {node: '>=18'} + + '@jimp/plugin-displace@1.6.0': + resolution: {integrity: sha512-4Y10X9qwr5F+Bo5ME356XSACEF55485j5nGdiyJ9hYzjQP9nGgxNJaZ4SAOqpd+k5sFaIeD7SQ0Occ26uIng5Q==} + engines: {node: '>=18'} + + '@jimp/plugin-dither@1.6.0': + resolution: {integrity: sha512-600d1RxY0pKwgyU0tgMahLNKsqEcxGdbgXadCiVCoGd6V6glyCvkNrnnwC0n5aJ56Htkj88PToSdF88tNVZEEQ==} + engines: {node: '>=18'} + + '@jimp/plugin-fisheye@1.6.0': + resolution: {integrity: sha512-E5QHKWSCBFtpgZarlmN3Q6+rTQxjirFqo44ohoTjzYVrDI6B6beXNnPIThJgPr0Y9GwfzgyarKvQuQuqCnnfbA==} + engines: {node: '>=18'} + + '@jimp/plugin-flip@1.6.0': + resolution: {integrity: sha512-/+rJVDuBIVOgwoyVkBjUFHtP+wmW0r+r5OQ2GpatQofToPVbJw1DdYWXlwviSx7hvixTWLKVgRWQ5Dw862emDg==} + engines: {node: '>=18'} + + '@jimp/plugin-hash@1.6.0': + resolution: {integrity: sha512-wWzl0kTpDJgYVbZdajTf+4NBSKvmI3bRI8q6EH9CVeIHps9VWVsUvEyb7rpbcwVLWYuzDtP2R0lTT6WeBNQH9Q==} + engines: {node: '>=18'} + + '@jimp/plugin-mask@1.6.0': + resolution: {integrity: sha512-Cwy7ExSJMZszvkad8NV8o/Z92X2kFUFM8mcDAhNVxU0Q6tA0op2UKRJY51eoK8r6eds/qak3FQkXakvNabdLnA==} + engines: {node: '>=18'} + + '@jimp/plugin-print@1.6.0': + resolution: {integrity: sha512-zarTIJi8fjoGMSI/M3Xh5yY9T65p03XJmPsuNet19K/Q7mwRU6EV2pfj+28++2PV2NJ+htDF5uecAlnGyxFN2A==} + engines: {node: '>=18'} + + '@jimp/plugin-quantize@1.6.0': + resolution: {integrity: sha512-EmzZ/s9StYQwbpG6rUGBCisc3f64JIhSH+ncTJd+iFGtGo0YvSeMdAd+zqgiHpfZoOL54dNavZNjF4otK+mvlg==} + engines: {node: '>=18'} + + '@jimp/plugin-resize@1.6.0': + resolution: {integrity: sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA==} + engines: {node: '>=18'} + + '@jimp/plugin-rotate@1.6.0': + resolution: {integrity: sha512-JagdjBLnUZGSG4xjCLkIpQOZZ3Mjbg8aGCCi4G69qR+OjNpOeGI7N2EQlfK/WE8BEHOW5vdjSyglNqcYbQBWRw==} + engines: {node: '>=18'} + + '@jimp/plugin-threshold@1.6.0': + resolution: {integrity: sha512-M59m5dzLoHOVWdM41O8z9SyySzcDn43xHseOH0HavjsfQsT56GGCC4QzU1banJidbUrePhzoEdS42uFE8Fei8w==} + engines: {node: '>=18'} + + '@jimp/types@1.6.0': + resolution: {integrity: sha512-7UfRsiKo5GZTAATxm2qQ7jqmUXP0DxTArztllTcYdyw6Xi5oT4RaoXynVtCD4UyLK5gJgkZJcwonoijrhYFKfg==} + engines: {node: '>=18'} + + '@jimp/utils@1.6.0': + resolution: {integrity: sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA==} + engines: {node: '>=18'} + '@leichtgewicht/ip-codec@2.0.5': resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==} @@ -492,6 +756,9 @@ packages: '@lit/reactive-element@2.1.2': resolution: {integrity: sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==} + '@mistralai/mistralai@1.12.0': + resolution: {integrity: sha512-oDr1hcS3wsIT/QupBG93TNiA5kilwBYoAIyl5BNYqMM2Ix/xsNq+wT8b++uhp/GTUMx44n+8Bn1mkATbwxe6bQ==} + '@mixmark-io/domino@2.2.0': resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} @@ -582,6 +849,9 @@ packages: '@push.rocks/isounique@1.0.5': resolution: {integrity: sha512-Z0BVqZZOCif1THTbIKWMgg0wxCzt9CyBtBBqQJiZ+jJ0KlQFrQHNHrPt81/LXe/L4x0cxWsn0bpL6W5DNSvNLw==} + '@push.rocks/levelcache@3.2.0': + resolution: {integrity: sha512-Ch0Oguta2I0SVi704kHghhBcgfyfS92ua1elRu9d8X1/9LMRYuqvvBAnyXyFxQzI3S8q8QC6EkRdd8CAAYSzRg==} + '@push.rocks/lik@6.2.2': resolution: {integrity: sha512-j64FFPPyMXeeUorjKJVF6PWaJUfiIrF3pc41iJH4lOh0UUpBAHpcNzHVxTR58orwbVA/h3Hz+DQd4b1Rq0dFDQ==} @@ -594,9 +864,24 @@ packages: '@push.rocks/qenv@6.1.3': resolution: {integrity: sha512-+z2hsAU/7CIgpYLFqvda8cn9rUBMHqLdQLjsFfRn5jPoD7dJ5rFlpkbhfM4Ws8mHMniwWaxGKo+q/YBhtzRBLg==} + '@push.rocks/smartagent@1.2.8': + resolution: {integrity: sha512-mnvZNmdS7Kg7uUJVDlVlfWls7KjWT/lXd76HP805ih3OIjujpIgYBjepZlZ1jp+xoAVGA80vBDtbWoxE6IZKiw==} + + '@push.rocks/smartai@0.11.1': + resolution: {integrity: sha512-GPOfy4h0ItHfQabfpmzmZYiSYAtXHpGdY6IJkjyW+IN10sgMQEbCpr/2u7MkgEDJHJYQZ49BWZH7/7GdtSxwrg==} + + '@push.rocks/smartarchive@5.2.1': + resolution: {integrity: sha512-TNv5q6QuBRX7jrzffiyb6A8AALNAr0kyAcJswa0l3ahBP1Q6zszNo9xOVXmW2gKX2KShtO/Y+Cn0i46n8lbnaQ==} + + '@push.rocks/smartarray@1.1.0': + resolution: {integrity: sha512-b5YgBmUdglOJH8zeUf2ZWdPCoqySgwvkycRi2BhA9zVZHkpASh39Ej0q0fxFJetlUVyYqGfVoMVjbVrLFfFV7g==} + '@push.rocks/smartbrowser@2.0.8': resolution: {integrity: sha512-0KWRZj3TuKo/sNwgPbiSE6WL+TMeR19t1JmXBZWh9n8iA2mpc4HhMrQAndEUdRCkx5ofSaHWojIRVFzGChj0Dg==} + '@push.rocks/smartbucket@3.3.10': + resolution: {integrity: sha512-0H2MioALspC8Aj0Q1FPCs2w4k2u9oJg7Q5yM8+1TZo7aRfrdxgM5HQ7z3apUaqC3ZEDewW6vSlttjHFHhMEC3A==} + '@push.rocks/smartbucket@4.3.0': resolution: {integrity: sha512-4nstzEduCKou4R5ekKH6kUjDZXWfrtjA1hIQ4MJmTbtncmm2+4+ixjaFThS2nS8Aa+fHcBgOtKkBv8wTsgvK/Q==} @@ -625,6 +910,9 @@ packages: '@push.rocks/smartdelay@3.0.5': resolution: {integrity: sha512-mUuI7kj2f7ztjpic96FvRIlf2RsKBa5arw81AHNsndbxO6asRcxuWL8dTVxouEIK8YsBUlj0AsrCkHhMbLQdHw==} + '@push.rocks/smartdeno@1.2.0': + resolution: {integrity: sha512-6S1plCaMUVOZiRSflfoz9Fqk9phACCuKmc7Z6SfTvfl+p9VcPUmewKgaa/0QiLOpiI6ksfxdfmkS5Rw5HpYeIA==} + '@push.rocks/smartdns@7.6.1': resolution: {integrity: sha512-nnP5+A2GOt0WsHrYhtKERmjdEHUchc+QbCCBEqlyeQTn+mNfx2WZvKVI1DFRJt8lamvzxP6Hr/BSe3WHdh4Snw==} @@ -667,6 +955,9 @@ packages: '@push.rocks/smartinteract@2.0.16': resolution: {integrity: sha512-eltvVRRUKBKd77DSFA4DPY2g4V4teZLNe8A93CDy/WglglYcUjxMoLY/b0DFTWCWKYT+yjk6Fe6p0FRrvX9Yvg==} + '@push.rocks/smartjimp@1.2.0': + resolution: {integrity: sha512-SPz8p2ZuphNqIXK/UDsNFrnpJn/jr6FbuBSMQc0V2v2ffQIF32ZqktKQpXpitiqD1K5JEYS56JAhlYHgrAu7yw==} + '@push.rocks/smartjson@5.2.0': resolution: {integrity: sha512-710e8UwovRfPgUtaBHcd6unaODUjV5fjxtGcGCqtaTcmvOV6VpasdVfT66xMDzQmWH2E9ZfHDJeso9HdDQzNQA==} @@ -718,6 +1009,9 @@ packages: '@push.rocks/smartpdf@3.3.0': resolution: {integrity: sha512-k4mBZAIl/TVBHDYQXaBZAgC8DdmHXsIZ3hRrLY3ysLr143YJ1VkwqQ2poqWh3A2SZQDrVfpKRYliUtjFRFrYVw==} + '@push.rocks/smartpdf@4.1.1': + resolution: {integrity: sha512-pC5gBDk4nk+xhRltS0ByTTSnVrwHjrrVfyrAgHYyiPKPZmYH5+Q4fZ+qzBrc6lEZSuCP8TEAeZcsGoOd3hAwvw==} + '@push.rocks/smartping@1.0.8': resolution: {integrity: sha512-Fvx1Db6hSsDOI6pdiCuS9GjtOX8ugx865YQrPg5vK2iw6Qj/srwyXcWLFYt+19WVKtvtWDJIAKbW+q3bXFsCeA==} @@ -1223,6 +1517,10 @@ packages: vue: optional: true + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} + engines: {node: '>=18'} + '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} @@ -1310,6 +1608,9 @@ packages: '@types/node-forge@1.3.14': resolution: {integrity: sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==} + '@types/node@16.9.1': + resolution: {integrity: sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==} + '@types/node@22.19.7': resolution: {integrity: sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==} @@ -1379,6 +1680,10 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -1423,6 +1728,9 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + any-base@1.1.0: + resolution: {integrity: sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==} + argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -1443,6 +1751,10 @@ packages: asynckit@0.4.0: resolution: {integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k=} + await-to-js@3.0.0: + resolution: {integrity: sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==} + engines: {node: '>=6.0.0'} + axios@1.13.2: resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} @@ -1509,6 +1821,9 @@ packages: resolution: {integrity: sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==} engines: {node: '>=10.0.0'} + bmp-ts@1.0.9: + resolution: {integrity: sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw==} + bn.js@4.12.2: resolution: {integrity: sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==} @@ -1734,6 +2049,10 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -1850,12 +2169,23 @@ packages: resolution: {integrity: sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=} engines: {node: '>= 0.6'} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} events-universal@1.0.1: resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + exif-parser@0.1.12: + resolution: {integrity: sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==} + express-force-ssl@0.3.2: resolution: {integrity: sha1-AbK0mK5v0uQRUrIrV6Phc3c69n4=} engines: {node: '>=0.2.2'} @@ -1911,14 +2241,25 @@ packages: fd-slicer@1.1.0: resolution: {integrity: sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=} + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + figures@6.1.0: resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} engines: {node: '>=18'} + file-type@16.5.4: + resolution: {integrity: sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==} + engines: {node: '>=10'} + file-type@19.6.0: resolution: {integrity: sha512-VZR5I7k5wkD0HgFnMsq5hOsSc710MJMu5Nc5QYsbe38NN5iPV/XTObYLc/cpttRTf6lX538+5uO1ZQRhYibiZQ==} engines: {node: '>=18'} + file-type@21.3.0: + resolution: {integrity: sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==} + engines: {node: '>=20'} + finalhandler@2.1.1: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} @@ -2006,6 +2347,9 @@ packages: resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} engines: {node: '>= 14'} + gifwrap@0.10.1: + resolution: {integrity: sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw==} + glob@11.1.0: resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} engines: {node: 20 || >=22} @@ -2093,6 +2437,9 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + image-q@4.0.0: + resolution: {integrity: sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -2176,6 +2523,13 @@ packages: resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} engines: {node: 20 || >=22} + jimp@1.6.0: + resolution: {integrity: sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg==} + engines: {node: '>=18'} + + jpeg-js@0.4.4: + resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==} + js-base64@3.7.8: resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} @@ -2193,6 +2547,10 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} @@ -2443,6 +2801,11 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} + mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + mime@4.1.0: resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==} engines: {node: '>=16'} @@ -2472,6 +2835,10 @@ packages: mitt@3.0.1: resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + modern-tar@0.7.3: + resolution: {integrity: sha512-4W79zekKGyYU4JXVmB78DOscMFaJth2gGhgfTl2alWE4rNe3nf4N2pqenQ0rEtIewrnD79M687Ouba3YGTLOvg==} + engines: {node: '>=18.0.0'} + mongodb-connection-string-url@3.0.2: resolution: {integrity: sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==} @@ -2568,6 +2935,9 @@ packages: observable-fns@0.6.1: resolution: {integrity: sha512-9gRK4+sRWzeN6AOewNBTLXir7Zl/i3GB6Yl26gK4flxz8BXVpD3kt8amREmWNb0mxYOGDotvE5a4N+PtGGKdkg==} + omggif@1.0.10: + resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -2579,6 +2949,18 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} + openai@6.16.0: + resolution: {integrity: sha512-fZ1uBqjFUjXzbGc35fFtYKEOxd20kd9fDpFeqWtsOZWiubY8CZ1NAlXHW3iathaFvqmNtCWMIsosCuyeI7Joxg==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + os-tmpdir@1.0.2: resolution: {integrity: sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=} engines: {node: '>=0.10.0'} @@ -2628,6 +3010,15 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-bmfont-ascii@1.0.6: + resolution: {integrity: sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==} + + parse-bmfont-binary@1.0.6: + resolution: {integrity: sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==} + + parse-bmfont-xml@1.1.6: + resolution: {integrity: sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==} + parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -2668,6 +3059,10 @@ packages: hasBin: true bundledDependencies: [] + peek-readable@4.1.0: + resolution: {integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==} + engines: {node: '>=8'} + peek-readable@5.4.2: resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} engines: {node: '>=14.16'} @@ -2686,14 +3081,30 @@ packages: resolution: {integrity: sha512-56ZMC0j7SCsMMLdOoUg12VZCfj/+ZO+yfOSjaNCRrmZZr6GLbN2X/Ui56T15dI8NhiHckaw5X2pvyfAomanwqQ==} engines: {node: '>=4.0.0'} + pixelmatch@5.3.0: + resolution: {integrity: sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==} + hasBin: true + pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pngjs@6.0.0: + resolution: {integrity: sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==} + engines: {node: '>=12.13.0'} + + pngjs@7.0.0: + resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} + engines: {node: '>=14.19.0'} + pretty-ms@9.3.0: resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} + process@0.11.10: + resolution: {integrity: sha1-czIwDoQBYb2j5podHZGn1LwW8YI=} + engines: {node: '>= 0.6.0'} + progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} @@ -2758,6 +3169,14 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readable-web-to-node-stream@3.0.4: + resolution: {integrity: sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==} + engines: {node: '>=8'} + readdirp@5.0.0: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} @@ -2825,6 +3244,10 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sax@1.4.4: + resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} + engines: {node: '>=11.0.0'} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -2849,6 +3272,10 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2880,6 +3307,10 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-xml-to-json@1.2.3: + resolution: {integrity: sha512-kWJDCr9EWtZ+/EYYM5MareWj2cRnZGF93YDNpH4jQiHB+hBIZnfPFSQiVMzZOdk+zXWqTZ/9fTeQNu2DqeiudA==} + engines: {node: '>=20.12.2'} + smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} @@ -2963,6 +3394,14 @@ packages: strnum@2.1.2: resolution: {integrity: sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==} + strtok3@10.3.4: + resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} + engines: {node: '>=18'} + + strtok3@6.3.0: + resolution: {integrity: sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==} + engines: {node: '>=10'} + strtok3@9.1.1: resolution: {integrity: sha512-FhwotcEqjr241ZbjFzjlIYg6c5/L/s4yBGWSMvJ9UoExiSqL+FnFA/CaeZx17WGaZMS/4SOZp8wH18jSS4R4lw==} engines: {node: '>=16'} @@ -2997,6 +3436,9 @@ packages: tiny-worker@2.3.0: resolution: {integrity: sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g==} + tinycolor2@1.6.0: + resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -3005,6 +3447,10 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + token-types@4.2.1: + resolution: {integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==} + engines: {node: '>=10'} + token-types@6.1.2: resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} engines: {node: '>=14.16'} @@ -3023,6 +3469,9 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -3119,6 +3568,9 @@ packages: resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} engines: {node: '>= 0.4'} + utif2@4.1.0: + resolution: {integrity: sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==} + util-deprecate@1.0.2: resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=} @@ -3212,6 +3664,17 @@ packages: utf-8-validate: optional: true + xml-parse-from-string@1.0.1: + resolution: {integrity: sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==} + + xml2js@0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} + engines: {node: '>=4.0.0'} + + xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + xmlhttprequest-ssl@2.1.2: resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} engines: {node: '>=0.4.0'} @@ -3248,6 +3711,11 @@ packages: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} + zod-to-json-schema@3.25.1: + resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} + peerDependencies: + zod: ^3.25 || ^4 + zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} @@ -3256,6 +3724,12 @@ packages: snapshots: + '@anthropic-ai/sdk@0.71.2(zod@3.25.76)': + dependencies: + json-schema-to-ts: 3.1.1 + optionalDependencies: + zod: 3.25.76 + '@api.global/typedrequest-interfaces@2.0.2': {} '@api.global/typedrequest-interfaces@3.0.19': {} @@ -4065,6 +4539,102 @@ snapshots: dependencies: happy-dom: 15.11.7 + '@img/colour@1.0.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.8.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + '@inquirer/checkbox@3.0.1': dependencies: '@inquirer/core': 9.2.1 @@ -4176,6 +4746,195 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@jimp/core@1.6.0': + dependencies: + '@jimp/file-ops': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + await-to-js: 3.0.0 + exif-parser: 0.1.12 + file-type: 16.5.4 + mime: 3.0.0 + + '@jimp/diff@1.6.0': + dependencies: + '@jimp/plugin-resize': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + pixelmatch: 5.3.0 + + '@jimp/file-ops@1.6.0': {} + + '@jimp/js-bmp@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + bmp-ts: 1.0.9 + + '@jimp/js-gif@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + gifwrap: 0.10.1 + omggif: 1.0.10 + + '@jimp/js-jpeg@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + jpeg-js: 0.4.4 + + '@jimp/js-png@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + pngjs: 7.0.0 + + '@jimp/js-tiff@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + utif2: 4.1.0 + + '@jimp/plugin-blit@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-blur@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/utils': 1.6.0 + + '@jimp/plugin-circle@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-color@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + tinycolor2: 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-contain@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/plugin-blit': 1.6.0 + '@jimp/plugin-resize': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-cover@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/plugin-crop': 1.6.0 + '@jimp/plugin-resize': 1.6.0 + '@jimp/types': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-crop@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-displace@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-dither@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + + '@jimp/plugin-fisheye@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-flip@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-hash@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/js-bmp': 1.6.0 + '@jimp/js-jpeg': 1.6.0 + '@jimp/js-png': 1.6.0 + '@jimp/js-tiff': 1.6.0 + '@jimp/plugin-color': 1.6.0 + '@jimp/plugin-resize': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + any-base: 1.1.0 + + '@jimp/plugin-mask@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-print@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/js-jpeg': 1.6.0 + '@jimp/js-png': 1.6.0 + '@jimp/plugin-blit': 1.6.0 + '@jimp/types': 1.6.0 + parse-bmfont-ascii: 1.0.6 + parse-bmfont-binary: 1.0.6 + parse-bmfont-xml: 1.1.6 + simple-xml-to-json: 1.2.3 + zod: 3.25.76 + + '@jimp/plugin-quantize@1.6.0': + dependencies: + image-q: 4.0.0 + zod: 3.25.76 + + '@jimp/plugin-resize@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-rotate@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/plugin-crop': 1.6.0 + '@jimp/plugin-resize': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-threshold@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/plugin-color': 1.6.0 + '@jimp/plugin-hash': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/types@1.6.0': + dependencies: + zod: 3.25.76 + + '@jimp/utils@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + tinycolor2: 1.6.0 + '@leichtgewicht/ip-codec@2.0.5': {} '@lit-labs/ssr-dom-shim@1.5.1': {} @@ -4184,6 +4943,11 @@ snapshots: dependencies: '@lit-labs/ssr-dom-shim': 1.5.1 + '@mistralai/mistralai@1.12.0': + dependencies: + zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) + '@mixmark-io/domino@2.2.0': {} '@module-federation/error-codes@0.22.0': {} @@ -4360,6 +5124,28 @@ snapshots: '@push.rocks/isounique@1.0.5': {} + '@push.rocks/levelcache@3.2.0': + dependencies: + '@push.rocks/lik': 6.2.2 + '@push.rocks/smartbucket': 3.3.10 + '@push.rocks/smartcache': 1.0.18 + '@push.rocks/smartenv': 5.0.13 + '@push.rocks/smartexit': 1.1.0 + '@push.rocks/smartfile': 11.2.7 + '@push.rocks/smartjson': 5.2.0 + '@push.rocks/smartpath': 6.0.0 + '@push.rocks/smartpromise': 4.2.3 + '@push.rocks/smartstring': 4.1.0 + '@push.rocks/smartunique': 3.0.9 + '@push.rocks/taskbuffer': 3.5.0 + '@tsclass/tsclass': 9.3.0 + transitivePeerDependencies: + - '@nuxt/kit' + - aws-crt + - react + - supports-color + - vue + '@push.rocks/lik@6.2.2': dependencies: '@push.rocks/smartdelay': 3.0.5 @@ -4414,6 +5200,79 @@ snapshots: '@push.rocks/smartlog': 3.1.10 '@push.rocks/smartpath': 6.0.0 + '@push.rocks/smartagent@1.2.8(typescript@5.9.3)(ws@8.19.0)(zod@3.25.76)': + dependencies: + '@push.rocks/smartai': 0.11.1(typescript@5.9.3)(ws@8.19.0)(zod@3.25.76) + '@push.rocks/smartbrowser': 2.0.8(typescript@5.9.3) + '@push.rocks/smartdeno': 1.2.0 + '@push.rocks/smartfs': 1.3.1 + '@push.rocks/smartrequest': 5.0.1 + '@push.rocks/smartshell': 3.3.0 + minimatch: 10.1.1 + transitivePeerDependencies: + - '@nuxt/kit' + - aws-crt + - bare-abort-controller + - bare-buffer + - bufferutil + - react + - react-native-b4a + - supports-color + - typescript + - utf-8-validate + - vue + - ws + - zod + + '@push.rocks/smartai@0.11.1(typescript@5.9.3)(ws@8.19.0)(zod@3.25.76)': + dependencies: + '@anthropic-ai/sdk': 0.71.2(zod@3.25.76) + '@mistralai/mistralai': 1.12.0 + '@push.rocks/smartarray': 1.1.0 + '@push.rocks/smartfs': 1.3.1 + '@push.rocks/smartpath': 6.0.0 + '@push.rocks/smartpdf': 4.1.1(typescript@5.9.3) + '@push.rocks/smartpromise': 4.2.3 + '@push.rocks/smartrequest': 5.0.1 + '@push.rocks/webstream': 1.0.10 + openai: 6.16.0(ws@8.19.0)(zod@3.25.76) + transitivePeerDependencies: + - '@nuxt/kit' + - aws-crt + - bare-abort-controller + - bare-buffer + - bufferutil + - react + - react-native-b4a + - supports-color + - typescript + - utf-8-validate + - vue + - ws + - zod + + '@push.rocks/smartarchive@5.2.1': + dependencies: + '@push.rocks/smartdelay': 3.0.5 + '@push.rocks/smartfile': 13.1.2 + '@push.rocks/smartpath': 6.0.0 + '@push.rocks/smartpromise': 4.2.3 + '@push.rocks/smartrequest': 5.0.1 + '@push.rocks/smartrx': 3.0.10 + '@push.rocks/smartstream': 3.2.5 + '@push.rocks/smartunique': 3.0.9 + '@push.rocks/smarturl': 3.1.0 + fflate: 0.8.2 + file-type: 21.3.0 + modern-tar: 0.7.3 + tar-stream: 3.1.7 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + - supports-color + + '@push.rocks/smartarray@1.1.0': {} + '@push.rocks/smartbrowser@2.0.8(typescript@5.9.3)': dependencies: '@push.rocks/smartdelay': 3.0.5 @@ -4429,6 +5288,20 @@ snapshots: - typescript - utf-8-validate + '@push.rocks/smartbucket@3.3.10': + dependencies: + '@aws-sdk/client-s3': 3.971.0 + '@push.rocks/smartmime': 2.0.4 + '@push.rocks/smartpath': 6.0.0 + '@push.rocks/smartpromise': 4.2.3 + '@push.rocks/smartrx': 3.0.10 + '@push.rocks/smartstream': 3.2.5 + '@push.rocks/smartstring': 4.1.0 + '@push.rocks/smartunique': 3.0.9 + '@tsclass/tsclass': 9.3.0 + transitivePeerDependencies: + - aws-crt + '@push.rocks/smartbucket@4.3.0': dependencies: '@aws-sdk/client-s3': 3.971.0 @@ -4521,6 +5394,18 @@ snapshots: dependencies: '@push.rocks/smartpromise': 4.2.3 + '@push.rocks/smartdeno@1.2.0': + dependencies: + '@push.rocks/smartarchive': 5.2.1 + '@push.rocks/smartfs': 1.3.1 + '@push.rocks/smartpath': 6.0.0 + '@push.rocks/smartshell': 3.3.0 + '@push.rocks/smartunique': 3.0.9 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + - supports-color + '@push.rocks/smartdns@7.6.1': dependencies: '@push.rocks/smartdelay': 3.0.5 @@ -4629,6 +5514,22 @@ snapshots: '@push.rocks/smartpromise': 4.2.3 inquirer: 11.1.0 + '@push.rocks/smartjimp@1.2.0': + dependencies: + '@push.rocks/levelcache': 3.2.0 + '@push.rocks/smartfile': 11.2.7 + '@push.rocks/smarthash': 3.2.6 + '@push.rocks/smartpath': 6.0.0 + '@push.rocks/smartrequest': 4.4.2 + jimp: 1.6.0 + sharp: 0.34.5 + transitivePeerDependencies: + - '@nuxt/kit' + - aws-crt + - react + - supports-color + - vue + '@push.rocks/smartjson@5.2.0': dependencies: '@push.rocks/smartenv': 5.0.13 @@ -4773,6 +5674,35 @@ snapshots: - typescript - utf-8-validate + '@push.rocks/smartpdf@4.1.1(typescript@5.9.3)': + dependencies: + '@push.rocks/smartbuffer': 3.0.5 + '@push.rocks/smartdelay': 3.0.5 + '@push.rocks/smartfile': 11.2.7 + '@push.rocks/smartjimp': 1.2.0 + '@push.rocks/smartnetwork': 4.4.0 + '@push.rocks/smartpath': 6.0.0 + '@push.rocks/smartpromise': 4.2.3 + '@push.rocks/smartpuppeteer': 2.0.5(typescript@5.9.3) + '@push.rocks/smartunique': 3.0.9 + '@tsclass/tsclass': 9.3.0 + '@types/express': 5.0.6 + express: 5.2.1 + pdf-lib: 1.17.1 + pdf2json: 3.2.0 + transitivePeerDependencies: + - '@nuxt/kit' + - aws-crt + - bare-abort-controller + - bare-buffer + - bufferutil + - react + - react-native-b4a + - supports-color + - typescript + - utf-8-validate + - vue + '@push.rocks/smartping@1.0.8': dependencies: '@types/ping': 0.4.4 @@ -5485,6 +6415,13 @@ snapshots: '@tempfix/lenis@1.3.20': {} + '@tokenizer/inflate@0.4.1': + dependencies: + debug: 4.4.3 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + '@tokenizer/token@0.3.0': {} '@tootallnate/quickjs-emscripten@0.23.0': {} @@ -5594,6 +6531,8 @@ snapshots: dependencies: '@types/node': 25.0.9 + '@types/node@16.9.1': {} + '@types/node@22.19.7': dependencies: undici-types: 6.21.0 @@ -5660,6 +6599,10 @@ snapshots: '@ungap/structured-clone@1.3.0': {} + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + accepts@1.3.8: dependencies: mime-types: 2.1.35 @@ -5702,6 +6645,8 @@ snapshots: ansi-styles@6.2.3: {} + any-base@1.1.0: {} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 @@ -5724,6 +6669,8 @@ snapshots: asynckit@0.4.0: {} + await-to-js@3.0.0: {} + axios@1.13.2(debug@4.4.3): dependencies: follow-redirects: 1.15.11(debug@4.4.3) @@ -5781,6 +6728,8 @@ snapshots: basic-ftp@5.1.0: {} + bmp-ts@1.0.9: {} + bn.js@4.12.2: {} body-parser@2.2.2: @@ -5986,6 +6935,8 @@ snapshots: dequal@2.0.3: {} + detect-libc@2.1.2: {} + devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -6132,6 +7083,8 @@ snapshots: etag@1.8.1: {} + event-target-shim@5.0.1: {} + eventemitter3@4.0.7: {} events-universal@1.0.1: @@ -6140,6 +7093,10 @@ snapshots: transitivePeerDependencies: - bare-abort-controller + events@3.3.0: {} + + exif-parser@0.1.12: {} + express-force-ssl@0.3.2: dependencies: lodash.assign: 3.2.0 @@ -6225,10 +7182,18 @@ snapshots: dependencies: pend: 1.2.0 + fflate@0.8.2: {} + figures@6.1.0: dependencies: is-unicode-supported: 2.1.0 + file-type@16.5.4: + dependencies: + readable-web-to-node-stream: 3.0.4 + strtok3: 6.3.0 + token-types: 4.2.1 + file-type@19.6.0: dependencies: get-stream: 9.0.1 @@ -6236,6 +7201,15 @@ snapshots: token-types: 6.1.2 uint8array-extras: 1.5.0 + file-type@21.3.0: + dependencies: + '@tokenizer/inflate': 0.4.1 + strtok3: 10.3.4 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + finalhandler@2.1.1: dependencies: debug: 4.4.3 @@ -6340,6 +7314,11 @@ snapshots: transitivePeerDependencies: - supports-color + gifwrap@0.10.1: + dependencies: + image-q: 4.0.0 + omggif: 1.0.10 + glob@11.1.0: dependencies: foreground-child: 3.3.1 @@ -6467,6 +7446,10 @@ snapshots: ieee754@1.2.1: {} + image-q@4.0.0: + dependencies: + '@types/node': 16.9.1 + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -6533,6 +7516,38 @@ snapshots: dependencies: '@isaacs/cliui': 8.0.2 + jimp@1.6.0: + dependencies: + '@jimp/core': 1.6.0 + '@jimp/diff': 1.6.0 + '@jimp/js-bmp': 1.6.0 + '@jimp/js-gif': 1.6.0 + '@jimp/js-jpeg': 1.6.0 + '@jimp/js-png': 1.6.0 + '@jimp/js-tiff': 1.6.0 + '@jimp/plugin-blit': 1.6.0 + '@jimp/plugin-blur': 1.6.0 + '@jimp/plugin-circle': 1.6.0 + '@jimp/plugin-color': 1.6.0 + '@jimp/plugin-contain': 1.6.0 + '@jimp/plugin-cover': 1.6.0 + '@jimp/plugin-crop': 1.6.0 + '@jimp/plugin-displace': 1.6.0 + '@jimp/plugin-dither': 1.6.0 + '@jimp/plugin-fisheye': 1.6.0 + '@jimp/plugin-flip': 1.6.0 + '@jimp/plugin-hash': 1.6.0 + '@jimp/plugin-mask': 1.6.0 + '@jimp/plugin-print': 1.6.0 + '@jimp/plugin-quantize': 1.6.0 + '@jimp/plugin-resize': 1.6.0 + '@jimp/plugin-rotate': 1.6.0 + '@jimp/plugin-threshold': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + + jpeg-js@0.4.4: {} + js-base64@3.7.8: {} js-tokens@4.0.0: {} @@ -6548,6 +7563,11 @@ snapshots: json-parse-even-better-errors@2.3.1: {} + json-schema-to-ts@3.1.1: + dependencies: + '@babel/runtime': 7.28.4 + ts-algebra: 2.0.0 + jsonfile@6.2.0: dependencies: universalify: 2.0.1 @@ -6986,6 +8006,8 @@ snapshots: dependencies: mime-db: 1.54.0 + mime@3.0.0: {} + mime@4.1.0: {} minimalistic-assert@1.0.1: {} @@ -7008,6 +8030,8 @@ snapshots: mitt@3.0.1: {} + modern-tar@0.7.3: {} + mongodb-connection-string-url@3.0.2: dependencies: '@types/whatwg-url': 11.0.5 @@ -7101,6 +8125,8 @@ snapshots: observable-fns@0.6.1: {} + omggif@1.0.10: {} + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -7115,6 +8141,11 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 + openai@6.16.0(ws@8.19.0)(zod@3.25.76): + optionalDependencies: + ws: 8.19.0 + zod: 3.25.76 + os-tmpdir@1.0.2: {} p-finally@1.0.0: {} @@ -7168,6 +8199,15 @@ snapshots: dependencies: callsites: 3.1.0 + parse-bmfont-ascii@1.0.6: {} + + parse-bmfont-binary@1.0.6: {} + + parse-bmfont-xml@1.1.6: + dependencies: + xml-parse-from-string: 1.0.1 + xml2js: 0.5.0 + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.28.6 @@ -7201,6 +8241,8 @@ snapshots: pdf2json@3.2.0: {} + peek-readable@4.1.0: {} + peek-readable@5.4.2: {} pend@1.2.0: {} @@ -7211,14 +8253,24 @@ snapshots: ping@0.4.4: {} + pixelmatch@5.3.0: + dependencies: + pngjs: 6.0.0 + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 + pngjs@6.0.0: {} + + pngjs@7.0.0: {} + pretty-ms@9.3.0: dependencies: parse-ms: 4.0.0 + process@0.11.10: {} + progress@2.0.3: {} property-information@7.1.0: {} @@ -7317,6 +8369,18 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 + readable-stream@4.7.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readable-web-to-node-stream@3.0.4: + dependencies: + readable-stream: 4.7.0 + readdirp@5.0.0: {} reflect-metadata@0.2.2: {} @@ -7418,6 +8482,8 @@ snapshots: safer-buffer@2.1.2: {} + sax@1.4.4: {} + semver@6.3.1: {} semver@7.7.3: {} @@ -7458,6 +8524,37 @@ snapshots: setprototypeof@1.2.0: {} + sharp@0.34.5: + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -7496,6 +8593,8 @@ snapshots: signal-exit@4.1.0: {} + simple-xml-to-json@1.2.3: {} + smart-buffer@4.2.0: {} socket.io-adapter@2.5.6: @@ -7617,6 +8716,15 @@ snapshots: strnum@2.1.2: {} + strtok3@10.3.4: + dependencies: + '@tokenizer/token': 0.3.0 + + strtok3@6.3.0: + dependencies: + '@tokenizer/token': 0.3.0 + peek-readable: 4.1.0 + strtok3@9.1.1: dependencies: '@tokenizer/token': 0.3.0 @@ -7674,12 +8782,19 @@ snapshots: dependencies: esm: 3.2.25 + tinycolor2@1.6.0: {} + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 toidentifier@1.0.1: {} + token-types@4.2.1: + dependencies: + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + token-types@6.1.2: dependencies: '@borewit/text-codec': 0.2.1 @@ -7696,6 +8811,8 @@ snapshots: trough@2.2.0: {} + ts-algebra@2.0.0: {} + tslib@1.14.1: {} tslib@2.8.1: {} @@ -7787,6 +8904,10 @@ snapshots: punycode: 1.4.1 qs: 6.14.1 + utif2@4.1.0: + dependencies: + pako: 1.0.11 + util-deprecate@1.0.2: {} uuid@9.0.1: {} @@ -7848,6 +8969,15 @@ snapshots: ws@8.19.0: {} + xml-parse-from-string@1.0.1: {} + + xml2js@0.5.0: + dependencies: + sax: 1.4.4 + xmlbuilder: 11.0.1 + + xmlbuilder@11.0.1: {} + xmlhttprequest-ssl@2.1.2: {} y18n@5.0.8: {} @@ -7880,6 +9010,10 @@ snapshots: yoctocolors-cjs@2.1.3: {} + zod-to-json-schema@3.25.1(zod@3.25.76): + dependencies: + zod: 3.25.76 + zod@3.25.76: {} zwitch@2.0.4: {} diff --git a/test/test.bankstatements.minicpm.ts b/test/test.bankstatements.minicpm.ts index c3e9c50..b16fa27 100644 --- a/test/test.bankstatements.minicpm.ts +++ b/test/test.bankstatements.minicpm.ts @@ -1,9 +1,9 @@ /** * Bank statement extraction using MiniCPM-V (visual extraction) * - * JSON per-page approach: + * JSON per-page approach with streaming output: * 1. Ask for structured JSON of all transactions per page - * 2. Consensus: extract twice, compare, retry if mismatch + * 2. Single pass extraction (no consensus) */ import { tap, expect } from '@git.zone/tstest/tapbundle'; import * as fs from 'fs'; @@ -66,11 +66,11 @@ function convertPdfToImages(pdfPath: string): string[] { } /** - * Query for JSON extraction + * Query for JSON extraction with streaming output */ async function queryJson(image: string, queryId: string): Promise { - console.log(` [${queryId}] Sending request to ${MODEL}...`); const startTime = Date.now(); + process.stdout.write(` [${queryId}] `); const response = await fetch(`${OLLAMA_URL}/api/chat`, { method: 'POST', @@ -82,25 +82,50 @@ async function queryJson(image: string, queryId: string): Promise { content: JSON_PROMPT, images: [image], }], - stream: false, + stream: true, options: { + num_ctx: 32768, num_predict: 4000, temperature: 0.1, }, }), }); - const elapsed = ((Date.now() - startTime) / 1000).toFixed(1); - if (!response.ok) { - console.log(` [${queryId}] ERROR: ${response.status} (${elapsed}s)`); + const elapsed = ((Date.now() - startTime) / 1000).toFixed(1); + process.stdout.write(`ERROR: ${response.status} (${elapsed}s)\n`); throw new Error(`Ollama API error: ${response.status}`); } - const data = await response.json(); - const content = (data.message?.content || '').trim(); - console.log(` [${queryId}] Response received (${elapsed}s, ${content.length} chars)`); - return content; + let content = ''; + const reader = response.body!.getReader(); + const decoder = new TextDecoder(); + + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value, { stream: true }); + for (const line of chunk.split('\n').filter(l => l.trim())) { + try { + const json = JSON.parse(line); + const token = json.message?.content || ''; + if (token) { + process.stdout.write(token); + content += token; + } + } catch { + // Ignore parse errors for partial chunks + } + } + } + } finally { + const elapsed = ((Date.now() - startTime) / 1000).toFixed(1); + process.stdout.write(` (${elapsed}s)\n`); + } + + return content.trim(); } /** @@ -284,102 +309,29 @@ function parseAmount(value: unknown): number { } /** - * Compare two transaction arrays for consensus - */ -function transactionArraysMatch(a: ITransaction[], b: ITransaction[]): boolean { - if (a.length !== b.length) return false; - - for (let i = 0; i < a.length; i++) { - const dateMatch = a[i].date === b[i].date; - const amountMatch = Math.abs(a[i].amount - b[i].amount) < 0.01; - if (!dateMatch || !amountMatch) return false; - } - - return true; -} - -/** - * Compare two transaction arrays and log differences - */ -function compareAndLogDifferences(txs1: ITransaction[], txs2: ITransaction[], pageNum: number): void { - if (txs1.length !== txs2.length) { - console.log(` [Page ${pageNum}] Length mismatch: Q1=${txs1.length}, Q2=${txs2.length}`); - return; - } - - for (let i = 0; i < txs1.length; i++) { - const dateMatch = txs1[i].date === txs2[i].date; - const amountMatch = Math.abs(txs1[i].amount - txs2[i].amount) < 0.01; - - if (!dateMatch || !amountMatch) { - console.log(` [Page ${pageNum}] Tx ${i + 1} differs:`); - console.log(` Q1: ${txs1[i].date} | ${txs1[i].amount}`); - console.log(` Q2: ${txs2[i].date} | ${txs2[i].amount}`); - } - } -} - -/** - * Extract transactions from a single page with consensus + * Extract transactions from a single page (single pass) */ async function extractTransactionsFromPage(image: string, pageNum: number): Promise { - const MAX_ATTEMPTS = 5; console.log(`\n ======== Page ${pageNum} ========`); - console.log(` [Page ${pageNum}] Starting JSON extraction...`); - for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) { - console.log(`\n [Page ${pageNum}] --- Attempt ${attempt}/${MAX_ATTEMPTS} ---`); + const queryId = `P${pageNum}`; + const response = await queryJson(image, queryId); + const transactions = parseJsonResponse(response, queryId); - // Extract twice in parallel - const q1Id = `P${pageNum}A${attempt}Q1`; - const q2Id = `P${pageNum}A${attempt}Q2`; - - const [response1, response2] = await Promise.all([ - queryJson(image, q1Id), - queryJson(image, q2Id), - ]); - - const txs1 = parseJsonResponse(response1, q1Id); - const txs2 = parseJsonResponse(response2, q2Id); - - console.log(` [Page ${pageNum}] Results: Q1=${txs1.length} txs, Q2=${txs2.length} txs`); - - if (txs1.length > 0 && transactionArraysMatch(txs1, txs2)) { - console.log(` [Page ${pageNum}] ✓ CONSENSUS REACHED: ${txs1.length} transactions`); - console.log(` [Page ${pageNum}] Transactions:`); - for (let i = 0; i < txs1.length; i++) { - const tx = txs1[i]; - console.log(` ${(i + 1).toString().padStart(2)}. ${tx.date} | ${tx.counterparty.substring(0, 30).padEnd(30)} | ${tx.amount >= 0 ? '+' : ''}${tx.amount.toFixed(2)}`); - } - return txs1; - } - - console.log(` [Page ${pageNum}] ✗ NO CONSENSUS`); - compareAndLogDifferences(txs1, txs2, pageNum); - - if (attempt < MAX_ATTEMPTS) { - console.log(` [Page ${pageNum}] Retrying...`); - } - } - - // Fallback: use last response - console.log(`\n [Page ${pageNum}] === FALLBACK (no consensus after ${MAX_ATTEMPTS} attempts) ===`); - const fallbackId = `P${pageNum}FALLBACK`; - const fallbackResponse = await queryJson(image, fallbackId); - const fallback = parseJsonResponse(fallbackResponse, fallbackId); - console.log(` [Page ${pageNum}] ~ FALLBACK RESULT: ${fallback.length} transactions`); - for (let i = 0; i < fallback.length; i++) { - const tx = fallback[i]; + console.log(` [Page ${pageNum}] Extracted ${transactions.length} transactions:`); + for (let i = 0; i < transactions.length; i++) { + const tx = transactions[i]; console.log(` ${(i + 1).toString().padStart(2)}. ${tx.date} | ${tx.counterparty.substring(0, 30).padEnd(30)} | ${tx.amount >= 0 ? '+' : ''}${tx.amount.toFixed(2)}`); } - return fallback; + + return transactions; } /** * Extract all transactions from bank statement */ async function extractTransactions(images: string[]): Promise { - console.log(` [Vision] Processing ${images.length} page(s) with ${MODEL} (JSON consensus)`); + console.log(` [Vision] Processing ${images.length} page(s) with ${MODEL} (single pass)`); const allTransactions: ITransaction[] = []; @@ -527,7 +479,7 @@ tap.test('summary', async () => { console.log(`\n======================================================`); console.log(` Bank Statement Summary (${MODEL})`); console.log(`======================================================`); - console.log(` Method: JSON per-page + consensus`); + console.log(` Method: JSON per-page (single pass)`); console.log(` Passed: ${passedCount}/${total}`); console.log(` Failed: ${failedCount}/${total}`); console.log(`======================================================\n`); diff --git a/test/test.invoices.minicpm.ts b/test/test.invoices.minicpm.ts index fc2af81..a319f36 100644 --- a/test/test.invoices.minicpm.ts +++ b/test/test.invoices.minicpm.ts @@ -67,9 +67,12 @@ const JSON_PROMPT = `Extract invoice data from this image. Return ONLY a JSON ob Return only the JSON, no explanation.`; /** - * Query MiniCPM-V for JSON output (fast, no thinking) + * Query MiniCPM-V for JSON output (fast, no thinking) with streaming */ async function queryJsonFast(images: string[]): Promise { + const startTime = Date.now(); + process.stdout.write(` [Fast] `); + const response = await fetch(`${OLLAMA_URL}/api/chat`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -80,8 +83,9 @@ async function queryJsonFast(images: string[]): Promise { content: JSON_PROMPT, images: images, }], - stream: false, + stream: true, options: { + num_ctx: 32768, num_predict: 1000, temperature: 0.1, }, @@ -92,14 +96,44 @@ async function queryJsonFast(images: string[]): Promise { throw new Error(`Ollama API error: ${response.status}`); } - const data = await response.json(); - return (data.message?.content || '').trim(); + let content = ''; + const reader = response.body!.getReader(); + const decoder = new TextDecoder(); + + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value, { stream: true }); + for (const line of chunk.split('\n').filter(l => l.trim())) { + try { + const json = JSON.parse(line); + const token = json.message?.content || ''; + if (token) { + process.stdout.write(token); + content += token; + } + } catch { + // Ignore parse errors for partial chunks + } + } + } + } finally { + const elapsed = ((Date.now() - startTime) / 1000).toFixed(1); + process.stdout.write(` (${elapsed}s)\n`); + } + + return content.trim(); } /** - * Query MiniCPM-V for JSON output with thinking enabled (slower, more accurate) + * Query MiniCPM-V for JSON output with thinking enabled (slower, more accurate) with streaming */ async function queryJsonWithThinking(images: string[]): Promise { + const startTime = Date.now(); + process.stdout.write(` [Think] `); + const response = await fetch(`${OLLAMA_URL}/api/chat`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -110,8 +144,9 @@ async function queryJsonWithThinking(images: string[]): Promise { content: `Think carefully about this invoice image, then ${JSON_PROMPT}`, images: images, }], - stream: false, + stream: true, options: { + num_ctx: 32768, num_predict: 2000, temperature: 0.1, }, @@ -122,8 +157,56 @@ async function queryJsonWithThinking(images: string[]): Promise { throw new Error(`Ollama API error: ${response.status}`); } - const data = await response.json(); - return (data.message?.content || '').trim(); + let content = ''; + let thinkingContent = ''; + let thinkingStarted = false; + let outputStarted = false; + const reader = response.body!.getReader(); + const decoder = new TextDecoder(); + + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value, { stream: true }); + for (const line of chunk.split('\n').filter(l => l.trim())) { + try { + const json = JSON.parse(line); + + // Stream thinking tokens + const thinking = json.message?.thinking || ''; + if (thinking) { + if (!thinkingStarted) { + process.stdout.write(`THINKING: `); + thinkingStarted = true; + } + process.stdout.write(thinking); + thinkingContent += thinking; + } + + // Stream content tokens + const token = json.message?.content || ''; + if (token) { + if (!outputStarted) { + if (thinkingStarted) process.stdout.write('\n [Think] '); + process.stdout.write(`OUTPUT: `); + outputStarted = true; + } + process.stdout.write(token); + content += token; + } + } catch { + // Ignore parse errors for partial chunks + } + } + } + } finally { + const elapsed = ((Date.now() - startTime) / 1000).toFixed(1); + process.stdout.write(` (${elapsed}s)\n`); + } + + return content.trim(); } /** diff --git a/test/test.invoices.nanonets.ts b/test/test.invoices.nanonets.ts index cbe42c9..d04d01f 100644 --- a/test/test.invoices.nanonets.ts +++ b/test/test.invoices.nanonets.ts @@ -12,6 +12,8 @@ import * as path from 'path'; import { execSync } from 'child_process'; import * as os from 'os'; import { ensureNanonetsOcr, ensureMiniCpm, isContainerRunning } from './helpers/docker.js'; +import { SmartAi } from '@push.rocks/smartai'; +import { DualAgentOrchestrator } from '@push.rocks/smartagent'; const NANONETS_URL = 'http://localhost:8000/v1'; const NANONETS_MODEL = 'nanonets/Nanonets-OCR2-3B'; @@ -19,8 +21,24 @@ const NANONETS_MODEL = 'nanonets/Nanonets-OCR2-3B'; const OLLAMA_URL = 'http://localhost:11434'; const EXTRACTION_MODEL = 'gpt-oss:20b'; -// Temp directory for storing markdown between stages -const TEMP_MD_DIR = path.join(os.tmpdir(), 'nanonets-invoices-markdown'); +// Persistent cache directory for storing markdown between runs +const MD_CACHE_DIR = path.join(process.cwd(), '.nogit/invoices-md'); + +// SmartAi instance for Ollama with optimized settings +const smartAi = new SmartAi({ + ollama: { + baseUrl: OLLAMA_URL, + model: EXTRACTION_MODEL, + defaultOptions: { + num_ctx: 32768, // Larger context for long invoices + thinking + temperature: 0, // Deterministic for JSON extraction + }, + defaultTimeout: 600000, // 10 minute timeout for large documents + }, +}); + +// DualAgentOrchestrator for structured task execution +let orchestrator: DualAgentOrchestrator; interface IInvoice { invoice_number: string; @@ -71,10 +89,13 @@ RULES: 7. total_amount: Final total with tax JSON only: -{"invoice_number":"X","invoice_date":"YYYY-MM-DD","vendor_name":"X","currency":"EUR","net_amount":0,"vat_amount":0,"total_amount":0}`; +{"invoice_number":"X","invoice_date":"YYYY-MM-DD","vendor_name":"X","currency":"EUR","net_amount":0,"vat_amount":0,"total_amount":0} + +Double check for valid JSON syntax. + +`; // Constants for smart batching -const MAX_VISUAL_TOKENS = 28000; // ~32K context minus prompt/output headroom const PATCH_SIZE = 14; // Qwen2.5-VL uses 14x14 patches /** @@ -359,95 +380,45 @@ function parseJsonToInvoice(response: string): IInvoice | null { } /** - * Extract invoice from markdown using GPT-OSS 20B (streaming) + * Extract invoice from markdown using smartagent DualAgentOrchestrator */ async function extractInvoiceFromMarkdown(markdown: string, queryId: string): Promise { const startTime = Date.now(); - console.log(` [${queryId}] Invoice: ${markdown.length} chars, Prompt: ${JSON_EXTRACTION_PROMPT.length} chars`); + console.log(` [${queryId}] Invoice: ${markdown.length} chars`); - const response = await fetch(`${OLLAMA_URL}/api/chat`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - model: EXTRACTION_MODEL, - messages: [ - { role: 'user', content: 'Hi there, how are you?' }, - { role: 'assistant', content: 'Good, how can I help you today?' }, - { role: 'user', content: `Here is an invoice document:\n\n${markdown}` }, - { role: 'assistant', content: 'I have read the invoice document you provided. I can see all the text content. What would you like me to do with it?' }, - { role: 'user', content: JSON_EXTRACTION_PROMPT }, - ], - stream: true, - options: { - num_ctx: 32768, // Larger context for long invoices + thinking - temperature: 0, // Deterministic for JSON extraction - }, - }), - signal: AbortSignal.timeout(600000), // 10 minute timeout for large documents - }); + // Build the extraction task with document context + const taskPrompt = `Extract the invoice data from this document and output ONLY the JSON: - if (!response.ok) { - const elapsed = ((Date.now() - startTime) / 1000).toFixed(1); - console.log(` [${queryId}] ERROR: ${response.status} (${elapsed}s)`); - throw new Error(`Ollama API error: ${response.status}`); - } +${markdown} - // Stream the response - let content = ''; - let thinkingContent = ''; - let thinkingStarted = false; - let outputStarted = false; - const reader = response.body!.getReader(); - const decoder = new TextDecoder(); +${JSON_EXTRACTION_PROMPT}`; try { - while (true) { - const { done, value } = await reader.read(); - if (done) break; + const result = await orchestrator.run(taskPrompt); - const chunk = decoder.decode(value, { stream: true }); + const elapsed = ((Date.now() - startTime) / 1000).toFixed(1); + console.log(` [${queryId}] Status: ${result.status}, Iterations: ${result.iterations} (${elapsed}s)`); - // Each line is a JSON object - for (const line of chunk.split('\n').filter(l => l.trim())) { - try { - const json = JSON.parse(line); + if (result.success && result.result) { + console.log(` [${queryId}] Result: ${result.result.substring(0, 100)}...`); + return parseJsonToInvoice(result.result); + } - // Stream thinking tokens - const thinking = json.message?.thinking || ''; - if (thinking) { - if (!thinkingStarted) { - process.stdout.write(` [${queryId}] THINKING: `); - thinkingStarted = true; - } - process.stdout.write(thinking); - thinkingContent += thinking; - } - - // Stream content tokens - const token = json.message?.content || ''; - if (token) { - if (!outputStarted) { - if (thinkingStarted) process.stdout.write('\n'); - process.stdout.write(` [${queryId}] OUTPUT: `); - outputStarted = true; - } - process.stdout.write(token); - content += token; - } - } catch { - // Ignore parse errors for partial chunks - } + // Fallback: try parsing from history + if (result.history?.length > 0) { + const lastMessage = result.history[result.history.length - 1]; + if (lastMessage?.content) { + return parseJsonToInvoice(lastMessage.content); } } - } finally { - if (thinkingStarted || outputStarted) process.stdout.write('\n'); + + return null; + } catch (error) { + const elapsed = ((Date.now() - startTime) / 1000).toFixed(1); + console.log(` [${queryId}] ERROR: ${error} (${elapsed}s)`); + throw error; } - - const elapsed = ((Date.now() - startTime) / 1000).toFixed(1); - console.log(` [${queryId}] Done: ${thinkingContent.length} thinking chars, ${content.length} output chars (${elapsed}s)`); - - return parseJsonToInvoice(content); } /** @@ -556,23 +527,45 @@ function findTestCases(): ITestCase[] { const testCases = findTestCases(); console.log(`\nFound ${testCases.length} invoice test cases\n`); -// Ensure temp directory exists -if (!fs.existsSync(TEMP_MD_DIR)) { - fs.mkdirSync(TEMP_MD_DIR, { recursive: true }); +// Ensure cache directory exists +if (!fs.existsSync(MD_CACHE_DIR)) { + fs.mkdirSync(MD_CACHE_DIR, { recursive: true }); } // -------- STAGE 1: OCR with Nanonets -------- -tap.test('Stage 1: Setup Nanonets', async () => { +tap.test('Stage 1: Convert invoices to markdown (with caching)', async () => { console.log('\n========== STAGE 1: Nanonets OCR ==========\n'); - const ok = await ensureNanonetsOcr(); - expect(ok).toBeTrue(); -}); -tap.test('Stage 1: Convert all invoices to markdown', async () => { - console.log('\n Converting all invoice PDFs to markdown with Nanonets-OCR-s...\n'); + // Check which invoices need OCR conversion + const needsConversion: ITestCase[] = []; + let cachedCount = 0; for (const tc of testCases) { + const mdPath = path.join(MD_CACHE_DIR, `${tc.name}.md`); + if (fs.existsSync(mdPath)) { + cachedCount++; + tc.markdownPath = mdPath; + console.log(` [CACHED] ${tc.name} - using cached markdown`); + } else { + needsConversion.push(tc); + } + } + + console.log(`\n Summary: ${cachedCount} cached, ${needsConversion.length} need conversion\n`); + + if (needsConversion.length === 0) { + console.log(' All invoices already cached, skipping Nanonets OCR\n'); + return; + } + + // Start Nanonets only if there are files to convert + console.log(' Starting Nanonets for OCR conversion...\n'); + const ok = await ensureNanonetsOcr(); + expect(ok).toBeTrue(); + + // Convert only the invoices that need conversion + for (const tc of needsConversion) { console.log(`\n === ${tc.name} ===`); const images = convertPdfToImages(tc.pdfPath); @@ -580,13 +573,13 @@ tap.test('Stage 1: Convert all invoices to markdown', async () => { const markdown = await convertDocumentToMarkdown(images, tc.name); - const mdPath = path.join(TEMP_MD_DIR, `${tc.name}.md`); + const mdPath = path.join(MD_CACHE_DIR, `${tc.name}.md`); fs.writeFileSync(mdPath, markdown); tc.markdownPath = mdPath; console.log(` Saved: ${mdPath}`); } - console.log('\n Stage 1 complete: All invoices converted to markdown\n'); + console.log(`\n Stage 1 complete: ${needsConversion.length} invoices converted to markdown\n`); }); tap.test('Stage 1: Stop Nanonets', async () => { @@ -605,6 +598,42 @@ tap.test('Stage 2: Setup Ollama + GPT-OSS 20B', async () => { const extractionOk = await ensureExtractionModel(); expect(extractionOk).toBeTrue(); + + // Initialize SmartAi and DualAgentOrchestrator + console.log(' [SmartAgent] Starting SmartAi...'); + await smartAi.start(); + + console.log(' [SmartAgent] Creating DualAgentOrchestrator...'); + orchestrator = new DualAgentOrchestrator({ + smartAiInstance: smartAi, + defaultProvider: 'ollama', + guardianPolicyPrompt: ` + JSON EXTRACTION POLICY: + - APPROVE all JSON extraction tasks + - This is a read-only operation - no file system or network access needed + - The task is to extract structured data from document text + `, + driverSystemMessage: `You are a precise JSON extraction assistant. Your only job is to extract invoice data from documents. + +CRITICAL RULES: +1. Output ONLY valid JSON - no markdown, no explanations, no thinking +2. Use the exact format requested +3. If you cannot find a value, use empty string "" or 0 for numbers + +When done, wrap your JSON in tags.`, + maxIterations: 3, + // Enable streaming for real-time progress visibility + onToken: (token, source) => { + if (source === 'driver') { + process.stdout.write(token); + } + }, + }); + + // No tools needed for JSON extraction + console.log(' [SmartAgent] Starting orchestrator...'); + await orchestrator.start(); + console.log(' [SmartAgent] Ready for extraction'); }); let passedCount = 0; @@ -619,7 +648,7 @@ for (const tc of testCases) { const startTime = Date.now(); - const mdPath = path.join(TEMP_MD_DIR, `${tc.name}.md`); + const mdPath = path.join(MD_CACHE_DIR, `${tc.name}.md`); if (!fs.existsSync(mdPath)) { throw new Error(`Markdown not found: ${mdPath}. Run Stage 1 first.`); } @@ -649,6 +678,14 @@ for (const tc of testCases) { } tap.test('Summary', async () => { + // Cleanup orchestrator and SmartAi + if (orchestrator) { + console.log('\n [SmartAgent] Stopping orchestrator...'); + await orchestrator.stop(); + } + console.log(' [SmartAgent] Stopping SmartAi...'); + await smartAi.stop(); + const totalInvoices = testCases.length; const accuracy = totalInvoices > 0 ? (passedCount / totalInvoices) * 100 : 0; const totalTimeMs = processingTimes.reduce((a, b) => a + b, 0); @@ -658,7 +695,7 @@ tap.test('Summary', async () => { console.log(` Invoice Summary (Nanonets + GPT-OSS 20B)`); console.log(`========================================`); console.log(` Stage 1: Nanonets-OCR-s (doc -> md)`); - console.log(` Stage 2: GPT-OSS 20B (md -> JSON)`); + console.log(` Stage 2: GPT-OSS 20B + SmartAgent (md -> JSON)`); console.log(` Passed: ${passedCount}/${totalInvoices}`); console.log(` Failed: ${failedCount}/${totalInvoices}`); console.log(` Accuracy: ${accuracy.toFixed(1)}%`); @@ -666,14 +703,7 @@ tap.test('Summary', async () => { console.log(` Total time: ${(totalTimeMs / 1000).toFixed(1)}s`); console.log(` Avg per inv: ${avgTimeSec.toFixed(1)}s`); console.log(`========================================\n`); - - // Cleanup temp files - try { - fs.rmSync(TEMP_MD_DIR, { recursive: true, force: true }); - console.log(` Cleaned up temp directory: ${TEMP_MD_DIR}\n`); - } catch { - // Ignore - } + console.log(` Cache location: ${MD_CACHE_DIR}\n`); }); export default tap.start();