@tencent-rtc/trtc-agent-skills 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. package/.cursor/rules/main.mdc +12 -0
  2. package/AGENTS.md +14 -104
  3. package/CLAUDE.md +15 -127
  4. package/CODEBUDDY.md +32 -118
  5. package/README.md +7 -5
  6. package/README.zh.md +7 -5
  7. package/bin/cli.js +133 -41
  8. package/hooks/__pycache__/cursor-adapter.cpython-313.pyc +0 -0
  9. package/hooks/cursor-adapter.py +45 -18
  10. package/hooks/hooks-cursor.json +5 -18
  11. package/hooks/hooks.json +6 -31
  12. package/knowledge-base/conference/web/index.yaml +143 -0
  13. package/knowledge-base/platform-slice-template.md +1041 -133
  14. package/knowledge-base/products.yaml +76 -0
  15. package/knowledge-base/scenario-spec.md +1316 -115
  16. package/knowledge-base/scenarios/conference/base/general-conference.md +22 -2
  17. package/knowledge-base/scenarios/conference/base/webinar-conference.md +14 -0
  18. package/knowledge-base/scenarios/conference/medical/1v1-video-consultation.md +19 -0
  19. package/knowledge-base/scenarios/conference/medical/medical-multidoctor-consultation.md +13 -0
  20. package/knowledge-base/scenarios/live/entertainment-live-room.md +12 -0
  21. package/knowledge-base/slice-spec.md +2377 -299
  22. package/knowledge-base/slices/conference/web/integration-audit.md +1 -1
  23. package/knowledge-base/slices/conference/web/login-auth.md +14 -1
  24. package/knowledge-base/tooling/aliases.yaml +92 -0
  25. package/knowledge-base/tooling/intent-signals.yaml +181 -0
  26. package/knowledge-base/tooling/symptom-keywords.yaml +21 -0
  27. package/package.json +1 -1
  28. package/skills/trtc/SKILL.md +202 -245
  29. package/skills/trtc/hooks/__pycache__/report_prompt.cpython-313.pyc +0 -0
  30. package/skills/{trtc-topic/guardrails → trtc/hooks}/gate_slice_read.py +12 -8
  31. package/skills/{trtc-topic/guardrails → trtc/hooks}/gate_slice_write.py +16 -12
  32. package/skills/{trtc-topic/guardrails → trtc/hooks}/stop_require_apply_evidence.py +22 -14
  33. package/skills/trtc/hooks/topic_phase_gate.py +161 -0
  34. package/skills/{trtc-topic → trtc}/runtime/README.md +2 -2
  35. package/skills/{trtc-onboarding/reference/reporting-protocol.md → trtc/runtime/REPORTING.md} +5 -5
  36. package/skills/{trtc-topic → trtc}/runtime/RUNTIME.md +5 -5
  37. package/skills/trtc/runtime/lib/__init__.py +0 -0
  38. package/skills/{trtc-topic → trtc}/runtime/package-lock.json +2 -2
  39. package/skills/{trtc-topic → trtc}/runtime/package.json +2 -2
  40. package/skills/{trtc-topic → trtc}/runtime/telemetry-bridge.mjs +1 -1
  41. package/skills/{trtc-topic/scripts → trtc/tools}/STATE-MACHINE-GUIDE.md +23 -23
  42. package/skills/trtc/tools/__init__.py +2 -0
  43. package/skills/trtc/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  44. package/skills/trtc/tools/__pycache__/query_classifier.cpython-313.pyc +0 -0
  45. package/skills/trtc/tools/__pycache__/reporting.cpython-313.pyc +0 -0
  46. package/skills/trtc/tools/__pycache__/search.cpython-313.pyc +0 -0
  47. package/skills/trtc/tools/__pycache__/session.cpython-313.pyc +0 -0
  48. package/skills/trtc/tools/apply.py +540 -0
  49. package/skills/trtc/tools/docs.py +712 -0
  50. package/skills/trtc/tools/docsbot.py +182 -0
  51. package/skills/trtc/tools/entry/render_ai_instructions.py +92 -0
  52. package/skills/trtc/tools/flow.py +1089 -0
  53. package/skills/{trtc-topic/scripts → trtc/tools}/init_slice_queue.py +5 -4
  54. package/skills/{trtc-topic/scripts → trtc/tools}/next_slice.py +5 -4
  55. package/skills/trtc/tools/query_classifier.py +301 -0
  56. package/skills/trtc/tools/reporting.py +447 -0
  57. package/skills/trtc/tools/search.py +817 -0
  58. package/skills/trtc/tools/session.py +1261 -0
  59. package/skills/trtc/tools/state_machine.py +690 -0
  60. package/skills/trtc-ai-service/README.md +195 -0
  61. package/skills/trtc-ai-service/README.zh-CN.md +193 -0
  62. package/skills/trtc-ai-service/SKILL.md +945 -0
  63. package/skills/trtc-ai-service/auto_adapters/README.md +40 -0
  64. package/skills/trtc-ai-service/auto_adapters/frontend-spa/README.md +27 -0
  65. package/skills/trtc-ai-service/auto_adapters/frontend-spa/angular/voice-agent.component.ts.tpl +131 -0
  66. package/skills/trtc-ai-service/auto_adapters/frontend-spa/manifest.yaml +57 -0
  67. package/skills/trtc-ai-service/auto_adapters/frontend-spa/react/VoiceAgent.tsx.tpl +142 -0
  68. package/skills/trtc-ai-service/auto_adapters/frontend-spa/vue/VoiceAgent.vue.tpl +121 -0
  69. package/skills/trtc-ai-service/auto_adapters/integration_templates/generic-backend.md +45 -0
  70. package/skills/trtc-ai-service/auto_adapters/integration_templates/generic-frontend.md +51 -0
  71. package/skills/trtc-ai-service/auto_adapters/integration_templates/generic-rest-api.md +93 -0
  72. package/skills/trtc-ai-service/auto_adapters/java-backend/README.md +25 -0
  73. package/skills/trtc-ai-service/auto_adapters/java-backend/manifest.yaml +30 -0
  74. package/skills/trtc-ai-service/auto_adapters/java-backend/quarkus/VoiceAgentFilter.java.tpl +64 -0
  75. package/skills/trtc-ai-service/auto_adapters/java-backend/springboot/VoiceAgentFilter.java.tpl +91 -0
  76. package/skills/trtc-ai-service/auto_adapters/manifest.yaml +43 -0
  77. package/skills/trtc-ai-service/auto_adapters/node-backend/README.md +25 -0
  78. package/skills/trtc-ai-service/auto_adapters/node-backend/express.js.tpl +40 -0
  79. package/skills/trtc-ai-service/auto_adapters/node-backend/fastify.js.tpl +27 -0
  80. package/skills/trtc-ai-service/auto_adapters/node-backend/koa.js.tpl +31 -0
  81. package/skills/trtc-ai-service/auto_adapters/node-backend/manifest.yaml +47 -0
  82. package/skills/trtc-ai-service/auto_adapters/python-backend/README.md +22 -0
  83. package/skills/trtc-ai-service/auto_adapters/python-backend/django.py.tpl +32 -0
  84. package/skills/trtc-ai-service/auto_adapters/python-backend/fastapi.py.tpl +35 -0
  85. package/skills/trtc-ai-service/auto_adapters/python-backend/flask.py.tpl +31 -0
  86. package/skills/trtc-ai-service/auto_adapters/python-backend/manifest.yaml +45 -0
  87. package/skills/trtc-ai-service/capabilities/__init__.py +43 -0
  88. package/skills/trtc-ai-service/capabilities/conversation-core/.env.example +29 -0
  89. package/skills/trtc-ai-service/capabilities/conversation-core/INTEGRATION.md +134 -0
  90. package/skills/trtc-ai-service/capabilities/conversation-core/INTERFACE_ADAPT.md +111 -0
  91. package/skills/trtc-ai-service/capabilities/conversation-core/QUICK_START.md +62 -0
  92. package/skills/trtc-ai-service/capabilities/conversation-core/manifest.yaml +250 -0
  93. package/skills/trtc-ai-service/capabilities/conversation-core/requirements.txt +6 -0
  94. package/skills/trtc-ai-service/capabilities/conversation-core/src/__init__.py +10 -0
  95. package/skills/trtc-ai-service/capabilities/conversation-core/src/_capability_loader.py +218 -0
  96. package/skills/trtc-ai-service/capabilities/conversation-core/src/agent.py +231 -0
  97. package/skills/trtc-ai-service/capabilities/conversation-core/src/credentials.py +132 -0
  98. package/skills/trtc-ai-service/capabilities/conversation-core/src/health.py +355 -0
  99. package/skills/trtc-ai-service/capabilities/conversation-core/src/log_filter.py +76 -0
  100. package/skills/trtc-ai-service/capabilities/conversation-core/src/modality.py +109 -0
  101. package/skills/trtc-ai-service/capabilities/conversation-core/src/server.py +312 -0
  102. package/skills/trtc-ai-service/capabilities/conversation-core/src/trtc_client.py +315 -0
  103. package/skills/trtc-ai-service/capabilities/conversation-core/src/usersig.py +90 -0
  104. package/skills/trtc-ai-service/capabilities/conversation-core/tests/test_skeleton.py +216 -0
  105. package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/README.md +48 -0
  106. package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/app.js +415 -0
  107. package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/index.html +68 -0
  108. package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/styles.css +136 -0
  109. package/skills/trtc-ai-service/capabilities/digital-human/README.md +31 -0
  110. package/skills/trtc-ai-service/capabilities/digital-human/manifest.yaml +64 -0
  111. package/skills/trtc-ai-service/capabilities/digital-human/src/__init__.py +2 -0
  112. package/skills/trtc-ai-service/capabilities/digital-human/src/router.py +43 -0
  113. package/skills/trtc-ai-service/capabilities/human-handoff/INTERFACE_ADAPT.md +353 -0
  114. package/skills/trtc-ai-service/capabilities/human-handoff/README.md +44 -0
  115. package/skills/trtc-ai-service/capabilities/human-handoff/manifest.yaml +227 -0
  116. package/skills/trtc-ai-service/capabilities/human-handoff/src/__init__.py +2 -0
  117. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/__init__.py +9 -0
  118. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/default_rest.py +242 -0
  119. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/factory.py +89 -0
  120. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/local_queue.py +258 -0
  121. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/mock.py +132 -0
  122. package/skills/trtc-ai-service/capabilities/human-handoff/src/core/__init__.py +25 -0
  123. package/skills/trtc-ai-service/capabilities/human-handoff/src/core/intent_detector.py +75 -0
  124. package/skills/trtc-ai-service/capabilities/human-handoff/src/core/models.py +163 -0
  125. package/skills/trtc-ai-service/capabilities/human-handoff/src/core/service.py +192 -0
  126. package/skills/trtc-ai-service/capabilities/human-handoff/src/feedback_store.py +54 -0
  127. package/skills/trtc-ai-service/capabilities/human-handoff/src/ports/__init__.py +4 -0
  128. package/skills/trtc-ai-service/capabilities/human-handoff/src/ports/handoff_client.py +86 -0
  129. package/skills/trtc-ai-service/capabilities/human-handoff/src/queue.py +62 -0
  130. package/skills/trtc-ai-service/capabilities/human-handoff/src/router.py +201 -0
  131. package/skills/trtc-ai-service/capabilities/human-handoff/src/summary_link.py +77 -0
  132. package/skills/trtc-ai-service/capabilities/human-handoff/src/trigger.py +25 -0
  133. package/skills/trtc-ai-service/capabilities/knowledge-base/INTERFACE_ADAPT.md +297 -0
  134. package/skills/trtc-ai-service/capabilities/knowledge-base/README.md +51 -0
  135. package/skills/trtc-ai-service/capabilities/knowledge-base/data/faq.json +20 -0
  136. package/skills/trtc-ai-service/capabilities/knowledge-base/manifest.yaml +211 -0
  137. package/skills/trtc-ai-service/capabilities/knowledge-base/src/__init__.py +8 -0
  138. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/__init__.py +9 -0
  139. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/default_rest.py +209 -0
  140. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/factory.py +86 -0
  141. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/local_json.py +172 -0
  142. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/mock.py +91 -0
  143. package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/__init__.py +12 -0
  144. package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/models.py +77 -0
  145. package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/scoring.py +73 -0
  146. package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/service.py +78 -0
  147. package/skills/trtc-ai-service/capabilities/knowledge-base/src/ports/__init__.py +4 -0
  148. package/skills/trtc-ai-service/capabilities/knowledge-base/src/ports/kb_client.py +61 -0
  149. package/skills/trtc-ai-service/capabilities/knowledge-base/src/retriever.py +56 -0
  150. package/skills/trtc-ai-service/capabilities/knowledge-base/src/router.py +85 -0
  151. package/skills/trtc-ai-service/capabilities/session-summary/INTERFACE_ADAPT.md +99 -0
  152. package/skills/trtc-ai-service/capabilities/session-summary/README.md +47 -0
  153. package/skills/trtc-ai-service/capabilities/session-summary/data/test_session.json +18 -0
  154. package/skills/trtc-ai-service/capabilities/session-summary/manifest.yaml +165 -0
  155. package/skills/trtc-ai-service/capabilities/session-summary/src/__init__.py +2 -0
  156. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/__init__.py +5 -0
  157. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/base.py +31 -0
  158. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/default_rest.py +67 -0
  159. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/factory.py +51 -0
  160. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/local_json.py +42 -0
  161. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/mock.py +22 -0
  162. package/skills/trtc-ai-service/capabilities/session-summary/src/recorder.py +210 -0
  163. package/skills/trtc-ai-service/capabilities/session-summary/src/router.py +93 -0
  164. package/skills/trtc-ai-service/capabilities/session-summary/src/summarizer.py +163 -0
  165. package/skills/trtc-ai-service/capabilities/tool-calling/INTERFACE_ADAPT.md +158 -0
  166. package/skills/trtc-ai-service/capabilities/tool-calling/README.md +50 -0
  167. package/skills/trtc-ai-service/capabilities/tool-calling/data/tools.yaml +58 -0
  168. package/skills/trtc-ai-service/capabilities/tool-calling/examples/__init__.py +1 -0
  169. package/skills/trtc-ai-service/capabilities/tool-calling/examples/local_tools.py +101 -0
  170. package/skills/trtc-ai-service/capabilities/tool-calling/manifest.yaml +146 -0
  171. package/skills/trtc-ai-service/capabilities/tool-calling/src/__init__.py +8 -0
  172. package/skills/trtc-ai-service/capabilities/tool-calling/src/dispatcher.py +54 -0
  173. package/skills/trtc-ai-service/capabilities/tool-calling/src/registry.py +219 -0
  174. package/skills/trtc-ai-service/capabilities/tool-calling/src/router.py +50 -0
  175. package/skills/trtc-ai-service/references/business-contract-spec.md +263 -0
  176. package/skills/trtc-ai-service/scenarios/custom-builder/README.md +86 -0
  177. package/skills/trtc-ai-service/scenarios/custom-builder/output-templates/recipe.yaml.j2 +194 -0
  178. package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q1-business-scenario.md +43 -0
  179. package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q2-io-modality.md +57 -0
  180. package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q3-ui-form.md +55 -0
  181. package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q4-capabilities.md +78 -0
  182. package/skills/trtc-ai-service/scenarios/customer-service/README.md +114 -0
  183. package/skills/trtc-ai-service/scenarios/customer-service/recipe.yaml +154 -0
  184. package/skills/trtc-ai-service/scenarios/customer-service/sample-data/README.md +32 -0
  185. package/skills/trtc-ai-service/scenarios/customer-service/sample-data/faq-sample.json +37 -0
  186. package/skills/trtc-ai-service/scenarios/customer-service/system-prompt.template.md +94 -0
  187. package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/app.js +347 -0
  188. package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/index.html +125 -0
  189. package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/styles.css +487 -0
  190. package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/tokens.css +71 -0
  191. package/skills/trtc-ai-service/scenarios/customer-service/ui/design-system/DESIGN_GUIDELINES.md +370 -0
  192. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/README.md +68 -0
  193. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/app.js +1307 -0
  194. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/data.js +40 -0
  195. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/index.html +233 -0
  196. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/mock-shop.json +21 -0
  197. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/styles.css +603 -0
  198. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/tokens.css +71 -0
  199. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/agent-link.js +323 -0
  200. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/app.js +458 -0
  201. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/index.html +109 -0
  202. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/styles.css +489 -0
  203. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/tokens.css +59 -0
  204. package/skills/trtc-ai-service/scripts/add-capability.py +364 -0
  205. package/skills/trtc-ai-service/scripts/contract-adapt.py +334 -0
  206. package/skills/trtc-ai-service/scripts/detect-stack.py +40 -0
  207. package/skills/trtc-ai-service/scripts/lib/__init__.py +20 -0
  208. package/skills/trtc-ai-service/scripts/lib/adapter_codegen.py +509 -0
  209. package/skills/trtc-ai-service/scripts/lib/arbitrator.py +152 -0
  210. package/skills/trtc-ai-service/scripts/lib/contract_resolver.py +519 -0
  211. package/skills/trtc-ai-service/scripts/lib/credential_validators.py +253 -0
  212. package/skills/trtc-ai-service/scripts/lib/curl_parser.py +303 -0
  213. package/skills/trtc-ai-service/scripts/lib/degrader.py +140 -0
  214. package/skills/trtc-ai-service/scripts/lib/injector.py +347 -0
  215. package/skills/trtc-ai-service/scripts/lib/manifest_resolver.py +288 -0
  216. package/skills/trtc-ai-service/scripts/lib/openapi_parser.py +289 -0
  217. package/skills/trtc-ai-service/scripts/lib/stack_detector.py +159 -0
  218. package/skills/trtc-ai-service/scripts/lib/tokens_compile.py +204 -0
  219. package/skills/trtc-ai-service/scripts/post-install-patch.py +225 -0
  220. package/skills/trtc-ai-service/scripts/setup-credentials.py +393 -0
  221. package/skills/trtc-ai-service/scripts/verify-credentials.py +108 -0
  222. package/skills/trtc-ai-service/start.sh +111 -0
  223. package/skills/trtc-ai-service/tests/__init__.py +1 -0
  224. package/skills/trtc-ai-service/tests/test_arbitrator.py +64 -0
  225. package/skills/trtc-ai-service/tests/test_capability_overlay.py +85 -0
  226. package/skills/trtc-ai-service/tests/test_contract_resolver.py +190 -0
  227. package/skills/trtc-ai-service/tests/test_handoff_ports.py +195 -0
  228. package/skills/trtc-ai-service/tests/test_kb_ports.py +195 -0
  229. package/skills/trtc-ai-service/tests/test_manifest_resolver.py +95 -0
  230. package/skills/trtc-ai-service/tests/test_recipe_assembly.py +175 -0
  231. package/skills/trtc-ai-service/tests/test_stack_and_degrader.py +101 -0
  232. package/skills/trtc-ai-service/tests/test_verify_credentials.py +285 -0
  233. package/skills/trtc-ai-service/triggers.yaml +29 -0
  234. package/skills/trtc-conference/SKILL.md +324 -0
  235. package/skills/trtc-conference/flows/onboarding.md +205 -0
  236. package/skills/trtc-conference/flows/topic.md +474 -0
  237. package/skills/trtc-conference/flows/troubleshoot.md +85 -0
  238. package/skills/trtc-conference/hooks/pretooluse_require_business_decisions.py +213 -0
  239. package/skills/trtc-conference/playbooks/medical-quickstart.md +84 -0
  240. package/skills/trtc-conference/playbooks/official-roomkit.md +97 -0
  241. package/skills/trtc-conference/references/local-usersig/basic-info-config.ts +39 -0
  242. package/skills/trtc-conference/references/usersig-handling.md +134 -0
  243. package/skills/trtc-conference/templates/medical-consultation/src/config/lib-generate-test-usersig-es.min.d.ts +4 -0
  244. package/skills/trtc-conference/templates/medical-consultation/src/config/lib-generate-test-usersig-es.min.js +2 -0
  245. package/skills/trtc-conference/tests/__pycache__/test_conference_onboarding_contract.cpython-313-pytest-9.0.2.pyc +0 -0
  246. package/skills/trtc-conference/tests/__pycache__/test_conference_topic_flow_contract.cpython-313-pytest-9.0.2.pyc +0 -0
  247. package/skills/trtc-conference/tests/test_conference_index_contract.py +43 -0
  248. package/skills/trtc-conference/tests/test_conference_onboarding_contract.py +103 -0
  249. package/skills/trtc-conference/tests/test_conference_template_contract.py +25 -0
  250. package/skills/trtc-conference/tests/test_conference_topic_flow_contract.py +132 -0
  251. package/skills/trtc-conference/tools/apply_checks.py +328 -0
  252. package/skills/trtc-conference/verify_lib/__init__.py +0 -0
  253. package/skills/{trtc-apply/guardrails/apply_lib → trtc-conference/verify_lib}/rule_parser.py +1 -1
  254. package/skills/trtc-docs/SKILL.md +91 -119
  255. package/.cursor/rules/ui-mode.mdc +0 -99
  256. package/ai-instructions/base.md +0 -13
  257. package/ai-instructions/ui-mode.md +0 -93
  258. package/knowledge-base/index.yaml +0 -462
  259. package/skills/trtc/room-builder/SKILL.md +0 -133
  260. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/README.md +0 -108
  261. package/skills/trtc/room-builder/tools/render_ai_instructions.py +0 -226
  262. package/skills/trtc-apply/SKILL.md +0 -97
  263. package/skills/trtc-onboarding/SKILL.md +0 -841
  264. package/skills/trtc-onboarding/reference/path-a1-demo.md +0 -103
  265. package/skills/trtc-onboarding/reference/path-a2-integrate.md +0 -737
  266. package/skills/trtc-onboarding/reference/path-b-troubleshoot.md +0 -186
  267. package/skills/trtc-onboarding/reference/path-c-expand.md +0 -43
  268. package/skills/trtc-onboarding/reference/supported-matrix.md +0 -100
  269. package/skills/trtc-search/SKILL.md +0 -228
  270. package/skills/trtc-topic/SKILL.md +0 -622
  271. package/skills/trtc-topic/scripts/apply.py +0 -581
  272. package/skills/trtc-topic/scripts/lib/state_machine.py +0 -328
  273. package/skills/trtc-topic/tests/README.md +0 -70
  274. package/skills/trtc-topic/tests/conftest.py +0 -72
  275. package/skills/trtc-topic/tests/test_apply_cli.py +0 -480
  276. package/skills/trtc-topic/tests/test_end_to_end.py +0 -305
  277. package/skills/trtc-topic/tests/test_finalize_session.py +0 -51
  278. package/skills/trtc-topic/tests/test_gates.py +0 -316
  279. package/skills/trtc-topic/tests/test_session_resolver.py +0 -260
  280. package/skills/trtc-topic/tests/test_state_machine.py +0 -414
  281. package/skills/trtc-topic/tests/test_stop_require_apply.py +0 -99
  282. package/skills/trtc-topic/tests/test_topic_skill_invariants.py +0 -130
  283. /package/skills/{trtc-topic → trtc}/runtime/lib/platforms.py +0 -0
  284. /package/skills/{trtc-topic → trtc}/runtime/telemetry_collector.py +0 -0
  285. /package/skills/{trtc-onboarding/reference → trtc/runtime}/usersig-handling.md +0 -0
  286. /package/skills/{trtc-topic/scripts → trtc/tools}/finalize_session.py +0 -0
  287. /package/skills/{trtc-apply/guardrails/apply_lib → trtc-ai-service/capabilities/conversation-core/tests}/__init__.py +0 -0
  288. /package/skills/{trtc-topic → trtc-conference}/references/execution-units.yaml +0 -0
  289. /package/skills/{trtc/room-builder/templates/scenarios/medical-consultation/src/config → trtc-conference/references/local-usersig}/lib-generate-test-usersig-es.min.d.ts +0 -0
  290. /package/skills/{trtc/room-builder/templates/scenarios/medical-consultation/src/config → trtc-conference/references/local-usersig}/lib-generate-test-usersig-es.min.js +0 -0
  291. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/docs/backend-contract.zh-CN.md +0 -0
  292. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/docs/integration.zh-CN.md +0 -0
  293. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/docs/theme.zh-CN.md +0 -0
  294. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/index.html +0 -0
  295. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/package.json +0 -0
  296. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/postcss.config.js +0 -0
  297. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/App.vue +0 -0
  298. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/ConsultationManagePanel.vue +0 -0
  299. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/LanguageSwitch.vue +0 -0
  300. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/LoadingSpinner.vue +0 -0
  301. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalAlert.vue +0 -0
  302. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalBusinessPanel.vue +0 -0
  303. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalButton.vue +0 -0
  304. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalConfirmDialog.vue +0 -0
  305. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalDataPanel.vue +0 -0
  306. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalRecordPanel.vue +0 -0
  307. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/PrescriptionPanel.vue +0 -0
  308. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/config/basic-info-config.ts +0 -0
  309. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/config/runtime-config.ts +0 -0
  310. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/env.d.ts +0 -0
  311. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationChatPanel.vue +0 -0
  312. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationMembersPanel.vue +0 -0
  313. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationTranscriptionPanel.vue +0 -0
  314. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationVideoStage.vue +0 -0
  315. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/InviteDoctorDialog.vue +0 -0
  316. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/KickMemberConfirmDialog.vue +0 -0
  317. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/types.ts +0 -0
  318. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationChat.ts +0 -0
  319. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationDevices.ts +0 -0
  320. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationParticipants.ts +0 -0
  321. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationPermissions.ts +0 -0
  322. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/utils.ts +0 -0
  323. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/en-US/index.ts +0 -0
  324. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/index.ts +0 -0
  325. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/medicalTranslate.ts +0 -0
  326. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/state.ts +0 -0
  327. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/zh-CN/index.ts +0 -0
  328. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/main.ts +0 -0
  329. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/mock/appointments.ts +0 -0
  330. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/mock/users.ts +0 -0
  331. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/router/index.ts +0 -0
  332. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/index.ts +0 -0
  333. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/appointmentService.ts +0 -0
  334. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/authService.ts +0 -0
  335. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/launchContext.ts +0 -0
  336. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/userService.ts +0 -0
  337. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/mock/appointmentService.ts +0 -0
  338. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/mock/authService.ts +0 -0
  339. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/mock/userService.ts +0 -0
  340. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/types.ts +0 -0
  341. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/shared/icons.ts +0 -0
  342. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/styles/index.css +0 -0
  343. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/styles/tailwind.css +0 -0
  344. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/styles/theme.css +0 -0
  345. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/auth.ts +0 -0
  346. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/format.ts +0 -0
  347. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/navigation.ts +0 -0
  348. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/session.ts +0 -0
  349. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/DoctorConsultationView.vue +0 -0
  350. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/DoctorDashboardView.vue +0 -0
  351. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/LoginView.vue +0 -0
  352. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientConsultationFinishedView.vue +0 -0
  353. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientConsultationView.vue +0 -0
  354. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientSelectDoctorView.vue +0 -0
  355. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientWaitingView.vue +0 -0
  356. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/tsconfig.json +0 -0
  357. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/tsconfig.node.json +0 -0
  358. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/vite.config.ts +0 -0
  359. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation//346/216/245/345/205/245/350/257/264/346/230/216.md" +0 -0
  360. /package/skills/{trtc-topic/runtime/lib → trtc-conference/tools}/__init__.py +0 -0
