aitable-workflow-cli 0.1.15 → 0.1.16-beta.1786022310508

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 (263) hide show
  1. package/package.json +3 -3
  2. package/templates/support-qa/lib/__tests__/declarative-matcher.test.ts +240 -0
  3. package/templates/support-qa/lib/__tests__/dingtalk-group-membership.test.ts +127 -0
  4. package/templates/support-qa/lib/__tests__/memory-events.test.ts +90 -0
  5. package/templates/support-qa/lib/action-dispatch.ts +1 -1
  6. package/templates/support-qa/lib/declarative-matcher.ts +398 -0
  7. package/templates/support-qa/lib/dingtalk-group-membership.ts +151 -0
  8. package/templates/support-qa/lib/guards.ts +18 -0
  9. package/templates/support-qa/lib/memory-events.ts +60 -41
  10. package/templates/support-qa/lib/preflight.ts +294 -0
  11. package/templates/support-qa/package.json +2 -4
  12. package/templates/support-qa/profiles/aitable/profile/fastpath/known-answers.yml +1 -1
  13. package/templates/support-qa/profiles/aitable/profile/troubleshoot/classifiers.yml +1 -1
  14. package/templates/support-qa/workflows/config-sync/recipes/config_sync.recipe.ts +10 -8
  15. package/templates/support-qa/workflows/daily-review/recipes/daily_review.recipe.ts +1 -1
  16. package/templates/support-qa/workflows/group-qa/recipes/answer.recipe.ts +2 -7
  17. package/templates/support-qa/workflows/group-qa/recipes/conversation_handler.recipe.ts +3 -3
  18. package/templates/support-qa/workflows/group-qa/recipes/fastpath.recipe.ts +5 -11
  19. package/templates/support-qa/workflows/group-qa/recipes/on-action.recipe.ts +4 -2
  20. package/templates/support-qa/workflows/group-qa/recipes/reply-to-group.recipe.ts +13 -7
  21. package/templates/support-qa/workflows/group-qa/recipes/troubleshoot.recipe.ts +12 -18
  22. package/templates/support-qa/workspaces/support/AGENTS.md +1 -1
  23. package/templates/aitable-handoff/.env.example +0 -17
  24. package/templates/aitable-handoff/aitable-workflow.config.yml +0 -64
  25. package/templates/aitable-handoff/coding-agents.config.json +0 -17
  26. package/templates/aitable-handoff/npmrc +0 -1
  27. package/templates/aitable-handoff/package.json +0 -16
  28. package/templates/aitable-handoff/roles/config-syncer.role.yml +0 -4
  29. package/templates/aitable-handoff/roles/daily-review.role.yml +0 -4
  30. package/templates/aitable-handoff/roles/faq-support.role.yml +0 -9
  31. package/templates/aitable-handoff/roles/faq-troubleshooter.role.yml +0 -17
  32. package/templates/aitable-handoff/roles/kb-editor.role.yml +0 -19
  33. package/templates/aitable-handoff/wiki/faq-support/01-/345/277/253/351/200/237/345/205/245/351/227/250/6/350/212/202/350/257/276/345/270/246/344/275/240/345/277/253/351/200/237/344/270/212/346/211/213AI/350/241/250/346/240/274.md +0 -43
  34. package/templates/aitable-handoff/wiki/faq-support/01-/345/277/253/351/200/237/345/205/245/351/227/250/AI/350/241/250/346/240/274/350/241/214/346/225/260/350/257/264/346/230/216.md +0 -85
  35. package/templates/aitable-handoff/wiki/faq-support/01-/345/277/253/351/200/237/345/205/245/351/227/250//344/275/277/347/224/250/345/277/253/346/215/267/351/224/256.md +0 -34
  36. package/templates/aitable-handoff/wiki/faq-support/01-/345/277/253/351/200/237/345/205/245/351/227/250//345/260/206Excel/346/226/207/344/273/266/345/257/274/345/205/245AI/350/241/250/346/240/274.md +0 -48
  37. package/templates/aitable-handoff/wiki/faq-support/01-/345/277/253/351/200/237/345/205/245/351/227/250//345/270/270/350/247/201/351/227/256/351/242/230.md +0 -88
  38. package/templates/aitable-handoff/wiki/faq-support/01-/345/277/253/351/200/237/345/205/245/351/227/250//346/250/241/346/235/277/344/270/255/345/277/203.md +0 -59
  39. package/templates/aitable-handoff/wiki/faq-support/01-/345/277/253/351/200/237/345/205/245/351/227/250//351/222/211/351/222/211AI/350/241/250/346/240/274/345/270/270/350/247/201/344/270/212/351/231/220.md +0 -181
  40. package/templates/aitable-handoff/wiki/faq-support/01-/345/277/253/351/200/237/345/205/245/351/227/250//351/222/211/351/222/211AI/350/241/250/346/240/274/345/277/253/351/200/237/344/270/212/346/211/213.md +0 -177
  41. package/templates/aitable-handoff/wiki/faq-support/02-/345/237/272/347/241/200/346/223/215/344/275/234/AI/350/241/250/346/240/274/347/232/204/345/257/274/345/207/272.md +0 -27
  42. package/templates/aitable-handoff/wiki/faq-support/02-/345/237/272/347/241/200/346/223/215/344/275/234//344/275/277/347/224/250/345/210/206/347/273/204.md +0 -67
  43. package/templates/aitable-handoff/wiki/faq-support/02-/345/237/272/347/241/200/346/223/215/344/275/234//344/275/277/347/224/250/345/241/253/350/211/262.md +0 -99
  44. package/templates/aitable-handoff/wiki/faq-support/02-/345/237/272/347/241/200/346/223/215/344/275/234//344/275/277/347/224/250/346/216/222/345/272/217.md +0 -66
  45. package/templates/aitable-handoff/wiki/faq-support/02-/345/237/272/347/241/200/346/223/215/344/275/234//344/275/277/347/224/250/347/255/233/351/200/211/345/222/214/347/255/233/351/200/211/346/235/241/344/273/266/347/273/204.md +0 -104
  46. package/templates/aitable-handoff/wiki/faq-support/02-/345/237/272/347/241/200/346/223/215/344/275/234//346/237/245/347/234/213/345/216/206/345/217/262/350/256/260/345/275/225.md +0 -79
  47. package/templates/aitable-handoff/wiki/faq-support/02-/345/237/272/347/241/200/346/223/215/344/275/234//347/224/250AI/350/241/250/346/240/274/344/270/200/350/241/250/344/270/200/345/212/251/347/220/206/345/217/221/346/266/210/346/201/257.md +0 -94
  48. package/templates/aitable-handoff/wiki/faq-support/02-/345/237/272/347/241/200/346/223/215/344/275/234//350/207/252/345/256/232/344/271/211/350/256/260/345/275/225/345/220/215/347/247/260.md +0 -35
  49. package/templates/aitable-handoff/wiki/faq-support/02-/345/237/272/347/241/200/346/223/215/344/275/234//350/207/252/345/256/232/344/271/211/350/256/260/345/275/225/350/257/246/346/203/205/351/241/265/345/222/214/345/241/253/345/206/231/351/241/265.md +0 -141
  50. package/templates/aitable-handoff/wiki/faq-support/02-/345/237/272/347/241/200/346/223/215/344/275/234//350/260/203/346/225/264/345/210/227/345/256/275.md +0 -42
  51. package/templates/aitable-handoff/wiki/faq-support/02-/345/237/272/347/241/200/346/223/215/344/275/234//350/260/203/346/225/264/350/241/214/351/253/230.md +0 -40
  52. package/templates/aitable-handoff/wiki/faq-support/03-/344/275/277/347/224/250/345/255/227/346/256/265//344/270/272/350/241/250/346/240/274/346/267/273/345/212/240/345/255/227/346/256/265.md +0 -188
  53. package/templates/aitable-handoff/wiki/faq-support/03-/344/275/277/347/224/250/345/255/227/346/256/265//345/215/225/351/200/211/345/244/232/351/200/211/345/255/227/346/256/265/345/220/214/346/255/245/345/205/266/344/273/226/350/241/250/351/200/211/351/241/271.md +0 -142
  54. package/templates/aitable-handoff/wiki/faq-support/03-/344/275/277/347/224/250/345/255/227/346/256/265//345/255/227/346/256/265/347/256/241/347/220/206.md +0 -44
  55. package/templates/aitable-handoff/wiki/faq-support/03-/344/275/277/347/224/250/345/255/227/346/256/265//345/255/227/346/256/265/347/261/273/345/236/213/345/210/227/350/241/250.md +0 -95
  56. package/templates/aitable-handoff/wiki/faq-support/03-/344/275/277/347/224/250/345/255/227/346/256/265//345/255/227/346/256/265/347/274/226/347/273/204.md +0 -138
  57. package/templates/aitable-handoff/wiki/faq-support/04-/344/275/277/347/224/250/350/241/250/345/215/225//350/241/250/345/215/225/345/221/250/346/234/237/345/210/206/350/241/250.md +0 -42
  58. package/templates/aitable-handoff/wiki/faq-support/04-/344/275/277/347/224/250/350/241/250/345/215/225//350/241/250/345/215/225/345/237/272/347/241/200/346/223/215/344/275/234.md +0 -344
  59. package/templates/aitable-handoff/wiki/faq-support/04-/344/275/277/347/224/250/350/241/250/345/215/225//350/241/250/345/215/225/346/230/216/347/273/206/350/241/250-/344/270/200/346/254/241/345/241/253/345/206/231/345/244/232/346/235/241/346/217/220/344/272/244.md +0 -174
  60. package/templates/aitable-handoff/wiki/faq-support/04-/344/275/277/347/224/250/350/241/250/345/215/225//350/241/250/345/215/225/351/242/204/345/241/253/351/273/230/350/256/244/345/200/274.md +0 -97
  61. package/templates/aitable-handoff/wiki/faq-support/05-/345/205/254/345/274/217/345/207/275/346/225/260//344/275/277/347/224/250AI/347/224/237/346/210/220/345/205/254/345/274/217.md +0 -26
  62. package/templates/aitable-handoff/wiki/faq-support/05-/345/205/254/345/274/217/345/207/275/346/225/260//344/275/277/347/224/250/345/205/254/345/274/217/345/207/275/346/225/260/345/270/270/350/247/201/351/227/256/351/242/230.md +0 -179
  63. package/templates/aitable-handoff/wiki/faq-support/05-/345/205/254/345/274/217/345/207/275/346/225/260//344/275/277/347/224/250/345/205/254/345/274/217/345/255/227/346/256/265.md +0 -81
  64. package/templates/aitable-handoff/wiki/faq-support/05-/345/205/254/345/274/217/345/207/275/346/225/260//344/275/277/347/224/250/345/207/275/346/225/260.md +0 -21
  65. package/templates/aitable-handoff/wiki/faq-support/05-/345/205/254/345/274/217/345/207/275/346/225/260//345/205/254/345/274/217/345/207/275/346/225/260/345/244/247/345/205/250.md +0 -433
  66. package/templates/aitable-handoff/wiki/faq-support/05-/345/205/254/345/274/217/345/207/275/346/225/260//345/205/254/345/274/217/346/224/257/346/214/201/346/230/276/347/244/272/346/240/274/345/274/217.md +0 -126
  67. package/templates/aitable-handoff/wiki/faq-support/05-/345/205/254/345/274/217/345/207/275/346/225/260//345/205/254/345/274/217/351/224/231/350/257/257/344/273/243/347/240/201/345/210/227/350/241/250.md +0 -30
  68. package/templates/aitable-handoff/wiki/faq-support/05-/345/205/254/345/274/217/345/207/275/346/225/260//345/207/275/346/225/260/345/256/236/350/267/265.md +0 -13
  69. package/templates/aitable-handoff/wiki/faq-support/06-/346/225/260/346/215/256/350/277/236/346/216/245/344/270/255/345/277/203//346/225/260/346/215/256/350/277/236/346/216/245/344/270/255/345/277/203.md +0 -169
  70. package/templates/aitable-handoff/wiki/faq-support/06-/346/225/260/346/215/256/350/277/236/346/216/245/344/270/255/345/277/203//347/273/204/347/273/207/345/206/205/345/205/261/344/272/253/346/225/260/346/215/256/346/272/220.md +0 -106
  71. package/templates/aitable-handoff/wiki/faq-support/06-/346/225/260/346/215/256/350/277/236/346/216/245/344/270/255/345/277/203//350/267/250AI/350/241/250/346/240/274/346/225/260/346/215/256/345/220/214/346/255/245.md +0 -176
  72. package/templates/aitable-handoff/wiki/faq-support/06-/346/225/260/346/215/256/350/277/236/346/216/245/344/270/255/345/277/203//351/222/211/351/222/211AI/345/220/254/350/256/260/346/225/260/346/215/256/345/220/214/346/255/245.md +0 -100
  73. package/templates/aitable-handoff/wiki/faq-support/06-/346/225/260/346/215/256/350/277/236/346/216/245/344/270/255/345/277/203//351/222/211/351/222/211OA/345/256/241/346/211/271/346/225/260/346/215/256/345/220/214/346/255/245.md +0 -194
  74. package/templates/aitable-handoff/wiki/faq-support/06-/346/225/260/346/215/256/350/277/236/346/216/245/344/270/255/345/277/203//351/222/211/351/222/211/345/276/205/345/212/236/346/225/260/346/215/256/345/220/214/346/255/245.md +0 -87
  75. package/templates/aitable-handoff/wiki/faq-support/06-/346/225/260/346/215/256/350/277/236/346/216/245/344/270/255/345/277/203//351/222/211/351/222/211/346/227/245/347/250/213/346/225/260/346/215/256/345/220/214/346/255/245.md +0 -92
  76. package/templates/aitable-handoff/wiki/faq-support/06-/346/225/260/346/215/256/350/277/236/346/216/245/344/270/255/345/277/203//351/222/211/351/222/211/350/200/203/345/213/244/346/211/223/345/215/241/346/225/260/346/215/256/345/220/214/346/255/245.md +0 -129
  77. package/templates/aitable-handoff/wiki/faq-support/06-/346/225/260/346/215/256/350/277/236/346/216/245/344/270/255/345/277/203//351/222/211/351/222/211/350/241/250/346/240/274/346/225/260/346/215/256/345/220/214/346/255/245.md +0 -229
  78. package/templates/aitable-handoff/wiki/faq-support/06-/346/225/260/346/215/256/350/277/236/346/216/245/344/270/255/345/277/203//351/222/211/351/222/211/351/200/232/350/256/257/345/275/225/346/225/260/346/215/256/345/220/214/346/255/245.md +0 -120
  79. package/templates/aitable-handoff/wiki/faq-support/07-/344/275/277/347/224/250/350/247/206/345/233/276//344/275/277/347/224/250AI/350/241/250/346/240/274/350/247/206/345/233/276.md +0 -219
  80. package/templates/aitable-handoff/wiki/faq-support/07-/344/275/277/347/224/250/350/247/206/345/233/276//345/210/206/344/272/253/350/247/206/345/233/276.md +0 -71
  81. package/templates/aitable-handoff/wiki/faq-support/07-/344/275/277/347/224/250/350/247/206/345/233/276//346/225/260/346/215/256/350/241/250/345/222/214/350/247/206/345/233/276/347/232/204/345/205/263/347/263/273.md +0 -48
  82. package/templates/aitable-handoff/wiki/faq-support/07-/344/275/277/347/224/250/350/247/206/345/233/276//346/227/245/345/216/206/350/247/206/345/233/276.md +0 -89
  83. package/templates/aitable-handoff/wiki/faq-support/07-/344/275/277/347/224/250/350/247/206/345/233/276//346/237/245/350/257/242/351/241/265/351/235/242.md +0 -116
  84. package/templates/aitable-handoff/wiki/faq-support/07-/344/275/277/347/224/250/350/247/206/345/233/276//347/224/230/347/211/271/345/233/276.md +0 -135
  85. package/templates/aitable-handoff/wiki/faq-support/07-/344/275/277/347/224/250/350/247/206/345/233/276//347/224/273/345/206/214/350/247/206/345/233/276.md +0 -28
  86. package/templates/aitable-handoff/wiki/faq-support/07-/344/275/277/347/224/250/350/247/206/345/233/276//347/234/213/346/235/277/350/247/206/345/233/276.md +0 -35
  87. package/templates/aitable-handoff/wiki/faq-support/07-/344/275/277/347/224/250/350/247/206/345/233/276//350/241/250/346/240/274/350/247/206/345/233/276.md +0 -116
  88. package/templates/aitable-handoff/wiki/faq-support/07-/344/275/277/347/224/250/350/247/206/345/233/276//351/200/217/350/247/206/350/241/250/350/247/206/345/233/276.md +0 -123
  89. package/templates/aitable-handoff/wiki/faq-support/08-/344/275/277/347/224/250/344/273/252/350/241/250/347/233/230/TOP_N/345/210/206/346/236/220.md +0 -78
  90. package/templates/aitable-handoff/wiki/faq-support/08-/344/275/277/347/224/250/344/273/252/350/241/250/347/233/230//344/273/252/350/241/250/347/233/230/344/270/255/346/267/273/345/212/240/345/244/232/344/270/252/346/225/260/346/215/256/346/272/220.md +0 -129
  91. package/templates/aitable-handoff/wiki/faq-support/08-/344/275/277/347/224/250/344/273/252/350/241/250/347/233/230//344/273/252/350/241/250/347/233/230/345/215/225/345/233/276/350/241/250/345/222/214AI/350/247/243/350/257/273/345/206/205/345/256/271/345/210/206/344/272/253.md +0 -104
  92. package/templates/aitable-handoff/wiki/faq-support/08-/344/275/277/347/224/250/344/273/252/350/241/250/347/233/230//344/273/252/350/241/250/347/233/230/345/270/270/350/247/201/351/227/256/351/242/230.md +0 -31
  93. package/templates/aitable-handoff/wiki/faq-support/08-/344/275/277/347/224/250/344/273/252/350/241/250/347/233/230//344/273/252/350/241/250/347/233/230/346/231/272/350/203/275/346/200/273/347/273/223/345/210/206/346/236/220.md +0 -57
  94. package/templates/aitable-handoff/wiki/faq-support/08-/344/275/277/347/224/250/344/273/252/350/241/250/347/233/230//344/273/252/350/241/250/347/233/230/347/273/204/344/273/266.md +0 -47
  95. package/templates/aitable-handoff/wiki/faq-support/08-/344/275/277/347/224/250/344/273/252/350/241/250/347/233/230//344/275/277/347/224/250AI/350/241/250/346/240/274/344/273/252/350/241/250/347/233/230.md +0 -226
  96. package/templates/aitable-handoff/wiki/faq-support/08-/344/275/277/347/224/250/344/273/252/350/241/250/347/233/230//344/275/277/347/224/250/350/207/252/345/212/250/345/214/226/346/265/201/347/250/213/345/217/221/351/200/201/344/273/252/350/241/250/347/233/230.md +0 -49
  97. package/templates/aitable-handoff/wiki/faq-support/08-/344/275/277/347/224/250/344/273/252/350/241/250/347/233/230//345/210/206/344/272/253/344/273/252/350/241/250/347/233/230.md +0 -74
  98. package/templates/aitable-handoff/wiki/faq-support/08-/344/275/277/347/224/250/344/273/252/350/241/250/347/233/230//345/234/250/344/273/252/350/241/250/347/233/230/344/270/255/347/255/233/351/200/211/346/225/260/346/215/256.md +0 -65
  99. package/templates/aitable-handoff/wiki/faq-support/08-/344/275/277/347/224/250/344/273/252/350/241/250/347/233/230//350/207/252/345/256/232/344/271/211/344/273/252/350/241/250/347/233/230/344/270/255/345/277/203.md +0 -93
  100. package/templates/aitable-handoff/wiki/faq-support/08-/344/275/277/347/224/250/344/273/252/350/241/250/347/233/230//350/267/237/351/232/217/350/256/277/351/227/256/350/200/205/346/235/203/351/231/220/347/273/237/350/256/241.md +0 -48
  101. package/templates/aitable-handoff/wiki/faq-support/09-/345/272/224/347/224/250/346/250/241/345/274/217//345/205/250/346/226/260/345/272/224/347/224/250/346/250/241/345/274/217.md +0 -155
  102. package/templates/aitable-handoff/wiki/faq-support/09-/345/272/224/347/224/250/346/250/241/345/274/217//345/210/227/350/241/250/347/273/204/344/273/266.md +0 -228
  103. package/templates/aitable-handoff/wiki/faq-support/09-/345/272/224/347/224/250/346/250/241/345/274/217//345/233/276/347/211/207.md +0 -93
  104. package/templates/aitable-handoff/wiki/faq-support/09-/345/272/224/347/224/250/346/250/241/345/274/217//346/214/211/351/222/256.md +0 -86
  105. package/templates/aitable-handoff/wiki/faq-support/09-/345/272/224/347/224/250/346/250/241/345/274/217//346/240/207/347/255/276/351/241/265.md +0 -97
  106. package/templates/aitable-handoff/wiki/faq-support/09-/345/272/224/347/224/250/346/250/241/345/274/217//350/247/206/345/233/276/347/273/204/344/273/266.md +0 -125
  107. package/templates/aitable-handoff/wiki/faq-support/09-/345/272/224/347/224/250/346/250/241/345/274/217//350/277/207/346/273/244/345/231/250.md +0 -110
  108. package/templates/aitable-handoff/wiki/faq-support/09-/345/272/224/347/224/250/346/250/241/345/274/217//351/200/217/350/247/206/350/241/250/347/273/204/344/273/266.md +0 -142
  109. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201/Webhook/345/217/202/346/225/260/347/232/204/350/257/246/347/273/206/350/257/264/346/230/216.md +0 -76
  110. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//344/270/200/350/241/250/344/270/200/345/217/267Agent/346/224/257/346/214/201/347/276/244/346/224/266/351/233/206.md +0 -150
  111. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//344/275/277/347/224/250webhook/350/247/246/345/217/221/350/207/252/345/212/250/345/214/226.md +0 -163
  112. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//344/275/277/347/224/250/344/270/215/345/220/214/350/272/253/344/273/275/345/217/221/351/200/201/351/222/211/351/222/211/346/266/210/346/201/257.md +0 -60
  113. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//344/275/277/347/224/250/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201.md +0 -219
  114. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//344/275/277/347/224/250/350/207/252/345/212/250/345/214/226/345/276/252/347/216/257/350/212/202/347/202/271.md +0 -63
  115. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//345/234/250/346/265/201/347/250/213/344/270/255/344/275/277/347/224/250AI/351/227/256/347/255/224.md +0 -69
  116. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//345/234/250/346/266/210/346/201/257/345/215/241/347/211/207/344/270/212/346/267/273/345/212/240/346/214/211/351/222/256.md +0 -93
  117. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//346/265/201/347/250/213/345/217/230/351/207/217/350/247/243/351/207/212/344/270/216/345/270/270/350/247/201/346/212/245/351/224/231.md +0 -158
  118. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//346/265/201/347/250/213/350/247/246/345/217/221/346/235/241/344/273/266/344/270/216/346/211/247/350/241/214/345/212/250/344/275/234/344/270/200/350/247/210.md +0 -310
  119. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//347/224/250AI/350/241/250/346/240/274/344/270/200/350/241/250/344/270/200/345/212/251/347/220/206/345/217/221/346/266/210/346/201/257-/350/207/252/345/212/250/345/214/226.md +0 -129
  120. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//347/224/250/346/237/245/346/211/276/350/256/260/345/275/225/345/217/221/351/200/201/347/273/204/345/220/210/345/255/227/346/256/265/351/200/232/347/237/245.md +0 -66
  121. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//350/207/252/345/212/250/345/214/226/345/210/233/345/273/272/351/222/211/351/222/211/345/276/205/345/212/236/346/210/226/346/227/245/347/250/213.md +0 -84
  122. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//350/207/252/345/212/250/345/214/226/345/217/221/350/265/267AI/347/224/265/350/257/235/345/244/226/345/221/274.md +0 -322
  123. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//350/207/252/345/212/250/345/214/226/345/217/221/350/265/267OA/345/256/241/346/211/271.md +0 -93
  124. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//350/207/252/345/212/250/345/214/226/345/217/221/351/200/201HTTP/350/257/267/346/261/202.md +0 -168
  125. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//350/207/252/345/212/250/345/214/226/345/270/270/350/247/201/351/227/256/351/242/230.md +0 -83
  126. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//350/207/252/345/212/250/345/214/226/346/211/271/351/207/217/345/217/221/351/202/256/344/273/266.md +0 -79
  127. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//350/207/252/345/212/250/345/214/226/346/224/257/346/214/201/346/217/222/345/205/245/345/223/252/344/272/233/345/217/230/351/207/217/345/206/205/345/256/271.md +0 -80
  128. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//350/207/252/345/212/250/345/214/226/346/233/264/345/244/232/346/211/247/350/241/214/345/212/250/344/275/234/344/275/277/347/224/250/346/214/207/345/215/227.md +0 -21
  129. package/templates/aitable-handoff/wiki/faq-support/10-/350/207/252/345/212/250/345/214/226/345/267/245/344/275/234/346/265/201//350/260/203/347/224/250/344/270/211/346/226/271/345/267/245/344/275/234/346/265/201/345/272/224/347/224/250.md +0 -161
  130. package/templates/aitable-handoff/wiki/faq-support/11-AI/350/241/250/346/240/274/345/212/251/347/220/206/AI/350/241/250/346/240/274/344/270/207/350/203/275/350/264/264/344/274/230/345/205/210/344/275/277/347/224/250/347/224/263/350/257/267.md +0 -67
  131. package/templates/aitable-handoff/wiki/faq-support/11-AI/350/241/250/346/240/274/345/212/251/347/220/206/AI/350/241/250/346/240/274/344/270/207/350/203/275/350/264/264/344/275/277/347/224/250/350/257/264/346/230/216.md +0 -63
  132. package/templates/aitable-handoff/wiki/faq-support/11-AI/350/241/250/346/240/274/345/212/251/347/220/206/AI/350/241/250/346/240/274/345/212/251/347/220/206.md +0 -107
  133. package/templates/aitable-handoff/wiki/faq-support/12-/351/253/230/347/272/247/346/235/203/351/231/220//344/275/277/347/224/250AI/350/241/250/346/240/274/351/253/230/347/272/247/346/235/203/351/231/220.md +0 -194
  134. package/templates/aitable-handoff/wiki/faq-support/12-/351/253/230/347/272/247/346/235/203/351/231/220//350/241/214/345/210/227/346/235/203/351/231/220/350/256/276/347/275/256/345/217/212/351/253/230/347/272/247/346/235/203/351/231/220/345/257/271/350/241/250/345/215/225/345/205/254/345/274/217/347/232/204/345/275/261/345/223/215.md +0 -32
  135. package/templates/aitable-handoff/wiki/faq-support/12-/351/253/230/347/272/247/346/235/203/351/231/220//351/242/204/350/247/210/351/253/230/347/272/247/346/235/203/351/231/220/347/273/223/346/236/234.md +0 -43
  136. package/templates/aitable-handoff/wiki/faq-support/12-/351/253/230/347/272/247/346/235/203/351/231/220//351/253/230/347/272/247/346/235/203/351/231/220/345/270/270/350/247/201/351/227/256/351/242/230.md +0 -47
  137. package/templates/aitable-handoff/wiki/faq-support/12-/351/253/230/347/272/247/346/235/203/351/231/220//351/253/230/347/272/247/346/235/203/351/231/220/347/232/204/351/273/230/350/256/244/350/247/222/350/211/262.md +0 -36
  138. package/templates/aitable-handoff/wiki/faq-support/13-/346/217/222/344/273/266/344/270/255/345/277/203/AI/350/241/250/346/240/274/344/270/211/346/226/271/346/217/222/344/273/266/344/275/277/347/224/250/346/216/210/346/235/203.md +0 -19
  139. package/templates/aitable-handoff/wiki/faq-support/13-/346/217/222/344/273/266/344/270/255/345/277/203/AI/350/241/250/346/240/274/346/217/222/344/273/266-/350/204/232/346/234/254/346/217/222/344/273/266.md +0 -42
  140. package/templates/aitable-handoff/wiki/faq-support/13-/346/217/222/344/273/266/344/270/255/345/277/203/AI/350/241/250/346/240/274/346/217/222/344/273/266-/350/207/252/345/256/232/344/271/211/346/217/222/344/273/266.md +0 -51
  141. package/templates/aitable-handoff/wiki/faq-support/13-/346/217/222/344/273/266/344/270/255/345/277/203/AI/350/241/250/346/240/274/346/217/222/344/273/266/344/270/255/345/277/203-/344/275/277/347/224/250/346/214/207/345/215/227.md +0 -97
  142. package/templates/aitable-handoff/wiki/faq-support/14-/347/256/241/347/220/206/345/220/216/345/217/260//344/275/277/347/224/250/346/225/260/346/215/256/350/257/264/346/230/216.md +0 -82
  143. package/templates/aitable-handoff/wiki/faq-support/14-/347/256/241/347/220/206/345/220/216/345/217/260//346/235/203/347/233/212/346/225/260/346/215/256/350/257/264/346/230/216.md +0 -111
  144. package/templates/aitable-handoff/wiki/faq-support/15-/345/234/272/346/231/257/345/256/236/350/267/265/AI/350/241/250/346/240/274/350/257/257/345/210/240/346/201/242/345/244/215/346/214/207/345/215/227.md +0 -37
  145. package/templates/aitable-handoff/wiki/faq-support/15-/345/234/272/346/231/257/345/256/236/350/267/265//345/234/250/350/241/250/346/240/274/344/270/255/346/240/207/350/256/260/351/207/215/345/244/215/345/206/205/345/256/271.md +0 -43
  146. package/templates/aitable-handoff/wiki/faq-support/15-/345/234/272/346/231/257/345/256/236/350/267/265//347/233/264/346/222/255/345/205/254/345/274/200/347/263/273/345/210/227/350/257/276.md +0 -21
  147. package/templates/aitable-handoff/wiki/faq-support/16-/344/273/230/350/264/271/346/235/203/347/233/212//351/222/211/351/222/211AI/350/241/250/346/240/274/344/273/230/350/264/271/346/235/203/347/233/212.md +0 -144
  148. package/templates/aitable-handoff/wiki/faq-support/16-/344/273/230/350/264/271/346/235/203/347/233/212//351/222/211/351/222/211AI/350/241/250/346/240/274/346/220/255/345/273/272/346/234/215/345/212/241.md +0 -95
  149. package/templates/aitable-handoff/wiki/faq-support/17-/345/205/254/345/221/212/AI/350/241/250/346/240/274-/346/216/222/347/211/210/346/211/223/345/215/260/345/215/207/347/272/247/350/257/264/346/230/216.md +0 -40
  150. package/templates/aitable-handoff/wiki/faq-support/17-/345/205/254/345/221/212/AI/350/241/250/346/240/274-/347/211/210/346/234/254/345/215/207/347/272/247/351/200/232/347/237/245.md +0 -21
  151. package/templates/aitable-handoff/wiki/faq-support/17-/345/205/254/345/221/212//350/267/250AI/350/241/250/346/240/274/346/225/260/346/215/256/345/220/214/346/255/245/350/260/203/346/225/264/350/257/264/346/230/216.md +0 -55
  152. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI /350/241/250/346/240/274/346/217/222/344/273/266 - /344/274/201/344/270/232/345/206/205/346/217/222/344/273/266/345/217/221/345/270/203/346/214/207/345/215/227.md" +0 -159
  153. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274 AI /345/255/227/346/256/265 /345/274/200/345/217/221/346/214/207/345/215/227/AI/350/241/250/346/240/274 AI /345/255/227/346/256/265/345/274/200/345/217/221/346/214/207/345/215/227/357/274/210FaaS/347/211/210/357/274/211.md" +0 -1362
  154. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274 AI /345/255/227/346/256/265 /345/274/200/345/217/221/346/214/207/345/215/227/AI/350/241/250/346/240/274 AI /345/255/227/346/256/265/345/274/200/345/217/221/346/214/207/345/215/227/357/274/210/345/205/254/345/274/217/347/211/210/357/274/211.md" +0 -556
  155. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274 AI /345/255/227/346/256/265 /345/274/200/345/217/221/346/214/207/345/215/227.md" +0 -15
  156. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/255/227/346/256/265/346/250/241/347/211/210 /344/275/277/347/224/250/346/214/207/345/215/227/AI /350/241/250/346/240/274 AI /345/255/227/346/256/265/345/270/270/350/247/201/346/212/245/351/224/231/350/257/264/346/230/216.md" +0 -649
  157. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/255/227/346/256/265/346/250/241/347/211/210 /344/275/277/347/224/250/346/214/207/345/215/227/Dify/346/231/272/350/203/275/344/275/223.md" +0 -55
  158. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/255/227/346/256/265/346/250/241/347/211/210 /344/275/277/347/224/250/346/214/207/345/215/227/GPTPro /345/255/227/346/256/265/346/215/267/345/276/204 /345/257/206/351/222/245/350/216/267/345/217/226/346/214/207/345/215/227.md" +0 -23
  159. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/255/227/346/256/265/346/250/241/347/211/210 /344/275/277/347/224/250/346/214/207/345/215/227/OpenClaw /345/260/217/351/276/231/350/231/276/345/212/251/346/211/213/351/205/215/347/275/256/346/225/231/347/250/213.md" +0 -27
  160. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/255/227/346/256/265/346/250/241/347/211/210 /344/275/277/347/224/250/346/214/207/345/215/227//345/233/275/345/206/205/345/244/226/345/277/253/351/200/222/347/211/251/346/265/201/344/277/241/346/201/257/346/237/245/350/257/242/344/275/277/347/224/250/346/214/207/345/215/227.md" +0 -907
  161. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/255/227/346/256/265/346/250/241/347/211/210 /344/275/277/347/224/250/346/214/207/345/215/227//345/277/253/351/200/222/347/211/251/346/265/201/346/237/245/350/257/242/345/212/251/346/211/213/344/275/277/347/224/250/346/214/207/345/215/227.md" +0 -1
  162. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/AI/350/241/250/346/240/274JSAPI /347/261/273/345/236/213/346/217/217/350/277/260.xlsx +0 -0
  163. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Base /346/250/241/345/235/227.md" +0 -391
  164. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/AttachmentField /351/231/204/344/273/266/345/255/227/346/256/265.md" +0 -200
  165. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/AutoNumberField /350/207/252/345/212/250/347/274/226/345/217/267/345/255/227/346/256/265.md" +0 -75
  166. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/BarcodeField /346/235/241/347/240/201/345/255/227/346/256/265.md" +0 -95
  167. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/BidirectionalLinkField /345/217/214/345/220/221/345/205/263/350/201/224/345/255/227/346/256/265.md" +0 -294
  168. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/CheckboxField /345/244/215/351/200/211/346/241/206/345/255/227/346/256/265.md" +0 -95
  169. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/CreatedTimeField /345/210/233/345/273/272/346/227/266/351/227/264/345/255/227/346/256/265.md" +0 -134
  170. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/CurrencyField /350/264/247/345/270/201/345/255/227/346/256/265.md" +0 -260
  171. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/DateField /346/227/245/346/234/237/345/255/227/346/256/265.md" +0 -183
  172. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/DepartmentField /351/203/250/351/227/250/345/255/227/346/256/265.md" +0 -111
  173. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/EmailField /351/202/256/347/256/261/345/255/227/346/256/265.md" +0 -99
  174. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/FilterUpField /346/237/245/346/211/276/345/274/225/347/224/250/345/255/227/346/256/265.md" +0 -73
  175. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/FormulaField /345/205/254/345/274/217/345/255/227/346/256/265.md" +0 -109
  176. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/GeoLocationField /345/234/260/347/220/206/344/275/215/347/275/256/345/255/227/346/256/265.md" +0 -33
  177. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/GroupField /347/276/244/347/273/204/345/255/227/346/256/265.md" +0 -111
  178. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/LastModifiedTimeField /346/234/200/345/220/216/346/233/264/346/226/260/346/227/266/351/227/264/345/255/227/346/256/265.md" +0 -134
  179. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/LookupField /345/205/263/350/201/224/345/274/225/347/224/250/345/255/227/346/256/265.md" +0 -71
  180. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/MultiSelectField /345/244/232/351/200/211/345/255/227/346/256/265.md" +0 -349
  181. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/NumberField /346/225/260/345/255/227/345/255/227/346/256/265.md" +0 -175
  182. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/PrimaryField /344/270/273/351/224/256/346/226/207/346/241/243/345/255/227/346/256/265.md" +0 -91
  183. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/ProgressField /350/277/233/345/272/246/345/255/227/346/256/265.md" +0 -324
  184. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/RatingField /350/257/204/345/210/206/345/255/227/346/256/265.md" +0 -320
  185. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/RichTextField /345/257/214/346/226/207/346/234/254/345/255/227/346/256/265.md" +0 -45
  186. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/SingleSelectField /345/215/225/351/200/211/345/255/227/346/256/265.md" +0 -336
  187. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/TelephoneField /347/224/265/350/257/235/345/255/227/346/256/265.md" +0 -99
  188. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/TextField /346/226/207/346/234/254/345/255/227/346/256/265.md" +0 -93
  189. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/UnidirectionalLinkFields /345/215/225/345/220/221/345/205/263/350/201/224/345/255/227/346/256/265.md" +0 -295
  190. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/UrlField /351/223/276/346/216/245/345/255/227/346/256/265.md" +0 -163
  191. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227/UserField /344/272/272/345/221/230/345/255/227/346/256/265.md" +0 -266
  192. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Field /346/250/241/345/235/227.md" +0 -379
  193. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Record /346/250/241/345/235/227.md" +0 -277
  194. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/Sheet /346/250/241/345/235/227.md" +0 -1013
  195. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/UI /346/250/241/345/235/227.md" +0 -472
  196. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/View /346/250/241/345/235/227/GridView /350/241/250/346/240/274/350/247/206/345/233/276.md" +0 -835
  197. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243/View /346/250/241/345/235/227.md" +0 -203
  198. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243//345/255/227/346/256/265/346/225/260/346/215/256/347/273/223/346/236/204.md +0 -65
  199. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/345/257/271/350/261/241/346/250/241/345/236/213API/345/217/202/350/200/203/346/226/207/346/241/243//350/257/273/345/206/231AI /350/241/250/346/240/274/346/250/241/345/236/213.md" +0 -29
  200. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/346/225/260/346/215/256/346/272/220 /345/274/200/345/217/221/346/214/207/345/215/227.md" +0 -607
  201. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/204/232/346/234/254/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/Base /346/250/241/345/235/227.md" +0 -391
  202. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/204/232/346/234/254/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/Field /346/250/241/345/235/227.md" +0 -379
  203. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/204/232/346/234/254/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/Input/346/250/241/345/235/227.md" +0 -331
  204. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/204/232/346/234/254/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/Output/346/250/241/345/235/227.md" +0 -197
  205. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/204/232/346/234/254/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/Record /346/250/241/345/235/227.md" +0 -277
  206. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/204/232/346/234/254/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/Sheet /346/250/241/345/235/227.md" +0 -1013
  207. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/204/232/346/234/254/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/UI /346/250/241/345/235/227.md" +0 -472
  208. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/204/232/346/234/254/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/View /346/250/241/345/235/227.md" +0 -203
  209. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/204/232/346/234/254/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227//345/255/227/346/256/265/346/225/260/346/215/256/347/273/223/346/236/204.md" +0 -65
  210. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/204/232/346/234/254/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227.md" +0 -142
  211. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/276/271/346/240/217/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/Base /346/250/241/345/235/227.md" +0 -391
  212. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/276/271/346/240/217/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/Event/344/272/213/344/273/266/346/250/241/345/235/227.md" +0 -182
  213. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/276/271/346/240/217/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/Field /346/250/241/345/235/227.md" +0 -379
  214. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/276/271/346/240/217/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/Record /346/250/241/345/235/227.md" +0 -277
  215. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/276/271/346/240/217/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/Sheet /346/250/241/345/235/227.md" +0 -1013
  216. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/276/271/346/240/217/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/UI /346/250/241/345/235/227.md" +0 -472
  217. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/276/271/346/240/217/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227/View /346/250/241/345/235/227.md" +0 -203
  218. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/276/271/346/240/217/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227//345/205/266/344/273/226/346/216/245/345/217/243.md" +0 -146
  219. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/276/271/346/240/217/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227//345/255/227/346/256/265/346/225/260/346/215/256/347/273/223/346/236/204.md" +0 -65
  220. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/276/271/346/240/217/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227//346/240/270/345/277/203/347/237/245/350/257/206.md" +0 -54
  221. package/templates/aitable-handoff/wiki/faq-support/18-/345/274/200/345/217/221/350/200/205/346/214/207/345/215/227/AI/350/241/250/346/240/274/350/276/271/346/240/217/346/217/222/344/273/266 /345/274/200/345/217/221/346/214/207/345/215/227.md" +0 -192
  222. package/templates/aitable-handoff/wiki/faq-support//351/222/211/351/222/211AI/350/241/250/346/240/274FAQ.md +0 -611
  223. package/templates/aitable-handoff/workflows/admin-kb-update/recipes/kb-refine.recipe.ts +0 -131
  224. package/templates/aitable-handoff/workflows/admin-kb-update/recipes/kb_sync_handler.recipe.ts +0 -130
  225. package/templates/aitable-handoff/workflows/admin-kb-update/workflow.yml +0 -125
  226. package/templates/aitable-handoff/workflows/config-sync/recipes/config_sync.recipe.ts +0 -448
  227. package/templates/aitable-handoff/workflows/config-sync/recipes/config_sync_handler.recipe.ts +0 -16
  228. package/templates/aitable-handoff/workflows/config-sync/workflow.yml +0 -73
  229. package/templates/aitable-handoff/workflows/daily-review/recipes/daily_review.recipe.ts +0 -529
  230. package/templates/aitable-handoff/workflows/daily-review/recipes/daily_review_handler.recipe.ts +0 -26
  231. package/templates/aitable-handoff/workflows/daily-review/recipes/memory-events.ts +0 -56
  232. package/templates/aitable-handoff/workflows/daily-review/workflow.yml +0 -92
  233. package/templates/aitable-handoff/workflows/group-qa/error-replies.json +0 -53
  234. package/templates/aitable-handoff/workflows/group-qa/recipes/answer.recipe.ts +0 -197
  235. package/templates/aitable-handoff/workflows/group-qa/recipes/conversation_handler.recipe.ts +0 -294
  236. package/templates/aitable-handoff/workflows/group-qa/recipes/issue-classifier.ts +0 -120
  237. package/templates/aitable-handoff/workflows/group-qa/recipes/known-error-match.recipe.ts +0 -75
  238. package/templates/aitable-handoff/workflows/group-qa/recipes/memory-events.ts +0 -55
  239. package/templates/aitable-handoff/workflows/group-qa/recipes/reply-to-group.recipe.ts +0 -132
  240. package/templates/aitable-handoff/workflows/group-qa/recipes/troubleshoot-issue.recipe.ts +0 -195
  241. package/templates/aitable-handoff/workflows/group-qa/workflow.yml +0 -210
  242. package/templates/aitable-handoff/workspaces/daily-review/AGENTS.md +0 -189
  243. package/templates/aitable-handoff/workspaces/faq-support/AGENTS.md +0 -448
  244. package/templates/aitable-handoff/workspaces/faq-support/contacts.json +0 -14
  245. package/templates/aitable-handoff/workspaces/faq-support/owner-map.json +0 -18
  246. package/templates/aitable-handoff/workspaces/faq-support/skills/bug-triage/SKILL.md +0 -130
  247. package/templates/aitable-handoff/workspaces/faq-troubleshooter/AGENTS.md +0 -53
  248. package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/SKILL.md +0 -58
  249. package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/aitable-import-troubleshooter/SKILL.md +0 -485
  250. package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/aitable-openapi-troubleshooter/SKILL.md +0 -183
  251. package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/import-openapi-e2e-troubleshooter/SKILL.md +0 -459
  252. package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/notable-datasource-troubleshooter/SKILL.md +0 -1286
  253. package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/notable-field-troubleshooter/SKILL.md +0 -673
  254. package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/spreadsheet-datasync-troubleshooter/SKILL.md +0 -322
  255. package/templates/aitable-handoff/workspaces/kb-editor/AGENTS.md +0 -32
  256. package/templates/support-qa/lib/assemble-cli.ts +0 -30
  257. package/templates/support-qa/lib/assemble.ts +0 -279
  258. package/templates/support-qa/lib/echo-guard.ts +0 -50
  259. package/templates/support-qa/lib/fastpath.ts +0 -227
  260. package/templates/support-qa/lib/owner-mention.ts +0 -140
  261. package/templates/support-qa/lib/profile-guard.ts +0 -55
  262. package/templates/support-qa/lib/send-failure-guard.ts +0 -59
  263. package/templates/support-qa/lib/troubleshoot.ts +0 -236
