diff --git a/.env.example b/.env.example index 570a099..8b40656 100644 --- a/.env.example +++ b/.env.example @@ -101,4 +101,4 @@ SOCIAL_ANALYTICS__PASSWORD=analytics-secret-change-me # Test相关 ############ SOCIAL_TEST__PHONE=8613812345678 -SOCIAL_TEST__PASSWORD=Test@123456 +SOCIAL_TEST__CODE=123456 diff --git a/.gitignore b/.gitignore index 026ae76..e57b211 100644 --- a/.gitignore +++ b/.gitignore @@ -308,8 +308,6 @@ infra/docker/supabase/volumes/storage/ # .opencode/ is now tracked - see .opencode/.gitignore for exclusions .opencode/opencode.json.old -# Agents and skills -.agents/ # Local git worktrees .worktrees/ diff --git a/.opencode/opencode.json b/.opencode/opencode.json index 12c787f..d571d20 100644 --- a/.opencode/opencode.json +++ b/.opencode/opencode.json @@ -1,10 +1,23 @@ { - "$schema": "https://opencode.ai/config.json", - "mcp": { - "supabase": { - "type": "remote", - "enabled": true, - "url": "http://localhost:8001/mcp" + "$schema": "https://opencode.ai/config.json", + "permission": { + "bash": { + "*": "allow", + "git checkout --*": "ask", + "git checkout -- *": "ask", + "git restore *": "ask", + "git reset --hard*": "ask", + "git reset HEAD*": "ask", + "git revert*": "ask", + "git clean*": "ask", + "git stash drop*": "ask" + } + }, + "mcp": { + "supabase": { + "type": "remote", + "enabled": true, + "url": "http://localhost:8001/mcp" + } } - } } diff --git a/.opencode/package-lock.json b/.opencode/package-lock.json new file mode 100644 index 0000000..0a345ba --- /dev/null +++ b/.opencode/package-lock.json @@ -0,0 +1,376 @@ +{ + "name": ".opencode", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@opencode-ai/plugin": "1.14.19" + } + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@opencode-ai/plugin": { + "version": "1.14.19", + "resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.14.19.tgz", + "integrity": "sha512-g0C8Viocybmet7nBqJK/1xrQnacRS1f30VmqRTPScPmWz+4knIZzc2TEQp8+920sN8rB6BuoGwfBUVRXJmavhQ==", + "license": "MIT", + "dependencies": { + "@opencode-ai/sdk": "1.14.19", + "effect": "4.0.0-beta.48", + "zod": "4.1.8" + }, + "peerDependencies": { + "@opentui/core": ">=0.1.101", + "@opentui/solid": ">=0.1.101" + }, + "peerDependenciesMeta": { + "@opentui/core": { + "optional": true + }, + "@opentui/solid": { + "optional": true + } + } + }, + "node_modules/@opencode-ai/sdk": { + "version": "1.14.19", + "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.14.19.tgz", + "integrity": "sha512-9sTGsi8/HlBBeaWfsUjdJ2yi/SqpRvqSld0IFXc3ldaPb1w1uIPvgCGzhlHYQtqatXxSaX5lTN7zpudMaE21aw==", + "license": "MIT", + "dependencies": { + "cross-spawn": "7.0.6" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/effect": { + "version": "4.0.0-beta.48", + "resolved": "https://registry.npmjs.org/effect/-/effect-4.0.0-beta.48.tgz", + "integrity": "sha512-MMAM/ZabuNdNmgXiin+BAanQXK7qM8mlt7nfXDoJ/Gn9V8i89JlCq+2N0AiWmqFLXjGLA0u3FjiOjSOYQk5uMw==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "fast-check": "^4.6.0", + "find-my-way-ts": "^0.1.6", + "ini": "^6.0.0", + "kubernetes-types": "^1.30.0", + "msgpackr": "^1.11.9", + "multipasta": "^0.2.7", + "toml": "^4.1.1", + "uuid": "^13.0.0", + "yaml": "^2.8.3" + } + }, + "node_modules/fast-check": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.7.0.tgz", + "integrity": "sha512-NsZRtqvSSoCP0HbNjUD+r1JH8zqZalyp6gLY9e7OYs7NK9b6AHOs2baBFeBG7bVNsuoukh89x2Yg3rPsul8ziQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^8.0.0" + }, + "engines": { + "node": ">=12.17.0" + } + }, + "node_modules/find-my-way-ts": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/find-my-way-ts/-/find-my-way-ts-0.1.6.tgz", + "integrity": "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==", + "license": "MIT" + }, + "node_modules/ini": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", + "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/kubernetes-types": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/kubernetes-types/-/kubernetes-types-1.30.0.tgz", + "integrity": "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==", + "license": "Apache-2.0" + }, + "node_modules/msgpackr": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.10.tgz", + "integrity": "sha512-iCZNq+HszvF+fC3anCm4nBmWEnbeIAfpDs6IStAEKhQ2YSgkjzVG2FF9XJqwwQh5bH3N9OUTUt4QwVN6MLMLtA==", + "license": "MIT", + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + } + }, + "node_modules/multipasta": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/multipasta/-/multipasta-0.2.7.tgz", + "integrity": "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==", + "license": "MIT" + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pure-rand": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.0.tgz", + "integrity": "sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/toml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/toml/-/toml-4.1.1.tgz", + "integrity": "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/uuid": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", + "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/yaml": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/zod": { + "version": "4.1.8", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/.trellis/tasks/archive/2026-04/00-bootstrap-guidelines/task.json b/.trellis/tasks/archive/2026-04/00-bootstrap-guidelines/task.json index e55ee5b..3310e44 100644 --- a/.trellis/tasks/archive/2026-04/00-bootstrap-guidelines/task.json +++ b/.trellis/tasks/archive/2026-04/00-bootstrap-guidelines/task.json @@ -13,11 +13,11 @@ "subtasks": [ { "name": "Fill backend guidelines", - "status": "pending" + "status": "completed" }, { "name": "Add code examples", - "status": "pending" + "status": "completed" } ], "children": [], diff --git a/.trellis/tasks/archive/2026-04/04-20-bootstrap-fullstack-guidelines/task.json b/.trellis/tasks/archive/2026-04/04-20-bootstrap-fullstack-guidelines/task.json index c85fba3..7982b04 100644 --- a/.trellis/tasks/archive/2026-04/04-20-bootstrap-fullstack-guidelines/task.json +++ b/.trellis/tasks/archive/2026-04/04-20-bootstrap-fullstack-guidelines/task.json @@ -14,7 +14,7 @@ "branch": null, "base_branch": "dev", "worktree_path": null, - "current_phase": 2, + "current_phase": 3, "next_action": [ { "phase": 1, diff --git a/.trellis/workspace/qzl/index.md b/.trellis/workspace/qzl/index.md index db39e67..7ace6e1 100644 --- a/.trellis/workspace/qzl/index.md +++ b/.trellis/workspace/qzl/index.md @@ -8,8 +8,8 @@ - **Active File**: `journal-1.md` -- **Total Sessions**: 0 -- **Last Active**: - +- **Total Sessions**: 1 +- **Last Active**: 2026-04-22 --- @@ -19,7 +19,7 @@ | File | Lines | Status | |------|-------|--------| -| `journal-1.md` | ~0 | Active | +| `journal-1.md` | ~40 | Active | --- @@ -29,6 +29,7 @@ | # | Date | Title | Commits | |---|------|-------|---------| +| 1 | 2026-04-22 | AgentScope CLI/Skill Runtime Simplification | - | --- diff --git a/.trellis/workspace/qzl/journal-1.md b/.trellis/workspace/qzl/journal-1.md index 4ae7243..f88f50f 100644 --- a/.trellis/workspace/qzl/journal-1.md +++ b/.trellis/workspace/qzl/journal-1.md @@ -5,3 +5,49 @@ --- +## 2026-04-22 - AgentScope CLI/Skill Runtime Simplification + +### Completed + +- Removed runtime injection of `tool_prompt.py` and deleted the file. +- Simplified router contract to a minimal `RouterAgentOutput`: + - `objective` + - `context_summary` + - `requires_tool_evidence` +- Removed router schema complexity that was not driving runtime behavior: + - `normalized_task_input` + - `task_typing` + - `result_typing` + - `execution_mode` + - related enums/models/exports/tests +- Simplified worker prompt back to a generic execution contract prompt instead of tool-specific instructions. +- Added runtime forcing for the first worker tool call when `requires_tool_evidence=true` by setting `tool_choice='required'` once. +- Added minimal compatibility for observed qwen tool-call shape where `project_cli.args` is emitted as a JSON string. + +### Verified Findings + +- Router is now producing the expected compact contract in persisted metadata. +- Direct provider calls with the current worker prompt and current tool schema do produce `tool_use(project_cli)`. +- `ReActAgent + Toolkit` can execute tool calls in isolation. +- Local direct `JsonReActAgent` execution can also reach the tool call path. + +### Current Blocker + +- Live integration is still not fully passing. +- In live runs, SSE/history still do not show persisted `TOOL_CALL_RESULT` messages. +- This means the remaining issue is no longer router schema complexity. +- Current evidence suggests the remaining fault is in the live AgentScope runtime/event path rather than in router intent extraction. + +### Important Distinction About Credentials + +- One observed local repro failed with `CREDENTIAL_INVALID`, but that repro used a plain user bearer token where the runtime expects a dedicated issued `tool_credential` JWT. +- That credential failure is real for that local repro, but it is not sufficient to explain the main live failure by itself. +- The main live failure is that tool events are still missing from SSE/history even after router contract simplification and forced tool choice. + +### Next Steps + +1. Trace the live runtime path from worker tool execution to `PipelineStageEmitter` and event persistence. +2. Confirm whether tool calls are being executed in live runs but dropped before SSE/history. +3. Inspect the tool-result parsing path around `parse_tool_agent_output(...)` and emitter state handling. +4. After live tool events are visible, rerun the calendar live integration until the sequence is stable. +5. Do one more cleanup pass to remove any remaining non-essential compatibility or glue. diff --git a/docs/protocols/calendar/timezone-policy.md b/docs/protocols/calendar/timezone-policy.md index bba750b..291d3f1 100644 --- a/docs/protocols/calendar/timezone-policy.md +++ b/docs/protocols/calendar/timezone-policy.md @@ -64,13 +64,20 @@ ## Error Codes -推荐错误码(由后端映射为 4xx): +当前实现(`backend/src/v1/schedule_items/service.py`)实际返回以下稳定错误码: -- `INVALID_DATETIME_FORMAT` -- `NAIVE_DATETIME_FORBIDDEN` -- `INVALID_TIMEZONE` -- `TIMEZONE_REQUIRED` -- `INVALID_TIME_RANGE` +- `SCHEDULE_ITEM_DATETIME_TIMEZONE_REQUIRED`:输入 datetime 缺少时区偏移 +- `SCHEDULE_ITEM_START_AT_TIMEZONE_REQUIRED`:`end_at` 校验阶段缺少可用的 `start_at` 时区信息 +- `SCHEDULE_ITEM_INVALID_TIME_RANGE`:`end_at <= start_at` + +说明:`timezone` 非法、`start_at/end_at` 无时区等基础结构错误在 schema 校验阶段由 FastAPI/Pydantic 返回 `422`,业务错误码表(`docs/protocols/common/http-error-codes.md`)目前仅登记服务层稳定码。 + +--- + +## Compatibility Strategy + +- 策略:`backward-compatible` +- 本次为文档对齐更新,不改变线上接口行为;客户端若仅按 HTTP 状态码处理不受影响。 --- diff --git a/docs/protocols/common/cache-key-scoping.md b/docs/protocols/common/cache-key-scoping.md index d3942b8..3643538 100644 --- a/docs/protocols/common/cache-key-scoping.md +++ b/docs/protocols/common/cache-key-scoping.md @@ -12,28 +12,29 @@ ### 1) 作用域级别 -- `anonymous`:未登录态(或未绑定用户上下文) +当前实现仅启用以下作用域: + - `user:`:已登录用户态 +未登录态实现说明: + +- `apps/lib/app/services/session_scope_manager.dart` 在登出后会调用 `CacheScope.resetProvider()`。 +- 当 provider 未配置时,`apps/lib/data/cache/cached_repository.dart` 会跳过 scoped cache 读写,而不是写入 `anonymous` 命名空间。 + ### 2) 键格式 客户端持久缓存最终键必须按以下格式生成: `cache::` -其中 `` 可以附带会话代际后缀(推荐): +当前实现未使用会话代际后缀(epoch/version token),最终键格式为: -- `user::v` -- `anonymous:v` - -该后缀用于切号并发场景,确保旧会话异步回写落在旧命名空间。 +- `cache:user::` 示例: - `cache:user:8ef4...:chat:history:first:default` -- `cache:user:8ef4...:v12:chat:history:first:default` -- `cache:user:8ef4...:v12:calendar:day:2026-03-29` -- `cache:anonymous:v13:inbox:list:all` +- `cache:user:8ef4...:calendar:day:2026-03-29` --- @@ -47,18 +48,18 @@ ### 应用层(必须) - 在认证状态变化时更新当前缓存作用域: - - 登录成功 -> `user:` - - 登出/失效 -> `anonymous` +- 登录成功 -> `user:` +- 登出/失效 -> 清空当前用户作用域并重置 provider(不进入 `anonymous` 作用域) --- ## 并发与切号安全 - 切号后,旧账号异步请求结果不得回写到新账号 UI 状态。 -- 推荐使用会话代际(epoch/token)保护异步回写。 -- 缓存分区与 UI 状态隔离必须同时存在: - - 仅有分区,无代际保护:仍可能出现瞬时回流显示。 - - 仅有代际保护,无分区:仍可能读取到旧持久缓存。 +- 当前实现依赖 `user:` 级别缓存分区 + 认证切换时清理上一用户前缀: +- - 登录切换:清理上一用户 `cache:user::` 前缀 +- - 登出:清理当前用户前缀并关闭 scoped cache 读写 +- 当前实现未引入 epoch/token 代际保护;若未来出现“切号后旧请求晚到并覆盖新 UI”问题,需要另行升级协议与实现。 --- @@ -67,7 +68,7 @@ ### 向后兼容 - 旧无作用域键允许保留在本地存储中,不参与新读取路径。 -- 新版本只读取带 `cache::` 前缀的键。 +- 新版本只读取带 `cache:user::` 前缀的键。 ### 迁移方式 @@ -79,5 +80,12 @@ ## 验收标准 1. 同设备 A/B 账号来回切换,不出现跨账号历史/列表串读。 -2. 登录后首次读取命中当前用户作用域键;登出后读取命中匿名作用域键。 +2. 登录后首次读取命中当前用户作用域键;登出后 scoped cache 不再参与读取。 3. Feature 仓库不再自行实现 userId 拼 key 逻辑。 + +--- + +## Compatibility Strategy + +- 策略:`backward-compatible` +- 本次为文档对齐更新,收敛未落地的 `anonymous`/epoch 设计,不改变现有应用行为。 diff --git a/docs/protocols/models/inbox-messages.md b/docs/protocols/models/inbox-messages.md index 77bb752..6bae2b9 100644 --- a/docs/protocols/models/inbox-messages.md +++ b/docs/protocols/models/inbox-messages.md @@ -215,12 +215,18 @@ data: {"event_id":"6f0d...","occurred_at":"2026-03-30T07:00:00Z","user_id":"..." "occurred_at": "datetime", "user_id": "uuid", "message_id": "uuid", + "event_type": "INBOX_MESSAGE_CREATED | INBOX_MESSAGE_READ_CHANGED | INBOX_MESSAGE_STATUS_CHANGED | INBOX_SNAPSHOT_REQUIRED", "op": "created | read_changed | status_changed | snapshot_required", "version": 1743313300000, "data": {} } ``` +说明: + +- SSE 帧的 `event:` 行与 payload 内 `event_type` 当前实现保持一致。 +- 客户端可优先使用 SSE `event`,也可在 payload 内读取 `event_type` 做调试或补偿。 + ### Delta 约定 - `created`: @@ -275,3 +281,10 @@ data: {"event_id":"6f0d...","occurred_at":"2026-03-30T07:00:00Z","user_id":"..." - 对 `message_type=calendar`,前端必须按 `content.type` 严格分发:`invite | updated | deleted`。 - 若 `content` 缺少协议必填字段(`schema_version/item/actor/summary`,以及 `updated` 的 `changes`),前端必须进入协议异常展示路径。 - 禁止将协议异常消息兜底渲染为“默认日历邀请”或其他正常业务消息。 + +--- + +## Compatibility Strategy + +- 策略:`backward-compatible` +- 本次仅补全文档遗漏字段 `event_type`,不改变现有 SSE wire 协议。 diff --git a/docs/protocols/models/users.md b/docs/protocols/models/users.md index d334590..cddc449 100644 --- a/docs/protocols/models/users.md +++ b/docs/protocols/models/users.md @@ -43,7 +43,7 @@ Base URL: `/api/v1/users` 字段说明: - `id`: 用户唯一标识符 (UUID) -- `username`: 用户名,3-30 字符 +- `username`: 用户名,当前后端更新接口约束为最大 30 字符(最小长度未在 API 层强制) - `phone`: E.164 格式手机号,可为 null - `avatar_url`: 头像 URL,可为 null - `bio`: 个人简介,最大 200 字符,可为 null @@ -142,3 +142,10 @@ Base URL: `/api/v1/users` ### Response `UserContext` 对象。 + +--- + +## Compatibility Strategy + +- 策略:`backward-compatible` +- 本次仅修正文档约束描述与实现一致,不改变接口字段与响应结构。 diff --git a/skills-lock.json b/skills-lock.json new file mode 100644 index 0000000..f88f2d0 --- /dev/null +++ b/skills-lock.json @@ -0,0 +1,10 @@ +{ + "version": 1, + "skills": { + "agentscope-skill": { + "source": "agentscope-ai/agentscope-skills", + "sourceType": "github", + "computedHash": "1515501dc701bfa9090bf32336ebd7f36225ff233a11598dc89a984cfe5be369" + } + } +}