@@ -0,0 +1,253 @@
1
+ """Three-key validation function module (Phase 3 Stage 5).
2
+
3
+ Design purpose:
4
+ - Share the same validation functions between ``scripts/setup-credentials.py``
5
+ (developer interactive fallback) and ``scripts/verify-credentials.py``
6
+ (AI-driven credential-less validation).
7
+ - The validation logic itself comes from ``capabilities/conversation-core/src/health.py``;
8
+ this module only handles "credential loading + result normalization to JSON."
9
+
10
+ Core API:
11
+ - ``validate_tencent(env)`` / ``validate_trtc(env, deep=True)`` / ``validate_llm(env)``
12
+ → All return a ``ValidationResult`` dataclass that can be serialized via ``to_dict()``
13
+ to ``{ok, type, error, message, latency_ms}``.
14
+
15
+ Security constraints (must follow):
16
+ - The entire process **only reads credentials from .env / process env**, never accepts keys via CLI arguments.
17
+ - Output JSON **does not contain** credential plaintext; the error field only holds error codes / brief messages.
18
+ - The caller (CLI / AI) should treat stdout as parseable JSON and not echo keys in the terminal.
19
+ """
20
+ from __future__ import annotations
21
+
22
+ import json
23
+ import os
24
+ import sys
25
+ from dataclasses import dataclass, field
26
+ from pathlib import Path
27
+ from typing import Dict, Iterable, List, Optional
28
+
29
+ # ---------------------------------------------------------------------------
30
+ # 1) Load conversation-core credential / health check modules
31
+ # ---------------------------------------------------------------------------
32
+ _HERE = Path(__file__).resolve().parent
33
+ _ROOT = _HERE.parent.parent
34
+ _CORE_DIR = _ROOT / "capabilities" / "conversation-core"
35
+
36
+ if str(_CORE_DIR) not in sys.path:
37
+ sys.path.insert(0, str(_CORE_DIR))
38
+
39
+ # Lazy imports: for verify-credentials.py to call after .env is loaded
40
+ def _imports():
41
+ from src.credentials import ( # type: ignore # noqa: WPS433
42
+ LlmCredential,
43
+ TencentCloudCredential,
44
+ TrtcCredential,
45
+ load_from_env,
46
+ )
47
+ from src.health import ( # type: ignore # noqa: WPS433
48
+ check_llm,
49
+ check_tencent_cloud,
50
+ check_trtc,
51
+ )
52
+
53
+ return {
54
+ "LlmCredential": LlmCredential,
55
+ "TencentCloudCredential": TencentCloudCredential,
56
+ "TrtcCredential": TrtcCredential,
57
+ "load_from_env": load_from_env,
58
+ "check_llm": check_llm,
59
+ "check_tencent_cloud": check_tencent_cloud,
60
+ "check_trtc": check_trtc,
61
+ }
62
+
63
+
64
+ # ---------------------------------------------------------------------------
65
+ # 2) Error codes → AI response hints (aligned with SKILL.md §5.5 lookup table)
66
+ # ---------------------------------------------------------------------------
67
+ _ERROR_HINTS: Dict[str, str] = {
68
+ "E001": "Tencent Cloud SecretId/SecretKey verification failed (AuthFailure / STS not enabled on account).",
69
+ "E002": "TRTC app credentials verification failed (SDKAppID does not belong to this account / SDKSecretKey mismatch).",
70
+ "E003": "LLM verification failed (auth 401/403 or non-200 response).",
71
+ "E004": "Network unreachable / timeout (check proxy / firewall).",
72
+ "E000": "Credential not configured or empty.",
73
+ }
74
+
75
+
76
+ # ---------------------------------------------------------------------------
77
+ # 3) Unified return structures
78
+ # ---------------------------------------------------------------------------
79
+ @dataclass
80
+ class ValidationResult:
81
+ """Validation result for a single key, serialized as verify-credentials.py stdout JSON."""
82
+
83
+ ok: bool
84
+ type: str # "tencent" | "trtc" | "llm" | "all"
85
+ error: str = "" # Error code (E000~E004 or empty)
86
+ message: str = "" # Human-readable description (no key plaintext)
87
+ latency_ms: int = 0
88
+
89
+ def to_dict(self) -> Dict:
90
+ return {
91
+ "ok": self.ok,
92
+ "type": self.type,
93
+ "error": self.error,
94
+ "message": self.message,
95
+ "latency_ms": self.latency_ms,
96
+ }
97
+
98
+
99
+ @dataclass
100
+ class BatchResult:
101
+ """Aggregate validation result (used when type=all)."""
102
+
103
+ ok: bool
104
+ items: List[ValidationResult] = field(default_factory=list)
105
+
106
+ def to_dict(self) -> Dict:
107
+ return {
108
+ "ok": self.ok,
109
+ "type": "all",
110
+ "items": [r.to_dict() for r in self.items],
111
+ }
112
+
113
+
114
+ # ---------------------------------------------------------------------------
115
+ # 4) .env loading (independent of dotenv, avoids extra dependencies)
116
+ # ---------------------------------------------------------------------------
117
+ def load_dotenv(env_path: Optional[Path] = None) -> Dict[str, str]:
118
+ """Read ``.env`` into ``os.environ``; returns newly added/overwritten key-value pairs.
119
+
120
+ Path priority: parameter > capabilities/conversation-core/.env > repo root .env.
121
+ Does not raise; returns empty dict if no file found.
122
+ """
123
+ candidates: List[Path] = []
124
+ if env_path is not None:
125
+ candidates.append(Path(env_path))
126
+ candidates.append(_CORE_DIR / ".env")
127
+ candidates.append(_ROOT / ".env")
128
+
129
+ seen: Dict[str, str] = {}
130
+ for c in candidates:
131
+ if not c.exists() or not c.is_file():
132
+ continue
133
+ try:
134
+ text = c.read_text(encoding="utf-8")
135
+ except OSError:
136
+ continue
137
+ for line in text.splitlines():
138
+ line = line.strip()
139
+ if not line or line.startswith("#") or "=" not in line:
140
+ continue
141
+ k, _, v = line.partition("=")
142
+ k = k.strip()
143
+ v = v.strip().strip('"').strip("'")
144
+ if k and k not in seen:
145
+ seen[k] = v
146
+ # 不覆盖已存在的进程级环境变量(CI / 容器优先)
147
+ os.environ.setdefault(k, v)
148
+ # 找到第一个就够;不再往下找以避免覆盖
149
+ if seen:
150
+ break
151
+ return seen
152
+
153
+
154
+ # ---------------------------------------------------------------------------
155
+ # 5) Single-key validation functions
156
+ # ---------------------------------------------------------------------------
157
+ def validate_tencent() -> ValidationResult:
158
+ """Validate Tencent Cloud API SecretId/SecretKey."""
159
+ mods = _imports()
160
+ creds = mods["load_from_env"]()
161
+ tc = creds.tencent_cloud
162
+ if not tc.configured:
163
+ return ValidationResult(
164
+ ok=False,
165
+ type="tencent",
166
+ error="E000",
167
+ message="TENCENT_CLOUD_SECRET_ID / TENCENT_CLOUD_SECRET_KEY not configured",
168
+ )
169
+ r = mods["check_tencent_cloud"](tc)
170
+ return ValidationResult(
171
+ ok=r.ok,
172
+ type="tencent",
173
+ error="" if r.ok else (r.error_code or "E001"),
174
+ message=r.detail if not r.ok else f"sts/GetFederationToken ok (region={tc.region})",
175
+ latency_ms=r.latency_ms,
176
+ )
177
+
178
+
179
+ def validate_trtc(deep: bool = True) -> ValidationResult:
180
+ """Validate TRTC SDKAppId / SDKSecretKey.
181
+
182
+ When deep=True and Tencent Cloud API credentials are configured, calls
183
+ ``DescribeTRTCRealTimeQualityData`` for ownership verification;
184
+ otherwise only does local UserSig self-consistency check.
185
+ """
186
+ mods = _imports()
187
+ creds = mods["load_from_env"]()
188
+ trtc = creds.trtc
189
+ tc = creds.tencent_cloud if deep else None
190
+ if not trtc.configured:
191
+ return ValidationResult(
192
+ ok=False,
193
+ type="trtc",
194
+ error="E000",
195
+ message="TRTC_SDK_APP_ID / TRTC_SDK_SECRET_KEY not configured",
196
+ )
197
+ r = mods["check_trtc"](trtc, tencent=tc if (tc and tc.configured) else None)
198
+ return ValidationResult(
199
+ ok=r.ok,
200
+ type="trtc",
201
+ error="" if r.ok else (r.error_code or "E002"),
202
+ message=r.detail or ("usersig/openapi ok" if r.ok else "trtc check failed"),
203
+ latency_ms=r.latency_ms,
204
+ )
205
+
206
+
207
+ def validate_llm() -> ValidationResult:
208
+ """Validate LLM API Key (OpenAI-compatible protocol)."""
209
+ mods = _imports()
210
+ creds = mods["load_from_env"]()
211
+ llm = creds.llm
212
+ if not llm.configured:
213
+ return ValidationResult(
214
+ ok=False,
215
+ type="llm",
216
+ error="E000",
217
+ message="LLM_API_KEY / LLM_API_URL / LLM_MODEL not configured",
218
+ )
219
+ r = mods["check_llm"](llm)
220
+ return ValidationResult(
221
+ ok=r.ok,
222
+ type="llm",
223
+ error="" if r.ok else (r.error_code or "E003"),
224
+ message=r.detail or (f"chat/completions 200 ok (model={llm.model})" if r.ok else "llm failed"),
225
+ latency_ms=r.latency_ms,
226
+ )
227
+
228
+
229
+ def validate_all() -> BatchResult:
230
+ """Validate all three keys sequentially; any failure → ok=False."""
231
+ items = [validate_tencent(), validate_trtc(deep=True), validate_llm()]
232
+ return BatchResult(ok=all(i.ok for i in items), items=items)
233
+
234
+
235
+ # ---------------------------------------------------------------------------
236
+ # 6) Error code → hint (for CLI non-JSON mode; AI does not read this)
237
+ # ---------------------------------------------------------------------------
238
+ def hint(error_code: str) -> str:
239
+ return _ERROR_HINTS.get(error_code, "")
240
+
241
+
242
+ # ---------------------------------------------------------------------------
243
+ # 7) Self-test: allows `python -m scripts.lib.credential_validators` to run independently
244
+ # ---------------------------------------------------------------------------
245
+ def _self_test() -> int:
246
+ load_dotenv()
247
+ out = validate_all()
248
+ print(json.dumps(out.to_dict(), ensure_ascii=False, indent=2))
249
+ return 0 if out.ok else 1
250
+
251
+
252
+ if __name__ == "__main__": # pragma: no cover
253
+ sys.exit(_self_test())
@@ -0,0 +1,303 @@
1
+ """curl command parser (Phase 3 Stage 4).
2
+
3
+ Parses curl commands pasted by users in the chat into unified ``ParsedApi`` data structures,
4
+ consumed by ``contract_resolver`` and ``adapter_codegen``.
5
+
6
+ Supported:
7
+ - Multi-line (trailing ``\\``) / single-line
8
+ - ``-X / --request <METHOD>``
9
+ - ``-H / --header 'k: v'`` (accumulates on repeated appearances)
10
+ - ``-d / --data / --data-raw / --data-binary '<body>'``
11
+ - ``--url <url>`` or URL as a positional argument
12
+ - Single-quoted / double-quoted strings (including escapes)
13
+ - Auto-detect Authorization → ``bearer``; custom ``X-*-Token`` → ``api_key``
14
+ - Auto-detect if body is JSON and extract ``request_schema`` fields accordingly
15
+
16
+ Not supported (when protocol_mismatch=True, contract_resolver triggers L3 fallback):
17
+ - multipart / form-data uploads
18
+ - ``--cookie``
19
+ - Non-JSON body (XML / GraphQL string body)
20
+ """
21
+ from __future__ import annotations
22
+
23
+ import json
24
+ import re
25
+ import shlex
26
+ from dataclasses import dataclass, field
27
+ from typing import Any, Dict, List, Optional, Tuple
28
+ from urllib.parse import urlparse, urlsplit
29
+
30
+
31
+ # ---------------------------------------------------------------------------
32
+ # 数据结构
33
+ # ---------------------------------------------------------------------------
34
+ @dataclass
35
+ class AuthSpec:
36
+ type: str = "none" # bearer | api_key | basic | none
37
+ location: str = "header" # header | query
38
+ name: str = "" # header 名 / query 键名
39
+
40
+ def to_dict(self) -> Dict:
41
+ return {"type": self.type, "location": self.location, "name": self.name}
42
+
43
+
44
+ @dataclass
45
+ class ParsedApi:
46
+ """curl / OpenAPI 解析后的统一表示。"""
47
+
48
+ method: str = "GET"
49
+ base_url: str = "" # https://crm.example.com
50
+ path: str = "/" # /api/v2/work_orders(不带 query)
51
+ query: Dict[str, str] = field(default_factory=dict)
52
+ headers: Dict[str, str] = field(default_factory=dict)
53
+ auth: AuthSpec = field(default_factory=AuthSpec)
54
+ request_schema: Dict[str, Any] = field(default_factory=dict)
55
+ response_schema: Dict[str, Any] = field(default_factory=dict)
56
+ body_format: str = "none" # json | form | raw | none
57
+ body_sample: Any = None # 原始 body(已解析为 dict / str)
58
+ source: str = "curl" # curl | openapi
59
+ raw: str = "" # 原始输入(供 codegen 调试)
60
+
61
+ def to_dict(self) -> Dict:
62
+ return {
63
+ "method": self.method,
64
+ "base_url": self.base_url,
65
+ "path": self.path,
66
+ "query": dict(self.query),
67
+ "auth": self.auth.to_dict(),
68
+ # 注意:schema 已经在 parse 阶段标准化过;这里**不再**重复 normalize,
69
+ # 否则像 "string[]" 这类已 normalized 的字面量会被二次降级为 "string"
70
+ "request_schema": dict(self.request_schema),
71
+ "response_schema": dict(self.response_schema),
72
+ "body_format": self.body_format,
73
+ "source": self.source,
74
+ }
75
+
76
+
77
+ # ---------------------------------------------------------------------------
78
+ # 工具函数
79
+ # ---------------------------------------------------------------------------
80
+ def _normalize_schema(node: Any) -> Any:
81
+ """把任意 dict / list 标准化为"字段 → 类型字符串"递归视图。"""
82
+ if isinstance(node, dict):
83
+ out: Dict[str, Any] = {}
84
+ for k, v in node.items():
85
+ out[k] = _normalize_schema(v)
86
+ return out
87
+ if isinstance(node, list):
88
+ if not node:
89
+ return "array<any>"
90
+ # 同质数组取第一个递归
91
+ first = _normalize_schema(node[0])
92
+ if isinstance(first, str):
93
+ return f"{first}[]"
94
+ return [first]
95
+ if isinstance(node, str):
96
+ return "string"
97
+ if isinstance(node, bool): # bool 必须在 int 之前判断
98
+ return "bool"
99
+ if isinstance(node, int):
100
+ return "int"
101
+ if isinstance(node, float):
102
+ return "float"
103
+ if node is None:
104
+ return "null"
105
+ return type(node).__name__
106
+
107
+
108
+ def _split_url(url: str) -> Tuple[str, str, Dict[str, str]]:
109
+ """``https://a.com/b?c=1`` → (``https://a.com``, ``/b``, {c:'1'})"""
110
+ parts = urlsplit(url)
111
+ if not parts.scheme:
112
+ # 用户可能贴了相对路径 /tickets
113
+ return ("", url.split("?", 1)[0], _parse_query(url.split("?", 1)[1] if "?" in url else ""))
114
+ base = f"{parts.scheme}://{parts.netloc}"
115
+ path = parts.path or "/"
116
+ return (base, path, _parse_query(parts.query))
117
+
118
+
119
+ def _parse_query(qs: str) -> Dict[str, str]:
120
+ out: Dict[str, str] = {}
121
+ for pair in qs.split("&"):
122
+ if not pair:
123
+ continue
124
+ if "=" in pair:
125
+ k, _, v = pair.partition("=")
126
+ out[k] = v
127
+ else:
128
+ out[pair] = ""
129
+ return out
130
+
131
+
132
+ _BEARER_RE = re.compile(r"^\s*Bearer\s+\S+\s*$", re.IGNORECASE)
133
+ _BASIC_RE = re.compile(r"^\s*Basic\s+\S+\s*$", re.IGNORECASE)
134
+
135
+
136
+ def _detect_auth(headers: Dict[str, str]) -> AuthSpec:
137
+ for k, v in headers.items():
138
+ if k.lower() == "authorization":
139
+ if _BEARER_RE.match(v):
140
+ return AuthSpec(type="bearer", location="header", name=k)
141
+ if _BASIC_RE.match(v):
142
+ return AuthSpec(type="basic", location="header", name=k)
143
+ return AuthSpec(type="bearer", location="header", name=k)
144
+ # 常见自定义鉴权头
145
+ if k.lower() in {"x-auth-token", "x-api-key", "x-access-token", "x-token"}:
146
+ return AuthSpec(type="api_key", location="header", name=k)
147
+ return AuthSpec(type="none", location="header", name="")
148
+
149
+
150
+ # ---------------------------------------------------------------------------
151
+ # 主解析逻辑
152
+ # ---------------------------------------------------------------------------
153
+ class CurlParseError(ValueError):
154
+ """curl 解析失败。"""
155
+
156
+
157
+ def parse_curl(raw: str) -> ParsedApi:
158
+ """主入口:解析任意 curl 字符串。
159
+
160
+ Raises
161
+ ------
162
+ CurlParseError
163
+ 当输入不是 curl 命令、缺少 URL、或无法 tokenize。
164
+ """
165
+ if not raw or not raw.strip():
166
+ raise CurlParseError("empty input")
167
+
168
+ # 1) 行尾 \ 拼接 + 去掉首个 curl 命令名
169
+ text = re.sub(r"\\\s*\n", " ", raw.strip())
170
+ # 替换非 ASCII 全角空格
171
+ text = text.replace("\u3000", " ")
172
+ try:
173
+ tokens = shlex.split(text, posix=True)
174
+ except ValueError as exc: # 不闭合引号
175
+ raise CurlParseError(f"shell tokenize failed: {exc}") from exc
176
+ if not tokens:
177
+ raise CurlParseError("no tokens after split")
178
+
179
+ # 跳过 curl 命令头(兼容用户漏贴的情况)
180
+ if tokens[0].lower().endswith("curl"):
181
+ tokens = tokens[1:]
182
+
183
+ method: Optional[str] = None
184
+ url: Optional[str] = None
185
+ headers: Dict[str, str] = {}
186
+ body_raw: Optional[str] = None
187
+ body_format = "none"
188
+
189
+ i = 0
190
+ while i < len(tokens):
191
+ t = tokens[i]
192
+ if t in ("-X", "--request"):
193
+ method = tokens[i + 1].upper()
194
+ i += 2
195
+ continue
196
+ if t in ("-H", "--header"):
197
+ kv = tokens[i + 1]
198
+ if ":" in kv:
199
+ k, _, v = kv.partition(":")
200
+ headers[k.strip()] = v.strip()
201
+ i += 2
202
+ continue
203
+ if t in ("-d", "--data", "--data-raw", "--data-binary", "--data-ascii", "--json"):
204
+ body_raw = tokens[i + 1]
205
+ body_format = "json" if t == "--json" else "raw"
206
+ i += 2
207
+ continue
208
+ if t == "--url":
209
+ url = tokens[i + 1]
210
+ i += 2
211
+ continue
212
+ if t in ("-G", "--get"):
213
+ method = method or "GET"
214
+ i += 1
215
+ continue
216
+ if t in ("-u", "--user"):
217
+ # basic auth: user:pass → 仅识别为 basic,不存原值
218
+ headers.setdefault("Authorization", "Basic <redacted>")
219
+ i += 2
220
+ continue
221
+ if t in ("-X", "--include", "-i", "-I", "--head", "-v", "--verbose",
222
+ "-s", "--silent", "-L", "--location", "-k", "--insecure",
223
+ "--compressed", "-f", "--fail"):
224
+ # 控制类参数,跳过
225
+ i += 1
226
+ continue
227
+ if t.startswith("--") or t.startswith("-"):
228
+ # 不认识的选项,吃掉它(防御性:可能带值)
229
+ if i + 1 < len(tokens) and not tokens[i + 1].startswith("-"):
230
+ i += 2
231
+ else:
232
+ i += 1
233
+ continue
234
+ # 位置参数:第一个非选项 token 当作 URL
235
+ if url is None:
236
+ url = t
237
+ i += 1
238
+
239
+ if not url:
240
+ raise CurlParseError("no URL found in curl command")
241
+
242
+ # 推断 method
243
+ if method is None:
244
+ method = "POST" if body_raw is not None else "GET"
245
+
246
+ base_url, path, query = _split_url(url)
247
+
248
+ # 解析 body 为 JSON(best effort)
249
+ request_schema: Dict[str, Any] = {}
250
+ body_sample: Any = body_raw
251
+ if body_raw:
252
+ stripped = body_raw.strip()
253
+ if stripped.startswith("{") or stripped.startswith("["):
254
+ try:
255
+ parsed = json.loads(stripped)
256
+ body_sample = parsed
257
+ body_format = "json"
258
+ if isinstance(parsed, dict):
259
+ request_schema = _normalize_schema(parsed) # type: ignore[assignment]
260
+ except json.JSONDecodeError:
261
+ body_format = "raw"
262
+ elif "&" in stripped and "=" in stripped:
263
+ # 简易 form-urlencoded
264
+ body_format = "form"
265
+ request_schema = {k: "string" for k in _parse_query(stripped).keys()}
266
+
267
+ auth = _detect_auth(headers)
268
+
269
+ return ParsedApi(
270
+ method=method,
271
+ base_url=base_url,
272
+ path=path,
273
+ query=query,
274
+ headers=headers,
275
+ auth=auth,
276
+ request_schema=request_schema,
277
+ response_schema={}, # curl 命令本身没有响应;用户可在第 2 步贴响应
278
+ body_format=body_format,
279
+ body_sample=body_sample,
280
+ source="curl",
281
+ raw=raw,
282
+ )
283
+
284
+
285
+ # ---------------------------------------------------------------------------
286
+ # 可选:从 curl 注释或额外的"# response: {...}"块中提取响应样例
287
+ # ---------------------------------------------------------------------------
288
+ _RESPONSE_HINT_RE = re.compile(
289
+ r"#\s*(?:resp|response)\s*[:=]\s*(\{.*?\}|\[.*?\])",
290
+ re.IGNORECASE | re.DOTALL,
291
+ )
292
+
293
+
294
+ def parse_curl_with_response(raw: str) -> ParsedApi:
295
+ """额外尝试从注释行中提取 ``# response: {...}`` 作为 response_schema。"""
296
+ api = parse_curl(raw)
297
+ m = _RESPONSE_HINT_RE.search(raw)
298
+ if m:
299
+ try:
300
+ api.response_schema = _normalize_schema(json.loads(m.group(1))) # type: ignore[assignment]
301
+ except json.JSONDecodeError:
302
+ pass
303
+ return api
@@ -0,0 +1,140 @@
1
+ """Three-tier fallback decision engine.
2
+
3
+ Input: tech stack detection result + adapter execution result.
4
+ Output: fallback level (L1 / L2 / L3) + user guidance content path.
5
+
6
+ | Level | Trigger Condition | Agent Behavior |
7
+ |:-----:|:--------------------------------------------|:--------------------------------------------|
8
+ | L1 | tech_stack matches adapter + codegen OK | Write directly into user project |
9
+ | L2 | tech_stack matches but codegen failed/conflict | Output INTEGRATION_GUIDE.md template + template code |
10
+ | L3 | tech_stack not recognized or not supported | Output generic REST API docs + SDK install commands |
11
+ """
12
+ from __future__ import annotations
13
+
14
+ from dataclasses import dataclass
15
+ from enum import Enum
16
+ from pathlib import Path
17
+ from typing import Dict, List, Optional
18
+
19
+
20
+ class DegradeLevel(str, Enum):
21
+ L1_AUTO = "L1"
22
+ L2_GUIDED = "L2"
23
+ L3_MANUAL = "L3"
24
+
25
+
26
+ @dataclass
27
+ class DegradeDecision:
28
+ level: DegradeLevel
29
+ reason: str
30
+ adapter: Optional[str] = None
31
+ tech_stack: Optional[str] = None
32
+ artifacts: List[str] = None # type: ignore[assignment]
33
+ remediation: str = ""
34
+
35
+ def to_dict(self) -> dict:
36
+ return {
37
+ "level": self.level.value,
38
+ "reason": self.reason,
39
+ "tech_stack": self.tech_stack,
40
+ "adapter": self.adapter,
41
+ "artifacts": self.artifacts or [],
42
+ "remediation": self.remediation,
43
+ }
44
+
45
+
46
+ def decide(
47
+ tech_stack: Optional[str],
48
+ adapter: Optional[str],
49
+ code_gen_ok: bool,
50
+ *,
51
+ fallback: Optional[Dict] = None,
52
+ code_gen_error: str = "",
53
+ ) -> DegradeDecision:
54
+ """根据上游信号产出降级决策。
55
+
56
+ Parameters
57
+ ----------
58
+ tech_stack
59
+ stack_detector.detect() 的 ``primary`` 字段。
60
+ adapter
61
+ manifest.integration.auto_adapters 中匹配到的适配器名。None 表示不支持。
62
+ code_gen_ok
63
+ L1 阶段实际尝试生成代码后的成功标志。
64
+ fallback
65
+ manifest.integration.fallback 节点内容(提供 guided_templates / manual_api)。
66
+ code_gen_error
67
+ L1 失败时的错误描述(写入 reason)。
68
+ """
69
+ fb = fallback or {}
70
+ if tech_stack and adapter and code_gen_ok:
71
+ return DegradeDecision(
72
+ level=DegradeLevel.L1_AUTO,
73
+ reason="tech stack matched and code generation succeeded",
74
+ tech_stack=tech_stack,
75
+ adapter=adapter,
76
+ artifacts=[],
77
+ remediation="",
78
+ )
79
+ if tech_stack and adapter and not code_gen_ok:
80
+ templates = list(fb.get("guided_templates") or [])
81
+ return DegradeDecision(
82
+ level=DegradeLevel.L2_GUIDED,
83
+ reason=code_gen_error
84
+ or "tech stack matched but code generation failed; provide manual guide",
85
+ tech_stack=tech_stack,
86
+ adapter=adapter,
87
+ artifacts=templates,
88
+ remediation=(
89
+ "Agent outputs INTEGRATION_GUIDE.md: includes template code + injection position notes; "
90
+ "user completes integration manually following the docs"
91
+ ),
92
+ )
93
+ # L3:未识别或无适配器
94
+ manual = fb.get("manual_api") or {}
95
+ artifacts = []
96
+ if manual.get("rest_endpoint"):
97
+ artifacts.append(f"rest_endpoint:{manual['rest_endpoint']}")
98
+ for sdk in manual.get("sdk_packages") or []:
99
+ for ecos, pkg in sdk.items():
100
+ artifacts.append(f"sdk:{ecos}:{pkg}")
101
+ return DegradeDecision(
102
+ level=DegradeLevel.L3_MANUAL,
103
+ reason=(
104
+ "tech stack not recognised or not in supported list"
105
+ if not tech_stack
106
+ else f"no adapter for tech_stack={tech_stack}"
107
+ ),
108
+ tech_stack=tech_stack,
109
+ adapter=None,
110
+ artifacts=artifacts,
111
+ remediation=(
112
+ "Agent outputs generic REST API integration docs (base URL /api/v1)"
113
+ " + SDK package install commands; integrator connects manually."
114
+ ),
115
+ )
116
+
117
+
118
+ # ---------------------------------------------------------------------------
119
+ # I/O modality fallback matrix: 4 independent channel toggles → 16 combinations, ensuring a viable path for each
120
+ # ---------------------------------------------------------------------------
121
+ def channel_combinations_matrix() -> List[Dict]:
122
+ """Return the fallback paths for all 16 channel combinations (used for docs & testing)."""
123
+ rows: List[Dict] = []
124
+ channels = ["voice_input", "text_input", "voice_output", "text_output"]
125
+ for mask in range(16):
126
+ state = {c: bool(mask & (1 << i)) for i, c in enumerate(channels)}
127
+ usable_in = state["voice_input"] or state["text_input"]
128
+ usable_out = state["voice_output"] or state["text_output"]
129
+ if not usable_in and not usable_out:
130
+ verdict = "silent_wait" # upper layer enters silent wait
131
+ elif not usable_in:
132
+ verdict = "output_only_broadcast"
133
+ elif not usable_out:
134
+ verdict = "input_only_logging"
135
+ else:
136
+ primary_in = "voice_input" if state["voice_input"] else "text_input"
137
+ primary_out = "voice_output" if state["voice_output"] else "text_output"
138
+ verdict = f"primary={primary_in}->{primary_out}"
139
+ rows.append({"state": state, "verdict": verdict})
140
+ return rows