@things-factory/ai-assistant 10.1.99 → 10.1.100
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/client/components/entry-review.ts +17 -4
- package/client/components/workspace-view.ts +6 -1
- package/client/utils/entry-proposal.ts +2 -1
- package/dist-client/components/entry-review.d.ts +1 -1
- package/dist-client/components/entry-review.js +19 -5
- package/dist-client/components/entry-review.js.map +1 -1
- package/dist-client/components/workspace-view.d.ts +1 -1
- package/dist-client/components/workspace-view.js +7 -2
- package/dist-client/components/workspace-view.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/utils/entry-proposal.d.ts +2 -0
- package/dist-client/utils/entry-proposal.js.map +1 -1
- package/dist-server/service/data-entry/entry-apply.js +2 -0
- package/dist-server/service/data-entry/entry-apply.js.map +1 -1
- package/dist-server/service/data-entry/entry-target.d.ts +52 -4
- package/dist-server/service/data-entry/entry-target.js +115 -10
- package/dist-server/service/data-entry/entry-target.js.map +1 -1
- package/dist-server/service/data-entry/entry-tools.d.ts +1 -1
- package/dist-server/service/data-entry/entry-tools.js +20 -9
- package/dist-server/service/data-entry/entry-tools.js.map +1 -1
- package/dist-server/service/data-entry/entry-update.js +3 -3
- package/dist-server/service/data-entry/entry-update.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/server/service/data-entry/data-entry-update.test.ts +61 -1
- package/server/service/data-entry/data-entry.test.ts +27 -4
- package/server/service/data-entry/entry-apply.ts +3 -1
- package/server/service/data-entry/entry-target.ts +137 -14
- package/server/service/data-entry/entry-tools.ts +21 -9
- package/server/service/data-entry/entry-update.ts +4 -3
- package/translations/en.json +7 -1
- package/translations/ja.json +7 -1
- package/translations/ko.json +7 -1
- package/translations/ms.json +7 -1
- package/translations/zh.json +7 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-target.js","sourceRoot":"","sources":["../../../server/service/data-entry/entry-target.ts"],"names":[],"mappings":";;;AAyJA,kCAEC;AAGD,kCAOC;AAGD,4CAOC;AASD,gDAgCC;AAED,sCAEC;AAED,oCAEC;AAGD,8CAEC;AAcD,sCAOC;AAED,8CAEC;AAkCD,wCAuBC;AAGD,wCAMC;AAQD,gDA2CC;AAGD,8CAGC;AAED,8BAEC;AAcD,oCAwBC;AAMD,0BAcC;AAMD,4DA4BC;AAeD,kCAoBC;AA5fD;;;;;;;;;;;;;GAaG;AACH,qCAA+B;AAuI/B;;;GAGG;AACH,SAAgB,WAAW,CAAC,QAAgB;IAC1C,OAAO,WAAW,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;AAC1C,CAAC;AAED,iGAAiG;AACjG,SAAgB,WAAW,CAAC,QAAgB,EAAE,SAA+B;IAC3E,MAAM,GAAG,GAAG,IAAA,eAAK,EAAC,QAAQ,CAAC,CAAA;IAC3B,MAAM,UAAU,GAAG,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,qBAAqB,CAAU,CAAA;IACpG,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,cAAc,SAAS,EAAE,CAAC,CAAA;IAChH,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAA;IAC/F,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;IAC5E,OAAO,GAAG,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAA;AAClF,CAAC;AAED,yEAAyE;AAClE,KAAK,UAAU,gBAAgB,CAAC,MAAmB,EAAE,KAAiB,EAAE,OAAqB;IAClG,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAM;IAC1B,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,kEAAkE;IACpE,CAAC;AACH,CAAC;AAEY,QAAA,gBAAgB,GAAG,GAAG,CAAA;AAEnC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAA;AAE9C,MAAM,GAAG,GAAG,oCAAoC,CAAA;AAEhD,oKAAoK;AACpK,SAAgB,kBAAkB,CAAC,MAAmB;IACpD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,MAAM,EAAE,GAAG,4BAA4B,CAAC,CAAA;IAC9H,IAAI,CAAC;QACH,WAAW,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAA;IACpC,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,CAAC,GAAG,mBAAmB,KAAK,EAAE,OAAO,IAAI,gBAAgB,GAAG,CAAC,CAAA;IACrH,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,CAAC,GAAG,qBAAqB,CAAC,CAAA;IAC5H,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,IAAI;YACxC,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC;YACnD,CAAC,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC;YACvD,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACxC,EAAE,CAAC;YAC9C,IAAI,CAAC;gBACH,WAAW,CAAC,QAAQ,IAAI,EAAE,EAAE,SAAS,CAAC,CAAA;YACxC,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,CAAC,GAAG,MAAM,IAAI,IAAI,KAAK,EAAE,OAAO,IAAI,gBAAgB,GAAG,CAAC,CAAA;YAChH,CAAC;QACH,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;QAC7D,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE;YAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,CAAC,GAAG,oBAAoB,IAAI,oBAAoB,CAAC,CAAA;IAC9K,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,CAAC,GAAG,uBAAuB,CAAC,CAAA;IAC9G,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAA;IAC/B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClC,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,CAAC,GAAG,eAAe,KAAK,CAAC,IAAI,UAAU,CAAC,CAAA;QACzH,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACrB,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM;YAChD,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,CAAC,GAAG,kBAAkB,KAAK,CAAC,IAAI,oBAAoB,CAAC,CAAA;IAC/G,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;AACjC,CAAC;AAED,SAAgB,aAAa,CAAC,GAAuB;IACnD,OAAO,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AAC3C,CAAC;AAED,SAAgB,YAAY;IAC1B,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;AAC9B,CAAC;AAED,iBAAiB;AACjB,SAAgB,iBAAiB;IAC/B,OAAO,CAAC,KAAK,EAAE,CAAA;AACjB,CAAC;AAED,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,EAAE,CAC/B,GAAG;KACA,KAAK,CAAC,MAAM,CAAC;KACb,MAAM,CAAC,OAAO,CAAC;KACf,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;KAClD,IAAI,CAAC,EAAE,CAAC,CAAA;AAEb,mHAAmH;AAC5G,MAAM,cAAc,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAA;AAAlE,QAAA,cAAc,kBAAoD;AACxE,MAAM,YAAY,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAA;AAAtD,QAAA,YAAY,gBAA0C;AAEnE,iHAAiH;AACjH,SAAgB,aAAa,CAAC,GAAW;IACvC,MAAM,MAAM,GAAG,GAAG;SACf,KAAK,CAAC,MAAM,CAAC;SACb,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAClD,IAAI,CAAC,EAAE,CAAC,CAAA;IACX,OAAO,UAAU,MAAM,SAAS,CAAA;AAClC,CAAC;AAED,SAAgB,iBAAiB,CAAC,GAAW;IAC3C,OAAO,cAAc,GAAG,EAAE,CAAA;AAC5B,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;AAEvH,gHAAgH;AAChH,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;IAChF,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IAC/C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IAC/F,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAA;IACtD,OAAO,MAAM,CAAC,OAAO,CAAC,CAAA;AACxB,CAAC;AAED,gHAAgH;AAChH,SAAS,MAAM,CAAC,KAAc;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IAC/C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAA;IAC5E,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAA;IAC5B,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACjF,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;IACrD,IAAI,IAAI,CAAC,cAAc,EAAE,KAAK,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,KAAK,GAAG;QAAE,OAAO,SAAS,CAAA;IACrH,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAA;AACxF,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAA;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IAC/C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACvC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACzD,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IAC1D,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,6GAA6G;AAC7G,SAAgB,cAAc,CAAC,KAAiB,EAAE,KAAc;IAC9D,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;YAC5B,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAA;QACjE,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;YAC5B,OAAO,IAAI,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAA;QAC9F,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;YAC1B,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAA;QAC/D,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;YAC7B,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAA;QAClE,CAAC;QACD,KAAK,MAAM;YACT,OAAO,KAAK,CAAC,MAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAA;QAChH;YACE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAA;IACzC,CAAC;AACH,CAAC;AAED,qFAAqF;AACrF,SAAgB,cAAc,CAAC,KAAiB,EAAE,CAAU,EAAE,CAAU;IACtE,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IACrC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAA;IACtC,MAAM,CAAC,GAAG,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAClC,MAAM,CAAC,GAAG,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAClC,OAAO,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAA;AACnG,CAAC;AAED;;;;;GAKG;AACH,SAAgB,kBAAkB,CAAC,MAAmB,EAAE,KAAc;IACpE,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,IAAI,wBAAgB,CAAA;IAC9C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;IAEvE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAQ,EAAE,KAAK,EAAY,EAAE;QAChE,MAAM,KAAK,GAAG,GAAG,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAA;QACnF,MAAM,MAAM,GAA4B,EAAE,CAAA;QAC1C,MAAM,MAAM,GAAiB,EAAE,CAAA;QAE/B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACtC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QAC7F,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YAC/B,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACjB,IAAI,KAAK,CAAC,QAAQ;oBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;gBACxF,SAAQ;YACV,CAAC;YACD,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;YACnD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;gBAC1B,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAK,EAAE,MAAM,EAAE,IAAI,KAAK,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;YACxI,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;YAC3B,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAkB,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC;YACxD,CAAC,CAAC,GAAG,CAAC,OAAO;iBACR,MAAM,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;iBAC5D,GAAG,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,CAAC;gBAClB,GAAG,CAAC,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnF,GAAG,CAAC,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC7E,CAAC,CAAC;YACP,CAAC,CAAC,EAAE,CAAA;QACN,IAAI,CAAC,OAAO,CAAC,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QAExE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;IAC3C,CAAC,CAAC,CAAA;IAEF,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,EAAE,CAAA;AACtD,CAAC;AAED,mHAAmH;AACnH,SAAgB,iBAAiB,CAAC,IAAgB,EAAE,KAAiC;IACnF,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;AAC1G,CAAC;AAED,SAAgB,SAAS,CAAC,GAAa;IACrC,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;AACjD,CAAC;AAED;;;;;;;GAOG;AAEH,MAAM,MAAM,GAAG,4BAA4B,CAAA;AAE3C,wDAAwD;AACxD,SAAgB,YAAY,CAAC,IAAoB,EAAE,KAAc;IAC/D,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAA;QACnE,MAAM,QAAQ,GAAG,KAAK,GAAG,CAAC,CAAA;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;QACxG,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QACpC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,uBAAuB,EAAE,GAAG,CAAC,CAAA;QACzD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAA;QAC/B,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC;YACnC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;YAC5C,IAAI,CAAC,IAAI;gBAAE,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,KAAK,CAAC,CAAA;QACrC,CAAC;QACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;IAC/D,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QACzF,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAA;QACrB,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAA;QACzB,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QAC5B,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QAC5B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACjM,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC;AAED;;;GAGG;AACH,SAAgB,OAAO,CAAC,IAAY,EAAE,KAAe;IACnD,MAAM,KAAK,GAAG,CAAC,CAAqB,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,CAAA;IACpE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QACvB,KAAK,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;YAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;YAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;YACpC,4GAA4G;YAC5G,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;gBAAE,SAAQ;YACtE,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;gBAAE,SAAQ;YAClF,IAAI,KAAK,KAAK,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;gBAAE,SAAQ;YACjF,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,wBAAwB,CAAC,IAAgB,EAAE,MAAoB,EAAE,KAA0B;IACzG,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IAC1F,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QACpB,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QAC/F,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM;YAAE,OAAO,GAAG,CAAA;QAChD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;QAClD,IAAI,CAAC,QAAQ,CAAC,MAAM;YAAE,OAAO,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,CAAA;QAEjH,MAAM,KAAK,GAAG,OAAO;aAClB,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;aAClF,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QAClC,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO,GAAG,CAAA;QAE7B,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YAC3C,MAAM,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YAChF,IAAI,EAAE,IAAI,CAAC;gBAAE,OAAO,EAAE,GAAG,GAAG,EAAE,QAAQ,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAA;QAC9E,CAAC;QAED,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAA;QACxG,MAAM,MAAM,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAA;QAC9B,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YAC1G,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY;gBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QAChH,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QACnG,OAAO,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,CAAA;IAC3B,CAAC,CAAC,CAAA;AACJ,CAAC;AAcD,yGAAyG;AACzG,SAAgB,WAAW,CACzB,IAAgB,EAChB,MAAoB,EACpB,QAAgF,EAChF,KAA0B;IAE1B,OAAO,MAAM;SACV,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;SACrF,GAAG,CAAC,KAAK,CAAC,EAAE;QACX,MAAM,GAAG,GAAG,CAAC,IAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAA;QACnL,MAAM,KAAK,GAAe,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;QAChH,MAAM,KAAK,GAAG,QAAQ,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC9G,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAA;YACtB,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAA;YAC9D,MAAM,IAAI,GAAG,QAAS,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAS,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YACnF,IAAI,IAAI,KAAK,SAAS;gBAAE,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;QAChI,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC,CAAC,CAAA;AACN,CAAC","sourcesContent":["/*\n * Data entry from material - what an application declares so the assistant can enter its records\n * (operato-application/design/ai/data-entry.md).\n *\n * A person hands the conversation what the records are made of - a bank export, a photo of a receipt,\n * lines pasted from a mail - and the assistant turns it into rows of one of the application's records.\n * Nothing is written by the model. It proposes the rows; the card shows them with what was wrong in\n * each and where each came from; a correction is said in the conversation and the model proposes again;\n * the person presses the button; the server enters each row **through the application's own GraphQL\n * mutation**, run with the person's request state - the same door, directives and checks as entering by hand.\n * There is no second way into the record.\n *\n * This file is pure - no framework, no database - so the rules a row passes are tested without a server.\n */\nimport { parse } from 'graphql'\n\nexport type EntryFieldType = 'string' | 'text' | 'number' | 'integer' | 'date' | 'boolean' | 'enum'\n\nexport interface EntryField {\n name: string\n type: EntryFieldType\n required?: boolean\n /** The allowed values of an `enum` field. */\n values?: string[]\n /** What the model reads about the field - English, like every tool description. */\n description?: string\n /** i18n key of the column heading on the card. Absent: the field name. */\n labelKey?: string\n /** A number field the card sums - and compares with the total the material prints (§ totals). */\n total?: boolean\n /** An enum's values on the card: `<prefix><value in lowercase>` - `text.expense-payment-` shows PERSONAL_CARD as 개인카드. */\n valueKeyPrefix?: string\n}\n\n/** Where a row came from - which file, and where in it. Shown on the card beside the row. */\nexport interface EntrySource {\n attachmentId?: string\n /** \"row 3\", \"the receipt photo\", \"the person's message\" - the model's words. */\n where?: string\n}\n\nexport interface EntryIssue {\n /** The field it is about. Absent: the row as a whole. */\n field?: string\n /** A code the screen translates: `ai-assistant.entry.issue.<code>`, or the target's own `messageKey`. */\n code: string\n messageKey?: string\n params?: Record<string, unknown>\n /** A blocking issue keeps the row out when the person presses the button. */\n blocking: boolean\n}\n\nexport interface EntryRowInput {\n values?: Record<string, unknown>\n sources?: EntrySource[]\n}\n\nexport interface EntryRow {\n index: number\n values: Record<string, unknown>\n sources: EntrySource[]\n issues: EntryIssue[]\n /** The line of a text source where this row's numbers and dates were all found - the server's check, not the model's word. */\n evidence?: { attachmentId: string; line: number }\n}\n\nexport interface EntryContext {\n /** The request state - domain, user, and when writing, `tx` and `afterCommit`. */\n state: any\n}\n\nexport interface EntryApplied {\n /** The created record's id, when there is one. */\n id?: string\n /** A short name for the conversation line - \"2026-09-12 · 택시 · ₩12,400\". */\n label?: string\n}\n\n/** What happened, for an application that writes down every assistant call (office's AI audit). */\nexport interface EntryEvent {\n phase: 'propose' | 'apply'\n tool: string\n rows: number\n ok: boolean\n applied?: number\n missed?: number\n error?: string\n /** propose: the rows as the model gave them; apply: the proposal key and each row's result. */\n detail?: unknown\n}\n\nexport interface EntryTarget {\n /** `<app>.<record>` - `office.expense-line`. */\n key: string\n /** i18n key of the record's name on the card. */\n labelKey: string\n /** What one row is, for the model. */\n description: string\n fields: EntryField[]\n /**\n * The application's own mutation that enters one record, as a GraphQL document with one root field -\n * `mutation ($line: NewExpenseLine!) { addExpenseLine(line: $line) { id } }`. Its root field is the door:\n * the propose tool is offered only to someone who passes it, and each row is entered by running it with\n * the person's request state, so `@privilege`, `@transaction` and the door's own checks apply as they do\n * to a person typing it in.\n */\n mutation: string\n /** The mutation's variables for one row. */\n variables(row: EntryRow): Record<string, unknown>\n /** What the conversation says of an entered row - its id and a short name. */\n appliedOf?(data: any, row: EntryRow): EntryApplied | undefined\n /** At most this many rows in one proposal. Default 200. */\n maxRows?: number\n /**\n * Read-only checks the application owns - a duplicate of what is already entered, a code that does not\n * exist. Asked when the rows are proposed and again when they are entered: the records may have moved.\n * Returns one list per row, in order.\n */\n check?(rows: EntryRow[], context: EntryContext): EntryIssue[][] | Promise<EntryIssue[][]>\n /** Told of every proposal and every entering - an application that audits its assistant writes it down. A throw is ignored. */\n record?(event: EntryEvent, context: EntryContext): void | Promise<void>\n /** Changing records that exist (design/ai/data-entry.md §5-1). Absent: this target only enters new ones. */\n update?: EntryUpdate\n}\n\n/** One record as the application's read query answers it - an `id` and the fields. */\nexport type EntryRecord = { id: string } & Record<string, unknown>\n\n/**\n * How records of a target are changed - every step through the application's API, as the person.\n *\n * Which record is meant is the server's to settle, never the model's memory: whichever way it was picked\n * (on screen, selected, described), the server reads it with `read` before a card is made and again before\n * it is written.\n */\nexport interface EntryUpdate {\n /** Reads the records by id, as the person - one they may not see is not found. */\n read: { query: string; variables(ids: string[]): Record<string, unknown>; recordsOf(data: any): EntryRecord[] }\n /** Finds candidates from what the person said - \"last week's 12,400 taxi\". */\n find?: { query: string; variables(criteria: Record<string, unknown>): Record<string, unknown>; recordsOf(data: any): EntryRecord[]; criteria: EntryField[] }\n /** The application's own mutation that changes one record. */\n mutation: string\n variables(change: { id: string; record: EntryRecord; values: Record<string, unknown> }): Record<string, unknown>\n /** How a record is named on the card - \"2026-09-12 · 카카오T\". */\n labelOf?(record: EntryRecord): string\n /** The fields that may change. Default: every declared field. */\n fields?: string[]\n}\n\n/**\n * `Mutation.<root field>` of the target's mutation - the one declaration both the tool's gate and the\n * entering read. A document that is not one mutation with one root field is refused at boot.\n */\nexport function entryDoorOf(mutation: string): string {\n return rootFieldOf(mutation, 'mutation')\n}\n\n/** `Query.<field>` or `Mutation.<field>` of a document with one operation and one root field. */\nexport function rootFieldOf(document: string, operation: 'query' | 'mutation'): string {\n const doc = parse(document)\n const operations = doc.definitions.filter((one: any) => one.kind === 'OperationDefinition') as any[]\n if (operations.length !== 1 || operations[0].operation !== operation) throw new Error(`is not one ${operation}`)\n const fields = operations[0].selectionSet.selections.filter((one: any) => one.kind === 'Field')\n if (fields.length !== 1) throw new Error('must have exactly one root field')\n return `${operation === 'query' ? 'Query' : 'Mutation'}.${fields[0].name.value}`\n}\n\n/** Tells the target, and never lets its record keeping stop the work. */\nexport async function recordEntryEvent(target: EntryTarget, event: EntryEvent, context: EntryContext): Promise<void> {\n if (!target.record) return\n try {\n await target.record(event, context)\n } catch {\n /* an audit that failed to write is the application's to report */\n }\n}\n\nexport const DEFAULT_MAX_ROWS = 200\n\nconst targets = new Map<string, EntryTarget>()\n\nconst KEY = /^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$/\n\n/** Validates and keeps a target - `registerEntryTarget` (entry-tools.ts) also opens its tool. A malformed declaration is refused at boot, not in a conversation. */\nexport function declareEntryTarget(target: EntryTarget): void {\n if (!KEY.test(target?.key ?? '')) throw new Error(`[ai-assistant] entry target key '${target?.key}' is not '<app>.<record>'.`)\n try {\n entryDoorOf(target.mutation ?? '')\n } catch (error: any) {\n throw new Error(`[ai-assistant] entry target '${target.key}': its mutation ${error?.message ?? 'does not parse'}.`)\n }\n if (typeof target.variables !== 'function') throw new Error(`[ai-assistant] entry target '${target.key}' has no variables.`)\n if (target.update) {\n for (const [what, document, operation] of [\n ['update.read', target.update.read?.query, 'query'],\n ['update.mutation', target.update.mutation, 'mutation'],\n ...(target.update.find ? [['update.find', target.update.find.query, 'query']] : [])\n ] as [string, string, 'query' | 'mutation'][]) {\n try {\n rootFieldOf(document ?? '', operation)\n } catch (error: any) {\n throw new Error(`[ai-assistant] entry target '${target.key}': ${what} ${error?.message ?? 'does not parse'}.`)\n }\n }\n const known = new Set(target.fields.map(field => field.name))\n for (const name of target.update.fields ?? []) if (!known.has(name)) throw new Error(`[ai-assistant] entry target '${target.key}': update field '${name}' is not declared.`)\n }\n if (!target.fields?.length) throw new Error(`[ai-assistant] entry target '${target.key}' declares no fields.`)\n const names = new Set<string>()\n for (const field of target.fields) {\n if (names.has(field.name)) throw new Error(`[ai-assistant] entry target '${target.key}' declares '${field.name}' twice.`)\n names.add(field.name)\n if (field.type === 'enum' && !field.values?.length)\n throw new Error(`[ai-assistant] entry target '${target.key}': enum field '${field.name}' lists no values.`)\n }\n targets.set(target.key, target)\n}\n\nexport function entryTargetOf(key: string | undefined): EntryTarget | undefined {\n return key ? targets.get(key) : undefined\n}\n\nexport function entryTargets(): EntryTarget[] {\n return [...targets.values()]\n}\n\n/** For tests. */\nexport function clearEntryTargets(): void {\n targets.clear()\n}\n\nconst pascalOf = (key: string) =>\n key\n .split(/[.-]/)\n .filter(Boolean)\n .map(part => part[0].toUpperCase() + part.slice(1))\n .join('')\n\n/** `office.expense-line` → `proposeOfficeExpenseLineChanges` / `findOfficeExpenseLine` - the tools of changing. */\nexport const changeToolName = (key: string) => `propose${pascalOf(key)}Changes`\nexport const findToolName = (key: string) => `find${pascalOf(key)}`\n\n/** `office.expense-line` → `proposeOfficeExpenseLineEntries` - one tool per target, so each has its own door. */\nexport function entryToolName(key: string): string {\n const pascal = key\n .split(/[.-]/)\n .filter(Boolean)\n .map(part => part[0].toUpperCase() + part.slice(1))\n .join('')\n return `propose${pascal}Entries`\n}\n\nexport function entryCategoryName(key: string): string {\n return `data-entry:${key}`\n}\n\nconst empty = (value: unknown) => value === undefined || value === null || (typeof value === 'string' && !value.trim())\n\n/** \"12,400\" · \"₩12,400\" · \"12 400\" → 12400. Only the separators people write; anything else is not a number. */\nfunction toNumber(value: unknown): number | undefined {\n if (typeof value === 'number') return Number.isFinite(value) ? value : undefined\n if (typeof value !== 'string') return undefined\n const cleaned = value.trim().replace(/^[₩$€¥£]\\s*/, '').replace(/[,\\s]/g, '').replace(/원$/, '')\n if (!/^-?\\d+(\\.\\d+)?$/.test(cleaned)) return undefined\n return Number(cleaned)\n}\n\n/** A calendar date as `YYYY-MM-DD` - \"2026.9.12\", \"2026/09/12\" too. A day that does not exist is not a date. */\nfunction toDate(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined\n const match = value.trim().match(/^(\\d{4})[-./](\\d{1,2})[-./](\\d{1,2})\\.?$/)\n if (!match) return undefined\n const [year, month, day] = [Number(match[1]), Number(match[2]), Number(match[3])]\n const date = new Date(Date.UTC(year, month - 1, day))\n if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day) return undefined\n return `${match[1]}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`\n}\n\nfunction toBoolean(value: unknown): boolean | undefined {\n if (typeof value === 'boolean') return value\n if (typeof value !== 'string') return undefined\n const text = value.trim().toLowerCase()\n if (['true', 'yes', 'y', '1'].includes(text)) return true\n if (['false', 'no', 'n', '0'].includes(text)) return false\n return undefined\n}\n\n/** One value in its field's type - or the code of why it is not. An empty value is the caller's to judge. */\nexport function readFieldValue(field: EntryField, value: unknown): { read?: unknown; code?: string } {\n switch (field.type) {\n case 'number': {\n const read = toNumber(value)\n return read === undefined ? { code: 'not-a-number' } : { read }\n }\n case 'integer': {\n const read = toNumber(value)\n return read === undefined || !Number.isInteger(read) ? { code: 'not-an-integer' } : { read }\n }\n case 'date': {\n const read = toDate(value)\n return read === undefined ? { code: 'not-a-date' } : { read }\n }\n case 'boolean': {\n const read = toBoolean(value)\n return read === undefined ? { code: 'not-a-boolean' } : { read }\n }\n case 'enum':\n return field.values!.includes(String(value).trim()) ? { read: String(value).trim() } : { code: 'not-in-list' }\n default:\n return { read: String(value).trim() }\n }\n}\n\n/** Two values of one field the same - \"12400.00\" read from the database is 12400. */\nexport function sameFieldValue(field: EntryField, a: unknown, b: unknown): boolean {\n if (empty(a) && empty(b)) return true\n if (empty(a) || empty(b)) return false\n const x = readFieldValue(field, a)\n const y = readFieldValue(field, b)\n return x.read !== undefined && y.read !== undefined ? x.read === y.read : String(a) === String(b)\n}\n\n/**\n * The rows as the target reads them - each value in its field's type, and what was wrong said as an issue.\n *\n * A value that does not fit is **kept as it was written and marked**, never dropped or guessed: the card\n * shows what the material said, and the person corrects it in the conversation.\n */\nexport function normalizeEntryRows(target: EntryTarget, input: unknown): { rows: EntryRow[]; cut: number } {\n const list = Array.isArray(input) ? input : []\n const max = target.maxRows ?? DEFAULT_MAX_ROWS\n const fields = new Map(target.fields.map(field => [field.name, field]))\n\n const rows = list.slice(0, max).map((raw: any, index): EntryRow => {\n const given = raw && typeof raw.values === 'object' && raw.values ? raw.values : {}\n const values: Record<string, unknown> = {}\n const issues: EntryIssue[] = []\n\n for (const name of Object.keys(given)) {\n if (!fields.has(name)) issues.push({ field: name, code: 'unknown-field', blocking: false })\n }\n\n for (const field of target.fields) {\n const value = given[field.name]\n if (empty(value)) {\n if (field.required) issues.push({ field: field.name, code: 'required', blocking: true })\n continue\n }\n const { read, code } = readFieldValue(field, value)\n if (read === undefined) {\n values[field.name] = value\n issues.push({ field: field.name, code: code!, params: code === 'not-in-list' ? { values: field.values } : undefined, blocking: true })\n } else {\n values[field.name] = read\n }\n }\n\n const sources: EntrySource[] = Array.isArray(raw?.sources)\n ? raw.sources\n .filter((one: any) => one && (one.attachmentId || one.where))\n .map((one: any) => ({\n ...(typeof one.attachmentId === 'string' ? { attachmentId: one.attachmentId } : {}),\n ...(typeof one.where === 'string' ? { where: one.where.slice(0, 120) } : {})\n }))\n : []\n if (!sources.length) issues.push({ code: 'no-source', blocking: false })\n\n return { index, values, sources, issues }\n })\n\n return { rows, cut: Math.max(0, list.length - max) }\n}\n\n/** Adds the target's own findings to each row. A check that throws marks nothing and is reported by the caller. */\nexport function withCheckedIssues(rows: EntryRow[], found: EntryIssue[][] | undefined): EntryRow[] {\n if (!found) return rows\n return rows.map((row, i) => (found[i]?.length ? { ...row, issues: [...row.issues, ...found[i]] } : row))\n}\n\nexport function isBlocked(row: EntryRow): boolean {\n return row.issues.some(issue => issue.blocking)\n}\n\n/* ── Checking the rows against the material (design/ai/data-entry.md §4-1) ─────────────────────────────\n *\n * A row cites where it came from; the model's word is not proof. For a text source the server looks: the\n * row's numbers and dates must stand together on one line of the cited file. Found - the row carries that\n * line as evidence. A value the file does not have is marked, unless the row also cites the person's\n * message (a correction said in the conversation). A photo cannot be read here - the row says so.\n * Names and descriptions are not looked for: the model tidies them, and a tidied name is not a wrong one.\n */\n\nconst PERSON = /person|message|user|사용자|말/i\n\n/** The ways a number or a date is written in a file. */\nexport function writtenForms(type: EntryFieldType, value: unknown): string[] {\n if (type === 'number' || type === 'integer') {\n if (typeof value !== 'number' || !Number.isFinite(value)) return []\n const negative = value < 0\n const abs = Math.abs(value)\n const fixed = Number.isInteger(abs) ? String(abs) : abs.toFixed(2).replace(/0+$/, '').replace(/\\.$/, '')\n const [int, frac] = fixed.split('.')\n const grouped = int.replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')\n const forms = new Set<string>()\n for (const whole of [int, grouped]) {\n forms.add(frac ? `${whole}.${frac}` : whole)\n if (!frac) forms.add(`${whole}.00`)\n }\n return [...forms].map(form => (negative ? `-${form}` : form))\n }\n if (type === 'date') {\n const match = typeof value === 'string' ? value.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/) : null\n if (!match) return []\n const [, y, m, d] = match\n const mm = String(Number(m))\n const dd = String(Number(d))\n return [`${y}-${m}-${d}`, `${y}.${m}.${d}`, `${y}/${m}/${d}`, `${y}${m}${d}`, `${y}.${mm}.${dd}`, `${y}/${mm}/${dd}`, `${y}-${mm}-${dd}`, `${y.slice(2)}.${m}.${d}`, `${y.slice(2)}/${m}/${d}`]\n }\n return []\n}\n\n/**\n * A form found as a whole number - \"12,400\" is not found in \"112,400\", \"12,4001\", \"12,400.50\" or \"12,400,000\";\n * \"2026-09-12\" not in \"2026-09-120\". A CSV's own commas are not part of the number.\n */\nexport function lineHas(line: string, forms: string[]): boolean {\n const digit = (c: string | undefined) => !!c && c >= '0' && c <= '9'\n return forms.some(form => {\n for (let at = line.indexOf(form); at >= 0; at = line.indexOf(form, at + 1)) {\n const before = line[at - 1]\n const after = line[at + form.length]\n /* A comma is also the column separator of a CSV: only a comma and three digits more continue the number. */\n if (digit(before) || (before === '.' && digit(line[at - 2]))) continue\n if (digit(after) || (after === '.' && digit(line[at + form.length + 1]))) continue\n if (after === ',' && /^,\\d{3}(?!\\d)/.test(line.slice(at + form.length))) continue\n return true\n }\n return false\n })\n}\n\n/**\n * Checks each row against the text of the files it cites. `texts` holds what could be read, by attachment id;\n * an id that is not there was an image, or could not be opened.\n */\nexport function verifyRowsAgainstSources(rows: EntryRow[], fields: EntryField[], texts: Map<string, string>): EntryRow[] {\n const checked = fields.filter(field => ['number', 'integer', 'date'].includes(field.type))\n return rows.map(row => {\n const files = row.sources.map(source => source.attachmentId).filter((id): id is string => !!id)\n if (!files.length || !checked.length) return row\n const readable = files.filter(id => texts.has(id))\n if (!readable.length) return { ...row, issues: [...row.issues, { code: 'source-not-checked', blocking: false }] }\n\n const forms = checked\n .map(field => ({ field, forms: writtenForms(field.type, row.values[field.name]) }))\n .filter(one => one.forms.length)\n if (!forms.length) return row\n\n for (const id of readable) {\n const lines = texts.get(id)!.split(/\\r?\\n/)\n const at = lines.findIndex(line => forms.every(one => lineHas(line, one.forms)))\n if (at >= 0) return { ...row, evidence: { attachmentId: id, line: at + 1 } }\n }\n\n const saidByPerson = row.sources.some(source => !source.attachmentId && PERSON.test(source.where ?? ''))\n const issues = [...row.issues]\n for (const one of forms) {\n const anywhere = readable.some(id => texts.get(id)!.split(/\\r?\\n/).some(line => lineHas(line, one.forms)))\n if (!anywhere && !saidByPerson) issues.push({ field: one.field.name, code: 'not-in-source', blocking: false })\n }\n if (issues.length === row.issues.length) issues.push({ code: 'source-scattered', blocking: false })\n return { ...row, issues }\n })\n}\n\nexport interface EntryTotal {\n field: string\n /** The sum over every row, and over the rows that will be entered. */\n all: number\n ready: number\n /** The total the material prints, as the model read it - and whether the server found it in the file. */\n declared?: number\n declaredFound?: boolean\n /** declared - all. */\n difference?: number\n}\n\n/** The sums of the fields declared `total`, and how they stand against the total the material prints. */\nexport function entryTotals(\n rows: EntryRow[],\n fields: EntryField[],\n declared: { field?: string; value?: unknown; attachmentId?: string } | undefined,\n texts: Map<string, string>\n): EntryTotal[] {\n return fields\n .filter(field => field.total && (field.type === 'number' || field.type === 'integer'))\n .map(field => {\n const sum = (list: EntryRow[]) => Math.round(list.reduce((acc, row) => acc + (typeof row.values[field.name] === 'number' ? (row.values[field.name] as number) : 0), 0) * 100) / 100\n const total: EntryTotal = { field: field.name, all: sum(rows), ready: sum(rows.filter(row => !isBlocked(row))) }\n const value = declared && (declared.field ?? field.name) === field.name ? toNumber(declared.value) : undefined\n if (value !== undefined) {\n total.declared = value\n total.difference = Math.round((value - total.all) * 100) / 100\n const text = declared!.attachmentId ? texts.get(declared!.attachmentId) : undefined\n if (text !== undefined) total.declaredFound = text.split(/\\r?\\n/).some(line => lineHas(line, writtenForms(field.type, value)))\n }\n return total\n })\n}\n\n"]}
|
|
1
|
+
{"version":3,"file":"entry-target.js","sourceRoot":"","sources":["../../../server/service/data-entry/entry-target.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Data entry from material - what an application declares so the assistant can enter its records\n * (operato-application/design/ai/data-entry.md).\n *\n * A person hands the conversation what the records are made of - a bank export, a photo of a receipt,\n * lines pasted from a mail - and the assistant turns it into rows of one of the application's records.\n * Nothing is written by the model. It proposes the rows; the card shows them with what was wrong in\n * each and where each came from; a correction is said in the conversation and the model proposes again;\n * the person presses the button; the server enters each row **through the application's own GraphQL\n * mutation**, run with the person's request state - the same door, directives and checks as entering by hand.\n * There is no second way into the record.\n *\n * This file is pure - no framework, no database - so the rules a row passes are tested without a server.\n */\nimport { parse } from 'graphql'\n\nexport type EntryFieldType = 'string' | 'text' | 'number' | 'integer' | 'date' | 'boolean' | 'enum' | 'reference'\n\nexport interface EntryField {\n name: string\n type: EntryFieldType\n required?: boolean\n /** The allowed values of an `enum` field. */\n values?: string[]\n /** What the model reads about the field - English, like every tool description. */\n description?: string\n /** i18n key of the column heading on the card. Absent: the field name. */\n labelKey?: string\n /** A number field the card sums - and compares with the total the material prints (§ totals). */\n total?: boolean\n /** An enum's values on the card: `<prefix><value in lowercase>` - `text.expense-payment-` shows PERSONAL_CARD as 개인카드. */\n valueKeyPrefix?: string\n /**\n * A `reference` field points at another record - a loan, an item, a location. The model knows it by a name or\n * a code; the server finds it through the application's query, as the person, and keeps its id. One match is\n * taken; none or several keep the row out and say so - the server never picks among several.\n */\n reference?: EntryReference\n}\n\nexport interface EntryReference {\n query: string\n /** The query's variables for what the model wrote - \"기업은행\", \"A-100\". */\n variables(text: string): Record<string, unknown>\n /** The records the answer holds that the text names - the application filters, the server does not guess. */\n recordsOf(data: any, text: string): { id: string; label?: string }[]\n}\n\n/** A resolved reference, as a row keeps it. */\nexport interface ReferenceValue {\n id: string\n label?: string\n}\n\n/** Where a row came from - which file, and where in it. Shown on the card beside the row. */\nexport interface EntrySource {\n attachmentId?: string\n /** \"row 3\", \"the receipt photo\" - the model's words, in the person's language. */\n where?: string\n /** The value came from what the person said in the conversation - shown in the screen's own words, never the model's. */\n person?: boolean\n}\n\nexport interface EntryIssue {\n /** The field it is about. Absent: the row as a whole. */\n field?: string\n /** A code the screen translates: `ai-assistant.entry.issue.<code>`, or the target's own `messageKey`. */\n code: string\n messageKey?: string\n params?: Record<string, unknown>\n /** A blocking issue keeps the row out when the person presses the button. */\n blocking: boolean\n}\n\nexport interface EntryRowInput {\n values?: Record<string, unknown>\n sources?: EntrySource[]\n}\n\nexport interface EntryRow {\n index: number\n values: Record<string, unknown>\n sources: EntrySource[]\n issues: EntryIssue[]\n /** The line of a text source where this row's numbers and dates were all found - the server's check, not the model's word. */\n evidence?: { attachmentId: string; line: number }\n}\n\nexport interface EntryContext {\n /** The request state - domain, user, and when writing, `tx` and `afterCommit`. */\n state: any\n}\n\nexport interface EntryApplied {\n /** The created record's id, when there is one. */\n id?: string\n /** A short name for the conversation line - \"2026-09-12 · 택시 · ₩12,400\". */\n label?: string\n}\n\n/** What happened, for an application that writes down every assistant call (office's AI audit). */\nexport interface EntryEvent {\n phase: 'propose' | 'apply'\n tool: string\n rows: number\n ok: boolean\n applied?: number\n missed?: number\n error?: string\n /** propose: the rows as the model gave them; apply: the proposal key and each row's result. */\n detail?: unknown\n}\n\nexport interface EntryTarget {\n /** `<app>.<record>` - `office.expense-line`. */\n key: string\n /** i18n key of the record's name on the card. */\n labelKey: string\n /** What one row is, for the model. */\n description: string\n fields: EntryField[]\n /**\n * The application's own mutation that enters one record, as a GraphQL document with one root field -\n * `mutation ($line: NewExpenseLine!) { addExpenseLine(line: $line) { id } }`. Its root field is the door:\n * the propose tool is offered only to someone who passes it, and each row is entered by running it with\n * the person's request state, so `@privilege`, `@transaction` and the door's own checks apply as they do\n * to a person typing it in.\n */\n mutation: string\n /** The mutation's variables for one row. */\n variables(row: EntryRow): Record<string, unknown>\n /** What the conversation says of an entered row - its id and a short name. */\n appliedOf?(data: any, row: EntryRow): EntryApplied | undefined\n /** At most this many rows in one proposal. Default 200. */\n maxRows?: number\n /**\n * Read-only checks the application owns - a duplicate of what is already entered, a code that does not\n * exist. Asked when the rows are proposed and again when they are entered: the records may have moved.\n * Returns one list per row, in order.\n */\n check?(rows: EntryRow[], context: EntryContext): EntryIssue[][] | Promise<EntryIssue[][]>\n /** Told of every proposal and every entering - an application that audits its assistant writes it down. A throw is ignored. */\n record?(event: EntryEvent, context: EntryContext): void | Promise<void>\n /** Changing records that exist (design/ai/data-entry.md §5-1). Absent: this target only enters new ones. */\n update?: EntryUpdate\n}\n\n/** One record as the application's read query answers it - an `id` and the fields. */\nexport type EntryRecord = { id: string } & Record<string, unknown>\n\n/**\n * How records of a target are changed - every step through the application's API, as the person.\n *\n * Which record is meant is the server's to settle, never the model's memory: whichever way it was picked\n * (on screen, selected, described), the server reads it with `read` before a card is made and again before\n * it is written.\n */\nexport interface EntryUpdate {\n /** Reads the records by id, as the person - one they may not see is not found. */\n read: { query: string; variables(ids: string[]): Record<string, unknown>; recordsOf(data: any, ids: string[]): EntryRecord[] }\n /** Finds candidates from what the person said - \"last week's 12,400 taxi\". */\n find?: { query: string; variables(criteria: Record<string, unknown>): Record<string, unknown>; recordsOf(data: any, criteria: Record<string, unknown>): EntryRecord[]; criteria: EntryField[] }\n /** The application's own mutation that changes one record. */\n mutation: string\n variables(change: { id: string; record: EntryRecord; values: Record<string, unknown> }): Record<string, unknown>\n /** How a record is named on the card - \"2026-09-12 · 카카오T\". */\n labelOf?(record: EntryRecord): string\n /** The fields that may change. Default: every declared field. */\n fields?: string[]\n}\n\n/**\n * `Mutation.<root field>` of the target's mutation - the one declaration both the tool's gate and the\n * entering read. A document that is not one mutation with one root field is refused at boot.\n */\nexport function entryDoorOf(mutation: string): string {\n return rootFieldOf(mutation, 'mutation')\n}\n\n/** `Query.<field>` or `Mutation.<field>` of a document with one operation and one root field. */\nexport function rootFieldOf(document: string, operation: 'query' | 'mutation'): string {\n const doc = parse(document)\n const operations = doc.definitions.filter((one: any) => one.kind === 'OperationDefinition') as any[]\n if (operations.length !== 1 || operations[0].operation !== operation) throw new Error(`is not one ${operation}`)\n const fields = operations[0].selectionSet.selections.filter((one: any) => one.kind === 'Field')\n if (fields.length !== 1) throw new Error('must have exactly one root field')\n return `${operation === 'query' ? 'Query' : 'Mutation'}.${fields[0].name.value}`\n}\n\n/** Tells the target, and never lets its record keeping stop the work. */\nexport async function recordEntryEvent(target: EntryTarget, event: EntryEvent, context: EntryContext): Promise<void> {\n if (!target.record) return\n try {\n await target.record(event, context)\n } catch {\n /* an audit that failed to write is the application's to report */\n }\n}\n\nexport const DEFAULT_MAX_ROWS = 200\n\n/* The model's way of saying a value came from the person - kept only to read older rows and loose words. */\nconst PERSON = /person|message|user|사용자|말/i\n\nconst targets = new Map<string, EntryTarget>()\n\nconst KEY = /^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$/\n\n/** Validates and keeps a target - `registerEntryTarget` (entry-tools.ts) also opens its tool. A malformed declaration is refused at boot, not in a conversation. */\nexport function declareEntryTarget(target: EntryTarget): void {\n if (!KEY.test(target?.key ?? '')) throw new Error(`[ai-assistant] entry target key '${target?.key}' is not '<app>.<record>'.`)\n try {\n entryDoorOf(target.mutation ?? '')\n } catch (error: any) {\n throw new Error(`[ai-assistant] entry target '${target.key}': its mutation ${error?.message ?? 'does not parse'}.`)\n }\n if (typeof target.variables !== 'function') throw new Error(`[ai-assistant] entry target '${target.key}' has no variables.`)\n if (target.update) {\n for (const [what, document, operation] of [\n ['update.read', target.update.read?.query, 'query'],\n ['update.mutation', target.update.mutation, 'mutation'],\n ...(target.update.find ? [['update.find', target.update.find.query, 'query']] : [])\n ] as [string, string, 'query' | 'mutation'][]) {\n try {\n rootFieldOf(document ?? '', operation)\n } catch (error: any) {\n throw new Error(`[ai-assistant] entry target '${target.key}': ${what} ${error?.message ?? 'does not parse'}.`)\n }\n }\n const known = new Set(target.fields.map(field => field.name))\n for (const name of target.update.fields ?? []) if (!known.has(name)) throw new Error(`[ai-assistant] entry target '${target.key}': update field '${name}' is not declared.`)\n }\n if (!target.fields?.length) throw new Error(`[ai-assistant] entry target '${target.key}' declares no fields.`)\n const names = new Set<string>()\n for (const field of target.fields) {\n if (field.type === 'reference') {\n try {\n rootFieldOf(field.reference?.query ?? '', 'query')\n } catch (error: any) {\n throw new Error(`[ai-assistant] entry target '${target.key}': reference field '${field.name}' ${error?.message ?? 'has no query'}.`)\n }\n }\n if (names.has(field.name)) throw new Error(`[ai-assistant] entry target '${target.key}' declares '${field.name}' twice.`)\n names.add(field.name)\n if (field.type === 'enum' && !field.values?.length)\n throw new Error(`[ai-assistant] entry target '${target.key}': enum field '${field.name}' lists no values.`)\n }\n targets.set(target.key, target)\n}\n\nexport function entryTargetOf(key: string | undefined): EntryTarget | undefined {\n return key ? targets.get(key) : undefined\n}\n\nexport function entryTargets(): EntryTarget[] {\n return [...targets.values()]\n}\n\n/** For tests. */\nexport function clearEntryTargets(): void {\n targets.clear()\n}\n\nconst pascalOf = (key: string) =>\n key\n .split(/[.-]/)\n .filter(Boolean)\n .map(part => part[0].toUpperCase() + part.slice(1))\n .join('')\n\n/** `office.expense-line` → `proposeOfficeExpenseLineChanges` / `findOfficeExpenseLine` - the tools of changing. */\nexport const changeToolName = (key: string) => `propose${pascalOf(key)}Changes`\nexport const findToolName = (key: string) => `find${pascalOf(key)}`\n\n/** `office.expense-line` → `proposeOfficeExpenseLineEntries` - one tool per target, so each has its own door. */\nexport function entryToolName(key: string): string {\n const pascal = key\n .split(/[.-]/)\n .filter(Boolean)\n .map(part => part[0].toUpperCase() + part.slice(1))\n .join('')\n return `propose${pascal}Entries`\n}\n\nexport function entryCategoryName(key: string): string {\n return `data-entry:${key}`\n}\n\nconst empty = (value: unknown) => value === undefined || value === null || (typeof value === 'string' && !value.trim())\n\n/** \"12,400\" · \"₩12,400\" · \"12 400\" → 12400. Only the separators people write; anything else is not a number. */\nfunction toNumber(value: unknown): number | undefined {\n if (typeof value === 'number') return Number.isFinite(value) ? value : undefined\n if (typeof value !== 'string') return undefined\n const cleaned = value.trim().replace(/^[₩$€¥£]\\s*/, '').replace(/[,\\s]/g, '').replace(/원$/, '')\n if (!/^-?\\d+(\\.\\d+)?$/.test(cleaned)) return undefined\n return Number(cleaned)\n}\n\n/** A calendar date as `YYYY-MM-DD` - \"2026.9.12\", \"2026/09/12\" too. A day that does not exist is not a date. */\nfunction toDate(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined\n const match = value.trim().match(/^(\\d{4})[-./](\\d{1,2})[-./](\\d{1,2})\\.?$/)\n if (!match) return undefined\n const [year, month, day] = [Number(match[1]), Number(match[2]), Number(match[3])]\n const date = new Date(Date.UTC(year, month - 1, day))\n if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day) return undefined\n return `${match[1]}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`\n}\n\nfunction toBoolean(value: unknown): boolean | undefined {\n if (typeof value === 'boolean') return value\n if (typeof value !== 'string') return undefined\n const text = value.trim().toLowerCase()\n if (['true', 'yes', 'y', '1'].includes(text)) return true\n if (['false', 'no', 'n', '0'].includes(text)) return false\n return undefined\n}\n\n/** One value in its field's type - or the code of why it is not. An empty value is the caller's to judge. */\nexport function readFieldValue(field: EntryField, value: unknown): { read?: unknown; code?: string } {\n switch (field.type) {\n case 'number': {\n const read = toNumber(value)\n return read === undefined ? { code: 'not-a-number' } : { read }\n }\n case 'integer': {\n const read = toNumber(value)\n return read === undefined || !Number.isInteger(read) ? { code: 'not-an-integer' } : { read }\n }\n case 'date': {\n const read = toDate(value)\n return read === undefined ? { code: 'not-a-date' } : { read }\n }\n case 'boolean': {\n const read = toBoolean(value)\n return read === undefined ? { code: 'not-a-boolean' } : { read }\n }\n case 'enum':\n return field.values!.includes(String(value).trim()) ? { read: String(value).trim() } : { code: 'not-in-list' }\n case 'reference':\n /* Resolved already ({ id }), or a name to look up ({ text }) - resolveReferences settles the second. */\n if (value && typeof value === 'object' && typeof (value as any).id === 'string') return { read: { id: (value as any).id, ...((value as any).label ? { label: String((value as any).label) } : {}) } }\n if (value && typeof value === 'object' && typeof (value as any).text === 'string') return { read: { text: (value as any).text } }\n return typeof value === 'string' || typeof value === 'number' ? { read: { text: String(value).trim() } } : { code: 'not-a-reference' }\n default:\n return { read: String(value).trim() }\n }\n}\n\n/** Two values of one field the same - \"12400.00\" read from the database is 12400. */\nexport function sameFieldValue(field: EntryField, a: unknown, b: unknown): boolean {\n if (empty(a) && empty(b)) return true\n if (empty(a) || empty(b)) return false\n if (field.type === 'reference') {\n const idOf = (v: any) => (v && typeof v === 'object' ? v.id ?? v.text : String(v))\n return idOf(a) === idOf(b)\n }\n const x = readFieldValue(field, a)\n const y = readFieldValue(field, b)\n return x.read !== undefined && y.read !== undefined ? x.read === y.read : String(a) === String(b)\n}\n\n/**\n * The rows as the target reads them - each value in its field's type, and what was wrong said as an issue.\n *\n * A value that does not fit is **kept as it was written and marked**, never dropped or guessed: the card\n * shows what the material said, and the person corrects it in the conversation.\n */\nexport function normalizeEntryRows(target: EntryTarget, input: unknown): { rows: EntryRow[]; cut: number } {\n const list = Array.isArray(input) ? input : []\n const max = target.maxRows ?? DEFAULT_MAX_ROWS\n const fields = new Map(target.fields.map(field => [field.name, field]))\n\n const rows = list.slice(0, max).map((raw: any, index): EntryRow => {\n const given = raw && typeof raw.values === 'object' && raw.values ? raw.values : {}\n const values: Record<string, unknown> = {}\n const issues: EntryIssue[] = []\n\n for (const name of Object.keys(given)) {\n if (!fields.has(name)) issues.push({ field: name, code: 'unknown-field', blocking: false })\n }\n\n for (const field of target.fields) {\n const value = given[field.name]\n if (empty(value)) {\n if (field.required) issues.push({ field: field.name, code: 'required', blocking: true })\n continue\n }\n const { read, code } = readFieldValue(field, value)\n if (read === undefined) {\n values[field.name] = value\n issues.push({ field: field.name, code: code!, params: code === 'not-in-list' ? { values: field.values } : undefined, blocking: true })\n } else {\n values[field.name] = read\n }\n }\n\n const sources: EntrySource[] = Array.isArray(raw?.sources)\n ? raw.sources\n .filter((one: any) => one && (one.attachmentId || one.where || one.person === true))\n .map((one: any): EntrySource => {\n /* \"the person's message\" written by the model is the person flag - the screen says it in its own words. */\n if (one.person === true || (!one.attachmentId && typeof one.where === 'string' && PERSON.test(one.where))) return { person: true }\n return {\n ...(typeof one.attachmentId === 'string' ? { attachmentId: one.attachmentId } : {}),\n ...(typeof one.where === 'string' ? { where: one.where.slice(0, 120) } : {})\n }\n })\n : []\n if (!sources.length) issues.push({ code: 'no-source', blocking: false })\n\n return { index, values, sources, issues }\n })\n\n return { rows, cut: Math.max(0, list.length - max) }\n}\n\n/** Adds the target's own findings to each row. A check that throws marks nothing and is reported by the caller. */\nexport function withCheckedIssues(rows: EntryRow[], found: EntryIssue[][] | undefined): EntryRow[] {\n if (!found) return rows\n return rows.map((row, i) => (found[i]?.length ? { ...row, issues: [...row.issues, ...found[i]] } : row))\n}\n\nexport function isBlocked(row: EntryRow): boolean {\n return row.issues.some(issue => issue.blocking)\n}\n\n/* ── Checking the rows against the material (design/ai/data-entry.md §4-1) ─────────────────────────────\n *\n * A row cites where it came from; the model's word is not proof. For a text source the server looks: the\n * row's numbers and dates must stand together on one line of the cited file. Found - the row carries that\n * line as evidence. A value the file does not have is marked, unless the row also cites the person's\n * message (a correction said in the conversation). A photo cannot be read here - the row says so.\n * Names and descriptions are not looked for: the model tidies them, and a tidied name is not a wrong one.\n */\n\n\n/** The ways a number or a date is written in a file. */\nexport function writtenForms(type: EntryFieldType, value: unknown): string[] {\n if (type === 'number' || type === 'integer') {\n if (typeof value !== 'number' || !Number.isFinite(value)) return []\n const negative = value < 0\n const abs = Math.abs(value)\n const fixed = Number.isInteger(abs) ? String(abs) : abs.toFixed(2).replace(/0+$/, '').replace(/\\.$/, '')\n const [int, frac] = fixed.split('.')\n const grouped = int.replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')\n const forms = new Set<string>()\n for (const whole of [int, grouped]) {\n forms.add(frac ? `${whole}.${frac}` : whole)\n if (!frac) forms.add(`${whole}.00`)\n }\n return [...forms].map(form => (negative ? `-${form}` : form))\n }\n if (type === 'date') {\n const match = typeof value === 'string' ? value.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/) : null\n if (!match) return []\n const [, y, m, d] = match\n const mm = String(Number(m))\n const dd = String(Number(d))\n return [`${y}-${m}-${d}`, `${y}.${m}.${d}`, `${y}/${m}/${d}`, `${y}${m}${d}`, `${y}.${mm}.${dd}`, `${y}/${mm}/${dd}`, `${y}-${mm}-${dd}`, `${y.slice(2)}.${m}.${d}`, `${y.slice(2)}/${m}/${d}`]\n }\n return []\n}\n\n/**\n * A form found as a whole number - \"12,400\" is not found in \"112,400\", \"12,4001\", \"12,400.50\" or \"12,400,000\";\n * \"2026-09-12\" not in \"2026-09-120\". A CSV's own commas are not part of the number.\n */\nexport function lineHas(line: string, forms: string[]): boolean {\n const digit = (c: string | undefined) => !!c && c >= '0' && c <= '9'\n return forms.some(form => {\n for (let at = line.indexOf(form); at >= 0; at = line.indexOf(form, at + 1)) {\n const before = line[at - 1]\n const after = line[at + form.length]\n /* A comma is also the column separator of a CSV: only a comma and three digits more continue the number. */\n if (digit(before) || (before === '.' && digit(line[at - 2]))) continue\n if (digit(after) || (after === '.' && digit(line[at + form.length + 1]))) continue\n if (after === ',' && /^,\\d{3}(?!\\d)/.test(line.slice(at + form.length))) continue\n return true\n }\n return false\n })\n}\n\n/**\n * Checks each row against the text of the files it cites. `texts` holds what could be read, by attachment id;\n * an id that is not there was an image, or could not be opened.\n */\nexport function verifyRowsAgainstSources(rows: EntryRow[], fields: EntryField[], texts: Map<string, string>): EntryRow[] {\n const checked = fields.filter(field => ['number', 'integer', 'date'].includes(field.type))\n return rows.map(row => {\n const files = row.sources.map(source => source.attachmentId).filter((id): id is string => !!id)\n if (!files.length || !checked.length) return row\n const readable = files.filter(id => texts.has(id))\n if (!readable.length) return { ...row, issues: [...row.issues, { code: 'source-not-checked', blocking: false }] }\n\n const forms = checked\n .map(field => ({ field, forms: writtenForms(field.type, row.values[field.name]) }))\n .filter(one => one.forms.length)\n if (!forms.length) return row\n\n for (const id of readable) {\n const lines = texts.get(id)!.split(/\\r?\\n/)\n const at = lines.findIndex(line => forms.every(one => lineHas(line, one.forms)))\n if (at >= 0) return { ...row, evidence: { attachmentId: id, line: at + 1 } }\n }\n\n const saidByPerson = row.sources.some(source => source.person)\n const issues = [...row.issues]\n for (const one of forms) {\n const anywhere = readable.some(id => texts.get(id)!.split(/\\r?\\n/).some(line => lineHas(line, one.forms)))\n if (!anywhere && !saidByPerson) issues.push({ field: one.field.name, code: 'not-in-source', blocking: false })\n }\n if (issues.length === row.issues.length) issues.push({ code: 'source-scattered', blocking: false })\n return { ...row, issues }\n })\n}\n\n/**\n * The total a file prints - a line named 합계 · 총계 · 총액 · total · sum, and the last amount on it. The server\n * reads it itself, so the card can compare even when the model did not say it (2026-10-01: once it did, once not).\n */\nexport function printedTotalOf(text: string): { value: number; line: number } | undefined {\n const lines = text.split(/\\r?\\n/)\n for (let i = lines.length - 1; i >= 0; i--) {\n if (!/(합\\s*계|총\\s*계|총\\s*액|total|sum)/i.test(lines[i])) continue\n const amounts = [...lines[i].matchAll(/-?\\d{1,3}(?:,\\d{3})+(?:\\.\\d+)?|-?\\d+(?:\\.\\d+)?/g)].map(match => Number(match[0].replace(/,/g, '')))\n if (amounts.length) return { value: amounts[amounts.length - 1], line: i + 1 }\n }\n return undefined\n}\n\nexport interface EntryTotal {\n field: string\n /** The sum over every row, and over the rows that will be entered. */\n all: number\n ready: number\n /** The total the material prints, as the model read it - and whether the server found it in the file. */\n declared?: number\n declaredFound?: boolean\n /** declared - all. */\n difference?: number\n /** Where the declared total came from - the model's reading, or the server's own from a file's total line. */\n declaredBy?: 'model' | 'file'\n}\n\n/** The sums of the fields declared `total`, and how they stand against the total the material prints. */\nexport function entryTotals(\n rows: EntryRow[],\n fields: EntryField[],\n declared: { field?: string; value?: unknown; attachmentId?: string } | undefined,\n texts: Map<string, string>\n): EntryTotal[] {\n const totalled = fields.filter(field => field.total && (field.type === 'number' || field.type === 'integer'))\n /* With one totalled field and no total from the model, the server looks for the file's own total line. */\n const printed = !declared && totalled.length === 1 ? [...texts.values()].map(printedTotalOf).find(Boolean) : undefined\n return totalled\n .map(field => {\n const sum = (list: EntryRow[]) => Math.round(list.reduce((acc, row) => acc + (typeof row.values[field.name] === 'number' ? (row.values[field.name] as number) : 0), 0) * 100) / 100\n const total: EntryTotal = { field: field.name, all: sum(rows), ready: sum(rows.filter(row => !isBlocked(row))) }\n if (printed) {\n total.declared = printed.value\n total.declaredFound = true\n total.declaredBy = 'file'\n total.difference = Math.round((printed.value - total.all) * 100) / 100\n return total\n }\n /*\n * With one totalled field the model's total is that field's, whatever it named it - on office's second card it\n * wrote the file's column name (이용금액) for amount, and the total was dropped (2026-10-01).\n */\n const mine = declared && (totalled.length === 1 || (declared.field ?? field.name) === field.name)\n const value = mine ? toNumber(declared!.value) : undefined\n if (value !== undefined) {\n total.declaredBy = 'model'\n total.declared = value\n total.difference = Math.round((value - total.all) * 100) / 100\n const text = declared!.attachmentId ? texts.get(declared!.attachmentId) : undefined\n if (text !== undefined) total.declaredFound = text.split(/\\r?\\n/).some(line => lineHas(line, writtenForms(field.type, value)))\n }\n return total\n })\n}\n\n/** The doors of the queries a target's reference fields reach - the person must pass them too. */\nexport function referenceDoorsOf(fields: EntryField[]): string[] {\n return [...new Set(fields.filter(field => field.type === 'reference' && field.reference).map(field => rootFieldOf(field.reference!.query, 'query')))]\n}\n\n/**\n * Settles each reference a row names by text, through the application's query as the person. One match keeps its\n * id and name; none or several keep the row out - several with their names, so the person can say which.\n */\nexport async function resolveReferences<T extends { values: Record<string, unknown>; issues: EntryIssue[] }>(\n fields: EntryField[],\n rows: T[],\n run: (document: string, variables: Record<string, unknown>) => Promise<{ data?: any; errors?: readonly { message: string }[] }>\n): Promise<T[]> {\n const references = fields.filter(field => field.type === 'reference' && field.reference)\n if (!references.length) return rows\n const asked = new Map<string, { id: string; label?: string }[] | Error>()\n for (const row of rows) {\n for (const field of references) {\n const value: any = row.values[field.name]\n if (!value || typeof value !== 'object' || typeof value.text !== 'string') continue\n const key = `${field.name}\\u0000${value.text}`\n if (!asked.has(key)) {\n try {\n const answer = await run(field.reference!.query, field.reference!.variables(value.text))\n asked.set(key, answer.errors?.length ? new Error(answer.errors[0].message) : field.reference!.recordsOf(answer.data, value.text) ?? [])\n } catch (error: any) {\n asked.set(key, error instanceof Error ? error : new Error(String(error)))\n }\n }\n const found = asked.get(key)!\n if (found instanceof Error) {\n row.issues.push({ field: field.name, code: 'reference-unreadable', params: { text: value.text }, blocking: true })\n } else if (found.length === 1) {\n row.values[field.name] = { id: found[0].id, ...(found[0].label ? { label: found[0].label } : {}) }\n } else {\n row.issues.push({\n field: field.name,\n code: found.length ? 'reference-ambiguous' : 'reference-not-found',\n params: { text: value.text, ...(found.length ? { candidates: found.slice(0, 5).map(one => one.label || one.id).join(', ') } : {}) },\n blocking: true\n })\n }\n }\n }\n return rows\n}\n\n"]}
|
|
@@ -2,7 +2,7 @@ import { type ToolCategory } from '@things-factory/ai-client-base';
|
|
|
2
2
|
import { type GraphqlRunner } from './entry-update.js';
|
|
3
3
|
import { type EntryRow, type EntryTarget } from './entry-target.js';
|
|
4
4
|
export type SourceTextLoader = (attachmentIds: string[], context: any) => Promise<Map<string, string>>;
|
|
5
|
-
export declare function proposeEntries(target: EntryTarget, args: any, context: any, loadTexts?: SourceTextLoader): Promise<{
|
|
5
|
+
export declare function proposeEntries(target: EntryTarget, args: any, context: any, loadTexts?: SourceTextLoader, run?: GraphqlRunner): Promise<{
|
|
6
6
|
rejected: boolean;
|
|
7
7
|
error: string;
|
|
8
8
|
message: string;
|
|
@@ -55,6 +55,8 @@ function fieldSchema(field) {
|
|
|
55
55
|
* whole request with it: "12,400" or "₩12,400" is the model's to write as 12400 (2026-10-01, office).
|
|
56
56
|
*/
|
|
57
57
|
const type = field.type === 'number' ? 'number' : field.type === 'integer' ? 'integer' : field.type === 'boolean' ? 'boolean' : 'string';
|
|
58
|
+
if (field.type === 'reference')
|
|
59
|
+
return { type: 'string', description: [field.description, field.required ? 'required' : 'optional', 'the name or code as the material or the person gives it - the server finds the record'].filter(Boolean).join('. ') };
|
|
58
60
|
const said = [
|
|
59
61
|
field.description,
|
|
60
62
|
field.required ? 'required' : 'optional',
|
|
@@ -76,7 +78,7 @@ function columnsOf(target) {
|
|
|
76
78
|
}));
|
|
77
79
|
}
|
|
78
80
|
const readSources = async (ids, context) => (await Promise.resolve().then(() => __importStar(require('./entry-sources.js')))).loadSourceTexts(ids, context);
|
|
79
|
-
async function proposeEntries(target, args, context, loadTexts = readSources) {
|
|
81
|
+
async function proposeEntries(target, args, context, loadTexts = readSources, run) {
|
|
80
82
|
const tool = (0, entry_target_js_1.entryToolName)(target.key);
|
|
81
83
|
const told = (event) => (0, entry_target_js_1.recordEntryEvent)(target, { phase: 'propose', tool, ...event }, { state: context?.state });
|
|
82
84
|
const { rows: normalized, cut } = (0, entry_target_js_1.normalizeEntryRows)(target, args?.rows);
|
|
@@ -88,7 +90,9 @@ async function proposeEntries(target, args, context, loadTexts = readSources) {
|
|
|
88
90
|
const declared = args?.declaredTotal && typeof args.declaredTotal === 'object' ? args.declaredTotal : undefined;
|
|
89
91
|
const cited = [...normalized.flatMap(row => row.sources.map(source => source.attachmentId)), declared?.attachmentId].filter((id) => typeof id === 'string' && !!id);
|
|
90
92
|
const texts = cited.length ? await loadTexts(cited, context).catch(() => new Map()) : new Map();
|
|
91
|
-
|
|
93
|
+
/* A name the model wrote for another record is settled to its id by the application's query, as the person. */
|
|
94
|
+
const resolved = await (0, entry_target_js_1.resolveReferences)(target.fields, normalized, run ?? (0, exports.runAsCaller)(context));
|
|
95
|
+
const read = (0, entry_target_js_1.verifyRowsAgainstSources)(resolved, target.fields, texts);
|
|
92
96
|
let rows = read;
|
|
93
97
|
let checkFailed;
|
|
94
98
|
if (target.check) {
|
|
@@ -149,7 +153,7 @@ function changeSpecs(target, run) {
|
|
|
149
153
|
kind: 'read',
|
|
150
154
|
name: (0, entry_target_js_1.changeToolName)(target.key),
|
|
151
155
|
/* The person must be able to read the records and change them by hand. */
|
|
152
|
-
doors: [(0, entry_target_js_1.rootFieldOf)(update.mutation, 'mutation'), readDoor],
|
|
156
|
+
doors: [...new Set([(0, entry_target_js_1.rootFieldOf)(update.mutation, 'mutation'), readDoor, ...(0, entry_target_js_1.referenceDoorsOf)((0, entry_update_js_1.changeableFields)(target))])],
|
|
153
157
|
description: `Propose changes to existing records: ${target.description} ` +
|
|
154
158
|
'Name each record by ref: "current" (the one on screen), "selected" (every row selected on screen) or an id a find tool returned. ' +
|
|
155
159
|
'The server reads each record, and the card shows what it holds now and what it becomes; nothing changes until the person presses it.',
|
|
@@ -192,7 +196,7 @@ function entryCategoryOf(target, run = exports.runAsCaller) {
|
|
|
192
196
|
kind: 'read',
|
|
193
197
|
name,
|
|
194
198
|
/* The person must be able to enter these records themselves - the tool is not a second way in. */
|
|
195
|
-
doors: [(0, entry_target_js_1.entryDoorOf)(target.mutation)],
|
|
199
|
+
doors: [(0, entry_target_js_1.entryDoorOf)(target.mutation), ...(0, entry_target_js_1.referenceDoorsOf)(target.fields)],
|
|
196
200
|
description: `Propose records to enter: ${target.description} ` +
|
|
197
201
|
'Pass every record found in the material as one row. The rows are shown to the person as a card; nothing is written until they press it.',
|
|
198
202
|
schema: {
|
|
@@ -210,8 +214,15 @@ function entryCategoryOf(target, run = exports.runAsCaller) {
|
|
|
210
214
|
},
|
|
211
215
|
sources: {
|
|
212
216
|
type: 'array',
|
|
213
|
-
description: 'Where this row came from: the attachment id and where in it
|
|
214
|
-
items: {
|
|
217
|
+
description: 'Where this row came from: the attachment id and where in it, and { person: true } for a value the person said.',
|
|
218
|
+
items: {
|
|
219
|
+
type: 'object',
|
|
220
|
+
properties: {
|
|
221
|
+
attachmentId: { type: 'string' },
|
|
222
|
+
where: { type: 'string', description: 'Where in the attachment, in the person\'s language ("3번째 줄", "영수증 사진").' },
|
|
223
|
+
person: { type: 'boolean', description: 'true when the value came from what the person said in the conversation.' }
|
|
224
|
+
}
|
|
225
|
+
}
|
|
215
226
|
}
|
|
216
227
|
},
|
|
217
228
|
required: ['values', 'sources']
|
|
@@ -231,7 +242,7 @@ function entryCategoryOf(target, run = exports.runAsCaller) {
|
|
|
231
242
|
},
|
|
232
243
|
required: ['rows']
|
|
233
244
|
},
|
|
234
|
-
builder: (args, context) => proposeEntries(target, args, context)
|
|
245
|
+
builder: (args, context) => proposeEntries(target, args, context, readSources, run(context))
|
|
235
246
|
};
|
|
236
247
|
return {
|
|
237
248
|
name: (0, entry_target_js_1.entryCategoryName)(target.key),
|
|
@@ -239,8 +250,8 @@ function entryCategoryOf(target, run = exports.runAsCaller) {
|
|
|
239
250
|
guidance: [
|
|
240
251
|
`- When the person gives material to enter as records (files, photos, pasted text), read all of it first - call readChatAttachment for a file sent in an earlier turn - then call ${name} once with every record as a row.`,
|
|
241
252
|
'- Never invent a value. Leave a field out when the material does not say it; the card marks it, and you ask the person for it.',
|
|
242
|
-
'- Give each row its sources: which attachment and where in it. A value the person gave or corrected in the conversation adds the source
|
|
243
|
-
'- When the material prints a total, pass it as declaredTotal exactly as printed - do not add it up yourself.',
|
|
253
|
+
'- Give each row its sources: which attachment and where in it, written in the person\'s language. A value the person gave or corrected in the conversation adds the source { person: true }. The server looks for each row\'s numbers and dates in the cited file and marks what it does not find.',
|
|
254
|
+
'- When the material prints a total, always pass it as declaredTotal exactly as printed - do not add it up yourself. The server also reads a total line of a text file itself.',
|
|
244
255
|
`- ${name} only proposes. Nothing is entered until the person presses the button on the card - never say the records were entered.`,
|
|
245
256
|
`- When the person corrects or drops rows, call ${name} again with the whole corrected set. The newest card replaces the earlier ones; an earlier card can no longer be entered.`,
|
|
246
257
|
...(target.update
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-tools.js","sourceRoot":"","sources":["../../../server/service/data-entry/entry-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The propose tool of each entry target (operato-application/design/ai/data-entry.md §3).\n *\n * One tool per target, so each carries its own door: the tool is offered only to a person who could enter\n * those records by hand, and its card cannot be made for someone who could not press it.\n *\n * The tool writes nothing. It reads the rows the model made from the material, puts each value in its\n * field's type, asks the target's own checks, and hands back a proposal - the card.\n */\nimport { registerToolCategory, type ToolCategory, type ToolSpec } from '@things-factory/ai-client-base'\n\nimport { findRecords, proposeChanges, changeableFields, type GraphqlRunner } from './entry-update.js'\nimport {\n changeToolName,\n findToolName,\n rootFieldOf,\n declareEntryTarget,\n entryTotals,\n verifyRowsAgainstSources,\n entryCategoryName,\n entryDoorOf,\n entryToolName,\n isBlocked,\n normalizeEntryRows,\n recordEntryEvent,\n withCheckedIssues,\n type EntryField,\n type EntryRow,\n type EntryTarget\n} from './entry-target.js'\n\nfunction fieldSchema(field: EntryField): any {\n /*\n * One type per field - Gemini's function schema (an OpenAPI 3.0 subset) refuses a list of types, and the\n * whole request with it: \"12,400\" or \"₩12,400\" is the model's to write as 12400 (2026-10-01, office).\n */\n const type = field.type === 'number' ? 'number' : field.type === 'integer' ? 'integer' : field.type === 'boolean' ? 'boolean' : 'string'\n const said = [\n field.description,\n field.required ? 'required' : 'optional',\n field.type === 'date' ? 'YYYY-MM-DD' : undefined,\n field.type === 'enum' ? `one of: ${field.values!.join(', ')}` : undefined\n ]\n .filter(Boolean)\n .join('. ')\n return { type, description: said }\n}\n\n/** What the card needs besides the rows - the columns, in the target's order. */\nfunction columnsOf(target: EntryTarget) {\n return target.fields.map(field => ({\n name: field.name,\n type: field.type,\n required: !!field.required,\n ...(field.labelKey ? { labelKey: field.labelKey } : {}),\n ...(field.valueKeyPrefix ? { valueKeyPrefix: field.valueKeyPrefix } : {})\n }))\n}\n\nexport type SourceTextLoader = (attachmentIds: string[], context: any) => Promise<Map<string, string>>\n\nconst readSources: SourceTextLoader = async (ids, context) => (await import('./entry-sources.js')).loadSourceTexts(ids, context)\n\nexport async function proposeEntries(target: EntryTarget, args: any, context: any, loadTexts: SourceTextLoader = readSources) {\n const tool = entryToolName(target.key)\n const told = (event: Omit<Parameters<typeof recordEntryEvent>[1], 'phase' | 'tool'>) => recordEntryEvent(target, { phase: 'propose', tool, ...event }, { state: context?.state })\n const { rows: normalized, cut } = normalizeEntryRows(target, args?.rows)\n if (!normalized.length) {\n await told({ rows: 0, ok: false, error: 'no-rows', detail: args })\n return { rejected: true, error: 'no-rows', message: 'no rows were given. Read the material and pass every record as a row.' }\n }\n\n /* The server looks in the cited files itself - the model's citation is not proof (design/ai/data-entry.md §4-1). */\n const declared = args?.declaredTotal && typeof args.declaredTotal === 'object' ? args.declaredTotal : undefined\n const cited = [...normalized.flatMap(row => row.sources.map(source => source.attachmentId)), declared?.attachmentId].filter((id): id is string => typeof id === 'string' && !!id)\n const texts = cited.length ? await loadTexts(cited, context).catch(() => new Map<string, string>()) : new Map<string, string>()\n const read = verifyRowsAgainstSources(normalized, target.fields, texts)\n\n let rows: EntryRow[] = read\n let checkFailed: string | undefined\n if (target.check) {\n try {\n rows = withCheckedIssues(read, await target.check(read, { state: context?.state }))\n } catch (error: any) {\n checkFailed = error?.message || 'check-failed'\n }\n }\n\n const blocked = rows.filter(isBlocked).length\n const totals = entryTotals(rows, target.fields, declared, texts)\n const verified = rows.filter(row => row.evidence).length\n const unmatched = rows.filter(row => row.issues.some(issue => issue.code === 'not-in-source')).length\n await told({ rows: rows.length, ok: true, detail: args })\n return {\n proposed: true,\n kind: 'entry',\n target: target.key,\n labelKey: target.labelKey,\n label: `${rows.length} ${target.key} rows`,\n icon: 'playlist_add',\n columns: columnsOf(target),\n rows,\n counts: { rows: rows.length, ready: rows.length - blocked, blocked, cut, verified, unmatched },\n ...(totals.length ? { totals } : {}),\n ...(typeof args?.note === 'string' && args.note.trim() ? { reason: args.note.trim().slice(0, 300) } : {}),\n ...(checkFailed ? { checkFailed } : {}),\n /* For the model - the card is the answer; it says what the person must still decide. */\n message:\n `proposed ${rows.length} rows (${rows.length - blocked} ready, ${blocked} blocked${cut ? `, ${cut} cut over the limit` : ''}; ` +\n `${verified} found line by line in their files, ${unmatched} with a value the file does not have). ` +\n totals.filter(total => total.difference).map(total => `${total.field}: the material's total differs from the rows by ${total.difference}. `).join('') +\n 'nothing is written until the person presses the button on the card. Tell them which rows are blocked or do not match their file, and why, and ask for what is missing.'\n }\n}\n\n/**\n * The application's API as the person who asked - the tool's own request state, no transaction handed on.\n * Loaded late so the rules are tested without the shell.\n */\nexport const runAsCaller = (context: any): GraphqlRunner => async (document, variables) => {\n const [{ GraphqlLocalClient }, { default: gql }] = await Promise.all([import('@things-factory/shell'), import('graphql-tag')])\n const { tx: _tx, afterCommit: _after, ...state } = context?.state ?? {}\n const operation = /^\\s*mutation\\b/.test(document) ? 'mutate' : 'query'\n const result: any =\n operation === 'mutate'\n ? await GraphqlLocalClient.client.mutate({ mutation: gql(document), variables, context: { state, t: context?.t } })\n : await GraphqlLocalClient.client.query({ query: gql(document), variables, context: { state, t: context?.t }, fetchPolicy: 'no-cache' })\n return { data: result.data, errors: result.errors }\n}\n\n/** The two tools of changing records - finding candidates, and the 수정안 (design/ai/data-entry.md §5-1). */\nfunction changeSpecs(target: EntryTarget, run: (context: any) => GraphqlRunner): ToolSpec[] {\n const update = target.update\n if (!update) return []\n const readDoor = rootFieldOf(update.read.query, 'query')\n const specs: ToolSpec[] = [\n {\n kind: 'read',\n name: changeToolName(target.key),\n /* The person must be able to read the records and change them by hand. */\n doors: [rootFieldOf(update.mutation, 'mutation'), readDoor],\n description:\n `Propose changes to existing records: ${target.description} ` +\n 'Name each record by ref: \"current\" (the one on screen), \"selected\" (every row selected on screen) or an id a find tool returned. ' +\n 'The server reads each record, and the card shows what it holds now and what it becomes; nothing changes until the person presses it.',\n schema: {\n type: 'object',\n properties: {\n changes: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n ref: { type: 'string', description: '\"current\", \"selected\", or a record id from a find tool - never a guessed id.' },\n values: { type: 'object', description: 'Only the fields that change, with their new values.', properties: Object.fromEntries(changeableFields(target).map(field => [field.name, fieldSchema(field)])) }\n },\n required: ['ref', 'values']\n }\n },\n note: { type: 'string', description: 'One line for the card.' }\n },\n required: ['changes']\n },\n builder: (args: any, context: any) => proposeChanges(target, args, context, run(context))\n } as ToolSpec\n ]\n if (update.find) {\n specs.push({\n kind: 'read',\n name: findToolName(target.key),\n doors: [rootFieldOf(update.find.query, 'query')],\n description: `Find existing records to change from what the person described: ${target.description} Returns candidates with their ids.`,\n schema: { type: 'object', properties: Object.fromEntries(update.find.criteria.map(field => [field.name, fieldSchema(field)])) },\n builder: (args: any, context: any) => findRecords(target, args, run(context))\n } as ToolSpec)\n }\n return specs\n}\n\nexport function entryCategoryOf(target: EntryTarget, run: (context: any) => GraphqlRunner = runAsCaller): ToolCategory {\n const name = entryToolName(target.key)\n const spec = {\n kind: 'read',\n name,\n /* The person must be able to enter these records themselves - the tool is not a second way in. */\n doors: [entryDoorOf(target.mutation)],\n description:\n `Propose records to enter: ${target.description} ` +\n 'Pass every record found in the material as one row. The rows are shown to the person as a card; nothing is written until they press it.',\n schema: {\n type: 'object',\n properties: {\n rows: {\n type: 'array',\n description: `At most ${target.maxRows ?? 200} rows.`,\n items: {\n type: 'object',\n properties: {\n values: {\n type: 'object',\n properties: Object.fromEntries(target.fields.map(field => [field.name, fieldSchema(field)]))\n },\n sources: {\n type: 'array',\n description: 'Where this row came from: the attachment id and where in it (\"row 3\", \"the receipt photo\"), or where: \"the person\\'s message\".',\n items: { type: 'object', properties: { attachmentId: { type: 'string' }, where: { type: 'string' } } }\n }\n },\n required: ['values', 'sources']\n }\n },\n note: { type: 'string', description: 'One line for the card - what this set is (\"September card statement\").' },\n declaredTotal: {\n type: 'object',\n description: 'The total the material itself prints, when it prints one - the card compares it with the sum of the rows. Never compute it yourself.',\n properties: {\n field: { type: 'string', description: `Which field it totals${target.fields.filter(field => field.total).length ? ` (${target.fields.filter(field => field.total).map(field => field.name).join(', ')})` : ''}.` },\n value: { type: 'number' },\n attachmentId: { type: 'string' },\n where: { type: 'string' }\n }\n }\n },\n required: ['rows']\n },\n builder: (args: any, context: any) => proposeEntries(target, args, context)\n } as ToolSpec\n\n return {\n name: entryCategoryName(target.key),\n description: `data entry: ${target.key}`,\n guidance: [\n `- When the person gives material to enter as records (files, photos, pasted text), read all of it first - call readChatAttachment for a file sent in an earlier turn - then call ${name} once with every record as a row.`,\n '- Never invent a value. Leave a field out when the material does not say it; the card marks it, and you ask the person for it.',\n '- Give each row its sources: which attachment and where in it. A value the person gave or corrected in the conversation adds the source where: \"the person\\'s message\". The server looks for each row\\'s numbers and dates in the cited file and marks what it does not find.',\n '- When the material prints a total, pass it as declaredTotal exactly as printed - do not add it up yourself.',\n `- ${name} only proposes. Nothing is entered until the person presses the button on the card - never say the records were entered.`,\n `- When the person corrects or drops rows, call ${name} again with the whole corrected set. The newest card replaces the earlier ones; an earlier card can no longer be entered.`,\n ...(target.update\n ? [\n `- To change records that exist, call ${changeToolName(target.key)}. Use ref \"current\" for the record on screen and \"selected\" for the rows selected there.${target.update.find ? ` Otherwise call ${findToolName(target.key)} first with what the person said; if more than one record matches, list them and ask which - never pick one yourself.` : ' Otherwise ask the person to open or select the record.'}`,\n `- ${changeToolName(target.key)} only proposes; the card shows each record's value now and after. Never say a record was changed.`\n ]\n : [])\n ].join('\\n'),\n specs: [spec, ...changeSpecs(target, run)]\n }\n}\n\n/**\n * What an application calls at boot to let the assistant enter one of its records.\n *\n * A mode opens it by naming the key in `entryTargets` (the tool is not in every conversation of the app).\n */\nexport function registerEntryTarget(target: EntryTarget): void {\n declareEntryTarget(target)\n registerToolCategory(entryCategoryOf(target))\n}\n"]}
|
|
1
|
+
{"version":3,"file":"entry-tools.js","sourceRoot":"","sources":["../../../server/service/data-entry/entry-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The propose tool of each entry target (operato-application/design/ai/data-entry.md §3).\n *\n * One tool per target, so each carries its own door: the tool is offered only to a person who could enter\n * those records by hand, and its card cannot be made for someone who could not press it.\n *\n * The tool writes nothing. It reads the rows the model made from the material, puts each value in its\n * field's type, asks the target's own checks, and hands back a proposal - the card.\n */\nimport { registerToolCategory, type ToolCategory, type ToolSpec } from '@things-factory/ai-client-base'\n\nimport { findRecords, proposeChanges, changeableFields, type GraphqlRunner } from './entry-update.js'\nimport {\n changeToolName,\n findToolName,\n rootFieldOf,\n declareEntryTarget,\n entryTotals,\n verifyRowsAgainstSources,\n entryCategoryName,\n entryDoorOf,\n entryToolName,\n isBlocked,\n normalizeEntryRows,\n referenceDoorsOf,\n resolveReferences,\n recordEntryEvent,\n withCheckedIssues,\n type EntryField,\n type EntryRow,\n type EntryTarget\n} from './entry-target.js'\n\nfunction fieldSchema(field: EntryField): any {\n /*\n * One type per field - Gemini's function schema (an OpenAPI 3.0 subset) refuses a list of types, and the\n * whole request with it: \"12,400\" or \"₩12,400\" is the model's to write as 12400 (2026-10-01, office).\n */\n const type = field.type === 'number' ? 'number' : field.type === 'integer' ? 'integer' : field.type === 'boolean' ? 'boolean' : 'string'\n if (field.type === 'reference') return { type: 'string', description: [field.description, field.required ? 'required' : 'optional', 'the name or code as the material or the person gives it - the server finds the record'].filter(Boolean).join('. ') }\n const said = [\n field.description,\n field.required ? 'required' : 'optional',\n field.type === 'date' ? 'YYYY-MM-DD' : undefined,\n field.type === 'enum' ? `one of: ${field.values!.join(', ')}` : undefined\n ]\n .filter(Boolean)\n .join('. ')\n return { type, description: said }\n}\n\n/** What the card needs besides the rows - the columns, in the target's order. */\nfunction columnsOf(target: EntryTarget) {\n return target.fields.map(field => ({\n name: field.name,\n type: field.type,\n required: !!field.required,\n ...(field.labelKey ? { labelKey: field.labelKey } : {}),\n ...(field.valueKeyPrefix ? { valueKeyPrefix: field.valueKeyPrefix } : {})\n }))\n}\n\nexport type SourceTextLoader = (attachmentIds: string[], context: any) => Promise<Map<string, string>>\n\nconst readSources: SourceTextLoader = async (ids, context) => (await import('./entry-sources.js')).loadSourceTexts(ids, context)\n\nexport async function proposeEntries(target: EntryTarget, args: any, context: any, loadTexts: SourceTextLoader = readSources, run?: GraphqlRunner) {\n const tool = entryToolName(target.key)\n const told = (event: Omit<Parameters<typeof recordEntryEvent>[1], 'phase' | 'tool'>) => recordEntryEvent(target, { phase: 'propose', tool, ...event }, { state: context?.state })\n const { rows: normalized, cut } = normalizeEntryRows(target, args?.rows)\n if (!normalized.length) {\n await told({ rows: 0, ok: false, error: 'no-rows', detail: args })\n return { rejected: true, error: 'no-rows', message: 'no rows were given. Read the material and pass every record as a row.' }\n }\n\n /* The server looks in the cited files itself - the model's citation is not proof (design/ai/data-entry.md §4-1). */\n const declared = args?.declaredTotal && typeof args.declaredTotal === 'object' ? args.declaredTotal : undefined\n const cited = [...normalized.flatMap(row => row.sources.map(source => source.attachmentId)), declared?.attachmentId].filter((id): id is string => typeof id === 'string' && !!id)\n const texts = cited.length ? await loadTexts(cited, context).catch(() => new Map<string, string>()) : new Map<string, string>()\n /* A name the model wrote for another record is settled to its id by the application's query, as the person. */\n const resolved = await resolveReferences(target.fields, normalized, run ?? runAsCaller(context))\n const read = verifyRowsAgainstSources(resolved, target.fields, texts)\n\n let rows: EntryRow[] = read\n let checkFailed: string | undefined\n if (target.check) {\n try {\n rows = withCheckedIssues(read, await target.check(read, { state: context?.state }))\n } catch (error: any) {\n checkFailed = error?.message || 'check-failed'\n }\n }\n\n const blocked = rows.filter(isBlocked).length\n const totals = entryTotals(rows, target.fields, declared, texts)\n const verified = rows.filter(row => row.evidence).length\n const unmatched = rows.filter(row => row.issues.some(issue => issue.code === 'not-in-source')).length\n await told({ rows: rows.length, ok: true, detail: args })\n return {\n proposed: true,\n kind: 'entry',\n target: target.key,\n labelKey: target.labelKey,\n label: `${rows.length} ${target.key} rows`,\n icon: 'playlist_add',\n columns: columnsOf(target),\n rows,\n counts: { rows: rows.length, ready: rows.length - blocked, blocked, cut, verified, unmatched },\n ...(totals.length ? { totals } : {}),\n ...(typeof args?.note === 'string' && args.note.trim() ? { reason: args.note.trim().slice(0, 300) } : {}),\n ...(checkFailed ? { checkFailed } : {}),\n /* For the model - the card is the answer; it says what the person must still decide. */\n message:\n `proposed ${rows.length} rows (${rows.length - blocked} ready, ${blocked} blocked${cut ? `, ${cut} cut over the limit` : ''}; ` +\n `${verified} found line by line in their files, ${unmatched} with a value the file does not have). ` +\n totals.filter(total => total.difference).map(total => `${total.field}: the material's total differs from the rows by ${total.difference}. `).join('') +\n 'nothing is written until the person presses the button on the card. Tell them which rows are blocked or do not match their file, and why, and ask for what is missing.'\n }\n}\n\n/**\n * The application's API as the person who asked - the tool's own request state, no transaction handed on.\n * Loaded late so the rules are tested without the shell.\n */\nexport const runAsCaller = (context: any): GraphqlRunner => async (document, variables) => {\n const [{ GraphqlLocalClient }, { default: gql }] = await Promise.all([import('@things-factory/shell'), import('graphql-tag')])\n const { tx: _tx, afterCommit: _after, ...state } = context?.state ?? {}\n const operation = /^\\s*mutation\\b/.test(document) ? 'mutate' : 'query'\n const result: any =\n operation === 'mutate'\n ? await GraphqlLocalClient.client.mutate({ mutation: gql(document), variables, context: { state, t: context?.t } })\n : await GraphqlLocalClient.client.query({ query: gql(document), variables, context: { state, t: context?.t }, fetchPolicy: 'no-cache' })\n return { data: result.data, errors: result.errors }\n}\n\n/** The two tools of changing records - finding candidates, and the 수정안 (design/ai/data-entry.md §5-1). */\nfunction changeSpecs(target: EntryTarget, run: (context: any) => GraphqlRunner): ToolSpec[] {\n const update = target.update\n if (!update) return []\n const readDoor = rootFieldOf(update.read.query, 'query')\n const specs: ToolSpec[] = [\n {\n kind: 'read',\n name: changeToolName(target.key),\n /* The person must be able to read the records and change them by hand. */\n doors: [...new Set([rootFieldOf(update.mutation, 'mutation'), readDoor, ...referenceDoorsOf(changeableFields(target))])],\n description:\n `Propose changes to existing records: ${target.description} ` +\n 'Name each record by ref: \"current\" (the one on screen), \"selected\" (every row selected on screen) or an id a find tool returned. ' +\n 'The server reads each record, and the card shows what it holds now and what it becomes; nothing changes until the person presses it.',\n schema: {\n type: 'object',\n properties: {\n changes: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n ref: { type: 'string', description: '\"current\", \"selected\", or a record id from a find tool - never a guessed id.' },\n values: { type: 'object', description: 'Only the fields that change, with their new values.', properties: Object.fromEntries(changeableFields(target).map(field => [field.name, fieldSchema(field)])) }\n },\n required: ['ref', 'values']\n }\n },\n note: { type: 'string', description: 'One line for the card.' }\n },\n required: ['changes']\n },\n builder: (args: any, context: any) => proposeChanges(target, args, context, run(context))\n } as ToolSpec\n ]\n if (update.find) {\n specs.push({\n kind: 'read',\n name: findToolName(target.key),\n doors: [rootFieldOf(update.find.query, 'query')],\n description: `Find existing records to change from what the person described: ${target.description} Returns candidates with their ids.`,\n schema: { type: 'object', properties: Object.fromEntries(update.find.criteria.map(field => [field.name, fieldSchema(field)])) },\n builder: (args: any, context: any) => findRecords(target, args, run(context))\n } as ToolSpec)\n }\n return specs\n}\n\nexport function entryCategoryOf(target: EntryTarget, run: (context: any) => GraphqlRunner = runAsCaller): ToolCategory {\n const name = entryToolName(target.key)\n const spec = {\n kind: 'read',\n name,\n /* The person must be able to enter these records themselves - the tool is not a second way in. */\n doors: [entryDoorOf(target.mutation), ...referenceDoorsOf(target.fields)],\n description:\n `Propose records to enter: ${target.description} ` +\n 'Pass every record found in the material as one row. The rows are shown to the person as a card; nothing is written until they press it.',\n schema: {\n type: 'object',\n properties: {\n rows: {\n type: 'array',\n description: `At most ${target.maxRows ?? 200} rows.`,\n items: {\n type: 'object',\n properties: {\n values: {\n type: 'object',\n properties: Object.fromEntries(target.fields.map(field => [field.name, fieldSchema(field)]))\n },\n sources: {\n type: 'array',\n description: 'Where this row came from: the attachment id and where in it, and { person: true } for a value the person said.',\n items: {\n type: 'object',\n properties: {\n attachmentId: { type: 'string' },\n where: { type: 'string', description: 'Where in the attachment, in the person\\'s language (\"3번째 줄\", \"영수증 사진\").' },\n person: { type: 'boolean', description: 'true when the value came from what the person said in the conversation.' }\n }\n }\n }\n },\n required: ['values', 'sources']\n }\n },\n note: { type: 'string', description: 'One line for the card - what this set is (\"September card statement\").' },\n declaredTotal: {\n type: 'object',\n description: 'The total the material itself prints, when it prints one - the card compares it with the sum of the rows. Never compute it yourself.',\n properties: {\n field: { type: 'string', description: `Which field it totals${target.fields.filter(field => field.total).length ? ` (${target.fields.filter(field => field.total).map(field => field.name).join(', ')})` : ''}.` },\n value: { type: 'number' },\n attachmentId: { type: 'string' },\n where: { type: 'string' }\n }\n }\n },\n required: ['rows']\n },\n builder: (args: any, context: any) => proposeEntries(target, args, context, readSources, run(context))\n } as ToolSpec\n\n return {\n name: entryCategoryName(target.key),\n description: `data entry: ${target.key}`,\n guidance: [\n `- When the person gives material to enter as records (files, photos, pasted text), read all of it first - call readChatAttachment for a file sent in an earlier turn - then call ${name} once with every record as a row.`,\n '- Never invent a value. Leave a field out when the material does not say it; the card marks it, and you ask the person for it.',\n '- Give each row its sources: which attachment and where in it, written in the person\\'s language. A value the person gave or corrected in the conversation adds the source { person: true }. The server looks for each row\\'s numbers and dates in the cited file and marks what it does not find.',\n '- When the material prints a total, always pass it as declaredTotal exactly as printed - do not add it up yourself. The server also reads a total line of a text file itself.',\n `- ${name} only proposes. Nothing is entered until the person presses the button on the card - never say the records were entered.`,\n `- When the person corrects or drops rows, call ${name} again with the whole corrected set. The newest card replaces the earlier ones; an earlier card can no longer be entered.`,\n ...(target.update\n ? [\n `- To change records that exist, call ${changeToolName(target.key)}. Use ref \"current\" for the record on screen and \"selected\" for the rows selected there.${target.update.find ? ` Otherwise call ${findToolName(target.key)} first with what the person said; if more than one record matches, list them and ask which - never pick one yourself.` : ' Otherwise ask the person to open or select the record.'}`,\n `- ${changeToolName(target.key)} only proposes; the card shows each record's value now and after. Never say a record was changed.`\n ]\n : [])\n ].join('\\n'),\n specs: [spec, ...changeSpecs(target, run)]\n }\n}\n\n/**\n * What an application calls at boot to let the assistant enter one of its records.\n *\n * A mode opens it by naming the key in `entryTargets` (the tool is not in every conversation of the app).\n */\nexport function registerEntryTarget(target: EntryTarget): void {\n declareEntryTarget(target)\n registerToolCategory(entryCategoryOf(target))\n}\n"]}
|
|
@@ -69,7 +69,7 @@ async function readRecords(target, ids, run) {
|
|
|
69
69
|
const answer = await run(update.read.query, update.read.variables([...new Set(ids)]));
|
|
70
70
|
if (answer.errors?.length)
|
|
71
71
|
throw new Error(answer.errors.map(one => one.message).join('; '));
|
|
72
|
-
return new Map((update.read.recordsOf(answer.data) ?? []).filter(record => record && typeof record.id === 'string').map(record => [record.id, record]));
|
|
72
|
+
return new Map((update.read.recordsOf(answer.data, [...new Set(ids)]) ?? []).filter(record => record && typeof record.id === 'string').map(record => [record.id, record]));
|
|
73
73
|
}
|
|
74
74
|
/** The change rows against what the records hold now. */
|
|
75
75
|
function changeRows(target, picked, records) {
|
|
@@ -132,7 +132,7 @@ async function proposeChanges(target, args, context, run) {
|
|
|
132
132
|
catch (error) {
|
|
133
133
|
return { rejected: true, error: 'read-failed', message: `could not read the records: ${error?.message ?? error}` };
|
|
134
134
|
}
|
|
135
|
-
const rows = changeRows(target, picked, records);
|
|
135
|
+
const rows = await (0, entry_target_js_1.resolveReferences)(changeableFields(target), changeRows(target, picked, records), run);
|
|
136
136
|
const blocked = rows.filter(blockedChange).length;
|
|
137
137
|
return {
|
|
138
138
|
proposed: true,
|
|
@@ -168,7 +168,7 @@ async function findRecords(target, args, run) {
|
|
|
168
168
|
const answer = await run(find.query, find.variables(criteria));
|
|
169
169
|
if (answer.errors?.length)
|
|
170
170
|
return { rejected: true, error: 'find-failed', message: answer.errors.map(one => one.message).join('; ') };
|
|
171
|
-
const found = (find.recordsOf(answer.data) ?? []).filter(record => record && typeof record.id === 'string');
|
|
171
|
+
const found = (find.recordsOf(answer.data, criteria) ?? []).filter(record => record && typeof record.id === 'string');
|
|
172
172
|
return {
|
|
173
173
|
total: found.length,
|
|
174
174
|
candidates: found.slice(0, exports.MAX_CANDIDATES).map(record => ({ id: record.id, ...(target.update?.labelOf ? { label: target.update.labelOf(record) } : {}), record })),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-update.js","sourceRoot":"","sources":["../../../server/service/data-entry/entry-update.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Changing records that exist - the 수정안 (operato-application/design/ai/data-entry.md §5-1).\n *\n * The most expensive mistake is changing the wrong record, so which record is meant is settled here, by the\n * server, never by the model's memory. A record is picked by the screen (the one being looked at, the rows\n * selected) or by an id the find tool handed back; whichever way, it is read again through the application's\n * read query as the person, and a record they cannot see is not found. The card shows what is there now and\n * what it becomes; pressing reads it once more, and a field that moved in between keeps its row out.\n *\n * Pure but for the GraphQL runner, which comes in as an argument - the rules are tested without a server.\n */\nimport {\n changeToolName,\n findToolName,\n readFieldValue,\n sameFieldValue,\n type EntryField,\n type EntryIssue,\n type EntryRecord,\n type EntryTarget\n} from './entry-target.js'\n\n/** Runs one of the application's queries or mutations as the person. */\nexport type GraphqlRunner = (document: string, variables: Record<string, unknown>) => Promise<{ data?: any; errors?: readonly { message: string }[] }>\n\n/** How the record of a change was picked - said on the card, so the person sees the ground of it. */\nexport type ChangeVia = 'current' | 'selected' | 'id'\n\nexport interface ChangeRow {\n index: number\n id: string\n via: ChangeVia\n label?: string\n /** What the record holds now, for the fields that change - read by the server. */\n before: Record<string, unknown>\n values: Record<string, unknown>\n issues: EntryIssue[]\n}\n\nexport const MAX_CHANGES = 100\n\nconst blockedChange = (row: { issues: EntryIssue[] }) => row.issues.some(issue => issue.blocking)\n\n/** The fields a target lets change. */\nexport function changeableFields(target: EntryTarget): EntryField[] {\n const names = target.update?.fields\n return names ? target.fields.filter(field => names.includes(field.name)) : target.fields\n}\n\n/**\n * The records the changes name. `current` is the record on screen, `selected` every row selected there -\n * both from the surface's host context, which is **not trusted**: an id from it is only a candidate, read\n * through the application before anything is shown. Any other ref is an id, from the find tool.\n */\nexport function resolveChangeRefs(\n targetKey: string,\n changes: unknown,\n host: Record<string, any> | undefined\n): { picked: { id: string; via: ChangeVia; values: Record<string, unknown> }[]; unresolved: string[] } {\n const picked: { id: string; via: ChangeVia; values: Record<string, unknown> }[] = []\n const unresolved: string[] = []\n const mine = (one: any) => !one?.target || one.target === targetKey\n for (const change of Array.isArray(changes) ? changes : []) {\n const values = change?.values && typeof change.values === 'object' ? change.values : {}\n const ref = typeof change?.ref === 'string' ? change.ref.trim() : ''\n if (ref === 'current') {\n const id = mine(host?.record) ? host?.record?.id : undefined\n if (typeof id === 'string' && id) picked.push({ id, via: 'current', values })\n else unresolved.push('current')\n } else if (ref === 'selected') {\n const ids = mine(host?.selection) && Array.isArray(host?.selection?.ids) ? host!.selection.ids.filter((id: unknown) => typeof id === 'string' && id) : []\n if (ids.length) for (const id of ids) picked.push({ id, via: 'selected', values })\n else unresolved.push('selected')\n } else if (ref) {\n picked.push({ id: ref, via: 'id', values })\n } else {\n unresolved.push('no-ref')\n }\n }\n return { picked: picked.slice(0, MAX_CHANGES), unresolved }\n}\n\n/** Reads the records by id through the application's read query, as the person. */\nexport async function readRecords(target: EntryTarget, ids: string[], run: GraphqlRunner): Promise<Map<string, EntryRecord>> {\n const update = target.update!\n const answer = await run(update.read.query, update.read.variables([...new Set(ids)]))\n if (answer.errors?.length) throw new Error(answer.errors.map(one => one.message).join('; '))\n return new Map((update.read.recordsOf(answer.data) ?? []).filter(record => record && typeof record.id === 'string').map(record => [record.id, record]))\n}\n\n/** The change rows against what the records hold now. */\nexport function changeRows(target: EntryTarget, picked: { id: string; via: ChangeVia; values: Record<string, unknown> }[], records: Map<string, EntryRecord>): ChangeRow[] {\n const fields = new Map(changeableFields(target).map(field => [field.name, field]))\n return picked.map((one, index): ChangeRow => {\n const record = records.get(one.id)\n const issues: EntryIssue[] = []\n const values: Record<string, unknown> = {}\n const before: Record<string, unknown> = {}\n for (const [name, value] of Object.entries(one.values)) {\n const field = fields.get(name)\n if (!field) {\n issues.push({ field: name, code: 'not-changeable', blocking: false })\n continue\n }\n const { read, code } = value === null || value === '' ? { read: null, code: undefined } : readFieldValue(field, value)\n if (read === undefined) {\n values[name] = value\n issues.push({ field: name, code: code!, params: code === 'not-in-list' ? { values: field.values } : undefined, blocking: true })\n } else {\n if (read === null && field.required) issues.push({ field: name, code: 'required', blocking: true })\n values[name] = read\n }\n if (record) before[name] = record[name] ?? null\n }\n if (!record) issues.push({ code: 'record-not-found', blocking: true })\n else if (Object.keys(values).length && Object.keys(values).every(name => sameFieldValue(fields.get(name)!, before[name], values[name])))\n issues.push({ code: 'no-change', blocking: true })\n if (!Object.keys(values).length && !issues.some(issue => issue.blocking)) issues.push({ code: 'nothing-to-change', blocking: true })\n return { index, id: one.id, via: one.via, ...(record && target.update?.labelOf ? { label: target.update.labelOf(record) } : {}), before, values, issues }\n })\n}\n\n/** What the card needs besides the rows - the fields that change, in the target's order. */\nfunction changedColumns(target: EntryTarget, rows: ChangeRow[]) {\n const used = new Set(rows.flatMap(row => Object.keys(row.values)))\n return changeableFields(target)\n .filter(field => used.has(field.name))\n .map(field => ({ name: field.name, type: field.type, ...(field.labelKey ? { labelKey: field.labelKey } : {}), ...(field.valueKeyPrefix ? { valueKeyPrefix: field.valueKeyPrefix } : {}) }))\n}\n\nexport async function proposeChanges(target: EntryTarget, args: any, context: any, run: GraphqlRunner) {\n const { picked, unresolved } = resolveChangeRefs(target.key, args?.changes, context?.host)\n if (!picked.length) {\n return {\n rejected: true,\n error: unresolved.length ? `unresolved-${unresolved[0]}` : 'no-changes',\n message:\n unresolved[0] === 'current' || unresolved[0] === 'selected'\n ? `the screen names no ${unresolved[0] === 'current' ? 'record' : 'selected rows'} of this kind. Ask the person which record, or call ${findToolName(target.key)}.`\n : `name each record: ref \"current\", \"selected\", or an id from ${findToolName(target.key)}. Never guess an id.`\n }\n }\n let records: Map<string, EntryRecord>\n try {\n records = await readRecords(target, picked.map(one => one.id), run)\n } catch (error: any) {\n return { rejected: true, error: 'read-failed', message: `could not read the records: ${error?.message ?? error}` }\n }\n const rows = changeRows(target, picked, records)\n const blocked = rows.filter(blockedChange).length\n return {\n proposed: true,\n kind: 'entry',\n op: 'update',\n target: target.key,\n labelKey: target.labelKey,\n label: `${rows.length} ${target.key} changes`,\n icon: 'edit_note',\n columns: changedColumns(target, rows),\n rows,\n counts: { rows: rows.length, ready: rows.length - blocked, blocked, cut: 0 },\n ...(typeof args?.note === 'string' && args.note.trim() ? { reason: args.note.trim().slice(0, 300) } : {}),\n message:\n `proposed ${rows.length} changes (${rows.length - blocked} ready, ${blocked} blocked). Nothing changes until the person presses the card. ` +\n 'Tell them which records are not found or would not change.'\n }\n}\n\nexport const MAX_CANDIDATES = 20\n\n/** Candidates for what the person described - the model lists them and asks when there is more than one. */\nexport async function findRecords(target: EntryTarget, args: any, run: GraphqlRunner) {\n const find = target.update?.find\n if (!find) return { rejected: true, error: 'no-find', message: 'this record cannot be searched.' }\n const criteria: Record<string, unknown> = {}\n for (const field of find.criteria) {\n const value = args?.[field.name]\n if (value === undefined || value === null || value === '') continue\n const { read } = readFieldValue(field, value)\n if (read !== undefined) criteria[field.name] = read\n }\n const answer = await run(find.query, find.variables(criteria))\n if (answer.errors?.length) return { rejected: true, error: 'find-failed', message: answer.errors.map(one => one.message).join('; ') }\n const found = (find.recordsOf(answer.data) ?? []).filter(record => record && typeof record.id === 'string')\n return {\n total: found.length,\n candidates: found.slice(0, MAX_CANDIDATES).map(record => ({ id: record.id, ...(target.update?.labelOf ? { label: target.update.labelOf(record) } : {}), record })),\n message:\n found.length === 1\n ? `one record matches; pass its id to ${changeToolName(target.key)}.`\n : found.length\n ? `${found.length} records match${found.length > MAX_CANDIDATES ? ` (first ${MAX_CANDIDATES} shown)` : ''}. List them to the person and ask which - never pick one yourself.`\n : 'no record matches. Tell the person and ask for more to go on.'\n }\n}\n\n/**\n * The rows of a pressed 수정안, against what the records hold now. A row whose field moved since the card was\n * made is kept out as `changed-since` - it is not overwritten unseen.\n */\nexport function stillAsProposed(target: EntryTarget, rows: ChangeRow[], now: Map<string, EntryRecord>): (ChangeRow & { now?: EntryRecord })[] {\n const fields = new Map(target.fields.map(field => [field.name, field]))\n return rows.map(row => {\n const record = now.get(row.id)\n if (!record) return { ...row, issues: [...row.issues, { code: 'record-not-found', blocking: true }] }\n const moved = Object.keys(row.values).find(name => fields.get(name) && !sameFieldValue(fields.get(name)!, record[name] ?? null, row.before[name]))\n return moved ? { ...row, now: record, issues: [...row.issues, { field: moved, code: 'changed-since', blocking: true }] } : { ...row, now: record }\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"entry-update.js","sourceRoot":"","sources":["../../../server/service/data-entry/entry-update.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Changing records that exist - the 수정안 (operato-application/design/ai/data-entry.md §5-1).\n *\n * The most expensive mistake is changing the wrong record, so which record is meant is settled here, by the\n * server, never by the model's memory. A record is picked by the screen (the one being looked at, the rows\n * selected) or by an id the find tool handed back; whichever way, it is read again through the application's\n * read query as the person, and a record they cannot see is not found. The card shows what is there now and\n * what it becomes; pressing reads it once more, and a field that moved in between keeps its row out.\n *\n * Pure but for the GraphQL runner, which comes in as an argument - the rules are tested without a server.\n */\nimport {\n changeToolName,\n findToolName,\n readFieldValue,\n resolveReferences,\n sameFieldValue,\n type EntryField,\n type EntryIssue,\n type EntryRecord,\n type EntryTarget\n} from './entry-target.js'\n\n/** Runs one of the application's queries or mutations as the person. */\nexport type GraphqlRunner = (document: string, variables: Record<string, unknown>) => Promise<{ data?: any; errors?: readonly { message: string }[] }>\n\n/** How the record of a change was picked - said on the card, so the person sees the ground of it. */\nexport type ChangeVia = 'current' | 'selected' | 'id'\n\nexport interface ChangeRow {\n index: number\n id: string\n via: ChangeVia\n label?: string\n /** What the record holds now, for the fields that change - read by the server. */\n before: Record<string, unknown>\n values: Record<string, unknown>\n issues: EntryIssue[]\n}\n\nexport const MAX_CHANGES = 100\n\nconst blockedChange = (row: { issues: EntryIssue[] }) => row.issues.some(issue => issue.blocking)\n\n/** The fields a target lets change. */\nexport function changeableFields(target: EntryTarget): EntryField[] {\n const names = target.update?.fields\n return names ? target.fields.filter(field => names.includes(field.name)) : target.fields\n}\n\n/**\n * The records the changes name. `current` is the record on screen, `selected` every row selected there -\n * both from the surface's host context, which is **not trusted**: an id from it is only a candidate, read\n * through the application before anything is shown. Any other ref is an id, from the find tool.\n */\nexport function resolveChangeRefs(\n targetKey: string,\n changes: unknown,\n host: Record<string, any> | undefined\n): { picked: { id: string; via: ChangeVia; values: Record<string, unknown> }[]; unresolved: string[] } {\n const picked: { id: string; via: ChangeVia; values: Record<string, unknown> }[] = []\n const unresolved: string[] = []\n const mine = (one: any) => !one?.target || one.target === targetKey\n for (const change of Array.isArray(changes) ? changes : []) {\n const values = change?.values && typeof change.values === 'object' ? change.values : {}\n const ref = typeof change?.ref === 'string' ? change.ref.trim() : ''\n if (ref === 'current') {\n const id = mine(host?.record) ? host?.record?.id : undefined\n if (typeof id === 'string' && id) picked.push({ id, via: 'current', values })\n else unresolved.push('current')\n } else if (ref === 'selected') {\n const ids = mine(host?.selection) && Array.isArray(host?.selection?.ids) ? host!.selection.ids.filter((id: unknown) => typeof id === 'string' && id) : []\n if (ids.length) for (const id of ids) picked.push({ id, via: 'selected', values })\n else unresolved.push('selected')\n } else if (ref) {\n picked.push({ id: ref, via: 'id', values })\n } else {\n unresolved.push('no-ref')\n }\n }\n return { picked: picked.slice(0, MAX_CHANGES), unresolved }\n}\n\n/** Reads the records by id through the application's read query, as the person. */\nexport async function readRecords(target: EntryTarget, ids: string[], run: GraphqlRunner): Promise<Map<string, EntryRecord>> {\n const update = target.update!\n const answer = await run(update.read.query, update.read.variables([...new Set(ids)]))\n if (answer.errors?.length) throw new Error(answer.errors.map(one => one.message).join('; '))\n return new Map((update.read.recordsOf(answer.data, [...new Set(ids)]) ?? []).filter(record => record && typeof record.id === 'string').map(record => [record.id, record]))\n}\n\n/** The change rows against what the records hold now. */\nexport function changeRows(target: EntryTarget, picked: { id: string; via: ChangeVia; values: Record<string, unknown> }[], records: Map<string, EntryRecord>): ChangeRow[] {\n const fields = new Map(changeableFields(target).map(field => [field.name, field]))\n return picked.map((one, index): ChangeRow => {\n const record = records.get(one.id)\n const issues: EntryIssue[] = []\n const values: Record<string, unknown> = {}\n const before: Record<string, unknown> = {}\n for (const [name, value] of Object.entries(one.values)) {\n const field = fields.get(name)\n if (!field) {\n issues.push({ field: name, code: 'not-changeable', blocking: false })\n continue\n }\n const { read, code } = value === null || value === '' ? { read: null, code: undefined } : readFieldValue(field, value)\n if (read === undefined) {\n values[name] = value\n issues.push({ field: name, code: code!, params: code === 'not-in-list' ? { values: field.values } : undefined, blocking: true })\n } else {\n if (read === null && field.required) issues.push({ field: name, code: 'required', blocking: true })\n values[name] = read\n }\n if (record) before[name] = record[name] ?? null\n }\n if (!record) issues.push({ code: 'record-not-found', blocking: true })\n else if (Object.keys(values).length && Object.keys(values).every(name => sameFieldValue(fields.get(name)!, before[name], values[name])))\n issues.push({ code: 'no-change', blocking: true })\n if (!Object.keys(values).length && !issues.some(issue => issue.blocking)) issues.push({ code: 'nothing-to-change', blocking: true })\n return { index, id: one.id, via: one.via, ...(record && target.update?.labelOf ? { label: target.update.labelOf(record) } : {}), before, values, issues }\n })\n}\n\n/** What the card needs besides the rows - the fields that change, in the target's order. */\nfunction changedColumns(target: EntryTarget, rows: ChangeRow[]) {\n const used = new Set(rows.flatMap(row => Object.keys(row.values)))\n return changeableFields(target)\n .filter(field => used.has(field.name))\n .map(field => ({ name: field.name, type: field.type, ...(field.labelKey ? { labelKey: field.labelKey } : {}), ...(field.valueKeyPrefix ? { valueKeyPrefix: field.valueKeyPrefix } : {}) }))\n}\n\nexport async function proposeChanges(target: EntryTarget, args: any, context: any, run: GraphqlRunner) {\n const { picked, unresolved } = resolveChangeRefs(target.key, args?.changes, context?.host)\n if (!picked.length) {\n return {\n rejected: true,\n error: unresolved.length ? `unresolved-${unresolved[0]}` : 'no-changes',\n message:\n unresolved[0] === 'current' || unresolved[0] === 'selected'\n ? `the screen names no ${unresolved[0] === 'current' ? 'record' : 'selected rows'} of this kind. Ask the person which record, or call ${findToolName(target.key)}.`\n : `name each record: ref \"current\", \"selected\", or an id from ${findToolName(target.key)}. Never guess an id.`\n }\n }\n let records: Map<string, EntryRecord>\n try {\n records = await readRecords(target, picked.map(one => one.id), run)\n } catch (error: any) {\n return { rejected: true, error: 'read-failed', message: `could not read the records: ${error?.message ?? error}` }\n }\n const rows = await resolveReferences(changeableFields(target), changeRows(target, picked, records), run)\n const blocked = rows.filter(blockedChange).length\n return {\n proposed: true,\n kind: 'entry',\n op: 'update',\n target: target.key,\n labelKey: target.labelKey,\n label: `${rows.length} ${target.key} changes`,\n icon: 'edit_note',\n columns: changedColumns(target, rows),\n rows,\n counts: { rows: rows.length, ready: rows.length - blocked, blocked, cut: 0 },\n ...(typeof args?.note === 'string' && args.note.trim() ? { reason: args.note.trim().slice(0, 300) } : {}),\n message:\n `proposed ${rows.length} changes (${rows.length - blocked} ready, ${blocked} blocked). Nothing changes until the person presses the card. ` +\n 'Tell them which records are not found or would not change.'\n }\n}\n\nexport const MAX_CANDIDATES = 20\n\n/** Candidates for what the person described - the model lists them and asks when there is more than one. */\nexport async function findRecords(target: EntryTarget, args: any, run: GraphqlRunner) {\n const find = target.update?.find\n if (!find) return { rejected: true, error: 'no-find', message: 'this record cannot be searched.' }\n const criteria: Record<string, unknown> = {}\n for (const field of find.criteria) {\n const value = args?.[field.name]\n if (value === undefined || value === null || value === '') continue\n const { read } = readFieldValue(field, value)\n if (read !== undefined) criteria[field.name] = read\n }\n const answer = await run(find.query, find.variables(criteria))\n if (answer.errors?.length) return { rejected: true, error: 'find-failed', message: answer.errors.map(one => one.message).join('; ') }\n const found = (find.recordsOf(answer.data, criteria) ?? []).filter(record => record && typeof record.id === 'string')\n return {\n total: found.length,\n candidates: found.slice(0, MAX_CANDIDATES).map(record => ({ id: record.id, ...(target.update?.labelOf ? { label: target.update.labelOf(record) } : {}), record })),\n message:\n found.length === 1\n ? `one record matches; pass its id to ${changeToolName(target.key)}.`\n : found.length\n ? `${found.length} records match${found.length > MAX_CANDIDATES ? ` (first ${MAX_CANDIDATES} shown)` : ''}. List them to the person and ask which - never pick one yourself.`\n : 'no record matches. Tell the person and ask for more to go on.'\n }\n}\n\n/**\n * The rows of a pressed 수정안, against what the records hold now. A row whose field moved since the card was\n * made is kept out as `changed-since` - it is not overwritten unseen.\n */\nexport function stillAsProposed(target: EntryTarget, rows: ChangeRow[], now: Map<string, EntryRecord>): (ChangeRow & { now?: EntryRecord })[] {\n const fields = new Map(target.fields.map(field => [field.name, field]))\n return rows.map(row => {\n const record = now.get(row.id)\n if (!record) return { ...row, issues: [...row.issues, { code: 'record-not-found', blocking: true }] }\n const moved = Object.keys(row.values).find(name => fields.get(name) && !sameFieldValue(fields.get(name)!, record[name] ?? null, row.before[name]))\n return moved ? { ...row, now: record, issues: [...row.issues, { field: moved, code: 'changed-since', blocking: true }] } : { ...row, now: record }\n })\n}\n"]}
|