@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,258 @@
1
+ """LocalQueueHandoffClient — default local implementation.
2
+
3
+ Zero external dependencies, in-process queuing + agent allocation. Migrated from the original queue.py implementation as the "default out-of-the-box" version.
4
+
5
+ Implementation notes:
6
+ - user_id also serves as ticket_id (keeping behavior consistent with old session_id)
7
+ - State machine:
8
+ PENDING ──connect──▶ PROCESSING
9
+ │ ▲ │
10
+ │ │ ▼
11
+ cancel/timeout cancel/close
12
+ - Single-process RLock protection; cross-process sync handled by integrator upper layer (e.g. Redis)
13
+ - Capacity and agent count read from environment variables; can be overridden via constructor
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import os
18
+ import threading
19
+ from typing import Dict, List, Optional
20
+
21
+ from ..core.models import (
22
+ OverallStatus,
23
+ Ticket,
24
+ TicketStatus,
25
+ TicketStatusEnum,
26
+ now_ts,
27
+ )
28
+ from ..ports.handoff_client import HandoffClient
29
+
30
+
31
+ class LocalQueueHandoffClient(HandoffClient):
32
+ """In-process in-memory queuing HandoffClient implementation."""
33
+
34
+ def __init__(
35
+ self,
36
+ *,
37
+ capacity: int = 50,
38
+ agent_pool_size: int = 1,
39
+ estimated_wait_per_slot: int = 30,
40
+ ) -> None:
41
+ self._lock = threading.RLock()
42
+ self._tickets: Dict[str, Ticket] = {} # ticket_id -> Ticket
43
+ self._waiting: List[str] = [] # ticket_id list, FIFO
44
+ self._connected: Dict[str, str] = {} # ticket_id -> agent_id
45
+ self._capacity = int(capacity)
46
+ self._pool = int(agent_pool_size)
47
+ self._wait_per_slot = max(1, int(estimated_wait_per_slot))
48
+
49
+ # ------------------------------------------------------------------
50
+ # HandoffClient required implementations
51
+ # ------------------------------------------------------------------
52
+ def create_ticket(
53
+ self,
54
+ *,
55
+ user_id: str,
56
+ subject: str = "",
57
+ description: str = "",
58
+ priority: str = "normal",
59
+ transcript: Optional[List[str]] = None,
60
+ ) -> Ticket:
61
+ if not user_id:
62
+ raise ValueError("user_id is required")
63
+ with self._lock:
64
+ # Only one in-progress ticket per user; if exists, refresh position and return
65
+ existing = self._find_active_by_user(user_id)
66
+ if existing is not None:
67
+ if existing.status == TicketStatusEnum.PROCESSING.value:
68
+ return existing
69
+ self._refresh_position(existing)
70
+ return existing
71
+
72
+ ticket_id = user_id # Compatible with old behavior: session_id is ticket_id
73
+ t = Ticket(
74
+ ticket_id=ticket_id,
75
+ user_id=user_id,
76
+ subject=subject,
77
+ description=description,
78
+ priority=priority or "normal",
79
+ transcript=list(transcript or []),
80
+ reason=description[:128] if description else "",
81
+ created_at=now_ts(),
82
+ updated_at=now_ts(),
83
+ )
84
+
85
+ # Queue full and no available agents: mark TIMEOUT
86
+ if (
87
+ len(self._waiting) >= self._capacity
88
+ and self._available_agents() == 0
89
+ ):
90
+ t.status = TicketStatusEnum.TIMEOUT.value
91
+ t.closed_at = now_ts()
92
+ self._tickets[ticket_id] = t
93
+ return t
94
+
95
+ t.status = TicketStatusEnum.PENDING.value
96
+ self._tickets[ticket_id] = t
97
+ self._waiting.append(ticket_id)
98
+
99
+ # Auto-connect if an agent is available
100
+ if self._available_agents() > 0:
101
+ self._auto_connect()
102
+ self._refresh_position(t)
103
+ return t
104
+
105
+ def query_status(self, ticket_id: str) -> Optional[TicketStatus]:
106
+ with self._lock:
107
+ t = self._tickets.get(ticket_id)
108
+ if t is None:
109
+ return None
110
+ return TicketStatus.from_ticket(t)
111
+
112
+ def cancel_ticket(self, ticket_id: str, reason: str = "") -> Optional[Ticket]:
113
+ with self._lock:
114
+ t = self._tickets.get(ticket_id)
115
+ if t is None:
116
+ return None
117
+ if t.status == TicketStatusEnum.PROCESSING.value:
118
+ self._connected.pop(ticket_id, None)
119
+ self._waiting = [s for s in self._waiting if s != ticket_id]
120
+ t.status = TicketStatusEnum.CANCELED.value
121
+ t.reason = reason or t.reason
122
+ t.closed_at = now_ts()
123
+ t.updated_at = now_ts()
124
+ self._refresh_all_positions()
125
+ return t
126
+
127
+ def overall_status(self) -> OverallStatus:
128
+ with self._lock:
129
+ return OverallStatus(
130
+ agent_pool_size=self._pool,
131
+ available_agents=self._available_agents(),
132
+ waiting=len(self._waiting),
133
+ connected=len(self._connected),
134
+ capacity=self._capacity,
135
+ )
136
+
137
+ # ------------------------------------------------------------------
138
+ # Dashboard helper methods
139
+ # ------------------------------------------------------------------
140
+ def list_tickets(
141
+ self,
142
+ *,
143
+ limit: int = 50,
144
+ status: Optional[str] = None,
145
+ ) -> List[Ticket]:
146
+ with self._lock:
147
+ items = list(self._tickets.values())
148
+ if status:
149
+ items = [t for t in items if t.status == status]
150
+ items.sort(
151
+ key=lambda x: (x.created_at or 0.0),
152
+ reverse=True,
153
+ )
154
+ return items[: max(1, int(limit))]
155
+
156
+ def update_status(
157
+ self,
158
+ ticket_id: str,
159
+ status: str,
160
+ *,
161
+ agent_id: Optional[str] = None,
162
+ ) -> Optional[Ticket]:
163
+ try:
164
+ new_status = TicketStatusEnum(status).value
165
+ except ValueError as exc:
166
+ raise ValueError(f"invalid status: {status}") from exc
167
+
168
+ with self._lock:
169
+ t = self._tickets.get(ticket_id)
170
+ if t is None:
171
+ return None
172
+
173
+ old_status = t.status
174
+ t.status = new_status
175
+ t.updated_at = now_ts()
176
+
177
+ if new_status == TicketStatusEnum.PROCESSING.value:
178
+ if old_status != TicketStatusEnum.PROCESSING.value:
179
+ if self._available_agents() <= 0 and ticket_id not in self._connected:
180
+ # Force connect (manual): open new slot outside agent pool
181
+ pass
182
+ t.agent_id = agent_id or t.agent_id or f"agent_{ticket_id[-4:]}"
183
+ self._connected[ticket_id] = t.agent_id
184
+ self._waiting = [s for s in self._waiting if s != ticket_id]
185
+ elif new_status in (
186
+ TicketStatusEnum.CLOSED.value,
187
+ TicketStatusEnum.CANCELED.value,
188
+ TicketStatusEnum.TIMEOUT.value,
189
+ ):
190
+ t.closed_at = now_ts()
191
+ self._connected.pop(ticket_id, None)
192
+ self._waiting = [s for s in self._waiting if s != ticket_id]
193
+ elif new_status == TicketStatusEnum.PENDING.value:
194
+ self._connected.pop(ticket_id, None)
195
+ if ticket_id not in self._waiting:
196
+ self._waiting.append(ticket_id)
197
+
198
+ self._refresh_all_positions()
199
+ if self._available_agents() > 0:
200
+ self._auto_connect()
201
+ return t
202
+
203
+ def get_or_attach(self, user_id: str) -> Optional[Ticket]:
204
+ with self._lock:
205
+ return self._find_active_by_user(user_id)
206
+
207
+ # ------------------------------------------------------------------
208
+ # Internal
209
+ # ------------------------------------------------------------------
210
+ def _available_agents(self) -> int:
211
+ return max(0, self._pool - len(self._connected))
212
+
213
+ def _find_active_by_user(self, user_id: str) -> Optional[Ticket]:
214
+ for t in self._tickets.values():
215
+ if t.user_id == user_id and t.status in (
216
+ TicketStatusEnum.PENDING.value,
217
+ TicketStatusEnum.PROCESSING.value,
218
+ ):
219
+ return t
220
+ return None
221
+
222
+ def _auto_connect(self) -> None:
223
+ while self._waiting and self._available_agents() > 0:
224
+ tid = self._waiting.pop(0)
225
+ t = self._tickets.get(tid)
226
+ if t is None:
227
+ continue
228
+ t.status = TicketStatusEnum.PROCESSING.value
229
+ t.updated_at = now_ts()
230
+ t.agent_id = f"agent_auto_{int(t.updated_at)}"
231
+ self._connected[tid] = t.agent_id
232
+
233
+ def _refresh_position(self, t: Ticket) -> None:
234
+ if (
235
+ t.status == TicketStatusEnum.PENDING.value
236
+ and t.ticket_id in self._waiting
237
+ ):
238
+ pos = self._waiting.index(t.ticket_id) + 1
239
+ t.queue_position = pos
240
+ t.eta_seconds = pos * self._wait_per_slot
241
+ else:
242
+ t.queue_position = 0
243
+ t.eta_seconds = 0
244
+
245
+ def _refresh_all_positions(self) -> None:
246
+ for t in self._tickets.values():
247
+ self._refresh_position(t)
248
+
249
+
250
+ # ---------------------------------------------------------------------------
251
+ # Factory: build default parameters from environment variables
252
+ # ---------------------------------------------------------------------------
253
+ def from_env() -> LocalQueueHandoffClient:
254
+ return LocalQueueHandoffClient(
255
+ capacity=int(os.getenv("HH_QUEUE_CAPACITY", "50")),
256
+ agent_pool_size=int(os.getenv("HH_AGENT_POOL_SIZE", "1")),
257
+ estimated_wait_per_slot=int(os.getenv("HH_WAIT_PER_SLOT", "30")),
258
+ )
@@ -0,0 +1,132 @@
1
+ """MockHandoffClient — mock implementation for Recipe demo recording.
2
+
3
+ Inherits LocalQueueHandoffClient, pre-seeds several sample tickets on startup so the agent dashboard has content immediately.
4
+
5
+ Differences from LocalQueueHandoffClient:
6
+ - Seeds example tickets at construction (one each for pending / processing / closed)
7
+ - Marks `is_mock = True`, making it easy to add a "demo data" watermark on the dashboard
8
+ - Demo data uses stable ticket_id prefix `demo_` for reproducible screenshots
9
+ """
10
+ from __future__ import annotations
11
+
12
+ from typing import List, Optional
13
+
14
+ from ..core.models import Ticket, TicketStatusEnum, now_ts
15
+ from .local_queue import LocalQueueHandoffClient
16
+
17
+
18
+ class MockHandoffClient(LocalQueueHandoffClient):
19
+ """Mock implementation for demos."""
20
+
21
+ is_mock = True
22
+
23
+ def __init__(
24
+ self,
25
+ *,
26
+ capacity: int = 50,
27
+ agent_pool_size: int = 2,
28
+ estimated_wait_per_slot: int = 30,
29
+ seed_demo_data: bool = True,
30
+ ) -> None:
31
+ super().__init__(
32
+ capacity=capacity,
33
+ agent_pool_size=agent_pool_size,
34
+ estimated_wait_per_slot=estimated_wait_per_slot,
35
+ )
36
+ if seed_demo_data:
37
+ self._seed()
38
+
39
+ def _seed(self) -> None:
40
+ """Seed demo data. Agent pool occupies 1 slot, leaving 1 free for live connection demos."""
41
+ ts_base = now_ts() - 600
42
+
43
+ # 1) Closed ticket (10 minutes ago)
44
+ closed = Ticket(
45
+ ticket_id="demo_closed_001",
46
+ user_id="demo_user_001",
47
+ subject="Invoice header correction",
48
+ description="Shipped order needs invoice header correction",
49
+ priority="normal",
50
+ status=TicketStatusEnum.CLOSED.value,
51
+ agent_id="agent_alice",
52
+ transcript=[
53
+ "User: Hi, I need to update the invoice header",
54
+ "AI: Which order is this regarding?",
55
+ "User: Order number SO20260601-0042",
56
+ "[handoff] User requested human agent",
57
+ "Agent Alice: Done. New invoice will be issued within 30 minutes.",
58
+ ],
59
+ reason="Invoice header correction",
60
+ created_at=ts_base,
61
+ updated_at=ts_base + 120,
62
+ closed_at=ts_base + 240,
63
+ )
64
+ self._tickets[closed.ticket_id] = closed
65
+
66
+ # 2) Processing ticket (occupies 1 agent slot)
67
+ processing = Ticket(
68
+ ticket_id="demo_processing_001",
69
+ user_id="demo_user_002",
70
+ subject="Return logistics issue",
71
+ description="Return not picked up for 5 days",
72
+ priority="high",
73
+ status=TicketStatusEnum.PROCESSING.value,
74
+ agent_id="agent_bob",
75
+ transcript=[
76
+ "User: My return has been requested 5 days and no one has picked it up yet",
77
+ "AI: Let me check the logistics status for you...",
78
+ "AI: Sorry, the logistics API is temporarily unavailable for real-time info",
79
+ "[handoff] Escalating to human agent",
80
+ "Agent Bob: Hello, I am following up on your logistics issue",
81
+ ],
82
+ reason="Return logistics issue",
83
+ created_at=ts_base + 300,
84
+ updated_at=ts_base + 320,
85
+ )
86
+ self._tickets[processing.ticket_id] = processing
87
+ self._connected[processing.ticket_id] = processing.agent_id # type: ignore[assignment]
88
+
89
+ # 3) Pending ticket (FIFO queue head)
90
+ pending = Ticket(
91
+ ticket_id="demo_pending_001",
92
+ user_id="demo_user_003",
93
+ subject="Refund progress inquiry",
94
+ description="Refund applied 3 days ago not received",
95
+ priority="normal",
96
+ status=TicketStatusEnum.PENDING.value,
97
+ transcript=[
98
+ "User: My refund from 3 days ago hasn't arrived yet",
99
+ "AI: Please provide your order number for lookup",
100
+ "User: Order SO20260605-0099",
101
+ "[handoff] Transfer to agent",
102
+ ],
103
+ reason="Refund progress",
104
+ created_at=ts_base + 540,
105
+ updated_at=ts_base + 540,
106
+ )
107
+ self._tickets[pending.ticket_id] = pending
108
+ self._waiting.append(pending.ticket_id)
109
+ self._refresh_all_positions()
110
+
111
+ def list_tickets(
112
+ self,
113
+ *,
114
+ limit: int = 50,
115
+ status: Optional[str] = None,
116
+ ) -> List[Ticket]:
117
+ # Mock mode defaults to reverse chrono by creation time, consistent with LocalQueue behavior
118
+ return super().list_tickets(limit=limit, status=status)
119
+
120
+
121
+ # ---------------------------------------------------------------------------
122
+ # Factory
123
+ # ---------------------------------------------------------------------------
124
+ def from_env() -> MockHandoffClient:
125
+ import os
126
+
127
+ return MockHandoffClient(
128
+ capacity=int(os.getenv("HH_QUEUE_CAPACITY", "50")),
129
+ agent_pool_size=int(os.getenv("HH_AGENT_POOL_SIZE", "2")),
130
+ estimated_wait_per_slot=int(os.getenv("HH_WAIT_PER_SLOT", "30")),
131
+ seed_demo_data=os.getenv("HH_MOCK_SEED", "1") not in ("0", "false", "False"),
132
+ )
@@ -0,0 +1,25 @@
1
+ """human-handoff core module."""
2
+ from .intent_detector import IntentDetector, is_handoff_intent
3
+ from .models import (
4
+ OverallStatus,
5
+ Ticket,
6
+ TicketStatus,
7
+ TicketStatusEnum,
8
+ now_ts,
9
+ to_legacy_state,
10
+ )
11
+ from .service import HandoffService, get_default_service, reset_default_service
12
+
13
+ __all__ = [
14
+ "HandoffService",
15
+ "IntentDetector",
16
+ "OverallStatus",
17
+ "Ticket",
18
+ "TicketStatus",
19
+ "TicketStatusEnum",
20
+ "get_default_service",
21
+ "is_handoff_intent",
22
+ "now_ts",
23
+ "reset_default_service",
24
+ "to_legacy_state",
25
+ ]
@@ -0,0 +1,75 @@
1
+ """Handoff intent detection: keyword strong matching + weak intent (with negative context recognition).
2
+
3
+ Migrated from original trigger.py. This module does **not depend** on any adapter or global state; pure functions.
4
+ """
5
+ from __future__ import annotations
6
+
7
+ import os
8
+ import re
9
+ from typing import List
10
+
11
+
12
+ _DEFAULT_TRIGGERS = [
13
+ "agent", "help", "support",
14
+ "real person", "talk to agent", "speak to a human", "human agent",
15
+ ]
16
+ _DEFAULT_INTENT = ["complain", "manager", "unsatisfied", "escalate"]
17
+
18
+
19
+ def _csv_env(key: str, default: List[str]) -> List[str]:
20
+ raw = os.getenv(key)
21
+ if not raw:
22
+ return list(default)
23
+ return [item.strip() for item in raw.split(",") if item.strip()]
24
+
25
+
26
+ class IntentDetector:
27
+ """Determine whether input text expresses a "handoff" intent using regex."""
28
+
29
+ def __init__(
30
+ self,
31
+ *,
32
+ triggers: List[str] | None = None,
33
+ intent_keywords: List[str] | None = None,
34
+ ) -> None:
35
+ self._triggers = triggers if triggers is not None else _csv_env(
36
+ "HH_TRIGGERS", _DEFAULT_TRIGGERS
37
+ )
38
+ self._intent = intent_keywords if intent_keywords is not None else _csv_env(
39
+ "HH_INTENT_KEYWORDS", _DEFAULT_INTENT
40
+ )
41
+ self._triggers_re = re.compile(
42
+ "|".join(re.escape(k) for k in self._triggers), re.IGNORECASE
43
+ )
44
+ self._intent_re = re.compile(
45
+ "|".join(re.escape(k) for k in self._intent), re.IGNORECASE
46
+ )
47
+ self._negative_re = re.compile(
48
+ r"\b(not|don't|do not|no|never)\b", re.IGNORECASE
49
+ )
50
+
51
+ def is_handoff_intent(self, text: str) -> bool:
52
+ if not text or len(text) > 4096:
53
+ return False
54
+ if self._triggers_re.search(text):
55
+ return True
56
+ if self._intent_re.search(text) and not self._negative_re.search(text):
57
+ return True
58
+ return False
59
+
60
+
61
+ # ---------------------------------------------------------------------------
62
+ # Default singleton (keeps behavior consistent with old trigger.py; tests can manually construct new instances to override)
63
+ # ---------------------------------------------------------------------------
64
+ _default_detector: IntentDetector | None = None
65
+
66
+
67
+ def get_default_detector() -> IntentDetector:
68
+ global _default_detector
69
+ if _default_detector is None:
70
+ _default_detector = IntentDetector()
71
+ return _default_detector
72
+
73
+
74
+ def is_handoff_intent(text: str) -> bool:
75
+ return get_default_detector().is_handoff_intent(text)
@@ -0,0 +1,163 @@
1
+ """human-handoff core models.
2
+
3
+ Defines unified domain models:
4
+ - TicketStatusEnum Ticket status (aligned with business_contract.ticket.status_query.response.status)
5
+ - Ticket Complete ticket record (transport object between adapters)
6
+ - TicketStatus Lightweight status view (returned by status_query)
7
+ - OverallStatus Overall queue status (dashboard use)
8
+
9
+ The core layer does not know any specific backend implementation; all adapters must use this module's data structures.
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import time
14
+ import uuid
15
+ from dataclasses import dataclass, field
16
+ from enum import Enum
17
+ from typing import Any, Dict, List, Optional
18
+
19
+
20
+ class TicketStatusEnum(str, Enum):
21
+ """Ticket status enum.
22
+
23
+ Business semantics mapping:
24
+ - PENDING User has applied; not yet assigned an agent (equivalent to old HandoffState.WAITING)
25
+ - PROCESSING Agent assigned, processing (equivalent to old HandoffState.CONNECTED)
26
+ - CLOSED Agent closed ticket
27
+ - CANCELED User actively canceled
28
+ - TIMEOUT Timeout, no agent connected
29
+ """
30
+
31
+ PENDING = "pending"
32
+ PROCESSING = "processing"
33
+ CLOSED = "closed"
34
+ CANCELED = "canceled"
35
+ TIMEOUT = "timeout"
36
+
37
+
38
+ # Status name mapping for old API compatibility (HandoffState era)
39
+ _LEGACY_STATE_MAP = {
40
+ TicketStatusEnum.PENDING.value: "waiting",
41
+ TicketStatusEnum.PROCESSING.value: "connected",
42
+ TicketStatusEnum.CLOSED.value: "closed",
43
+ TicketStatusEnum.CANCELED.value: "canceled",
44
+ TicketStatusEnum.TIMEOUT.value: "timeout",
45
+ }
46
+
47
+
48
+ def to_legacy_state(status: str) -> str:
49
+ """Convert new TicketStatusEnum value back to old API state name."""
50
+ if not status:
51
+ return "idle"
52
+ return _LEGACY_STATE_MAP.get(status, status)
53
+
54
+
55
+ @dataclass
56
+ class Ticket:
57
+ """Ticket record. Transport object between adapters.
58
+
59
+ user_id and ticket_id default to the same value in LocalQueue implementation (using session_id),
60
+ REST implementation uses ticket_id returned by the business side.
61
+ """
62
+
63
+ ticket_id: str
64
+ user_id: str
65
+ subject: str = ""
66
+ description: str = ""
67
+ priority: str = "normal"
68
+ status: str = TicketStatusEnum.PENDING.value
69
+ queue_position: int = 0
70
+ eta_seconds: int = 0
71
+ agent_id: Optional[str] = None
72
+ transcript: List[str] = field(default_factory=list)
73
+ reason: str = "" # Trigger reason summary (compatible with old field)
74
+ created_at: Optional[float] = None
75
+ updated_at: Optional[float] = None
76
+ closed_at: Optional[float] = None
77
+ extra: Dict[str, Any] = field(default_factory=dict)
78
+
79
+ @staticmethod
80
+ def new_id() -> str:
81
+ return f"tk_{uuid.uuid4().hex[:12]}"
82
+
83
+ def to_dict(self) -> dict:
84
+ return {
85
+ "ticket_id": self.ticket_id,
86
+ "session_id": self.user_id,
87
+ "user_id": self.user_id,
88
+ "subject": self.subject,
89
+ "description": self.description,
90
+ "priority": self.priority,
91
+ "status": self.status,
92
+ "queue_position": self.queue_position,
93
+ "eta_seconds": self.eta_seconds,
94
+ "agent_id": self.agent_id,
95
+ "transcript": list(self.transcript),
96
+ "reason": self.reason,
97
+ "created_at": self.created_at,
98
+ "updated_at": self.updated_at,
99
+ "closed_at": self.closed_at,
100
+ # Written at ticket creation by human-handoff - session-summary linkage (None if capability not installed)
101
+ "session_summary": self.extra.get("session_summary"),
102
+ # Written by HandoffService.submit_feedback (None if not yet rated)
103
+ "feedback": self.extra.get("feedback"),
104
+ }
105
+
106
+ def to_legacy_dict(self) -> dict:
107
+ """Field format returned by old REST API (/api/v1/handoff/*), keeps Web Demo compatibility."""
108
+ return {
109
+ "session_id": self.user_id,
110
+ "state": to_legacy_state(self.status),
111
+ "reason": self.reason,
112
+ "requested_at": self.created_at,
113
+ "connected_at": self.updated_at if self.status == TicketStatusEnum.PROCESSING.value else None,
114
+ "closed_at": self.closed_at,
115
+ "agent_id": self.agent_id,
116
+ "queue_position": self.queue_position,
117
+ "estimated_wait_seconds": self.eta_seconds,
118
+ }
119
+
120
+
121
+ @dataclass
122
+ class TicketStatus:
123
+ """Response model corresponding to business_contract.ticket.status_query."""
124
+
125
+ ticket_id: str
126
+ status: str
127
+ agent_id: Optional[str] = None
128
+ queue_position: int = 0
129
+ eta_seconds: int = 0
130
+ updated_at: Optional[float] = None
131
+
132
+ @classmethod
133
+ def from_ticket(cls, t: Ticket) -> "TicketStatus":
134
+ return cls(
135
+ ticket_id=t.ticket_id,
136
+ status=t.status,
137
+ agent_id=t.agent_id,
138
+ queue_position=t.queue_position,
139
+ eta_seconds=t.eta_seconds,
140
+ updated_at=t.updated_at or t.created_at,
141
+ )
142
+
143
+
144
+ @dataclass
145
+ class OverallStatus:
146
+ agent_pool_size: int
147
+ available_agents: int
148
+ waiting: int
149
+ connected: int
150
+ capacity: int
151
+
152
+ def to_dict(self) -> dict:
153
+ return {
154
+ "agent_pool_size": self.agent_pool_size,
155
+ "available_agents": self.available_agents,
156
+ "waiting": self.waiting,
157
+ "connected": self.connected,
158
+ "capacity": self.capacity,
159
+ }
160
+
161
+
162
+ def now_ts() -> float:
163
+ return time.time()