• Bug: '我要报价纸盒' -> agent put product '纸盒' into 客户名称, FK-lookup failed, then asked to CREATE a customer named 纸盒.
    
    - System prompt rule 6: 新增报价 ALWAYS collectForm first; never map product/spec/盒型 to 客户名称;
      unknown customer -> let user pick from dropdown, never invent or offer to create.
    - collectForm(entityKeyword, knownFieldsJson?): pre-fills the form from what the user already said
      (产品/数量/尺寸); customer/product render as dropdowns to pick real records.
    - FK-not-found message no longer implies creating (was '请确认是否已存在' -> LLM read as 'create it?');
      now '不是系统里已有的X,请从下拉选真实存在的X,不要新建'.
    
    Verified: '我要报价纸盒,1000个,长和宽50cm,高5cm' -> collectForm with 产品名称=纸盒(prefilled),
    长/宽=50/高=5/数量=1000(prefilled), 客户名称=empty dropdown (no more guessing/create-customer).
    zichun authored
     
    Browse Code »
  • User: form rendered every field as a plain text box; no type (dropdown/date/number), and
    FK fields didn't pull options from their source tables.
    
    - FormCollect schema now carries per-field type: fkselect | select | number | date | text
      (+ options for select, fkTable for fkselect, hint for placeholder).
      Types inferred from column data type for generic forms; curated for quote.
    - New GET /api/agent/form/options?table=&q=&brandsid= -> FK options from the source table
      (elecustomer/eleproduct/elematerials...), whitelisted to tables that appear as sFkTable in the
      field dict (rejects arbitrary tables e.g. gdslogininfo), tenant-filtered + LIMIT.
    - chat.html renderFormCollect renders by type: fkselect = searchable <input list=datalist> that
      fetches options on focus/typing; select = <select>; number = <input type=number>; date picker; text.
    - Fix: tolerant label matching (strip parentheticals) so '多数量' maps whether or not the LLM keeps
      the '(逗号分隔)' hint -> multi-qty rows now reliably created.
    
    Verified via agent: quote form shows 客户/产品/物料=fkselect, 单位/印刷/颜色/单双面=select,
    尺寸/数量/单价/系数=number; options endpoint returns real names (客户 q=Little -> Little Antelope);
    non-FK table rejected; full write incl 多数量 (BJD202607086 -> 2000/4000/6000).
    zichun authored
     
    Browse Code »
  • User: chat form showed only 7 fields vs ERP's full 报价单. Root cause: 报价 is a cross-table
    master-detail form; 印刷/颜色/单双面/部件/单价/系数/材料备注/多数量 live in slave tables, not the master.
    
    - FormResolverService.curatedFields(quote): 17 fields tagged by target table (master/slave/note/manyqtys);
      印刷/颜色/单双面 have no column -> written as note into slave sMaterialsMemo.
    - ProposeWriteTool.proposeQuote: routes fields to quoquotationmaster + quoquotationslave(印刷/部件, sParentId cascade) +
      quoquotationmanyqtys(多数量, one row per qty); FK name->id, type-coerce; emits __tables__ structured payload.
    - ErpClient.createMulti + OpController: multi-table addUpdateDelBusinessData (master + slaves in one call).
    - Pricing (核价) intentionally left to ERP (control/materials/process rows are engine-generated).
    
    Verified via agent (real write): collectForm shows all 17 fields; created BJD202607084 = master(Little Antelope/妇科三醇乳膏/1.8mm双灰板/5000/12x8x5/3.5) + slave(只/部件30x20/系数1/材料备注含印刷=胶印;颜色=彩色;单双面=单面) + manyqtys(1000/3000/5000).
    zichun authored
     
    Browse Dir »
  • Root cause of the reported failure:
    - collectForm sourced fields from gdsconfigformslave -> quote master's form config only exposes 3 system/header fields (失效时间/制单人/单据日期); user filled 单据日期(tCreateDate,datetime)='12' -> ERP type mismatch.
    - proposeCreate never coerced by column type, never FK-resolved names, used addBusinessData (no billNo).
    
    Fixes:
    - FormResolverService: businessFields() curated authoritative label->{col,fk} for quoquotationmaster (客户名称/产品名称/数量/长/宽/高/单价 -> real writable cols sCustomerId/sProductId(FK)/dQty/dLength/dWidth/dHeight/dPrice), field-dict fallback for other tables; columnTypes/coerce/typeDefault/resolveFk/nextBillNo(BJD+YYYYMM+seq); isSystemColumn excludes reserve/money/rate/discount/person/date/bool/tenant/maker; resolveMasterForm excludes param/slave/control/config/color secondary tables.
    - collectForm: fields from businessFields (excludes system/header); gdsconfigformslave fallback.
    - proposeCreate: label->{col,fk} via businessFields; FK name->id; type-coerce; skip system cols; auto sId/sFormId + generated sBillNo; type-correct required defaults.
    - ErpClient.createForm: addUpdateDelBusinessData(handleType=add)+moduleId (was addBusinessData).
    - ProposeWriteTool.resolveForm unified to FormResolverService.
    
    Verified via agent end-to-end (real write): collectForm shows correct fields; created quoquotationmaster BJD202607082 = Little Antelope / 妇科三醇乳膏 / qty5000 / dims / price, tenant+maker+date auto-injected.
    zichun authored
     
    Browse Dir »
  • …ormCollect + Skills + KgSearch
    
    - AgentIdentity + AgentFactory: build agent per request with token+form-allowlist carried in tool instances (per-call context; robust vs LC4j callback threading)
    - ErpClient: token-aware read/write/examine; user-token expiry does NOT silently re-login as dev-admin (no privilege escalation)
    - AuthzService: devIdentity()/userIdentity() resolve granted-form set (sAuthsId)
    - proposeExamine tool + OpController examine dispatch + forward user Authorization on confirm
    - InteractionTool.askUser (structured options), FormCollectTool.collectForm (real gdsconfigformslave schema)
    - SkillService + SkillTool.loadSkill + ai_skill digest in system prompt
    - KgQueryTool.kgSearch: L2 neighbors/flow + L3 field->table
    - tools ErpReadTool/ProposeWriteTool/QueryTool/FormCollectTool now per-request (not @Component)
    zichun authored
     
    Browse File »
  • …i_op_queue staging cols + ai_skill registry
    
    - proposeCreate tool -> ai_op_queue draft(payload) -> confirm executes addBusinessData
    - ai_op_queue: add sPayload/sSourceRef/bAutoExecute/sResultBillId/sErrorMsg/tExecutedDate/tExpireAt (create/examine/auto-flow ready)
    - ai_skill registry table + seed playbooks (Skills §6)
    - QueryTool: self-repair retry (feed SQL error back to model, up to 3x)
    - TracingChatModelListener: per-call LLM latency/token/error trace (Langfuse hook point)
    zichun authored
     
    Browse Code »
  • - AuthzService: form-level allowlist ported from backend getsAuthsIdNew (sysjurisdiction sKey set); sysadmin=all; wired into Read/lookupRecord/proposeUpdate/proposeDelete (admin dev-login => all-access; enforces per-user once prod passes through user token)
    - proposeDelete + ErpClient.deleteForm (handleType=del) + OpController branches op type; HITL-gated like update
    - docs/security-findings.md: report of the 5 current-system vulns (backend form-perm off, read-API-can-write, NL2SQL no-tenant/over-privilege/partial-SQL-safety/cache-skips-validation) for the business
    - Verified end-to-end: read after authz = 93; propose-delete card -> confirm -> row actually deleted; audit rows written.
    zichun authored
     
    Browse File »

  • - ai_op_queue: staging table for AI write ops (draft|confirmed|executed|failed|cancelled)
    - ProposeWriteTool.proposeUpdate(entity, record, field, newValue): self-resolves the entity master table (excludes viw_* report views), resolves field via 字段字典, locates the unique record + old value, stages a DRAFT to ai_op_queue — DOES NOT execute; returns a proposal
    - ErpClient.updateForm: executes via ERP addUpdateDelBusinessData with the frontend-compatible payload {data:[{sTable,name:master,column:[{handleType:update,sId,field:value}]}]}
    - OpController: deterministic (non-LLM) POST /op/{id}/confirm (executes + writes back status) / cancel / GET pending
    - AgentChatController.onToolExecuted: on proposeUpdate, attach conversation + push write_proposal SSE
    - chat.html: confirm/cancel card + result echo
    - system prompt: proposeUpdate flow; never claim a write is done before confirm
    
    Verified end-to-end: '把必胜客简称改成必胜客中国' -> proposal card -> confirm -> ERP update -> DB changed; cancel -> DB unchanged. Nothing executes without explicit user confirm.
    zichun authored
     
    Browse File »