@@ -0,0 +1,294 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { parse as parseYaml } from "yaml";
4
+ import { isCapabilityEnabled, loadClassifierRules, loadReplyRules } from "./declarative-matcher.js";
5
+ import type { PreflightIssue } from "aitable-workflow-core";
6
+ import { SUPPORT_ACTIONS, KB_STATUS, KB_STATUS_VALUES } from "./contract.js";
7
+
8
+ /**
9
+ * support-qa 实例 preflight(纯校验,零写盘)
10
+ *
11
+ * 由 core 的 preflight 扩展点在 `aitable-workflow config` 与 `run` / `setup` 启动期加载
12
+ * (约定:实例根 `lib/preflight.ts` 导出 `preflight(configDir)`)。
13
+ *
14
+ * 分档语义(core 按此决定停到什么程度):
15
+ * - fatal:实例级不可信 → 拒绝启动。profile.yml 结构错、persona 缺失/为空、
16
+ * persona 疑似放开通用闸门("闸门只准收紧不准放开"纪律的落点)。
17
+ * - error:可归因到单个 workflow → 只停该轨道,其余工作流照跑。
18
+ * - warn :L3 可选能力关不上 → 该能力优雅关闭,主环照跑。
19
+ *
20
+ * 为什么不再写盘:persona 早已由 core 读取 profile 的 `persona: { file }` 并注入每次
21
+ * coding.run 的 prompt(registry.resolvePersonaFile → RoleContext → agent-adapter),
22
+ * 曾经生成的 workspaces/<role>/persona.md 是第二条冗余通路,已删。
23
+ * 但 core 对 persona 读取失败只 warn + 跳过该角色(会静默降级成 persona=role-id 的
24
+ * 临时角色),因此「persona.file 存在且非空」必须由本文件按 fatal 拦住。
25
+ */
26
+
27
+ const GROUP_QA_WORKFLOW = "group-qa";
28
+ const ADMIN_KB_WORKFLOW = "admin-kb-update";
29
+
30
+ /** persona 疑似放开通用闸门的特征:闸门只准收紧,不准放开 */
31
+ const PERSONA_GATE_RELAXING = /忽略(上述|以上|通用)|必须回复所有|无据也(可以|要)回答|不用静默/;
32
+
33
+ function readRawProfile(configDir: string, issues: PreflightIssue[]): Record<string, unknown> | null {
34
+ const file = path.resolve(configDir, "profile", "profile.yml");
35
+ if (!existsSync(file)) {
36
+ issues.push({ level: "fatal", message: `profile/profile.yml 不存在: ${file}` });
37
+ return null;
38
+ }
39
+ try {
40
+ const raw = (parseYaml(readFileSync(file, "utf8")) ?? {}) as Record<string, unknown>;
41
+ if (raw.schema_version !== 2) {
42
+ issues.push({
43
+ level: "fatal",
44
+ message: `profile.yml schema_version 必须为 2(当前: ${raw.schema_version ?? "缺失"})。请按迁移指引升级。`,
45
+ });
46
+ return null;
47
+ }
48
+ return raw;
49
+ } catch (err) {
50
+ issues.push({
51
+ level: "fatal",
52
+ message: `profile/profile.yml 解析失败: ${err instanceof Error ? err.message : String(err)}`,
53
+ });
54
+ return null;
55
+ }
56
+ }
57
+
58
+ /** collections 校验:trim、去空、必须是不含 .. 的相对路径、目录须存在 */
59
+ function validateCollections(configDir: string, raw: unknown, issues: PreflightIssue[]): void {
60
+ const list = Array.isArray(raw)
61
+ ? raw.map((c) =>
62
+ typeof c === "string" ? c.trim()
63
+ : c && typeof c === "object" && "collection" in c ? String((c as { collection: string }).collection).trim()
64
+ : String(c ?? "").trim())
65
+ : [];
66
+ if (list.length === 0 || list.some((c) => !c)) {
67
+ issues.push({
68
+ level: "fatal",
69
+ message: "roles.support.knowledge_scope.kb_collections 缺失、为空或含空字符串(必填)",
70
+ });
71
+ }
72
+ for (const c of list.filter(Boolean)) {
73
+ if (path.isAbsolute(c) || c.split(/[\\/]/).includes("..")) {
74
+ issues.push({ level: "fatal", message: `kb_collections 必须是实例内的相对路径(不含 ..): ${c}` });
75
+ continue;
76
+ }
77
+ if (!existsSync(path.resolve(configDir, c))) {
78
+ issues.push({ level: "fatal", message: `kb_collections 目录不存在: ${c}` });
79
+ }
80
+ }
81
+ }
82
+
83
+ /**
84
+ * persona 校验(两项都是 fatal,缺一不可):
85
+ * 1. `{ file }` 引用的文件必须存在且内容非空——否则 core 会静默跳过该角色,
86
+ * Agent 拿到的 persona 退化成角色 id 字面量,答疑质量无声崩塌;
87
+ * 2. 内容不得含"放开通用闸门"的措辞。
88
+ */
89
+ function validatePersona(configDir: string, supportRole: Record<string, unknown> | undefined, issues: PreflightIssue[]): void {
90
+ if (!supportRole) return;
91
+ const personaField = supportRole.persona;
92
+ let personaText = "";
93
+
94
+ if (typeof personaField === "string") {
95
+ personaText = personaField.trim();
96
+ if (!personaText) {
97
+ issues.push({ level: "fatal", message: "roles.support.persona 为空字符串" });
98
+ return;
99
+ }
100
+ } else if (personaField && typeof personaField === "object" && "file" in personaField) {
101
+ const fileRel = String((personaField as { file: string }).file ?? "").trim();
102
+ if (!fileRel) {
103
+ issues.push({ level: "fatal", message: "roles.support.persona.file 为空" });
104
+ return;
105
+ }
106
+ const abs = path.resolve(configDir, "profile", fileRel);
107
+ if (!existsSync(abs)) {
108
+ issues.push({ level: "fatal", message: `roles.support.persona.file 引用的文件不存在: profile/${fileRel}` });
109
+ return;
110
+ }
111
+ personaText = readFileSync(abs, "utf8").trim();
112
+ if (!personaText) {
113
+ issues.push({ level: "fatal", message: `roles.support.persona.file 文件内容为空: profile/${fileRel}` });
114
+ return;
115
+ }
116
+ } else {
117
+ issues.push({ level: "fatal", message: "roles.support.persona 缺失(必填)" });
118
+ return;
119
+ }
120
+
121
+ if (PERSONA_GATE_RELAXING.test(personaText)) {
122
+ issues.push({
123
+ level: "fatal",
124
+ message: "persona 内容疑似放开通用闸门(只准收紧,不准放开),请修改后重试",
125
+ });
126
+ }
127
+ }
128
+
129
+ /** 集合严格相等比较 */
130
+ function diffSets(actual: string[], expected: readonly string[]): { missing: string[]; extra: string[] } {
131
+ const a = new Set(actual);
132
+ const e = new Set(expected);
133
+ return { missing: expected.filter((v) => !a.has(v)), extra: actual.filter((v) => !e.has(v)) };
134
+ }
135
+
136
+ function getIn(obj: unknown, ...keys: string[]): unknown {
137
+ let current = obj;
138
+ for (const key of keys) {
139
+ if (!current || typeof current !== "object") return undefined;
140
+ current = (current as Record<string, unknown>)[key];
141
+ }
142
+ return current;
143
+ }
144
+
145
+ /**
146
+ * on_action policies 闭集校验:键必须 ⊆ SUPPORT_ACTIONS;group 只允许 answer / silent。
147
+ * group 只表达「群里说不说话」(轴1);Owner 指引由 Runtime 按「action 需要找人 + Owner
148
+ * 可解析」派生(轴2),不存在「通知 Owner」档位。
149
+ */
150
+ function validateOnActionPolicies(groupQaWf: unknown, issues: PreflightIssue[]): void {
151
+ const onActionStep = getIn(groupQaWf, "steps", "on_action") as Record<string, unknown> | undefined;
152
+ const policiesRaw = onActionStep?.policies;
153
+ if (policiesRaw && typeof policiesRaw === "object") {
154
+ const { extra } = diffSets(Object.keys(policiesRaw), SUPPORT_ACTIONS);
155
+ if (extra.length > 0) {
156
+ issues.push({
157
+ level: "error",
158
+ workflowId: GROUP_QA_WORKFLOW,
159
+ message: `on_action.policies 含未知 action [${extra.join(",")}],合法值: [${SUPPORT_ACTIONS.join(",")}]`,
160
+ });
161
+ }
162
+ for (const [actionName, cfg] of Object.entries(policiesRaw as Record<string, { group?: unknown }>)) {
163
+ const group = cfg && typeof cfg === "object" ? cfg.group : undefined;
164
+ if (group === undefined) continue;
165
+ if (group !== "answer" && group !== "silent") {
166
+ issues.push({
167
+ level: "error",
168
+ workflowId: GROUP_QA_WORKFLOW,
169
+ message: `on_action.policies.${actionName}.group 只能是 answer / silent(Owner 尾注不在 group 里配,由 Runtime 按 action 与 Owner 解析结果派生),实际: ${JSON.stringify(group)}`,
170
+ });
171
+ }
172
+ }
173
+ }
174
+ // 旧 on_silence 步配置仍存在 → 提醒迁移(拍平 action 后该步已改名 on_action)
175
+ if (getIn(groupQaWf, "steps", "on_silence")) {
176
+ issues.push({
177
+ level: "warn",
178
+ workflowId: GROUP_QA_WORKFLOW,
179
+ message: "workflows.group-qa.steps.on_silence 已废弃(拍平 action 后步为 on_action):请迁移为 steps.on_action.policies(track/group)",
180
+ });
181
+ }
182
+ }
183
+
184
+ /** group-qa 单选列 options 与 contract 常量的镜像强校验(双源分家会让路由静默错位) */
185
+ function validateGroupQaFieldOptions(configDir: string, issues: PreflightIssue[]): void {
186
+ const groupQaFile = path.resolve(configDir, "workflows", GROUP_QA_WORKFLOW, "workflow.yml");
187
+ if (!existsSync(groupQaFile)) return;
188
+ try {
189
+ const wf = (parseYaml(readFileSync(groupQaFile, "utf8")) ?? {}) as Record<string, any>;
190
+ const defs = Array.isArray(wf?.tracker?.field_definitions) ? wf.tracker.field_definitions : [];
191
+ for (const [fieldName, expected] of [
192
+ ["处置动作", SUPPORT_ACTIONS],
193
+ ["知识沉淀", KB_STATUS_VALUES],
194
+ ] as const) {
195
+ const matched = defs.filter((d: any) => d?.name === fieldName);
196
+ if (matched.length !== 1) {
197
+ issues.push({
198
+ level: "error",
199
+ workflowId: GROUP_QA_WORKFLOW,
200
+ message: `field_definitions 中「${fieldName}」字段必须恰好 1 个,实际 ${matched.length} 个`,
201
+ });
202
+ continue;
203
+ }
204
+ const options = Array.isArray(matched[0]?.options) ? matched[0].options.map((o: any) => String(o)) : [];
205
+ const { missing, extra } = diffSets(options, expected);
206
+ if (missing.length > 0 || extra.length > 0) {
207
+ issues.push({
208
+ level: "error",
209
+ workflowId: GROUP_QA_WORKFLOW,
210
+ message: `「${fieldName}」options 与 lib/contract.ts 不一致:缺[${missing.join(",")}] 多[${extra.join(",")}]`,
211
+ });
212
+ }
213
+ }
214
+ } catch (err) {
215
+ issues.push({
216
+ level: "error",
217
+ workflowId: GROUP_QA_WORKFLOW,
218
+ message: `workflow.yml 解析失败: ${err instanceof Error ? err.message : String(err)}`,
219
+ });
220
+ }
221
+ }
222
+
223
+ /** admin-kb-update 事件过滤锚点:锚错了知识更新轨道根本不拉单 */
224
+ function validateAdminKbFilter(workflows: Record<string, Record<string, unknown>>, issues: PreflightIssue[]): void {
225
+ const adminKbWf = workflows[ADMIN_KB_WORKFLOW];
226
+ if (!adminKbWf) return;
227
+ const esConfig = getIn(adminKbWf, "event_sources", "管理员更新监听") as Record<string, unknown> | undefined;
228
+ const filterEquals = typeof esConfig?.filter === "object" && esConfig.filter
229
+ ? String((esConfig.filter as Record<string, unknown>).equals ?? "")
230
+ : "";
231
+ if (filterEquals && filterEquals !== KB_STATUS.READY_TO_PERSIST) {
232
+ issues.push({
233
+ level: "error",
234
+ workflowId: ADMIN_KB_WORKFLOW,
235
+ message: `事件过滤 filter.equals="${filterEquals}" 必须为 "${KB_STATUS.READY_TO_PERSIST}"(否则知识更新轨道不拉单)`,
236
+ });
237
+ }
238
+ }
239
+
240
+ /** L3 可选能力预检(一律 warn:运行期缺失即优雅关闭,不阻断 L0 主环) */
241
+ function validateOptionalCapabilities(configDir: string, groupQaWf: unknown, issues: PreflightIssue[]): void {
242
+ const fastpathStep = getIn(groupQaWf, "steps", "fastpath") as Record<string, unknown> | undefined;
243
+ const fastpathRel = typeof fastpathStep?.rules === "string" ? fastpathStep.rules.trim() : "";
244
+ if (fastpathRel) {
245
+ const { issues: fpIssues } = loadReplyRules(configDir, fastpathRel);
246
+ for (const msg of fpIssues) {
247
+ issues.push({ level: "warn", workflowId: GROUP_QA_WORKFLOW, message: `fastpath: ${msg}` });
248
+ }
249
+ }
250
+
251
+ const troubleshootStep = getIn(groupQaWf, "steps", "troubleshoot") as Record<string, unknown> | undefined;
252
+ const skillsDirRel = typeof troubleshootStep?.skills_dir === "string" ? troubleshootStep.skills_dir.trim() : "";
253
+ if (skillsDirRel && !isCapabilityEnabled(configDir, skillsDirRel)) {
254
+ issues.push({
255
+ level: "warn",
256
+ workflowId: GROUP_QA_WORKFLOW,
257
+ message: `troubleshoot: skills_dir 目录不存在,整档将关闭: ${skillsDirRel}`,
258
+ });
259
+ }
260
+ const classifiersRel = typeof troubleshootStep?.classifiers === "string" ? troubleshootStep.classifiers.trim() : "";
261
+ if (classifiersRel) {
262
+ const { issues: tsIssues } = loadClassifierRules(configDir, classifiersRel);
263
+ for (const msg of tsIssues) {
264
+ issues.push({ level: "warn", workflowId: GROUP_QA_WORKFLOW, message: `troubleshoot: ${msg}` });
265
+ }
266
+ // classifier.module 合法性不在此交叉校验:模块闭集来自功能模块人员配置表
267
+ // (config-sync 运行期快照),拼写不匹配时运行期降级并记 owner_resolution_failed。
268
+ }
269
+ }
270
+
271
+ /** core preflight 扩展点约定的导出 */
272
+ export function preflight(configDir: string): PreflightIssue[] {
273
+ const issues: PreflightIssue[] = [];
274
+
275
+ const raw = readRawProfile(configDir, issues);
276
+ if (!raw) return issues; // profile 读不了,后续校验都无意义
277
+
278
+ const roles = (raw.roles ?? {}) as Record<string, Record<string, unknown>>;
279
+ const workflows = (raw.workflows ?? {}) as Record<string, Record<string, unknown>>;
280
+ const supportRole = roles.support;
281
+ const groupQaWf = workflows[GROUP_QA_WORKFLOW];
282
+
283
+ const roleName = typeof supportRole?.name === "string" ? supportRole.name.trim() : "";
284
+ if (!roleName) issues.push({ level: "fatal", message: "roles.support.name 缺失(必填)" });
285
+ validateCollections(configDir, (supportRole?.knowledge_scope as Record<string, unknown> | undefined)?.kb_collections, issues);
286
+ validatePersona(configDir, supportRole, issues);
287
+
288
+ validateOnActionPolicies(groupQaWf, issues);
289
+ validateGroupQaFieldOptions(configDir, issues);
290
+ validateAdminKbFilter(workflows, issues);
291
+ validateOptionalCapabilities(configDir, groupQaWf, issues);
292
+
293
+ return issues;
294
+ }
@@ -5,10 +5,8 @@
5
5
  "type": "module",
