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.
- package/package.json +3 -3
- package/templates/support-qa/lib/__tests__/declarative-matcher.test.ts +240 -0
- package/templates/support-qa/lib/__tests__/dingtalk-group-membership.test.ts +127 -0
- package/templates/support-qa/lib/__tests__/memory-events.test.ts +90 -0
- package/templates/support-qa/lib/action-dispatch.ts +1 -1
- package/templates/support-qa/lib/declarative-matcher.ts +398 -0
- package/templates/support-qa/lib/dingtalk-group-membership.ts +151 -0
- package/templates/support-qa/lib/guards.ts +18 -0
- package/templates/support-qa/lib/memory-events.ts +60 -41
- package/templates/support-qa/lib/preflight.ts +294 -0
- package/templates/support-qa/package.json +2 -4
- package/templates/support-qa/profiles/aitable/profile/fastpath/known-answers.yml +1 -1
- package/templates/support-qa/profiles/aitable/profile/troubleshoot/classifiers.yml +1 -1
- package/templates/support-qa/workflows/config-sync/recipes/config_sync.recipe.ts +10 -8
- package/templates/support-qa/workflows/daily-review/recipes/daily_review.recipe.ts +1 -1
- package/templates/support-qa/workflows/group-qa/recipes/answer.recipe.ts +2 -7
- package/templates/support-qa/workflows/group-qa/recipes/conversation_handler.recipe.ts +3 -3
- package/templates/support-qa/workflows/group-qa/recipes/fastpath.recipe.ts +5 -11
- package/templates/support-qa/workflows/group-qa/recipes/on-action.recipe.ts +4 -2
- package/templates/support-qa/workflows/group-qa/recipes/reply-to-group.recipe.ts +13 -7
- package/templates/support-qa/workflows/group-qa/recipes/troubleshoot.recipe.ts +12 -18
- package/templates/support-qa/workspaces/support/AGENTS.md +1 -1
- package/templates/aitable-handoff/.env.example +0 -17
- package/templates/aitable-handoff/aitable-workflow.config.yml +0 -64
- package/templates/aitable-handoff/coding-agents.config.json +0 -17
- package/templates/aitable-handoff/npmrc +0 -1
- package/templates/aitable-handoff/package.json +0 -16
- package/templates/aitable-handoff/roles/config-syncer.role.yml +0 -4
- package/templates/aitable-handoff/roles/daily-review.role.yml +0 -4
- package/templates/aitable-handoff/roles/faq-support.role.yml +0 -9
- package/templates/aitable-handoff/roles/faq-troubleshooter.role.yml +0 -17
- package/templates/aitable-handoff/roles/kb-editor.role.yml +0 -19
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/templates/aitable-handoff/wiki/faq-support//351/222/211/351/222/211AI/350/241/250/346/240/274FAQ.md +0 -611
- package/templates/aitable-handoff/workflows/admin-kb-update/recipes/kb-refine.recipe.ts +0 -131
- package/templates/aitable-handoff/workflows/admin-kb-update/recipes/kb_sync_handler.recipe.ts +0 -130
- package/templates/aitable-handoff/workflows/admin-kb-update/workflow.yml +0 -125
- package/templates/aitable-handoff/workflows/config-sync/recipes/config_sync.recipe.ts +0 -448
- package/templates/aitable-handoff/workflows/config-sync/recipes/config_sync_handler.recipe.ts +0 -16
- package/templates/aitable-handoff/workflows/config-sync/workflow.yml +0 -73
- package/templates/aitable-handoff/workflows/daily-review/recipes/daily_review.recipe.ts +0 -529
- package/templates/aitable-handoff/workflows/daily-review/recipes/daily_review_handler.recipe.ts +0 -26
- package/templates/aitable-handoff/workflows/daily-review/recipes/memory-events.ts +0 -56
- package/templates/aitable-handoff/workflows/daily-review/workflow.yml +0 -92
- package/templates/aitable-handoff/workflows/group-qa/error-replies.json +0 -53
- package/templates/aitable-handoff/workflows/group-qa/recipes/answer.recipe.ts +0 -197
- package/templates/aitable-handoff/workflows/group-qa/recipes/conversation_handler.recipe.ts +0 -294
- package/templates/aitable-handoff/workflows/group-qa/recipes/issue-classifier.ts +0 -120
- package/templates/aitable-handoff/workflows/group-qa/recipes/known-error-match.recipe.ts +0 -75
- package/templates/aitable-handoff/workflows/group-qa/recipes/memory-events.ts +0 -55
- package/templates/aitable-handoff/workflows/group-qa/recipes/reply-to-group.recipe.ts +0 -132
- package/templates/aitable-handoff/workflows/group-qa/recipes/troubleshoot-issue.recipe.ts +0 -195
- package/templates/aitable-handoff/workflows/group-qa/workflow.yml +0 -210
- package/templates/aitable-handoff/workspaces/daily-review/AGENTS.md +0 -189
- package/templates/aitable-handoff/workspaces/faq-support/AGENTS.md +0 -448
- package/templates/aitable-handoff/workspaces/faq-support/contacts.json +0 -14
- package/templates/aitable-handoff/workspaces/faq-support/owner-map.json +0 -18
- package/templates/aitable-handoff/workspaces/faq-support/skills/bug-triage/SKILL.md +0 -130
- package/templates/aitable-handoff/workspaces/faq-troubleshooter/AGENTS.md +0 -53
- package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/SKILL.md +0 -58
- package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/aitable-import-troubleshooter/SKILL.md +0 -485
- package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/aitable-openapi-troubleshooter/SKILL.md +0 -183
- package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/import-openapi-e2e-troubleshooter/SKILL.md +0 -459
- package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/notable-datasource-troubleshooter/SKILL.md +0 -1286
- package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/notable-field-troubleshooter/SKILL.md +0 -673
- package/templates/aitable-handoff/workspaces/faq-troubleshooter/skills/troubleshooting/spreadsheet-datasync-troubleshooter/SKILL.md +0 -322
- package/templates/aitable-handoff/workspaces/kb-editor/AGENTS.md +0 -32
- package/templates/support-qa/lib/assemble-cli.ts +0 -30
- package/templates/support-qa/lib/assemble.ts +0 -279
- package/templates/support-qa/lib/echo-guard.ts +0 -50
- package/templates/support-qa/lib/fastpath.ts +0 -227
- package/templates/support-qa/lib/owner-mention.ts +0 -140
- package/templates/support-qa/lib/profile-guard.ts +0 -55
- package/templates/support-qa/lib/send-failure-guard.ts +0 -59
- 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": "
|
|
9
|
-
"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,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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
//
|
|
77
|
-
//
|
|
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 {
|
|
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
|
-
*
|
|
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 =
|
|
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
|
|
3
|
-
import {
|
|
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
|
-
*
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 {
|
|
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
|
|
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 (
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
type
|
|
17
|
-
} from "../../../lib/
|
|
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
|
|
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:
|
|
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 (!
|
|
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 (!
|
|
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 } =
|
|
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 =
|
|
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
|
-
|
|
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"}}
|