From 2c0cfb85d00571e270bb52be6af9628c135b4672 Mon Sep 17 00:00:00 2001 From: zh Date: Mon, 28 Sep 2026 20:21:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(agent):=20Pi=20=E5=AD=90=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E6=8E=A5=E5=85=A5=EF=BC=88A3.3=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 server/agent/pi/runtime.ts:用官方 RpcClient 拉起 pi --mode rpc,一个会话一个进程(ADR-0006)。启动参数带 --no-builtin-tools / --no-extensions / --no-skills / --no-context-files,Pi 自带的 read/bash/edit/write 全部关掉,工具只能来自能力目录(扩展桥在 A3.11 接)。密钥经环境变量注入子进程(不进命令行,避免进程列表泄露);Pi 自己的 session 文件放 ~/.aps/pi-sessions 只作同引擎恢复,会话历史仍归平台。事件映射:message_update(text_delta)→text、tool_execution_start/end→tool_call/tool_result、message_end(assistant, stopReason=error)→error 并按六分类归一、agent_settled→turn_end。配置层加引擎选择:有密钥自动用 Pi、否则假引擎,可用 APS_ENGINE 覆盖;要求 Pi 但没有密钥时明确回退并告警。未配置密钥时 createSession 快速失败并给出配置指引,不再静默挂住。测试 56 → 60(59 通过 + 1 条需 APS_PI_INTEGRATION=1 的真实调用默认跳过);用假密钥实测:401 在 340ms 内被归到 forbidden,随后正常收尾。过程中修掉自身缺陷:错误回合的 finishReason 被 turn_end 覆盖回 stop,改为取最严重结果。 --- .env.example | 4 + .../2026-09-28T12-18-49-579Z_raw-probe.jsonl | 8 + pnpm-lock.yaml | 1022 ++++++++++++++++- pnpm-workspace.yaml | 5 +- scripts/config.test.mjs | 16 + scripts/pi-probe.mjs | 29 + scripts/pi-runtime.test.mjs | 72 ++ server/agent/pi/runtime.ts | 228 ++++ server/app/turn-runner.ts | 12 +- server/config.ts | 15 + server/index.ts | 19 +- server/package.json | 8 +- 12 files changed, 1398 insertions(+), 40 deletions(-) create mode 100644 .tmp-pi-sessions/2026-09-28T12-18-49-579Z_raw-probe.jsonl create mode 100644 scripts/pi-probe.mjs create mode 100644 scripts/pi-runtime.test.mjs create mode 100644 server/agent/pi/runtime.ts diff --git a/.env.example b/.env.example index f4ffd00..7d357cc 100644 --- a/.env.example +++ b/.env.example @@ -26,6 +26,10 @@ APS_PORT=5199 # 默认 ~/.aps/aps.sqlite;服务端部署时显式指定 # APS_DB_PATH= +# ---- 引擎选择 ---- +# 留空 = 有密钥就用 Pi、没密钥用假引擎;也可显式写 fake | pi +# APS_ENGINE= + # ---- 开发期开关 ---- # 1=注册假 Provider(用于联调与演示;默认不注册,能力清单为空) # APS_DEV_PROVIDER=1 \ No newline at end of file diff --git a/.tmp-pi-sessions/2026-09-28T12-18-49-579Z_raw-probe.jsonl b/.tmp-pi-sessions/2026-09-28T12-18-49-579Z_raw-probe.jsonl new file mode 100644 index 0000000..acd55e3 --- /dev/null +++ b/.tmp-pi-sessions/2026-09-28T12-18-49-579Z_raw-probe.jsonl @@ -0,0 +1,8 @@ +{"type":"session","version":3,"id":"raw-probe","timestamp":"2026-09-28T12:18:49.579Z","cwd":"D:\\workspace\\github\\aps-agent"} +{"type":"model_change","id":"c5ce29c8","parentId":null,"timestamp":"2026-09-28T12:18:49.620Z","provider":"deepseek","modelId":"deepseek-chat"} +{"type":"thinking_level_change","id":"d7ce43d9","parentId":"c5ce29c8","timestamp":"2026-09-28T12:18:49.620Z","thinkingLevel":"high"} +{"type":"message","id":"9daf9ab7","parentId":"d7ce43d9","timestamp":"2026-09-28T12:18:49.642Z","message":{"role":"system","content":"","sections":{"preamble":"You are an expert coding assistant operating inside pi, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.","tools":"\n(none)\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n","rules":"\n- Be concise in your responses\n- Show file paths clearly when working with files\n","docs":"\nPi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI):\n- Main documentation: D:\\workspace\\github\\aps-agent\\node_modules\\.pnpm\\@earendil-works+pi-coding-agent@0.87.1_ws@8.22.0\\node_modules\\@earendil-works\\pi-coding-agent\\README.md\n- Additional docs: D:\\workspace\\github\\aps-agent\\node_modules\\.pnpm\\@earendil-works+pi-coding-agent@0.87.1_ws@8.22.0\\node_modules\\@earendil-works\\pi-coding-agent\\docs\n- Examples: D:\\workspace\\github\\aps-agent\\node_modules\\.pnpm\\@earendil-works+pi-coding-agent@0.87.1_ws@8.22.0\\node_modules\\@earendil-works\\pi-coding-agent\\examples (extensions, custom tools, SDK)\n- When reading pi docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory\n- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), pi packages (docs/packages.md), environment variables (docs/environment-variables.md)\n- When working on pi topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read pi .md files completely and follow links to related docs (e.g., tui.md for TUI API details)\n","cwd":"\nD:/workspace/github/aps-agent\n"},"timestamp":1790597929641}} +{"type":"message","id":"421a57b6","parentId":"9daf9ab7","timestamp":"2026-09-28T12:18:49.642Z","message":{"role":"user","content":[{"type":"text","text":"用一句话回答:1+1 等于几"}],"timestamp":1790597929640}} +{"type":"message","id":"5ab3ce68","parentId":"421a57b6","timestamp":"2026-09-28T12:18:49.873Z","message":{"role":"assistant","content":[],"api":"openai-completions","provider":"deepseek","model":"deepseek-chat","usage":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0,"totalTokens":0,"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0,"total":0}},"stopReason":"error","timestamp":1790597929656,"errorMessage":"401: {\"message\":\"Authentication Fails, Your api key: ****-key is invalid (request_id: 91c7a4c1-9f68-4283-9b12-a1c985d6b703)\",\"type\":\"authentication_error\",\"param\":null,\"code\":\"invalid_request_error\"}"}} +{"type":"message","id":"290decc4","parentId":"5ab3ce68","timestamp":"2026-09-28T12:19:10.278Z","message":{"role":"user","content":[{"type":"text","text":"用一句话回答:1+1 等于几"}],"timestamp":1790597950276}} +{"type":"message","id":"a69d0b1e","parentId":"290decc4","timestamp":"2026-09-28T12:19:10.444Z","message":{"role":"assistant","content":[],"api":"openai-completions","provider":"deepseek","model":"deepseek-chat","usage":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0,"totalTokens":0,"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0,"total":0}},"stopReason":"error","timestamp":1790597950292,"errorMessage":"401: {\"message\":\"Authentication Fails, Your api key: ****-key is invalid (request_id: 37c34f4b-4e59-42c6-970f-23b3cb2958ea)\",\"type\":\"authentication_error\",\"param\":null,\"code\":\"invalid_request_error\"}"}} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d27c575..c450ea4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,7 +19,7 @@ importers: version: link:server '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.11.0) + version: 10.0.1(eslint@10.11.0(jiti@2.7.0)) '@types/node': specifier: ^26.6.2 version: 26.6.2 @@ -28,7 +28,7 @@ importers: version: 8.20.0 eslint: specifier: ^10.11.0 - version: 10.11.0 + version: 10.11.0(jiti@2.7.0) prettier: specifier: ^3.9.9 version: 3.9.9 @@ -37,7 +37,7 @@ importers: version: 6.0.3 typescript-eslint: specifier: ^8.70.1 - version: 8.70.1(eslint@10.11.0)(typescript@6.0.3) + version: 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) client/app: dependencies: @@ -59,10 +59,10 @@ importers: version: 19.3.0(@types/react@19.3.0) '@vitejs/plugin-react': specifier: ^5.1.0 - version: 5.2.0(vite@7.3.6(@types/node@26.6.2)(lightningcss@1.33.0)) + version: 5.2.0(vite@7.3.6(@types/node@26.6.2)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0)) vite: specifier: ^7.2.0 - version: 7.3.6(@types/node@26.6.2)(lightningcss@1.33.0) + version: 7.3.6(@types/node@26.6.2)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0) client/desktop: {} @@ -85,6 +85,12 @@ importers: '@aps/provider-sdk': specifier: workspace:* version: link:provider-sdk + '@earendil-works/pi-agent-core': + specifier: 0.87.1 + version: 0.87.1(ws@8.22.0) + '@earendil-works/pi-coding-agent': + specifier: 0.87.1 + version: 0.87.1(ws@8.22.0) server/provider-sdk: dependencies: @@ -94,6 +100,95 @@ importers: packages: + '@anthropic-ai/sdk@0.124.0': + resolution: {integrity: sha512-cN5O8i9UVxHeOQAzj/XjshWXG8KiibJDw9OGpH2Z/eR3n/RBxdoLxDJOcfqAJWvjaMDFfHTBADU04hWRJVkDyA==} + hasBin: true + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + + '@aws-sdk/client-bedrock-runtime@3.1127.0': + resolution: {integrity: sha512-IDl/lrPb90aH+pZFHGNDmgH9nAUQj5PlZH1sJ3w7RikctyjHSnY3oNjZhrLoaBoQn/rNK0zsP6OHEqEhj2tdLA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.978.1': + resolution: {integrity: sha512-LbY9aGsEiznDWmUc30Nwv3aIX/+dbwTx8KfS0yOC3NPYMO+O91e6jkT1azf34FwjOndq8/Q+RcVVZz5xnerwdg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.72': + resolution: {integrity: sha512-xTKO/FWJPozTIXbozVnVGoNBhaGba8TBcx+KyUjRVeOlXE+dUc7GTR1cLvu0uTdIdmemzaFbqqCshXeZA1fZew==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.74': + resolution: {integrity: sha512-u91E/hT8f4d1xy0Jl7VG4nVKJ3lxbrZkoBTeSVoJdWBiSEUMwMS/9+e0H/aJVQV//Lt5wuzP+E69v4aRSsNTmw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.973.17': + resolution: {integrity: sha512-ged4KXdBkvIC81bLvNHHuQKdKak/VXhQTR1NWYTTqW0474nlmsxy9O/vlgTIohDDWH3xpBdtVMZRyjb+DnocDA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.79': + resolution: {integrity: sha512-L+Z85anONJd8MaiuraO4wRxATCdEejBZ3K3eymzWI5JPXa9sOS9CkIm72PBKqXKX+Z9p9NGMX5AIMXm0LEflgw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.84': + resolution: {integrity: sha512-oHt854odINVwzwsh+c5x69j0ajm4DbqqqVJ+O1ECsCIZeMDAbzFpXItaqP7UZstJj/ATdTk/KFSH0LaNAgV+kA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.72': + resolution: {integrity: sha512-rLIp2xbMjX/k9/od7APpqq1ZgXXnV0pOL1Th3ZsL8Wu0TRtBsDTVS8iPqcfRFcHakFxPvR04OSTv2ka2qOb/2A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.973.16': + resolution: {integrity: sha512-IGihaJfFZYacJJr/odqILCoK7W/mvrZ7cuK7ECn3sAu4vLC6u0V8bS7mCGbdugJ8Aum2tnvqmx0F2MRFp2rn9g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.78': + resolution: {integrity: sha512-/y9WvNtlcPBGLR0qc1a+9J/xtYZfVczvLUOuXaVWylzttH7ewsxwHtjmiJSolNrVSDorIxHGHMU61CbonRkmwA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/eventstream-handler-node@3.972.35': + resolution: {integrity: sha512-a8xilRoRaalvSPZdfrs0VY3/BPc0uYhXW56Z/k6nmZ5Vk430LHeowf9APIPq8utM3tMJSNGSSuJMlB9YrPsN+A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-eventstream@3.972.30': + resolution: {integrity: sha512-B6gvZlcnRBNWraKgyEjKsbhv+VjtbyHmpU7hmtTHzXpDSxHPpCJnYLpglEOOsF+SFne20DbZC5IVC1aNr2Pb4A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-websocket@3.972.54': + resolution: {integrity: sha512-bhESdru8u8KosziH8jcVta/NM/dNreeRz2+2aU86si5bfBYOiJ6IiqD+9U4URUcU5WJO3Yw+jO3GLDIHlscXMQ==} + engines: {node: '>= 14.0.0'} + + '@aws-sdk/nested-clients@3.997.46': + resolution: {integrity: sha512-oRxtBcka/JGHGs9l9p9IVajGoTP8vTPmoAzdHGy4Qcy9P5vPnDf6nhIeM/COQNY9k/OahImTRaLkHftoXvfcmQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.996.47': + resolution: {integrity: sha512-Zk08macMvQTHzQJCLJVkOlviVoqwYMrpXv4lmLN7b7sAbiMoOK7Go0NYdR5UeF+MW8LIbRmwrNy9u/5VvX1U5g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1127.0': + resolution: {integrity: sha512-Dv2TMWBshJ+tF6ahs2Sy5bh4Iabsd4GAQqVvE9XZmYmnoaVbpS2QKIKE/HRacc7bTtbjEEvP+laGzHvHlf1CiQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1138.0': + resolution: {integrity: sha512-GpyAr0DD63YOEmYFM6Df+gJuIgC92MMTiBK4FTKfxii5MJ9ge20epR7LyroulscYlG89J+ZB2ivFDPjvfQhzdw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.974.6': + resolution: {integrity: sha512-v/clNZzZnDxGyvpHMOGpJKVXFAExJzUNAAjaWGdcx8QAcXLGwTaOkw33p5SHAi0YAioK32xB3hWwOekRVfmfKg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/xml-builder@3.972.41': + resolution: {integrity: sha512-ctjVSyCMegrWfXlx6VqzSBFI6UqmQ5ZlnfMhdLIiWmhoH8UAQxSCP5N3OpG7X3k4LnS7ou74C4mt20+bfTW2aQ==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.3.0': + resolution: {integrity: sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==} + engines: {node: '>=18.0.0'} + '@babel/code-frame@7.29.7': resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} @@ -165,6 +260,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + '@babel/template@7.29.7': resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} @@ -183,6 +282,32 @@ packages: '@cacheable/utils@2.5.0': resolution: {integrity: sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==} + '@earendil-works/chord@0.87.1': + resolution: {integrity: sha512-bg7IkJGFcEaMqqYgOGUiq5Ky9RghpRfrlZ8I/v/1b4bBZ02A7t3E+6uhPRbadwWb/kWsnVFbZsqOKRN4a3LLCg==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-agent-core@0.87.1': + resolution: {integrity: sha512-Zev3B0HK7YS5A4EZQ2XnEqiJuirx6QBiltJ+LpmjV5a/+2IU0cfKtIfnkNkORK707XOvKBY2WRtk7cAwHpbh2Q==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-ai@0.87.1': + resolution: {integrity: sha512-X/3PfQBnnoeVdO9Cv8zHghUMglzlgNZYGNzoPnbRoGnHl3Rw3TlA2UKSUB7BRHUOxMryHXYa8dnjWZlbRheDZA==} + engines: {node: '>=22.19.0'} + hasBin: true + + '@earendil-works/pi-coding-agent@0.87.1': + resolution: {integrity: sha512-m8ArJUtVcQMSe1lLE/Ei7vX/JV7O39sWmWBsXV2NOU70F0qCp8GubA24pT3LnwTmM6LL2xV80/h6sQg85n69ew==} + engines: {node: '>=22.19.0'} + hasBin: true + + '@earendil-works/pi-telemetry@0.87.1': + resolution: {integrity: sha512-MC6TRQH5lgMXpcN+Vku2WMI2T8BsiUPzMQHGo81uqFZD3/9O79WWJAysEDGuzduP6R4tvtgwMLwmqIxynM10JQ==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-tui@0.87.1': + resolution: {integrity: sha512-YEH2vRyOeiO7hhN6j6AE6YwKSq2Kz2f3XR8bj1TbR+aGE/JsnY1hLPMI2pvaZfRM1n9Y00tejxFQ4zbzvF7nkQ==} + engines: {node: '>=22.19.0'} + '@esbuild/aix-ppc64@0.28.2': resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} engines: {node: '>=18'} @@ -378,6 +503,15 @@ packages: resolution: {integrity: sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@google/genai@2.21.0': + resolution: {integrity: sha512-+PDtco2/Z0ONdzCGekCoCT+O1VJS9xJQNN4XzQpXG/t3El/SWWMkCWlFRO1KmivOHPa4Q0VjUYu1HBKCZ/v33Q==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.25.2 + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -430,6 +564,33 @@ packages: os: [linux] libc: [glibc] + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.1': + resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.2': + resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} + '@rolldown/pluginutils@1.0.0-rc.3': resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} @@ -571,6 +732,36 @@ packages: cpu: [x64] os: [win32] + '@silvia-odwyer/photon-node@0.3.4': + resolution: {integrity: sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==} + + '@smithy/core@3.35.0': + resolution: {integrity: sha512-zRMhfkByhT2snNdr1si24vJitU6Cr9ix2MikUfWmkAgp4jrNP0GcKSP5YvwQ+TlI8AZXER5QOGJn3JsVtSD9/A==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.5.2': + resolution: {integrity: sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.8.0': + resolution: {integrity: sha512-ycSJu3tFAQ4v04CBB0agqFMVsSQ1iG3yw+SpgxRqKfaURpQD4CZ8Wn0zPMmSnOuTpTh65Vz+EA0rMrw089wvkA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.12.1': + resolution: {integrity: sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.7.4': + resolution: {integrity: sha512-tHy0K0VtqNd5Y7Y41h0a0Lhh0L1GzC08dTWg0F7vRJWFtTENg7IZikf3wQkanYIRdb7ngoIPMTmqgUi401fEeQ==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.19.0': + resolution: {integrity: sha512-r7jh49VJxGerfAcTQA6gXcKc+98zOp/tqRwzYjgOE+iSQsP6cEU1hq2QzbuipmP68QtYdY9wKEhiCQZIzHgZ4Q==} + engines: {node: '>=18.0.0'} + + '@stablelib/base64@1.0.1': + resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -603,6 +794,9 @@ packages: '@types/react@19.3.0': resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==} + '@types/retry@0.12.0': + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + '@typescript-eslint/eslint-plugin@8.70.1': resolution: {integrity: sha512-nDNrUQ/4ruSNYbu749TRY7cfrzPtoLHEXSNBI8aaNY32LlZCajixqRf3FqcKC4p5Cam4VOHYx/t+i5+nKXvrqA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -678,6 +872,14 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + agent-base@9.0.0: + resolution: {integrity: sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==} + engines: {node: '>= 20'} + ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} @@ -688,11 +890,20 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + baseline-browser-mapping@2.11.25: resolution: {integrity: sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw==} engines: {node: '>=6.0.0'} hasBin: true + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + brace-expansion@5.0.12: resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} engines: {node: 20 || >=22} @@ -702,12 +913,19 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + cacheable@2.5.0: resolution: {integrity: sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==} caniuse-lite@1.0.30001810: resolution: {integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==} + chalk@6.0.0: + resolution: {integrity: sha512-2uNTXIuTTxk7ciZgAU1BQcgnchcG0xXnrs6jzkQfj9SsRa9M2s5zE8WT96hS6KmG4MzWHSrvH43DF1m4XRkrFg==} + engines: {node: '>=22'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -718,6 +936,10 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -734,6 +956,13 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + electron-to-chromium@1.5.437: resolution: {integrity: sha512-1z60R0Nb+kYPnGUrQ6PvMjTVINDGMfqQZ/mI5FJIHvTotlA6noI+YJWakbjaFM+qhLXg9WnK3RUeYSO5ixSHJA==} @@ -792,6 +1021,9 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -801,6 +1033,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-sha256@1.3.0: + resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} + fast-uri@3.1.8: resolution: {integrity: sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==} @@ -813,6 +1048,10 @@ packages: picomatch: optional: true + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + file-entry-cache@11.1.5: resolution: {integrity: sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==} @@ -826,29 +1065,79 @@ packages: flatted@3.4.4: resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + gaxios@7.3.1: + resolution: {integrity: sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ==} + engines: {node: '>=18'} + + gcp-metadata@8.1.2: + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} + engines: {node: '>=18'} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + google-auth-library@10.9.1: + resolution: {integrity: sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==} + engines: {node: '>=18'} + + google-logging-utils@1.1.3: + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} + engines: {node: '>=14'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + grok-mermaid@0.2.3: + resolution: {integrity: sha512-/4KopAbsjvuRP9MdPtlDjOHUmUVEohOX73JNcsWpzAtFxh+bq5+Dhb6gzvRieLDwIPQIR3/vy8V1NNTuz4Zsmg==} + engines: {node: '>=18'} + hashery@1.5.1: resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==} engines: {node: '>=20'} + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + hookified@1.15.1: resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==} hookified@2.2.0: resolution: {integrity: sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==} + hosted-git-info@9.0.3: + resolution: {integrity: sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==} + engines: {node: ^20.17.0 || >=22.9.0} + + http-proxy-agent@9.1.0: + resolution: {integrity: sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig==} + engines: {node: '>= 20'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + https-proxy-agent@9.1.0: + resolution: {integrity: sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==} + engines: {node: '>= 20'} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -857,6 +1146,10 @@ packages: resolution: {integrity: sha512-HpbUakT7xp5miBUywCHf36ZEuAJNklBJDDsGpUIjMzOSmM8ELSfA9Sa/QDPeNeqeoN31u+UTCkL4klCOVvRm4Q==} engines: {node: '>= 4'} + ignore@7.0.8: + resolution: {integrity: sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==} + engines: {node: '>= 4'} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -872,6 +1165,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -880,6 +1177,13 @@ packages: engines: {node: '>=6'} hasBin: true + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + + json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -894,6 +1198,12 @@ packages: engines: {node: '>=6'} hasBin: true + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + keyv@5.6.0: resolution: {integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==} @@ -979,9 +1289,21 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + lru-cache@11.5.3: + resolution: {integrity: sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + marked@18.0.11: + resolution: {integrity: sha512-HnslJfsZkRPBDJRHvVtAaWlZHEpSu7u8LgQuJCELjRKuWR+hpq4A7sLq3p8HaI9ypVoXDXxV34CsQJEe1+J5Aw==} + engines: {node: '>= 20'} + hasBin: true + minimatch@10.2.6: resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} engines: {node: 18 || 20 || >=22} @@ -997,10 +1319,30 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-releases@2.0.56: resolution: {integrity: sha512-x0InOIyzgdk+eyaWaRJFH5snEtiImgBgblZ2CyPrLmqqcuMQkEvcDPHbzqbD8eDsSeJbVOjn+crzyzHaM4D+/A==} engines: {node: '>=18'} + openai@6.40.0: + resolution: {integrity: sha512-MWtTjd/gQt4jpbji61NTgFWJLoY/PdRJ6wG9/ZDRMYNMlBKrCrSlkLI+KgHP1vR1qT6LKSAyAqIxno6lcK9JiA==} + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1013,6 +1355,13 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + + partial-json@0.1.7: + resolution: {integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -1041,6 +1390,22 @@ packages: engines: {node: '>=14'} hasBin: true + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + + protobufjs@7.6.6: + resolution: {integrity: sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg==} + engines: {node: '>=12.0.0'} + + proxy-agent-negotiate@1.1.0: + resolution: {integrity: sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==} + engines: {node: '>= 20'} + peerDependencies: + kerberos: ^2.0.0 + peerDependenciesMeta: + kerberos: + optional: true + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1066,11 +1431,22 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + rollup@4.63.4: resolution: {integrity: sha512-4U0liVayNIoLp3GFl1FcI8561WepLnZ1rqfraGh7S9B3Ur5F9S283y8Futii7RUU2C/97tOBmBy7nYvhoiOpbQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + scheduler@0.28.0: resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==} @@ -1091,24 +1467,39 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + standardwebhooks@1.1.1: + resolution: {integrity: sha512-bCbX9ZEyFkWPsRz7Bl3NuQUJohmwGSev/yhr7vhaGPlc4AfIrspIRa6cPTBuI1ItmrTDJ4d/S2hCsfe4+vQGnQ==} + tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} + ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + typebox@1.3.27: + resolution: {integrity: sha512-zu+jc1pcy4UiNThxikUr36f0Rybk9PEeCg/NE6adeWr/SKsdNO4EzZHYRDlv2YCVAfj3Odq3dESSo/jNyoBXzA==} + typescript-eslint@8.70.1: resolution: {integrity: sha512-AcWG7KDjZ2THNXsgwttMaGmzVi0VFRlFYfqFHYQRbDpF3owuYbuiL8c7UUrd2k8s3PoSfIQrWfrGXfcElrWLYA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1124,6 +1515,10 @@ packages: undici-types@8.9.0: resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==} + undici@8.10.2: + resolution: {integrity: sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==} + engines: {node: '>=22.19.0'} + update-browserslist-db@1.3.3: resolution: {integrity: sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==} hasBin: true @@ -1173,6 +1568,10 @@ packages: yaml: optional: true + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1182,15 +1581,219 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + ws@8.22.0: + resolution: {integrity: sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} snapshots: + '@anthropic-ai/sdk@0.124.0': + dependencies: + json-schema-to-ts: 3.1.1 + standardwebhooks: 1.1.1 + + '@aws-sdk/client-bedrock-runtime@3.1127.0': + dependencies: + '@aws-sdk/core': 3.978.1 + '@aws-sdk/credential-provider-node': 3.972.84 + '@aws-sdk/eventstream-handler-node': 3.972.35 + '@aws-sdk/middleware-eventstream': 3.972.30 + '@aws-sdk/middleware-websocket': 3.972.54 + '@aws-sdk/token-providers': 3.1127.0 + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/node-http-handler': 4.12.1 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/core@3.978.1': + dependencies: + '@aws-sdk/types': 3.974.6 + '@aws-sdk/xml-builder': 3.972.41 + '@aws/lambda-invoke-store': 0.3.0 + '@smithy/core': 3.35.0 + '@smithy/signature-v4': 5.7.4 + '@smithy/types': 4.19.0 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.72': + dependencies: + '@aws-sdk/core': 3.978.1 + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.74': + dependencies: + '@aws-sdk/core': 3.978.1 + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/node-http-handler': 4.12.1 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.973.17': + dependencies: + '@aws-sdk/core': 3.978.1 + '@aws-sdk/credential-provider-env': 3.972.72 + '@aws-sdk/credential-provider-http': 3.972.74 + '@aws-sdk/credential-provider-login': 3.972.79 + '@aws-sdk/credential-provider-process': 3.972.72 + '@aws-sdk/credential-provider-sso': 3.973.16 + '@aws-sdk/credential-provider-web-identity': 3.972.78 + '@aws-sdk/nested-clients': 3.997.46 + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/credential-provider-imds': 4.5.2 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-login@3.972.79': + dependencies: + '@aws-sdk/core': 3.978.1 + '@aws-sdk/nested-clients': 3.997.46 + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-node@3.972.84': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.72 + '@aws-sdk/credential-provider-http': 3.972.74 + '@aws-sdk/credential-provider-ini': 3.973.17 + '@aws-sdk/credential-provider-process': 3.972.72 + '@aws-sdk/credential-provider-sso': 3.973.16 + '@aws-sdk/credential-provider-web-identity': 3.972.78 + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/credential-provider-imds': 4.5.2 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-process@3.972.72': + dependencies: + '@aws-sdk/core': 3.978.1 + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.973.16': + dependencies: + '@aws-sdk/core': 3.978.1 + '@aws-sdk/nested-clients': 3.997.46 + '@aws-sdk/token-providers': 3.1138.0 + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-web-identity@3.972.78': + dependencies: + '@aws-sdk/core': 3.978.1 + '@aws-sdk/nested-clients': 3.997.46 + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/eventstream-handler-node@3.972.35': + dependencies: + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-eventstream@3.972.30': + dependencies: + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-websocket@3.972.54': + dependencies: + '@aws-sdk/core': 3.978.1 + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/signature-v4': 5.7.4 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.997.46': + dependencies: + '@aws-sdk/core': 3.978.1 + '@aws-sdk/signature-v4-multi-region': 3.996.47 + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/node-http-handler': 4.12.1 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.996.47': + dependencies: + '@aws-sdk/types': 3.974.6 + '@smithy/signature-v4': 5.7.4 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1127.0': + dependencies: + '@aws-sdk/core': 3.978.1 + '@aws-sdk/nested-clients': 3.997.46 + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1138.0': + dependencies: + '@aws-sdk/core': 3.978.1 + '@aws-sdk/nested-clients': 3.997.46 + '@aws-sdk/types': 3.974.6 + '@smithy/core': 3.35.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/types@3.974.6': + dependencies: + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.41': + dependencies: + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.3.0': {} + '@babel/code-frame@7.29.7': dependencies: '@babel/helper-validator-identifier': 7.29.7 @@ -1280,6 +1883,8 @@ snapshots: '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 + '@babel/runtime@7.29.7': {} + '@babel/template@7.29.7': dependencies: '@babel/code-frame': 7.29.7 @@ -1315,6 +1920,86 @@ snapshots: hashery: 1.5.1 keyv: 5.6.0 + '@earendil-works/chord@0.87.1': + dependencies: + esbuild: 0.28.2 + + '@earendil-works/pi-agent-core@0.87.1(ws@8.22.0)': + dependencies: + '@earendil-works/chord': 0.87.1 + '@earendil-works/pi-ai': 0.87.1(ws@8.22.0) + '@earendil-works/pi-telemetry': 0.87.1 + diff: 8.0.4 + ignore: 7.0.8 + typebox: 1.3.27 + yaml: 2.9.0 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - kerberos + - supports-color + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-ai@0.87.1(ws@8.22.0)': + dependencies: + '@anthropic-ai/sdk': 0.124.0 + '@aws-sdk/client-bedrock-runtime': 3.1127.0 + '@earendil-works/pi-telemetry': 0.87.1 + '@google/genai': 2.21.0 + '@smithy/node-http-handler': 4.12.1 + http-proxy-agent: 9.1.0 + https-proxy-agent: 9.1.0 + openai: 6.40.0(ws@8.22.0) + partial-json: 0.1.7 + typebox: 1.3.27 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - kerberos + - supports-color + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-coding-agent@0.87.1(ws@8.22.0)': + dependencies: + '@earendil-works/chord': 0.87.1 + '@earendil-works/pi-agent-core': 0.87.1(ws@8.22.0) + '@earendil-works/pi-ai': 0.87.1(ws@8.22.0) + '@earendil-works/pi-tui': 0.87.1 + '@silvia-odwyer/photon-node': 0.3.4 + chalk: 6.0.0 + cross-spawn: 7.0.6 + diff: 8.0.4 + grok-mermaid: 0.2.3 + highlight.js: 10.7.3 + hosted-git-info: 9.0.3 + ignore: 7.0.8 + jiti: 2.7.0 + minimatch: 10.2.6 + proper-lockfile: 4.1.2 + semver: 7.8.5 + typebox: 1.3.27 + undici: 8.10.2 + yaml: 2.9.0 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - kerberos + - supports-color + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-telemetry@0.87.1': {} + + '@earendil-works/pi-tui@0.87.1': + dependencies: + get-east-asian-width: 1.6.0 + marked: 18.0.11 + '@esbuild/aix-ppc64@0.28.2': optional: true @@ -1393,9 +2078,9 @@ snapshots: '@esbuild/win32-x64@0.28.2': optional: true - '@eslint-community/eslint-utils@4.10.1(eslint@10.11.0)': + '@eslint-community/eslint-utils@4.10.1(eslint@10.11.0(jiti@2.7.0))': dependencies: - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -1416,9 +2101,9 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.11.0)': + '@eslint/js@10.0.1(eslint@10.11.0(jiti@2.7.0))': optionalDependencies: - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) '@eslint/object-schema@3.0.5': {} @@ -1427,6 +2112,17 @@ snapshots: '@eslint/core': 1.2.1 levn: 0.4.1 + '@google/genai@2.21.0': + dependencies: + google-auth-library: 10.9.1 + p-retry: 4.6.2 + protobufjs: 7.6.6 + ws: 8.22.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 @@ -1473,6 +2169,26 @@ snapshots: '@napi-rs/lzma-linux-x64-gnu@1.5.1': optional: true + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.1': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.2': {} + '@rolldown/pluginutils@1.0.0-rc.3': {} '@rollup/rollup-android-arm-eabi@4.63.4': @@ -1550,6 +2266,43 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.63.4': optional: true + '@silvia-odwyer/photon-node@0.3.4': {} + + '@smithy/core@3.35.0': + dependencies: + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.5.2': + dependencies: + '@smithy/core': 3.35.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.8.0': + dependencies: + '@smithy/core': 3.35.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.12.1': + dependencies: + '@smithy/core': 3.35.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.7.4': + dependencies: + '@smithy/core': 3.35.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@smithy/types@4.19.0': + dependencies: + tslib: 2.8.1 + + '@stablelib/base64@1.0.1': {} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.29.9 @@ -1589,15 +2342,17 @@ snapshots: dependencies: csstype: 3.2.3 - '@typescript-eslint/eslint-plugin@8.70.1(@typescript-eslint/parser@8.70.1(eslint@10.11.0)(typescript@6.0.3))(eslint@10.11.0)(typescript@6.0.3)': + '@types/retry@0.12.0': {} + + '@typescript-eslint/eslint-plugin@8.70.1(@typescript-eslint/parser@8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.70.1(eslint@10.11.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.70.1 - '@typescript-eslint/type-utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) + '@typescript-eslint/type-utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.70.1 - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) ignore: 7.0.10 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) @@ -1605,14 +2360,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.70.1(eslint@10.11.0)(typescript@6.0.3)': + '@typescript-eslint/parser@8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.70.1 '@typescript-eslint/types': 8.70.1 '@typescript-eslint/typescript-estree': 8.70.1(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.70.1 debug: 4.4.3 - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -1635,13 +2390,13 @@ snapshots: dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.70.1(eslint@10.11.0)(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.70.1 '@typescript-eslint/typescript-estree': 8.70.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) debug: 4.4.3 - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: @@ -1664,13 +2419,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.70.1(eslint@10.11.0)(typescript@6.0.3)': + '@typescript-eslint/utils@8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.10.1(eslint@10.11.0) + '@eslint-community/eslint-utils': 4.10.1(eslint@10.11.0(jiti@2.7.0)) '@typescript-eslint/scope-manager': 8.70.1 '@typescript-eslint/types': 8.70.1 '@typescript-eslint/typescript-estree': 8.70.1(typescript@6.0.3) - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -1680,7 +2435,7 @@ snapshots: '@typescript-eslint/types': 8.70.1 eslint-visitor-keys: 5.0.1 - '@vitejs/plugin-react@5.2.0(vite@7.3.6(@types/node@26.6.2)(lightningcss@1.33.0))': + '@vitejs/plugin-react@5.2.0(vite@7.3.6(@types/node@26.6.2)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7 '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) @@ -1688,7 +2443,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-rc.3 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.3.6(@types/node@26.6.2)(lightningcss@1.33.0) + vite: 7.3.6(@types/node@26.6.2)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0) transitivePeerDependencies: - supports-color @@ -1698,6 +2453,10 @@ snapshots: acorn@8.18.0: {} + agent-base@7.1.4: {} + + agent-base@9.0.0: {} + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 @@ -1714,8 +2473,14 @@ snapshots: balanced-match@4.0.4: {} + base64-js@1.5.1: {} + baseline-browser-mapping@2.11.25: {} + bignumber.js@9.3.1: {} + + bowser@2.14.1: {} + brace-expansion@5.0.12: dependencies: balanced-match: 4.0.4 @@ -1728,6 +2493,8 @@ snapshots: node-releases: 2.0.56 update-browserslist-db: 1.3.3(browserslist@4.29.0) + buffer-equal-constant-time@1.0.1: {} + cacheable@2.5.0: dependencies: '@cacheable/memory': 2.2.0 @@ -1738,6 +2505,8 @@ snapshots: caniuse-lite@1.0.30001810: {} + chalk@6.0.0: {} + convert-source-map@2.0.0: {} cross-spawn@7.0.6: @@ -1748,6 +2517,8 @@ snapshots: csstype@3.2.3: {} + data-uri-to-buffer@4.0.1: {} + debug@4.4.3: dependencies: ms: 2.1.3 @@ -1757,6 +2528,12 @@ snapshots: detect-libc@2.1.2: optional: true + diff@8.0.4: {} + + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + electron-to-chromium@1.5.437: {} esbuild@0.28.2: @@ -1803,9 +2580,9 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.11.0: + eslint@10.11.0(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.10.1(eslint@10.11.0) + '@eslint-community/eslint-utils': 4.10.1(eslint@10.11.0(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.5 '@eslint/config-helpers': 0.7.0 @@ -1835,6 +2612,8 @@ snapshots: minimatch: 10.2.6 natural-compare: 1.4.0 optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 transitivePeerDependencies: - supports-color @@ -1856,18 +2635,27 @@ snapshots: esutils@2.0.3: {} + extend@3.0.2: {} + fast-deep-equal@3.1.3: {} fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} + fast-sha256@1.3.0: {} + fast-uri@3.1.8: {} fdir@6.5.0(picomatch@4.0.7): optionalDependencies: picomatch: 4.0.7 + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + file-entry-cache@11.1.5: dependencies: flat-cache: 6.1.23 @@ -1885,27 +2673,99 @@ snapshots: flatted@3.4.4: {} + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + fsevents@2.3.3: optional: true + gaxios@7.3.1: + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + transitivePeerDependencies: + - supports-color + + gcp-metadata@8.1.2: + dependencies: + gaxios: 7.3.1 + google-logging-utils: 1.1.3 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + gensync@1.0.0-beta.2: {} + get-east-asian-width@1.6.0: {} + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 + google-auth-library@10.9.1: + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.3.1 + gcp-metadata: 8.1.2 + google-logging-utils: 1.1.3 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + + google-logging-utils@1.1.3: {} + + graceful-fs@4.2.11: {} + + grok-mermaid@0.2.3: {} + hashery@1.5.1: dependencies: hookified: 1.15.1 + highlight.js@10.7.3: {} + hookified@1.15.1: {} hookified@2.2.0: {} + hosted-git-info@9.0.3: + dependencies: + lru-cache: 11.5.3 + + http-proxy-agent@9.1.0: + dependencies: + agent-base: 9.0.0 + debug: 4.4.3 + proxy-agent-negotiate: 1.1.0 + transitivePeerDependencies: + - kerberos + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@9.1.0: + dependencies: + agent-base: 9.0.0 + debug: 4.4.3 + proxy-agent-negotiate: 1.1.0 + transitivePeerDependencies: + - kerberos + - supports-color + ignore@5.3.2: {} ignore@7.0.10: {} + ignore@7.0.8: {} + imurmurhash@0.1.4: {} is-extglob@2.1.1: {} @@ -1916,10 +2776,21 @@ snapshots: isexe@2.0.0: {} + jiti@2.7.0: {} + js-tokens@4.0.0: {} jsesc@3.1.0: {} + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + + json-schema-to-ts@3.1.1: + dependencies: + '@babel/runtime': 7.29.7 + ts-algebra: 2.0.0 + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} @@ -1928,6 +2799,17 @@ snapshots: json5@2.2.3: {} + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@4.0.1: + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + keyv@5.6.0: dependencies: '@keyv/serialize': 1.1.1 @@ -1991,10 +2873,16 @@ snapshots: dependencies: p-locate: 5.0.0 + long@5.3.2: {} + + lru-cache@11.5.3: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 + marked@18.0.11: {} + minimatch@10.2.6: dependencies: brace-expansion: 5.0.12 @@ -2005,8 +2893,20 @@ snapshots: natural-compare@1.4.0: {} + node-domexception@1.0.0: {} + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-releases@2.0.56: {} + openai@6.40.0(ws@8.22.0): + optionalDependencies: + ws: 8.22.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -2024,6 +2924,13 @@ snapshots: dependencies: p-limit: 3.1.0 + p-retry@4.6.2: + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + + partial-json@0.1.7: {} + path-exists@4.0.0: {} path-key@3.1.1: {} @@ -2042,6 +2949,28 @@ snapshots: prettier@3.9.9: {} + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + + protobufjs@7.6.6: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.2 + '@types/node': 26.6.2 + long: 5.3.2 + + proxy-agent-negotiate@1.1.0: {} + punycode@2.3.1: {} qified@0.10.1: @@ -2059,6 +2988,10 @@ snapshots: require-from-string@2.0.2: {} + retry@0.12.0: {} + + retry@0.13.1: {} + rollup@4.63.4: dependencies: '@types/estree': 1.0.9 @@ -2091,6 +3024,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.63.4 fsevents: 2.3.3 + safe-buffer@5.2.1: {} + scheduler@0.28.0: {} semver@6.3.1: {} @@ -2103,28 +3038,41 @@ snapshots: shebang-regex@3.0.0: {} + signal-exit@3.0.7: {} + source-map-js@1.2.1: {} + standardwebhooks@1.1.1: + dependencies: + '@stablelib/base64': 1.0.1 + fast-sha256: 1.3.0 + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.7) picomatch: 4.0.7 + ts-algebra@2.0.0: {} + ts-api-utils@2.5.0(typescript@6.0.3): dependencies: typescript: 6.0.3 + tslib@2.8.1: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.70.1(eslint@10.11.0)(typescript@6.0.3): + typebox@1.3.27: {} + + typescript-eslint@8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.70.1(@typescript-eslint/parser@8.70.1(eslint@10.11.0)(typescript@6.0.3))(eslint@10.11.0)(typescript@6.0.3) - '@typescript-eslint/parser': 8.70.1(eslint@10.11.0)(typescript@6.0.3) + '@typescript-eslint/eslint-plugin': 8.70.1(@typescript-eslint/parser@8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.70.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - eslint: 10.11.0 + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.11.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -2133,6 +3081,8 @@ snapshots: undici-types@8.9.0: {} + undici@8.10.2: {} + update-browserslist-db@1.3.3(browserslist@4.29.0): dependencies: browserslist: 4.29.0 @@ -2143,7 +3093,7 @@ snapshots: dependencies: punycode: 2.3.1 - vite@7.3.6(@types/node@26.6.2)(lightningcss@1.33.0): + vite@7.3.6(@types/node@26.6.2)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0): dependencies: esbuild: 0.28.2 fdir: 6.5.0(picomatch@4.0.7) @@ -2154,7 +3104,11 @@ snapshots: optionalDependencies: '@types/node': 26.6.2 fsevents: 2.3.3 + jiti: 2.7.0 lightningcss: 1.33.0 + yaml: 2.9.0 + + web-streams-polyfill@3.3.3: {} which@2.0.2: dependencies: @@ -2162,6 +3116,10 @@ snapshots: word-wrap@1.2.5: {} + ws@8.22.0: {} + yallist@3.1.1: {} + yaml@2.9.0: {} + yocto-queue@0.1.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4e2e70b..c2f8ba5 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,4 +9,7 @@ packages: # pnpm 11:允许执行安装脚本的依赖。esbuild 是 vite 的构建依赖,需要 postinstall。 allowBuilds: - esbuild: true \ No newline at end of file + # Pi 依赖链带 postinstall;装它们是 Pi 官方推荐的接入方式(ADR-0006) + '@google/genai': true + esbuild: true + protobufjs: true diff --git a/scripts/config.test.mjs b/scripts/config.test.mjs index 5a1237d..24dc916 100644 --- a/scripts/config.test.mjs +++ b/scripts/config.test.mjs @@ -81,4 +81,20 @@ test('配置文件损坏时报错,不静默降级', async () => { test('配置文件路径:默认在用户目录,可用 APS_CONFIG_FILE 覆盖', () => { assert.equal(configFilePath({ env: {}, homeDir: 'C:/Users/test' }).replace(/\\/g, '/'), 'C:/Users/test/.aps/config.json'); assert.equal(configFilePath({ env: { APS_CONFIG_FILE: 'D:/cfg/aps.json' }, homeDir: 'C:/Users/test' }), 'D:/cfg/aps.json'); +}); + +test('引擎选择:没密钥用假引擎,有密钥自动选 Pi,可显式覆盖', async () => { + await withConfigFile(undefined, async ({ dir, file }) => { + const noKey = loadConfig({ env: { APS_CONFIG_FILE: file }, homeDir: dir }); + assert.equal(noKey.engine.kind, 'fake', '没有密钥时应回退到假引擎'); + }); + + const content = JSON.stringify({ llm: { apiKey: 'sk-file-123' } }); + await withConfigFile(content, async ({ dir, file }) => { + const withKey = loadConfig({ env: { APS_CONFIG_FILE: file }, homeDir: dir }); + assert.equal(withKey.engine.kind, 'pi', '有密钥时应自动选 Pi'); + + const forced = loadConfig({ env: { APS_CONFIG_FILE: file, APS_ENGINE: 'fake' }, homeDir: dir }); + assert.equal(forced.engine.kind, 'fake', '显式配置应覆盖自动选择'); + }); }); \ No newline at end of file diff --git a/scripts/pi-probe.mjs b/scripts/pi-probe.mjs new file mode 100644 index 0000000..c706bb3 --- /dev/null +++ b/scripts/pi-probe.mjs @@ -0,0 +1,29 @@ +#!/usr/bin/env node +/** + * Pi 子进程接线探测(开发用)。 + * + * 拉起 Pi、发一句话、把映射后的事件打出来。没有配置密钥时也能跑: + * 它会走到"模型不可用",正好用来验证进程、协议与错误映射这三段接线。 + * + * 用法:node scripts/pi-probe.mjs [提问] + */ +import { createPiRuntime } from '@aps/server/agent/pi/runtime'; + +const prompt = process.argv[2] ?? '用一句话回答:1+1 等于几'; +const runtime = createPiRuntime({ provider: process.env.APS_LLM_PROVIDER ?? 'deepseek', model: process.env.APS_LLM_MODEL ?? 'deepseek-chat', apiKey: process.env.APS_LLM_API_KEY ?? '', turnTimeoutMs: 30_000 }); + +console.log(`引擎:${runtime.name}`); +const session = await runtime.createSession({ sessionId: 'probe-1', subject: { userId: 'probe', tenantId: 'probe' }, projectId: null, tools: [] }); +console.log(`会话已创建:${session.id}`); + +const controller = new AbortController(); +const started = Date.now(); +try { + for await (const event of session.send(prompt, { signal: controller.signal })) { + console.log(`[${String(Date.now() - started).padStart(5)}ms] ${event.type}`, JSON.stringify(event).slice(0, 260)); + if (event.type === 'turn_end') break; + } +} finally { + await session.dispose(); + console.log('子进程已停止'); +} \ No newline at end of file diff --git a/scripts/pi-runtime.test.mjs b/scripts/pi-runtime.test.mjs new file mode 100644 index 0000000..9ccb8b7 --- /dev/null +++ b/scripts/pi-runtime.test.mjs @@ -0,0 +1,72 @@ +/** + * Pi 运行时用例(任务 A3.3)。 + * + * 1. 未配置密钥时必须快速失败并给出指引(不是静默挂住) + * 2. 真实跑一轮:需要 APS_PI_INTEGRATION=1 且提供密钥(网络调用,默认跳过) + * —— 密钥有效时断言收到文本;无效时断言错误被归到六分类之一;两者都必须以 turn_end 收尾 + */ +import assert from 'node:assert/strict'; +import { test } from 'node:test'; + +import { classifyPiFailure } from '@aps/server/agent/pi/runtime'; + +const integrationEnabled = process.env.APS_PI_INTEGRATION === '1'; +const apiKey = process.env.APS_LLM_API_KEY ?? process.env.DEEPSEEK_API_KEY ?? ''; + +test('未配置模型密钥时快速失败并给出配置指引', async () => { + // 环境变量也算配置来源,这里临时清掉,确保「真的没有密钥」 + const saved = process.env.DEEPSEEK_API_KEY; + delete process.env.DEEPSEEK_API_KEY; + try { + const { createPiRuntime } = await import('@aps/server/agent/pi/runtime'); + const runtime = createPiRuntime({ provider: 'deepseek', model: 'deepseek-chat', apiKey: '' }); + await assert.rejects( + () => runtime.createSession({ sessionId: 'no-key', subject: { userId: 'u', tenantId: 't' }, projectId: null, tools: [] }), + /未配置模型密钥/, + ); + } finally { + if (saved !== undefined) process.env.DEEPSEEK_API_KEY = saved; + } +}); + +test('错误文本按六分类归一', () => { + assert.equal(classifyPiFailure('401: Authentication Fails'), 'forbidden'); + assert.equal(classifyPiFailure('429 rate limit exceeded'), 'rate_limited'); + assert.equal(classifyPiFailure('connect ETIMEDOUT'), 'unavailable'); + assert.equal(classifyPiFailure('something odd'), 'unavailable'); +}); + +test('真实跑一轮:Pi 子进程接入', { skip: !integrationEnabled ? '需要 APS_PI_INTEGRATION=1 与密钥(会真实调用模型)' : false }, async () => { + const { createPiRuntime } = await import('@aps/server/agent/pi/runtime'); + const runtime = createPiRuntime({ provider: 'deepseek', model: 'deepseek-chat', apiKey, turnTimeoutMs: 60_000 }); + const session = await runtime.createSession({ + sessionId: `it-${Date.now()}`, + subject: { userId: 'it', tenantId: 'it' }, + projectId: null, + tools: [], + }); + + const events = []; + try { + for await (const event of session.send('只用一句话回答:1+1 等于几')) { + events.push(event); + if (event.type === 'turn_end') break; + } + } finally { + await session.dispose(); + } + + const types = events.map((event) => event.type); + assert.ok(types.includes('turn_end'), `必须以 turn_end 收尾,实际:${types.join(',')}`); + const failed = events.find((event) => event.type === 'error'); + const text = events.filter((event) => event.type === 'text').map((event) => event.delta).join(''); + if (failed) { + assert.ok( + ['invalid_argument', 'forbidden', 'conflict', 'rate_limited', 'unavailable', 'unknown_result'].includes(failed.kind), + `错误分类必须合法,实际 ${failed.kind}`, + ); + console.log(`(本轮模型调用失败,已按 ${failed.kind} 归一)`); + } else { + assert.ok(text.length > 0 || types.includes('message_end'), `既没有文本也没有错误,事件:${types.join(',')}`); + } +}); \ No newline at end of file diff --git a/server/agent/pi/runtime.ts b/server/agent/pi/runtime.ts new file mode 100644 index 0000000..0fa8a26 --- /dev/null +++ b/server/agent/pi/runtime.ts @@ -0,0 +1,228 @@ +/** + * Pi 引擎适配(任务 A3.3,ADR-0006):把 Pi 作为长驻子进程驱动。 + * + * - 用官方 RpcClient 拉起 `pi --mode rpc`,协议是标准输入输出的 JSONL + * - 工具面:启动参数带 --no-builtin-tools / --no-extensions,Pi 自带的 read/bash/edit/write 全部关掉; + * 平台的工具由 Pi 侧扩展桥提供(A3.11),扩展还没接之前 Pi 手里没有工具(评测里对应场景跳过) + * - 事件面:把 Pi 的会话事件映射成平台的 RuntimeEvent,上层只认平台类型 + * - 状态:平台保存会话历史;Pi 自己的 session 文件放在平台管理目录里,只作同引擎恢复用(ADR-0003) + */ +import { existsSync } from 'node:fs'; +import { homedir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { RpcClient, type JsonAgentSessionEvent } from '@earendil-works/pi-coding-agent'; +import type { ExecutionReceipt } from '@aps/contracts'; + +import type { AgentRuntime, CreateRuntimeSessionInput, RuntimeEvent, RuntimeSession, SendOptions } from '../runtime.js'; + +export interface PiRuntimeOptions { + provider?: string; + model?: string; + apiKey?: string; + cwd?: string; + cliPath?: string; + /** Pi 自己的会话文件目录(默认 ~/.aps/pi-sessions) */ + sessionDir?: string; + /** 额外的 CLI 参数,慎用:会覆盖不了默认的关闭项,只是追加 */ + extraArgs?: string[]; + /** 单回合最长等待(毫秒),超时按引擎错误处理 */ + turnTimeoutMs?: number; +} + +/** provider → 环境变量名:密钥走环境,不进命令行(命令行会被进程列表看到) */ +const API_KEY_ENV: Record = { + deepseek: 'DEEPSEEK_API_KEY', + openai: 'OPENAI_API_KEY', + anthropic: 'ANTHROPIC_API_KEY', + google: 'GEMINI_API_KEY', +}; + +const DEFAULT_TURN_TIMEOUT_MS = 120_000; +const POLL_MS = 25; + +/** + * RpcClient 默认找的是包里的 dist/cli.js,实际可执行入口在 dist/bundle/cli.js,必须显式给。 + * + * 三种取法依次尝试:ESM 解析(这个包的 exports 只声明了 import 条件,CJS 的 require.resolve 会失败)、 + * 仓库根下的包目录、server 包下的包目录。 + */ +function defaultCliPath(): string { + const candidates: string[] = []; + try { + const resolver = (import.meta as unknown as { resolve?: (specifier: string) => string }).resolve; + const resolved = resolver?.('@earendil-works/pi-coding-agent'); + if (resolved) candidates.push(join(dirname(fileURLToPath(resolved)), 'bundle', 'cli.js')); + } catch { + /* 落到下面的候选路径 */ + } + for (const root of [process.cwd(), join(process.cwd(), 'server')]) { + candidates.push(join(root, 'node_modules', '@earendil-works', 'pi-coding-agent', 'dist', 'bundle', 'cli.js')); + } + return candidates.find((candidate) => existsSync(candidate)) ?? ''; +} + +/** 把 Pi 的失败文本归到平台的六分类(实施设计 5) */ +export function classifyPiFailure(detail: string): 'forbidden' | 'rate_limited' | 'unavailable' | 'unknown_result' { + if (/401|403|auth|api key|unauthor/i.test(detail)) return 'forbidden'; + if (/429|rate.?limit|too many/i.test(detail)) return 'rate_limited'; + if (/timeout|ETIMEDOUT|ECONNRESET|ENOTFOUND|socket hang up/i.test(detail)) return 'unavailable'; + return 'unavailable'; +} + +/** Pi 的事件联合很宽,这里只映射平台需要的部分,其余忽略 */ +export function mapPiEvent(event: JsonAgentSessionEvent): RuntimeEvent[] { + const raw = event as unknown as Record; + const type = String(raw.type ?? ''); + + switch (type) { + case 'message_update': { + const inner = raw.assistantMessageEvent as Record | undefined; + if (inner && inner.type === 'text_delta' && typeof inner.delta === 'string') { + return [{ type: 'text', delta: inner.delta }]; + } + return []; + } + case 'tool_execution_start': + return [ + { + type: 'tool_call', + callId: String(raw.toolCallId ?? ''), + capabilityId: String(raw.toolName ?? ''), + args: raw.args, + }, + ]; + case 'tool_execution_end': { + const callId = String(raw.toolCallId ?? ''); + const receipt: ExecutionReceipt = { + executionId: callId, + status: raw.isError === true ? 'failed' : 'succeeded', + result: raw.result, + ...(raw.isError === true ? { errorKind: 'unknown_result' as const } : {}), + }; + return [{ type: 'tool_result', callId, receipt }]; + } + case 'message_end': { + // 模型调用失败不是独立事件:助手消息带 stopReason=error 与 errorMessage(实测形状) + const message = raw.message as { role?: string; stopReason?: string; errorMessage?: string } | undefined; + if (!message || message.role !== 'assistant') return []; + if (message.stopReason !== 'error' && message.errorMessage === undefined) return []; + const detail = typeof message.errorMessage === 'string' ? message.errorMessage : ''; + return [{ type: 'error', kind: classifyPiFailure(detail), message: detail || '模型调用失败(未提供详情)' }]; + } + case 'agent_settled': + // Pi 明确表示不会再自动继续(重试、压缩、排队都结束了) + return [{ type: 'turn_end', reason: 'stop' }]; + case 'error': { + const reason = raw.reason ?? raw.error; + const detail = typeof reason === 'string' ? reason : 'Pi 报错(未提供详情)'; + return [{ type: 'error', kind: classifyPiFailure(detail), message: detail }]; + } + default: + return []; + } +} + +export function createPiRuntime(options: PiRuntimeOptions = {}): AgentRuntime { + const provider = options.provider ?? 'deepseek'; + const model = options.model ?? 'deepseek-chat'; + const sessionDir = options.sessionDir ?? join(homedir(), '.aps', 'pi-sessions'); + const turnTimeoutMs = options.turnTimeoutMs ?? DEFAULT_TURN_TIMEOUT_MS; + + return { + name: `pi:${provider}/${model}`, + async createSession(input: CreateRuntimeSessionInput): Promise { + const env: Record = {}; + for (const [key, value] of Object.entries(process.env)) { + if (value !== undefined) env[key] = value; + } + if (options.apiKey !== undefined && options.apiKey !== '') { + env[API_KEY_ENV[provider] ?? 'DEEPSEEK_API_KEY'] = options.apiKey; + } + + const cliPath = options.cliPath ?? defaultCliPath(); + const client = new RpcClient({ + ...(cliPath === '' ? {} : { cliPath }), + ...(options.cwd === undefined ? {} : { cwd: options.cwd }), + provider, + model, + env, + args: [ + // 工具只来自能力目录:关掉内置工具与自动发现的扩展/技能(A3.11 再接扩展桥) + '--no-builtin-tools', + '--no-extensions', + '--no-skills', + '--no-prompt-templates', + '--no-context-files', + '--session-dir', + sessionDir, + '--session-id', + input.sessionId, + ...(input.system === undefined ? [] : ['--system-prompt', input.system]), + ...(options.extraArgs ?? []), + ], + }); + + if ((options.apiKey ?? '') === '' && (env[API_KEY_ENV[provider] ?? 'DEEPSEEK_API_KEY'] ?? '') === '') { + throw new Error(`Pi 引擎未配置模型密钥:请在 ~/.aps/config.json 的 llm.apiKey 里填写,或设置 ${API_KEY_ENV[provider] ?? 'DEEPSEEK_API_KEY'}(ADR-0011)`); + } + + await client.start(); + + return { + id: `pi-${input.sessionId}`, + async *send(text: string, sendOptions?: SendOptions): AsyncIterable { + const queue: RuntimeEvent[] = []; + let wake: (() => void) | undefined; + let aborted = false; + + const unsubscribe = client.onEvent((event) => { + queue.push(...mapPiEvent(event)); + wake?.(); + wake = undefined; + }); + + try { + await client.prompt(text); + const deadline = Date.now() + turnTimeoutMs; + while (Date.now() < deadline) { + if (sendOptions?.signal?.aborted === true && !aborted) { + aborted = true; + await client.abort(); + } + while (queue.length > 0) { + const next = queue.shift() as RuntimeEvent; + if (next.type === 'turn_end') { + yield { type: 'turn_end', reason: aborted ? 'cancelled' : next.reason }; + return; + } + yield next; + } + await new Promise((resolve) => { + wake = resolve; + setTimeout(resolve, POLL_MS); + }); + } + yield { type: 'error', kind: 'unknown_result', message: `Pi 回合超过 ${turnTimeoutMs}ms 未结束` }; + yield { type: 'turn_end', reason: 'error' }; + } catch (error) { + yield { type: 'error', kind: 'unknown_result', message: error instanceof Error ? error.message : 'Pi 子进程异常' }; + yield { type: 'turn_end', reason: 'error' }; + } finally { + unsubscribe(); + } + }, + resolveToolResult(_callId: string, _receipt: ExecutionReceipt): void { + // 工具由 Pi 侧扩展执行(A3.11):回执要经扩展桥送回去,这里暂时无处可送 + }, + abort(): void { + void client.abort(); + }, + async dispose(): Promise { + await client.stop(); + }, + }; + }, + }; +} \ No newline at end of file diff --git a/server/app/turn-runner.ts b/server/app/turn-runner.ts index 96d0d31..3365d7e 100644 --- a/server/app/turn-runner.ts +++ b/server/app/turn-runner.ts @@ -40,7 +40,8 @@ export async function runTurn(input: TurnRunnerInput): Promise { const { runtimeSession, sessionId, runId, assistantMessageId, publish, invoke, signal } = input; let emitted = ''; let toolCalls = 0; - let finishReason: TurnResult['finishReason'] = 'stop'; + let sawError = false; + let lastTurnEndReason: TurnResult['finishReason'] = 'stop'; publish({ sessionId, runId, type: 'run.state', data: { state: 'running' } }); @@ -94,11 +95,11 @@ export async function runTurn(input: TurnRunnerInput): Promise { type: 'error', data: { code: `engine.${event.kind}`, message: event.message, retryable: event.kind !== 'forbidden', errorKind: event.kind }, }); - finishReason = 'error'; + sawError = true; break; } case 'turn_end': { - finishReason = event.reason; + lastTurnEndReason = event.reason; break; } default: @@ -106,7 +107,7 @@ export async function runTurn(input: TurnRunnerInput): Promise { } } } catch (error) { - finishReason = 'error'; + sawError = true; publish({ sessionId, runId, @@ -115,7 +116,8 @@ export async function runTurn(input: TurnRunnerInput): Promise { }); } - if (signal.aborted && finishReason === 'stop') finishReason = 'cancelled'; + // 结束原因取「最严重的那个」:取消 > 错误 > 正常结束,避免被 turn_end 覆盖回 stop + const finishReason: TurnResult['finishReason'] = signal.aborted ? 'cancelled' : sawError ? 'error' : lastTurnEndReason; publish({ sessionId, runId, diff --git a/server/config.ts b/server/config.ts index ba48c54..63eaaa2 100644 --- a/server/config.ts +++ b/server/config.ts @@ -19,8 +19,14 @@ export interface LlmConfig { apiKey: string; } +export interface EngineConfig { + /** fake = 假引擎(默认);pi = Pi 子进程(A3.3) */ + kind: 'fake' | 'pi'; +} + export interface PlatformConfig { llm: LlmConfig; + engine: EngineConfig; database: { path: string }; server: { host: string; port: number }; /** 客户端构建产物目录,可覆盖(默认仓库内 client/app/dist) */ @@ -47,6 +53,7 @@ export function configFilePath(input: LoadConfigInput = {}): string { interface FileConfig { llm?: Partial; + engine?: Partial; database?: { path?: string }; server?: { host?: string; port?: number }; clientDist?: string; @@ -76,8 +83,15 @@ export function loadConfig(input: LoadConfigInput = {}): PlatformConfig { const port = Number.parseInt(env.APS_PORT ?? '', 10); + // 引擎选择:显式配置优先;没配就按「有没有密钥」自动决定——没密钥只能用假引擎(ADR-0011) + const requestedEngine = (env.APS_ENGINE ?? file.engine?.kind ?? '').toLowerCase(); + const engine: EngineConfig = { + kind: requestedEngine === 'pi' || requestedEngine === 'fake' ? (requestedEngine as EngineConfig['kind']) : apiKey.trim() !== '' ? 'pi' : 'fake', + }; + return { llm: { provider, baseUrl, model, apiKey }, + engine, database: { path: dbPath }, server: { host: env.APS_HOST ?? file.server?.host ?? '127.0.0.1', @@ -96,6 +110,7 @@ export function isEngineConfigured(config: PlatformConfig): boolean { export function redactConfig(config: PlatformConfig): Record { return { llm: { + engine: { kind: config.engine.kind }, provider: config.llm.provider, baseUrl: config.llm.baseUrl, model: config.llm.model, diff --git a/server/index.ts b/server/index.ts index 0c9bbde..eb309b7 100644 --- a/server/index.ts +++ b/server/index.ts @@ -41,10 +41,11 @@ export async function startServer(options: StartOptions = {}): Promise 配置里的 engine.kind;选 pi 但没密钥时明确回退到假引擎 */ +async function selectRuntime(config: ReturnType): Promise { + if (config.engine.kind !== 'pi') { + const { createFakeRuntime } = await import('./agent/fake-runtime.js'); + const { createRulePlanner, plannerToFakeTurn } = await import('./agent/rule-planner.js'); + return createFakeRuntime({ name: 'fake', planner: plannerToFakeTurn(createRulePlanner()) }); + } + if (config.llm.apiKey.trim() === '') { + console.error('警告:配置要求 Pi 引擎但没有模型密钥,已回退到假引擎(ADR-0011 允许未配置时降级)'); + const { createFakeRuntime } = await import('./agent/fake-runtime.js'); + const { createRulePlanner, plannerToFakeTurn } = await import('./agent/rule-planner.js'); + return createFakeRuntime({ name: 'fake', planner: plannerToFakeTurn(createRulePlanner()) }); + } + const { createPiRuntime } = await import('./agent/pi/runtime.js'); + return createPiRuntime({ provider: config.llm.provider, model: config.llm.model, apiKey: config.llm.apiKey }); } \ No newline at end of file diff --git a/server/package.json b/server/package.json index a6eb325..b156414 100644 --- a/server/package.json +++ b/server/package.json @@ -22,6 +22,10 @@ "types": "./dist/agent/fake-runtime.d.ts", "default": "./dist/agent/fake-runtime.js" }, + "./agent/pi/runtime": { + "types": "./dist/agent/pi/runtime.d.ts", + "default": "./dist/agent/pi/runtime.js" + }, "./agent/conformance": { "types": "./dist/agent/conformance.d.ts", "default": "./dist/agent/conformance.js" @@ -40,6 +44,8 @@ }, "dependencies": { "@aps/contracts": "workspace:*", - "@aps/provider-sdk": "workspace:*" + "@aps/provider-sdk": "workspace:*", + "@earendil-works/pi-agent-core": "0.87.1", + "@earendil-works/pi-coding-agent": "0.87.1" } } \ No newline at end of file