6
6
  "description": "通用群答疑助手(由 aitable-workflow init --template support-qa 生成)。业务差异全部在 profile/profile.yml。",
7
7
  "scripts": {
8
- "run": "npm run assemble && aitable-workflow run",
9
- "setup": "npm run assemble && aitable-workflow setup",
10
- "assemble": "tsx lib/assemble-cli.ts",
11
- "check": "tsx lib/assemble-cli.ts --check"
8
+ "run": "aitable-workflow run",
9
+ "setup": "aitable-workflow setup"
12
10
  },
13
11
  "dependencies": {
14
12
  "aitable-workflow-core": "^0.1.5",
@@ -1,6 +1,6 @@
1
1
  # fastpath 声明式规则(钉钉 AI 表格 profile)——由 error-replies.json(51) 迁移生成
2
2
  # 单向匹配:消息包含 contains 文案即秒回(key 便于排障追溯);safety 安全兜底优先级最高。
3
- # 迁移来源:aitable-handoff known-error-match(双向 includes 已修为单向)。
3
+ # 单向匹配不反向:短消息不会误命中长规则。
4
4
 
5
5
  safety:
6
6
  keywords: ["由于可能涉及敏感内容或临时限制"]
@@ -1,5 +1,5 @@
1
1
  # troubleshoot 声明式分类器(钉钉 AI 表格 profile)
2
- # 迁移自 aitable-handoff issue-classifier.ts:把硬编码正则收敛为声明式规则。
2
+ # 把硬编码正则收敛为声明式分类规则。
3
3
  # 命中 → 由 troubleshoot 排查 Agent 读 skills_dir 的对应 Skill 完成排查;都不命中 → 交语义答疑。
4
4
 
5
5
  classifiers:
@@ -1,12 +1,16 @@
1
- import { execFile } from "node:child_process";
2
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
2
  import path from "node:path";
4
- import { promisify } from "node:util";
5
3
  import { z } from "zod";
6
- import { normalizeByType, tableRefConfigSchema, globalVarRefPath, type RecipeDefinition, type RecipeContext, type RecipeResult } from "aitable-workflow-core";
4
+ import { DwsClient, normalizeByType, tableRefConfigSchema, globalVarRefPath, type RecipeDefinition, type RecipeContext, type RecipeResult } from "aitable-workflow-core";
7
5
  import { normalizeModuleOwners, type ModuleOwners } from "../../../lib/owner-resolver.js";
8
6
 
9
- const execFileAsync = promisify(execFile);
7
+ /**
8
+ * dws 命令统一走 core 的 DwsClient(而非自建 execFile):拿到退避重试(消化 dws 后端
9
+ * 偶发 TIMEOUT / 伪 AUTH_PERMISSION_DENIED)与连续失败升级告警,并让 success=false /
10
+ * degraded=true 的响应直接抛错 —— 本 recipe 的三个拉取块都包在 try/catch 里降级为
11
+ * 「保留旧值」,比静默同步一份空快照安全。
12
+ */
13
+ const dws = new DwsClient({ bin: "dws", timeoutMs: 30_000 });
10
14
 
11
15
  /** 从配置取 globalVar key:接受 "${globalVar.x}" 引用(解析出 x)或裸 key;空则回退默认。 */
12
16
  function varKey(raw: unknown, fallback: string): string {
@@ -33,8 +37,7 @@ type FetchResult<T> = { ok: true; data: T } | { ok: false; error: string };
33
37
  const CONTACT_CONCURRENCY = 5;
34
38
 
35
39
  async function dwsJson(args: string[], timeoutMs = 30_000): Promise<{ records: Rec[] }> {
36
- const { stdout } = await execFileAsync("dws", args, { encoding: "utf-8", timeout: timeoutMs, maxBuffer: 5 * 1024 * 1024 });
37
- const parsed = JSON.parse(stdout.trim()) as unknown;
40
+ const parsed = await dws.runJson(args, { timeoutMs });
38
41
  return { records: extractRecords(parsed) };
39
42
  }
40
43
 
@@ -49,8 +52,7 @@ function extractRecords(raw: unknown): Rec[] {
49
52
  }
50
53
 
51
54
  async function dwsRaw(args: string[], timeoutMs = 15_000): Promise<unknown> {
52
- const { stdout } = await execFileAsync("dws", args, { encoding: "utf-8", timeout: timeoutMs, maxBuffer: 5 * 1024 * 1024 });
53
- return JSON.parse(stdout.trim());
55
+ return dws.runJson(args, { timeoutMs });
54
56
  }
55
57
 
56
58
  /** 有界并发地映射:最多 limit 个任务同时进行,返回与输入等长的结果数组。 */
@@ -19,7 +19,7 @@ import { KB_STATUS } from "../../../lib/contract.js";
19
19
  * 各群消息不内联进 prompt(单群 500 条可达数百 KB,会打爆 agent),而是落盘到工作目录下
20
20
  * .today/<序号>-<群ID>.md,prompt 只给文件清单让 agent 自行 Read;coding.run 结束即删除。
21
21
  *
22
- * 群列表适配:aitable-handoff 的群是动态的,由 config-sync 发布到 globalVar(group_configs)。
22
+ * 群列表适配:群是动态的,由 config-sync 发布到 globalVar(group_configs)。
23
23
  * step.config.conversation_ids 二选一:静态数组,或引用 ${globalVar.group_configs}(无隐式回退)。
24
24
  */
25
25
 
@@ -3,7 +3,6 @@ import path from "node:path";
3
3
  import { z } from "zod";
4
4
  import type { RecipeDefinition, RecipeContext, RecipeResult } from "aitable-workflow-core";
5
5
  import { contractPromptBlock, extractSupportReply, type SupportReply } from "../../../lib/contract.js";
6
- import { profileAssembleGuard } from "../../../lib/profile-guard.js";
7
6
  import { SUPPORT_DECISION_CONTENT, SUPPORT_MEMORY_KINDS, SUPPORT_MEMORY_ROLES, questionKey, supportEntry, supportScope } from "../../../lib/memory-events.js";
8
7
 
9
8
  /**
@@ -73,12 +72,8 @@ const recipe: RecipeDefinition = {
73
72
  };
74
73
  }
75
74
 
76
- // 装配前置(评审 P1/P3):校验+装配 profile 产物;校验失败则阻断作答(agent_failure
77
- // 静默留痕,运营可见),绝不带着错误/降级的 profile 继续调 agent 。同一闸门也前置在
78
- // fastpath/troubleshoot(见 lib/profile-guard.ts),确保 L3 直出路径不绕过校验。
79
- // 正式入口是 `npm run assemble`(写盘)/ `npm run check`(preflight)。
80
- const guard = profileAssembleGuard(ctx, log);
81
- if (guard) return guard;
75
+ // profile 校验已前移到启动期(core preflight 扩展点加载 lib/preflight.ts):
76
+ // 配置错在 `aitable-workflow run` 启动瞬间就报,不再每条消息判一次再降级静默。
82
77
  const roleId = ctx.roleContext?.id?.trim() || "support";
83
78
  const workDir = path.resolve(ctx.configDir, "workspaces", roleId);
84
79
 
@@ -11,7 +11,7 @@ import {
11
11
  } from "aitable-workflow-core";
12
12
  import { z } from "zod";
13
13
  import { SUPPORT_MEMORY_KINDS, SUPPORT_MEMORY_ROLES, supportEntry, supportScope } from "../../../lib/memory-events.js";
14
- import { isRecentOutboundEcho } from "../../../lib/echo-guard.js";
14
+ import { echoWindow } from "../../../lib/guards.js";
15
15
 
16
16
  /**
17
17
  * 会话消息处理器(support-qa L0)
@@ -20,7 +20,7 @@ import { isRecentOutboundEcho } from "../../../lib/echo-guard.js";
20
20
  * - onEvent 纯同步(无长 await):回声过滤 → 摄入本轮消息 + 构建「近期对话上下文」→ pushEvent 建单。
21
21
  * - 内存里按 conversationId 维护近期消息环形缓冲(容量/TTL 限制,重启清空)。
22
22
  *
23
- * 与 aitable-handoff 版的三处 Pattern 级差异:
23
+ * 三处 Pattern 级行为要点:
24
24
  * 1. 出站回声防护:reply 发布的内容指纹命中 → 按机器人消息处理(只记历史不建单),
25
25
  * 防 webhook 回复以真人名义回流造成自激(评测硬用例 G1)。
26
26
  * 2. 管理员/真人同事消息写入短期记忆(role=admin):学习通道(daily-review 提炼
@@ -168,7 +168,7 @@ const recipe: EventHandlerRecipeDefinition = {
168
168
  const groupConfig = getGroupBots().get(conversationId);
169
169
  const botSets = groupConfig?.identity ?? emptySets;
170
170
  // 出站回声:webhook 回复以真人名义回流时身份匹配失效,用内容指纹兜底(G1)
171
- const isEcho = isRecentOutboundEcho(ctx.getGlobalVar, content);
171
+ const isEcho = echoWindow.has(ctx.getGlobalVar, content);
172
172
  const isBot = isEcho || matchesIdentity(botSets, senderName, senderOpenId);
173
173
  const isAdmin = !isBot && matchesIdentity(adminSets, senderName, senderOpenId);
174
174
 
@@ -1,7 +1,6 @@
1
1
  import { z } from "zod";
2
- import type { RecipeDefinition, RecipeContext, RecipeResult } from "aitable-workflow-core";
3
- import { profileAssembleGuard } from "../../../lib/profile-guard.js";
4
- import { loadFastpathRules, matchFastpath } from "../../../lib/fastpath.js";
2
+ import { type RecipeDefinition, type RecipeContext, type RecipeResult } from "aitable-workflow-core";
3
+ import { loadReplyRules, matchReplyRules } from "../../../lib/declarative-matcher.js";
5
4
 
6
5
  /**
7
6
  * fastpath 确定性秒回(support-qa L3,group-qa 首步,非 LLM)
@@ -15,7 +14,7 @@ import { loadFastpathRules, matchFastpath } from "../../../lib/fastpath.js";
15
14
  * - 未命中任何规则 → 透传给 answer 走语义答疑(语义匹配不属于 fastpath)。
16
15
  *
17
16
  * 命中即建行:本步返回 output(含 answer)且不置 tracker:false,on_demand 下建行留痕
18
- * (与 aitable-handoff 已知错误秒回一致)。
17
+ * (已知错误秒回的建行语义)。
19
18
  */
20
19
  const recipe: RecipeDefinition = {
21
20
  meta: {
@@ -45,19 +44,14 @@ const recipe: RecipeDefinition = {
45
44
  return { status: "success", output: {}, tracker: false, logs: ["空消息,透传"] };
46
45
  }
47
46
 
48
- // 装配闸门前置(评审 P1):fastpath 命中即直出固定话术并让 answer 跳过,故 profile
49
- // 装配错误时也必须阻断(与 answer 一致),不得带病秒回。
50
- const guard = profileAssembleGuard(ctx, log);
51
- if (guard) return guard;
52
-
53
- const { config, issues } = loadFastpathRules(ctx.configDir, ctx.config.rules);
47
+ const { config, issues } = loadReplyRules(ctx.configDir, ctx.config.rules as string | undefined);
54
48
  for (const i of issues) log(`[fastpath] ${i}`);
55
49
  if (!config) {
56
50
  // 未配置/文件缺失 → fastpath 关闭,透传 answer
57
51
  return { status: "success", output: {}, tracker: false, logs: ["fastpath 未启用,透传"] };
58
52
  }
59
53
 
60
- const match = matchFastpath(config, content);
54
+ const match = matchReplyRules(config, content);
61
55
  if (!match) {
62
56
  log("未命中 fastpath 规则,交给 answer");
63
57
  return { status: "success", output: {}, tracker: false, logs: ["未命中 fastpath"] };
@@ -2,10 +2,10 @@ import { existsSync } from "node:fs";
2
2
  import nodePath from "node:path";
3
3
  import { z } from "zod";
4
4
  import { resolveGlobalVarRef, type RecipeDefinition, type RecipeContext, type RecipeResult } from "aitable-workflow-core";
5
+ import { resolveGroupMention } from "../../../lib/dingtalk-group-membership.js";
5
6
  import { SUPPORT_ACTIONS, type SupportAction, KB_STATUS } from "../../../lib/contract.js";
6
7
  import { DEFAULT_ON_ACTION, type ActionPolicy, type ActionPolicyOverrides } from "../../../lib/profile.js";
7
8
  import { resolveOwner, type OwnerResolution } from "../../../lib/owner-resolver.js";
8
- import { resolveOwnerGroupMention } from "../../../lib/owner-mention.js";
9
9
  import { buildActionDispatch, needsOwnerResolution, shouldRecordOwnerFailure } from "../../../lib/action-dispatch.js";
10
10
  import { SUPPORT_MEMORY_KINDS, SUPPORT_MEMORY_ROLES, supportEntry, supportScope } from "../../../lib/memory-events.js";
11
11
 
@@ -84,7 +84,9 @@ const recipe: RecipeDefinition = {
84
84
  const ownersRef = String(ctx.config.module_owners ?? "${globalVar.module_owners}");
85
85
  owner = resolveOwner(resolveGlobalVarRef(ownersRef, ctx.getGlobalVar), module);
86
86
  if (owner.status === "resolved") {
87
- const mention = await resolveOwnerGroupMention(
87
+ // 能否真实 @:只校验 Owner 在不在当前群(联系人已由 config-sync 解析进快照)。
88
+ // 任何失败降级为 mode=name → 下游只渲染花名,不写假 @。
89
+ const mention = await resolveGroupMention(
88
90
  conversationId,
89
91
  { userId: owner.ownerUserId, openDingTalkId: owner.ownerOpenDingTalkId },
90
92
  );
@@ -1,12 +1,18 @@
1
1
  import { z } from "zod";
2
2
  import type { RecipeDefinition, RecipeContext, RecipeResult, ReplyToConversationOptions } from "aitable-workflow-core";
3
- import { resolveGlobalVarRef } from "aitable-workflow-core";
3
+ import { createFingerprintWindow, resolveGlobalVarRef } from "aitable-workflow-core";
4
4
  import { SUPPORT_MEMORY_KINDS, SUPPORT_MEMORY_ROLES, questionKey, supportEntry, supportScope } from "../../../lib/memory-events.js";
5
- import { publishSentFingerprint } from "../../../lib/echo-guard.js";
6
- import { shouldRecordSendFailure } from "../../../lib/send-failure-guard.js";
5
+ import { echoWindow } from "../../../lib/guards.js";
7
6
  import { needsOwnerResolution } from "../../../lib/action-dispatch.js";
8
7
  import type { SupportAction } from "../../../lib/contract.js";
9
8
 
9
+ const sendFailureWindow = createFingerprintWindow({
10
+ key: "send_failure_marks",
11
+ ttlMs: 10 * 60 * 1000,
12
+ capacity: 50,
13
+ maxPartLength: [300, 300, 200],
14
+ });
15
+
10
16
  /** 群配置(config-sync 发布到 globalVar 的形状):出站选路与凭据引用据此传给 replyToConversation。 */
11
17
  type GroupConfig = { groupId: string; corpId?: string; inbound?: string; outbound?: string; credRef?: string };
12
18
 
@@ -20,7 +26,7 @@ function loadGroupConfig(ctx: RecipeContext, ref: string, conversationId: string
20
26
  * 回复群消息(support-qa L0)
21
27
  *
22
28
  * 通过 messaging toolkit 的 replyToConversation 自动选路(session sessionWebhook → webhook 降级),
23
- * recipe 不感知传输细节。发送可靠性不变量(继承 aitable-handoff 生产验证):
29
+ * recipe 不感知传输细节。发送可靠性不变量(生产验证过):
24
30
  * - via=skipped 按失败处理(无可用通道 ≠ 已发送),记 send_failed;
25
31
  * 其中 configError(如 credRef 未命中 webhook_creds 命名集)返回 retryable=false,
26
32
  * 由调度层阻塞待人工改配置,不空转重试;
@@ -87,7 +93,7 @@ const recipe: RecipeDefinition = {
87
93
  log(`未能发送到群 ${conversationId} (via=skipped${reason ? `, reason=${reason}` : ""})`);
88
94
  const skipReason = reason ?? "无可用出站通道";
89
95
  // 重试风暴去重:同群+同待发内容+同原因在窗口内只留痕一次,重试只写日志
90
- if (shouldRecordSendFailure(ctx.getGlobalVar, ctx.setGlobalVar, { conversationId, content: answer, reason: `skipped:${skipReason}` })) {
96
+ if (sendFailureWindow.mark(ctx.getGlobalVar, ctx.setGlobalVar, conversationId, answer, `skipped:${skipReason}`)) {
91
97
  try {
92
98
  await toolkit.memory.append(
93
99
  supportScope(conversationId),
@@ -119,7 +125,7 @@ const recipe: RecipeDefinition = {
119
125
  log(`已发送到群 ${conversationId} (via=${via}${reason ? `, reason=${reason}` : ""})`);
120
126
  // 回声防护:发布出站内容指纹(conversation_handler 据此识别回流消息)
121
127
  try {
122
- publishSentFingerprint(ctx.getGlobalVar, ctx.setGlobalVar, answer);
128
+ echoWindow.mark(ctx.getGlobalVar, ctx.setGlobalVar, answer);
123
129
  } catch (fpErr) {
124
130
  log(`发布回声指纹失败(不影响主流程): ${fpErr instanceof Error ? fpErr.message : String(fpErr)}`);
125
131
  }
@@ -146,7 +152,7 @@ const recipe: RecipeDefinition = {
146
152
  const msg = error instanceof Error ? error.message : String(error);
147
153
  log(`发送失败: ${msg}`);
148
154
  // 与 skipped 分支同源的重试风暴去重(异常原因不同则各记一次)
149
- if (shouldRecordSendFailure(ctx.getGlobalVar, ctx.setGlobalVar, { conversationId, content: answer, reason: `error:${msg}` })) {
155
+ if (sendFailureWindow.mark(ctx.getGlobalVar, ctx.setGlobalVar, conversationId, answer, `error:${msg}`)) {
150
156
  try {
151
157
  await toolkit.memory.append(
152
158
  supportScope(conversationId),
@@ -7,20 +7,19 @@ import {
7
7
  type RecipeDefinition,
8
8
  type RecipeResult,
9
9
  } from "aitable-workflow-core";
10
- import { profileAssembleGuard } from "../../../lib/profile-guard.js";
11
10
  import {
12
- classifyIssue,
13
- isGroupTroubleshootingEnabled,
14
- isTroubleshootEnabled,
15
- loadClassifiers,
16
- type ClassifyResult,
17
- } from "../../../lib/troubleshoot.js";
11
+ classifyMessage,
12
+ isCapabilityEnabled,
13
+ isGroupToggleEnabled,
14
+ loadClassifierRules,
15
+ type ClassifyMatch,
16
+ } from "../../../lib/declarative-matcher.js";
18
17
  import { SUPPORT_DECISION_CONTENT, SUPPORT_MEMORY_KINDS, SUPPORT_MEMORY_ROLES, questionKey, supportEntry, supportScope } from "../../../lib/memory-events.js";
19
18
 
20
19
  /**
21
20
  * 问题排查(support-qa L3,group-qa 中段,requiresAgent)
22
21
  *
23
- * 声明式分类器(profile/troubleshoot/classifiers.yml)取代 handoff 硬编码 issue-classifier.ts:
22
+ * 声明式分类器(profile/troubleshoot/classifiers.yml)取代硬编码 issue-classifier:
24
23
  * 确定性识别问题类型 → 启动独立排查 Agent(读 skills_dir 的 Skill 完成真实排查)→ 按契约回复。
25
24
  *
26
25
  * 三重开关(任一不满足即透传给 answer,本步 tracker:false 不表态):
@@ -80,7 +79,7 @@ function extractDecision(raw: string): TroubleshootDecision | null {
80
79
  }
81
80
 
82
81
  function buildPrompt(args: {
83
- route: ClassifyResult;
82
+ route: ClassifyMatch;
84
83
  content: string;
85
84
  context: string;
86
85
  senderName: string;
@@ -182,15 +181,10 @@ const recipe: RecipeDefinition = {
182
181
  return { status: "success", output: {}, tracker: false, logs: ["空消息,透传"] };
183
182
  }
184
183
 
185
- // 装配闸门前置(评审 P1):排查命中即启动独立 Agent 并直出回复,故 profile
186
- // 装配错误时必须阻断(与 answer 一致),不得带病启动排查作答。
187
- const guard = profileAssembleGuard(ctx, log);
188
- if (guard) return guard;
189
-
190
184
  const skillsDir = ctx.config.skills_dir as string | undefined;
191
185
 
192
186
  // 开关 1:整档开关(skills_dir 未配置或目录不存在 → 整档关闭)
193
- if (!isTroubleshootEnabled(ctx.configDir, skillsDir)) {
187
+ if (!isCapabilityEnabled(ctx.configDir, skillsDir)) {
194
188
  log("troubleshoot 未启用(skills_dir 未配置或不存在),交给 answer");
195
189
  return { status: "success", output: {}, tracker: false, logs: ["troubleshoot 未启用"] };
196
190
  }
@@ -198,15 +192,15 @@ const recipe: RecipeDefinition = {
198
192
  // 开关 2:按群开关(群配置表 troubleshootingEnabled 明确为真)
199
193
  const groupsRef = String(ctx.config.conversation_ids ?? "${globalVar.group_configs}");
200
194
  const groupConfigs = resolveGlobalVarRef(groupsRef, ctx.getGlobalVar);
201
- if (!isGroupTroubleshootingEnabled(groupConfigs, conversationId)) {
195
+ if (!isGroupToggleEnabled(groupConfigs, conversationId, "troubleshootingEnabled")) {
202
196
  log(`群 ${conversationId || "(缺失)"} 未开启问题排查,交给 answer`);
203
197
  return { status: "success", output: {}, tracker: false, logs: ["问题排查未开启"] };
204
198
  }
205
199
 
206
200
  // 开关 3:声明式分类命中
207
- const { config, issues } = loadClassifiers(ctx.configDir, ctx.config.classifiers as string | undefined);
201
+ const { config, issues } = loadClassifierRules(ctx.configDir, ctx.config.classifiers as string | undefined);
208
202
  for (const i of issues) log(`[troubleshoot] ${i}`);
209
- const route = classifyIssue(config, content);
203
+ const route = classifyMessage(config, content);
210
204
  if (!route) {
211
205
  log("未命中确定性排查分类,交给 answer");
212
206
  return { status: "success", output: {}, tracker: false, logs: ["未命中排查分类"] };
@@ -1,6 +1,6 @@
1
1
  # 群知识库答疑助手 — Agent 执行规范(support-qa Pattern 基座)
2
2
 
3
- 你是一名【群知识库答疑助手】。你的具体人设与负责的产品领域,以本目录下 `persona.md`(若存在,由 profile 注入)为准,下文统称"你负责的产品"。
3
+ 你是一名【群知识库答疑助手】。你的具体人设与负责的产品领域,以本次任务提示词开头注入的『# 角色设定』块为准(由 profile 的 `roles.support.persona` 提供),下文统称"你负责的产品"。
4
4
 
5
5
  你的任务:收到一条群消息后,先按【三、闸门规则】判定处置动作(action),再基于【知识库】提供准确解答,并【只输出一个严格 JSON 对象】。知识库有据时就尽量把问题答清楚(默认目标);仅在无据 / 越界 / 有风险时才判无 reply 类 action。
6
6
 
@@ -1,17 +0,0 @@
1
- # LLM(知识库编译 + 技术问答推理)
2
- IDEALAB_API_KEY=your-idealab-key
3
-
4
- # 群 webhook(url+secret)来自 config-sync 发布的 globalVar:group_configs,无需在此配置
5
- # 管理员名单来自 config-sync 发布的 globalVar:admins
6
- # dws CLI 需在 PATH:消息拉取(群答疑)、aitable/contact(config-sync)
7
-
8
- # 钉钉企业机器人凭证(内部 robot 群):dingtalk_stream 入站 + messaging.robot 会话内 @人 出站,同一套凭据。
9
- # 占位:按你的应用命名并填真实值;勿写死到 workflow.yml 或表格。仅用外部 webhook 群可忽略。
10
- DINGTALK_CLIENT_ID=your-dingtalk-app-client-id
11
- DINGTALK_CLIENT_SECRET=your-dingtalk-app-client-secret
12
-
13
- # 钉钉 Stream 机器人凭据(credRef→凭据 的 JSON map)。
14
- DINGTALK_ROBOTS={"botA":{"client_id":"CHANGE_ME","client_secret":"CHANGE_ME"}}
15
-
16
- # 钉钉 Webhook 凭据(credRef→{url,secret?} 的 JSON map);仅用 robot 回复的群可忽略
17
- DINGTALK_WEBHOOK={"default":{"url":"https://oapi.dingtalk.com/robot/send?access_token=CHANGE_ME","secret":"CHANGE_ME"}}