@lqc123qwe/car-runtime 1.21.0 → 1.22.0
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/dist/SHA256SUMS +1 -1
- package/dist/car-runtime-1.22.0.tgz +0 -0
- package/dist/car-runtime-1.22.0.tgz.sig.bundle +1 -0
- package/dist/release-audit.jsonl +4 -4
- package/dist/runtime-core/chatStep.d.ts +6 -0
- package/dist/runtime-core/chatStep.js +65 -22
- package/dist/runtime-core/llm.js +64 -14
- package/dist/runtime-core/types.d.ts +3 -0
- package/dist/sbom.json +6 -6
- package/dist/session/log.js +24 -16
- package/package.json +1 -1
- package/src/runtime-core/chatStep.ts +70 -21
- package/src/runtime-core/llm.ts +67 -15
- package/src/runtime-core/types.ts +3 -0
- package/src/session/log.ts +23 -16
- package/dist/car-runtime-1.21.0.tgz +0 -0
- package/dist/car-runtime-1.21.0.tgz.sig.bundle +0 -1
package/dist/SHA256SUMS
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
47b365f175bdb123a4dcf713285a6e4cf28176cb047d99b5891416901769a710 car-runtime-1.22.0.tgz
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"base64Signature":"MEUCIQDVLKF0NzvACUkwTxZp7SiwxmQ1Eg+T44sWztixTvbO+QIgAj4PlRzeD3Rz24/J5yq8RnyvmXlLHQfpEYKCUcLCr+g=","cert":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUc2RENDQm02Z0F3SUJBZ0lVRXFGMng5bWh4Z0FFMXUxMUpHdTZlMzIrWXlJd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpZeE1URTBNRGMxTVRRd1doY05Nall4TVRFME1EZ3dNVFF3V2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVNUFhxRVRZRTk4Rm5DTG1SS3h5YUhzaWl5bzI1WnNlS2x1QzIKV0FFVTgxVVYwdHZWUnRCWWVkOWNvZ2hjN0NFemZvc2Z1bjZQMDU3Vk0wSmFnQlRyZzZPQ0JZMHdnZ1dKTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWZCZ05WSFNNRUdEQVdnQlRmCjArblBWaVFSbHZtbzJPa29WYUxHTGhoa1B6QmlCZ05WSFJFQkFmOEVXREJXaGxSb2RIUndjem92TDJkcGRHaDEKWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHpMM0psYkdWaApjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakl5TGpBd09RWUtLd1lCQkFHRHZ6QUJBUVFyYUhSMGNITTZMeTkwCmIydGxiaTVoWTNScGIyNXpMbWRwZEdoMVluVnpaWEpqYjI1MFpXNTBMbU52YlRBVkJnb3JCZ0VFQVlPL01BRUMKQkFkeVpXeGxZWE5sTURZR0Npc0dBUVFCZzc4d0FRTUVLRGt6TVdNNVpHTTVZamd6TUdJd1kySXlZemxrTkdObApNakUzTmpkaVpHUTFOVEJrT1RNeU4ySXdGUVlLS3dZQkJBR0R2ekFCQkFRSGNtVnNaV0Z6WlRBZ0Jnb3JCZ0VFCkFZTy9NQUVGQkJKc2NXTTJNalF2WTJGeUxYSjFiblJwYldVd0hnWUtLd1lCQkFHRHZ6QUJCZ1FRY21WbWN5OTAKWVdkekx6RXVNakl1TURBN0Jnb3JCZ0VFQVlPL01BRUlCQzBNSzJoMGRIQnpPaTh2ZEc5clpXNHVZV04wYVc5dQpjeTVuYVhSb2RXSjFjMlZ5WTI5dWRHVnVkQzVqYjIwd1pBWUtLd1lCQkFHRHZ6QUJDUVJXREZSb2RIUndjem92CkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHoKTDNKbGJHVmhjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakl5TGpBd09BWUtLd1lCQkFHRHZ6QUJDZ1FxRENnNQpNekZqT1dSak9XSTRNekJpTUdOaU1tTTVaRFJqWlRJeE56WTNZbVJrTlRVd1pEa3pNamRpTUIwR0Npc0dBUVFCCmc3OHdBUXNFRHd3TloybDBhSFZpTFdodmMzUmxaREExQmdvckJnRUVBWU8vTUFFTUJDY01KV2gwZEhCek9pOHYKWjJsMGFIVmlMbU52YlM5c2NXTTJNalF2WTJGeUxYSjFiblJwYldVd09BWUtLd1lCQkFHRHZ6QUJEUVFxRENnNQpNekZqT1dSak9XSTRNekJpTUdOaU1tTTVaRFJqWlRJeE56WTNZbVJrTlRVd1pEa3pNamRpTUNBR0Npc0dBUVFCCmc3OHdBUTRFRWd3UWNtVm1jeTkwWVdkekx6RXVNakl1TURBYUJnb3JCZ0VFQVlPL01BRVBCQXdNQ2pFek5qRXgKT1RJM01UUXdLUVlLS3dZQkJBR0R2ekFCRUFRYkRCbG9kSFJ3Y3pvdkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMApNQmdHQ2lzR0FRUUJnNzh3QVJFRUNnd0lOamt5TXpRMU5qUXdaQVlLS3dZQkJBR0R2ekFCRWdSV0RGUm9kSFJ3CmN6b3ZMMmRwZEdoMVlpNWpiMjB2YkhGak5qSTBMMk5oY2kxeWRXNTBhVzFsTHk1bmFYUm9kV0l2ZDI5eWEyWnMKYjNkekwzSmxiR1ZoYzJVdWVXMXNRSEpsWm5NdmRHRm5jeTh4TGpJeUxqQXdPQVlLS3dZQkJBR0R2ekFCRXdRcQpEQ2c1TXpGak9XUmpPV0k0TXpCaU1HTmlNbU01WkRSalpUSXhOelkzWW1Sa05UVXdaRGt6TWpkaU1CY0dDaXNHCkFRUUJnNzh3QVJRRUNRd0hjbVZzWldGelpUQlpCZ29yQmdFRUFZTy9NQUVWQkVzTVNXaDBkSEJ6T2k4dloybDAKYUhWaUxtTnZiUzlzY1dNMk1qUXZZMkZ5TFhKMWJuUnBiV1V2WVdOMGFXOXVjeTl5ZFc1ekx6UXpOVGN6TURJMwpNVGsyTDJGMGRHVnRjSFJ6THpFd0ZnWUtLd1lCQkFHRHZ6QUJGZ1FJREFad2RXSnNhV013VUFZS0t3WUJCQUdECnZ6QUJHQVJDREVCeVpYQnZPbXh4WXpZeU5FQTJPVEl6TkRVMk5DOWpZWEl0Y25WdWRHbHRaVUF4TXpZeE1Ua3kKTnpFME9uSmxaanB5WldaekwzUmhaM012TVM0eU1pNHdNSUdMQmdvckJnRUVBZFo1QWdRQ0JIMEVld0I1QUhjQQozVDB3YXNiSEVUSmpHUjRjbVdjM0FxSktYcmplUEszL2g0cHlnQzhwN280QUFBR2gyUXBuaEFBQUJBTUFTREJHCkFpRUE2TU5RWks2bXM4aElQZTFPdXk3RmNwY2FCRnJXci9zNkZJV0RCcE9tUjI0Q0lRRFZxcjR3eVRMT21KTloKWEloSXRYUEo1MFQzVzZ4M29aVU5JaXFmd3gyOW5EQUtCZ2dxaGtqT1BRUURBd05vQURCbEFqQVlFRVkwQUEydQpSUXo0enpRSFg3SENtMnIzT1UzRDRtQ3p3STRETzdVNmVCQXdweFJ5RTQ3QW5aclg1KzNZVVJBQ01RQ2lTaHhrCkdycUJSWVhUdXV0VGhDY09RSTRRTGhqTWtLanNiYWNFU1pLRDBTWmtOTTFEN3U4TWxIVksrWGQ2RThBPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==","rekorBundle":{"SignedEntryTimestamp":"MEYCIQDlhHKIxkm2Q8f4998THn2ni5scGkUTarkBoBnQm3pdSgIhAK2ypQcND+k8yy70KbMxrz90gusnFZEeaiCU14yJ5WbP","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI0N2IzNjVmMTc1YmRiMTIzYTRkY2Y3MTMyODVhNmU0Y2YyODE3NmNiMDQ3ZDk5YjU4OTE0MTY5MDE3NjlhNzEwIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUURWTEtGME56dkFDVWt3VHhacDdTaXd4bVExRWcrVDQ0c1d6dGl4VHZiTytRSWdBajRQbFJ6ZUQzUnoyNC9KNXlxOFJueXZtWGxMSFFmcEVZS0NVY0xDcitnPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVYzJSRU5EUW0wMlowRjNTVUpCWjBsVlJYRkdNbmc1YldoNFowRkZNWFV4TVVwSGRUWmxNeklyV1hsSmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFVUlRCTlJHTXhUVlJSZDFkb1kwNU5hbGw0VFZSRk1FMUVaM2ROVkZGM1YycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZOVUZoeFJWUlpSVGs0Um01RFRHMVNTM2g1WVVoemFXbDViekkxV25ObFMyeDFReklLVjBGRlZUZ3hWVll3ZEhaV1VuUkNXV1ZrT1dOdloyaGpOME5GZW1admMyWjFialpRTURVM1ZrMHdTbUZuUWxSeVp6WlBRMEpaTUhkbloxZEtUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFtbENaMDVXU0ZKRlFrRm1PRVZYUkVKWGFHeFNiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmlTRVpxVG1wSk1Fd3lUbWhqYVRGNVpGYzFNR0ZYTVd4TWVUVnVZVmhTYjJSWFNYWmtNamw1WVRKYWMySXpaSHBNTTBwc1lrZFdhQXBqTWxWMVpWY3hjMUZJU214YWJrMTJaRWRHYm1ONU9IaE1ha2w1VEdwQmQwOVJXVXRMZDFsQ1FrRkhSSFo2UVVKQlVWRnlZVWhTTUdOSVRUWk1lVGt3Q21JeWRHeGlhVFZvV1ROU2NHSXlOWHBNYldSd1pFZG9NVmx1Vm5wYVdFcHFZakkxTUZwWE5UQk1iVTUyWWxSQlZrSm5iM0pDWjBWRlFWbFBMMDFCUlVNS1FrRmtlVnBYZUd4WldFNXNUVVJaUjBOcGMwZEJVVkZDWnpjNGQwRlJUVVZMUkd0NlRWZE5OVnBIVFRWWmFtZDZUVWRKZDFreVNYbFplbXhyVGtkT2JBcE5ha1V6VG1wa2FWcEhVVEZPVkVKclQxUk5lVTR5U1hkR1VWbExTM2RaUWtKQlIwUjJla0ZDUWtGUlNHTnRWbk5hVjBaNldsUkJaMEpuYjNKQ1owVkZDa0ZaVHk5TlFVVkdRa0pLYzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMGhuV1V0TGQxbENRa0ZIUkhaNlFVSkNaMUZSWTIxV2JXTjVPVEFLV1Zka2VreDZSWFZOYWtsMVRVUkJOMEpuYjNKQ1owVkZRVmxQTDAxQlJVbENRekJOU3pKb01HUklRbnBQYVRoMlpFYzVjbHBYTkhWWlYwNHdZVmM1ZFFwamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcVlqSXdkMXBCV1V0TGQxbENRa0ZIUkhaNlFVSkRVVkpYUkVaU2IyUklVbmRqZW05MkNrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUV3eVRtaGphVEY1WkZjMU1HRlhNV3hNZVRWdVlWaFNiMlJYU1haa01qbDVZVEphYzJJelpIb0tURE5LYkdKSFZtaGpNbFYxWlZjeGMxRklTbXhhYmsxMlpFZEdibU41T0hoTWFrbDVUR3BCZDA5QldVdExkMWxDUWtGSFJIWjZRVUpEWjFGeFJFTm5OUXBOZWtacVQxZFNhazlYU1RSTmVrSnBUVWRPYVUxdFRUVmFSRkpxV2xSSmVFNTZXVE5aYlZKclRsUlZkMXBFYTNwTmFtUnBUVUl3UjBOcGMwZEJVVkZDQ21jM09IZEJVWE5GUkhkM1Rsb3liREJoU0ZacFRGZG9kbU16VW14YVJFRXhRbWR2Y2tKblJVVkJXVTh2VFVGRlRVSkRZMDFLVjJnd1pFaENlazlwT0hZS1dqSnNNR0ZJVm1sTWJVNTJZbE01YzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMDlCV1V0TGQxbENRa0ZIUkhaNlFVSkVVVkZ4UkVObk5RcE5la1pxVDFkU2FrOVhTVFJOZWtKcFRVZE9hVTF0VFRWYVJGSnFXbFJKZUU1NldUTlpiVkpyVGxSVmQxcEVhM3BOYW1ScFRVTkJSME5wYzBkQlVWRkNDbWMzT0hkQlVUUkZSV2QzVVdOdFZtMWplVGt3V1Zka2VreDZSWFZOYWtsMVRVUkJZVUpuYjNKQ1owVkZRVmxQTDAxQlJWQkNRWGROUTJwRmVrNXFSWGdLVDFSSk0wMVVVWGRMVVZsTFMzZFpRa0pCUjBSMmVrRkNSVUZSWWtSQ2JHOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUFwTlFtZEhRMmx6UjBGUlVVSm5OemgzUVZKRlJVTm5kMGxPYW10NVRYcFJNVTVxVVhkYVFWbExTM2RaUWtKQlIwUjJla0ZDUldkU1YwUkdVbTlrU0ZKM0NtTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJZa2hHYWs1cVNUQk1NazVvWTJreGVXUlhOVEJoVnpGc1RIazFibUZZVW05a1YwbDJaREk1ZVdFeVduTUtZak5rZWt3elNteGlSMVpvWXpKVmRXVlhNWE5SU0Vwc1dtNU5kbVJIUm01amVUaDRUR3BKZVV4cVFYZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JYZFJjUXBFUTJjMVRYcEdhazlYVW1wUFYwazBUWHBDYVUxSFRtbE5iVTAxV2tSU2FscFVTWGhPZWxreldXMVNhMDVVVlhkYVJHdDZUV3BrYVUxQ1kwZERhWE5IQ2tGUlVVSm5OemgzUVZKUlJVTlJkMGhqYlZaeldsZEdlbHBVUWxwQ1oyOXlRbWRGUlVGWlR5OU5RVVZXUWtWelRWTlhhREJrU0VKNlQyazRkbG95YkRBS1lVaFdhVXh0VG5aaVV6bHpZMWROTWsxcVVYWlpNa1o1VEZoS01XSnVVbkJpVjFWMldWZE9NR0ZYT1hWamVUbDVaRmMxZWt4NlVYcE9WR042VFVSSk13cE5WR3N5VERKR01HUkhWblJqU0ZKNlRIcEZkMFpuV1V0TGQxbENRa0ZIUkhaNlFVSkdaMUZKUkVGYWQyUlhTbk5oVjAxM1ZVRlpTMHQzV1VKQ1FVZEVDblo2UVVKSFFWSkRSRVZDZVZwWVFuWlBiWGg0V1hwWmVVNUZRVEpQVkVsNlRrUlZNazVET1dwWldFbDBZMjVXZFdSSGJIUmFWVUY0VFhwWmVFMVVhM2tLVG5wRk1FOXVTbXhhYW5CNVdsZGFla3d6VW1oYU0wMTJUVk0wZVUxcE5IZE5TVWRNUW1kdmNrSm5SVVZCWkZvMVFXZFJRMEpJTUVWbGQwSTFRVWhqUVFvelZEQjNZWE5pU0VWVVNtcEhValJqYlZkak0wRnhTa3RZY21wbFVFc3pMMmcwY0hsblF6aHdOMjgwUVVGQlIyZ3lVWEJ1YUVGQlFVSkJUVUZUUkVKSENrRnBSVUUyVFU1UldrczJiWE00YUVsUVpURlBkWGszUm1Od1kyRkNSbkpYY2k5ek5rWkpWMFJDY0U5dFVqSTBRMGxSUkZaeGNqUjNlVlJNVDIxS1Rsb0tXRWxvU1hSWVVFbzFNRlF6VnpaNE0yOWFWVTVKYVhGbWQzZ3lPVzVFUVV0Q1oyZHhhR3RxVDFCUlVVUkJkMDV2UVVSQ2JFRnFRVmxGUlZrd1FVRXlkUXBTVVhvMGVucFJTRmczU0VOdE1uSXpUMVV6UkRSdFEzcDNTVFJFVHpkVk5tVkNRWGR3ZUZKNVJUUTNRVzVhY2xnMUt6TlpWVkpCUTAxUlEybFRhSGhyQ2tkeWNVSlNXVmhVZFhWMFZHaERZMDlSU1RSUlRHaHFUV3RMYW5OaVlXTkZVMXBMUkRCVFdtdE9UVEZFTjNVNFRXeElWa3NyV0dRMlJUaEJQUW90TFMwdExVVk9SQ0JEUlZKVVNVWkpRMEZVUlMwdExTMHRDZz09In19fX0=","integratedTime":1794642701,"logIndex":3873143698,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}
|
package/dist/release-audit.jsonl
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{"stage":"archive","detail":"git archive HEAD → car-runtime-1.
|
|
2
|
-
{"stage":"sha256sums","detail":"SHA256SUMS
|
|
3
|
-
{"stage":"sbom","detail":"55 个组件(运行时依赖 0 项)","ts":
|
|
4
|
-
{"stage":"cosign-keyless","detail":"signed car-runtime-1.
|
|
1
|
+
{"stage":"archive","detail":"git archive HEAD → car-runtime-1.22.0.tgz(444663 bytes,树哈希锚定)","ts":1794642698888}
|
|
2
|
+
{"stage":"sha256sums","detail":"SHA256SUMS 47b365f175bdb123…(裸字节复核通过)","ts":1794642698889}
|
|
3
|
+
{"stage":"sbom","detail":"55 个组件(运行时依赖 0 项)","ts":1794642698894}
|
|
4
|
+
{"stage":"cosign-keyless","detail":"signed car-runtime-1.22.0.tgz (keyless OIDC + Rekor)","ts":1794642701495}
|
|
@@ -53,10 +53,16 @@ export interface ChatStepOptions {
|
|
|
53
53
|
* 同纪律);同请求同名只回调一次;
|
|
54
54
|
* - 纯渲染提示:不落链、不持久、不影响 ModelStep 与 N1(事实本体仍以落盘行为准,
|
|
55
55
|
* assistant 事件到达前 UI 呈现的增量属临时态);缺省(undefined)= 零行为变化。
|
|
56
|
+
* 1.22(D-C1/D-C2):+thinkingDelta = 思考流式上屏数据源(桌面批消费)——掩蔽流
|
|
57
|
+
* (独立 StreamRedactor 实例,与 assistant 文本同脱敏纪律;链侧 thinking 禁改写不变,
|
|
58
|
+
* 审计面原文唯一事实源 = 链);渲染提示级(同 toolName,无对拍红线——1.19 红线面
|
|
59
|
+
* 不被 thinking 破坏,D-T6 延续);内核 spec 内断言:thinkingDelta 之和 + flush
|
|
60
|
+
* ≡ 掩蔽(thinking 事件 payload 之和)。
|
|
56
61
|
*/
|
|
57
62
|
onDelta?: (d: {
|
|
58
63
|
textDelta?: string;
|
|
59
64
|
toolName?: string;
|
|
65
|
+
thinkingDelta?: string;
|
|
60
66
|
}) => void;
|
|
61
67
|
}
|
|
62
68
|
/** ModelStep 加法扩展:脱敏计数留痕(S15 secretsRedacted 同名口径) */
|
|
@@ -35,11 +35,18 @@ export async function chatStep(opts) {
|
|
|
35
35
|
const redactor = new StreamRedactor();
|
|
36
36
|
let text = '';
|
|
37
37
|
const calls = new Map();
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
let
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
const thinkingBlocks = [];
|
|
39
|
+
let thCurText = '';
|
|
40
|
+
let thCurSig = '';
|
|
41
|
+
const sealThinkingBlock = () => {
|
|
42
|
+
if (thCurText.length)
|
|
43
|
+
thinkingBlocks.push({ text: thCurText, ...(thCurSig ? { signature: thCurSig } : {}) });
|
|
44
|
+
thCurText = '';
|
|
45
|
+
thCurSig = '';
|
|
46
|
+
};
|
|
47
|
+
// 1.22(D-C1):思考掩蔽流——独立 StreamRedactor 实例(与 assistant 文本同脱敏纪律;
|
|
48
|
+
// 链侧禁改写不变,UI 显示面与审计原文面分离)
|
|
49
|
+
const thinkingRedactor = new StreamRedactor();
|
|
43
50
|
let stopReason;
|
|
44
51
|
let errorDetail;
|
|
45
52
|
let usage;
|
|
@@ -79,13 +86,29 @@ export async function chatStep(opts) {
|
|
|
79
86
|
cur.argsBuf += chunk.toolCallDelta.argumentsDelta;
|
|
80
87
|
calls.set(idx, cur);
|
|
81
88
|
}
|
|
82
|
-
// 1.21(
|
|
83
|
-
|
|
84
|
-
|
|
89
|
+
// 1.21(D-T1)→ 1.22(D-B1 多块):thinking 三面捕获——块数组累积(签名随块独立)+
|
|
90
|
+
// 掩蔽流回调(D-C1:独立 redactor,masked 非空才回调)
|
|
91
|
+
if (chunk.thinkingBlockStart !== undefined)
|
|
92
|
+
sealThinkingBlock();
|
|
93
|
+
if (chunk.thinkingDelta !== undefined) {
|
|
94
|
+
thCurText += chunk.thinkingDelta;
|
|
95
|
+
if (opts.onDelta) {
|
|
96
|
+
const masked = thinkingRedactor.push(chunk.thinkingDelta);
|
|
97
|
+
if (masked)
|
|
98
|
+
opts.onDelta({ thinkingDelta: masked });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
85
101
|
if (chunk.thinkingSignatureDelta !== undefined)
|
|
86
|
-
|
|
87
|
-
if (chunk.thinkingRedacted !== undefined)
|
|
88
|
-
|
|
102
|
+
thCurSig += chunk.thinkingSignatureDelta;
|
|
103
|
+
if (chunk.thinkingRedacted !== undefined) {
|
|
104
|
+
sealThinkingBlock(); // redacted = 独立块(不与前文本块拼接)
|
|
105
|
+
thinkingBlocks.push({ text: chunk.thinkingRedacted, redacted: true });
|
|
106
|
+
if (opts.onDelta) {
|
|
107
|
+
const masked = thinkingRedactor.push(chunk.thinkingRedacted);
|
|
108
|
+
if (masked)
|
|
109
|
+
opts.onDelta({ thinkingDelta: masked });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
89
112
|
if (chunk.error)
|
|
90
113
|
errorDetail = chunk.error.message;
|
|
91
114
|
if (chunk.usage)
|
|
@@ -106,6 +129,13 @@ export async function chatStep(opts) {
|
|
|
106
129
|
if (tail && opts.onDelta)
|
|
107
130
|
opts.onDelta({ textDelta: tail });
|
|
108
131
|
text += tail;
|
|
132
|
+
// 1.22(D-B1/D-C1):流尾封板末块 + 思考掩蔽流 flush 残段(渲染提示面,先于 finish 兜底——flush 不抛错)
|
|
133
|
+
sealThinkingBlock();
|
|
134
|
+
{
|
|
135
|
+
const thTail = thinkingRedactor.flush();
|
|
136
|
+
if (thTail && opts.onDelta)
|
|
137
|
+
opts.onDelta({ thinkingDelta: thTail });
|
|
138
|
+
}
|
|
109
139
|
// 1.11-S2(D-33 / 计量设计 §3.3):请求级 usage 事实落链(拿到 usage 的最后一个 chunk 即请求
|
|
110
140
|
// 收尾;撞限/异常 turn 照常落——截断前已完成请求的 usage 事实不吞)。缺失 = provider 未回,
|
|
111
141
|
// 禁补造;actor='runtime'、不进模型消息流(deriveMessages 不投影 usage,§2.5 红线)
|
|
@@ -122,20 +152,33 @@ export async function chatStep(opts) {
|
|
|
122
152
|
providerRaw: usage.providerRaw,
|
|
123
153
|
});
|
|
124
154
|
}
|
|
125
|
-
// 5a. 1.21(R-TOKENHUB-1 / D-T2):thinking
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
// redacted 形态 payload = data
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
155
|
+
// 5a. 1.21(R-TOKENHUB-1 / D-T2)→ 1.22(D-B1):thinking 事件落链——一块一事件(append-only
|
|
156
|
+
// 最窄面,审计/投影按序聚合自然成立)。actor='model',先于 assistant/toolCall(投影层按同
|
|
157
|
+
// turn 首 toolCall 附加回传)。payload = 块原文禁改写(签名完整性 > 脱敏改写——改写即回传
|
|
158
|
+
// 校验失败);secretsRedacted 仅计数留痕(审计信号,不复写);redacted 形态 payload = data
|
|
159
|
+
// 全文(meta.redacted=true)。**单块链(含 redacted 单块)meta 无 blockIndex = 与 1.21.1
|
|
160
|
+
// 逐字节同形(D-B1 兼容线);多块链每块带 blockIndex(0 起块序)**。无 thinking 块 = 零新
|
|
161
|
+
// 事件(D-T5 字节兼容,链形态与 1.20 全等)。
|
|
162
|
+
if (thinkingBlocks.length === 1) {
|
|
163
|
+
const b = thinkingBlocks[0];
|
|
164
|
+
const secretsInThinking = scanSecrets(b.text).hits.length;
|
|
165
|
+
log.append('model', 'thinking', turnId, b.text, {
|
|
166
|
+
...(b.redacted ? { redacted: true } : {}),
|
|
167
|
+
...(b.signature ? { signature: b.signature } : {}),
|
|
136
168
|
...(secretsInThinking ? { secretsRedacted: secretsInThinking } : {}),
|
|
137
169
|
});
|
|
138
170
|
}
|
|
171
|
+
else if (thinkingBlocks.length > 1) {
|
|
172
|
+
thinkingBlocks.forEach((b, i) => {
|
|
173
|
+
const secretsInThinking = scanSecrets(b.text).hits.length;
|
|
174
|
+
log.append('model', 'thinking', turnId, b.text, {
|
|
175
|
+
...(b.redacted ? { redacted: true } : {}),
|
|
176
|
+
...(b.signature ? { signature: b.signature } : {}),
|
|
177
|
+
...(secretsInThinking ? { secretsRedacted: secretsInThinking } : {}),
|
|
178
|
+
blockIndex: i,
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
}
|
|
139
182
|
// 5. assistant 文本落 M7(脱敏后 + 计数留痕;空文本不产事件)
|
|
140
183
|
// flush 后兜底复扫只计数不复写:流式遮蔽已生效,>0 即流式边界逃逸的审计信号
|
|
141
184
|
let secretsRedacted = 0;
|
package/dist/runtime-core/llm.js
CHANGED
|
@@ -370,8 +370,13 @@ async function* parseSseStream(body, model, adapterId) {
|
|
|
370
370
|
}))
|
|
371
371
|
: [];
|
|
372
372
|
const text = typeof delta.content === 'string' && delta.content.length ? delta.content : undefined;
|
|
373
|
+
// 1.22(D-A2):openai 形 thinking 捕获——delta.reasoning_content(DeepSeek 官方 + new-api
|
|
374
|
+
// 家族标准形态)→ thinkingDelta chunk(复用 1.21 anthropic 捕获字段,chatStep 零改动)。
|
|
375
|
+
// 回传面不做(D-A1):已知 openai 形上游零需求且 DeepSeek 官方拒绝收回传(输入含
|
|
376
|
+
// reasoning_content → 400);enforce 契约网关真出现时按 1.21 模式另立项。
|
|
377
|
+
const reasoningContent = typeof delta.reasoning_content === 'string' && delta.reasoning_content.length ? delta.reasoning_content : undefined;
|
|
373
378
|
// LlmChunk 单 toolCallDelta 口径:同事件多条 tool_calls 顺序展开为多 chunk
|
|
374
|
-
if (!text && !toolCallDeltas.length && finish === undefined) {
|
|
379
|
+
if (!text && reasoningContent === undefined && !toolCallDeltas.length && finish === undefined) {
|
|
375
380
|
// 空事件但携 usage(部分 compat 网关形态):usage 不随空事件丢失
|
|
376
381
|
if (usage)
|
|
377
382
|
yield { usage };
|
|
@@ -380,6 +385,7 @@ async function* parseSseStream(body, model, adapterId) {
|
|
|
380
385
|
const chunks = [];
|
|
381
386
|
if (toolCallDeltas.length === 0) {
|
|
382
387
|
chunks.push({
|
|
388
|
+
...(reasoningContent !== undefined ? { thinkingDelta: reasoningContent } : {}),
|
|
383
389
|
...(text !== undefined ? { delta: text } : {}),
|
|
384
390
|
...(finish !== undefined
|
|
385
391
|
? { finishReason: finish, ...(finish === 'error' ? { error: { code: 'B080001', message: `未映射的 finish_reason "${raw}"` } } : {}) }
|
|
@@ -390,6 +396,7 @@ async function* parseSseStream(body, model, adapterId) {
|
|
|
390
396
|
for (let i = 0; i < toolCallDeltas.length; i++) {
|
|
391
397
|
const last = i === toolCallDeltas.length - 1;
|
|
392
398
|
chunks.push({
|
|
399
|
+
...(i === 0 && reasoningContent !== undefined ? { thinkingDelta: reasoningContent } : {}),
|
|
393
400
|
...(i === 0 && text !== undefined ? { delta: text } : {}),
|
|
394
401
|
toolCallDelta: toolCallDeltas[i],
|
|
395
402
|
...(last && finish !== undefined
|
|
@@ -606,12 +613,36 @@ function toAnthropic(req, apiKey, cache) {
|
|
|
606
613
|
turns.push({ role: 'user', content: pendingToolResults });
|
|
607
614
|
pendingToolResults = [];
|
|
608
615
|
};
|
|
616
|
+
// 1.21.1(R-TOKENHUB-1 二分实证):同轮拆分重放合并——投影形态 [assistant(text)][assistant(toolCall)…]
|
|
617
|
+
// 在 tools 声明在场时被 tokenhub 网关严格路径拒绝(400 reasoning_content must be passed back,
|
|
618
|
+
// 与 thinking 是否已在 wire 无关——P-B/P-C vs P-D 四探针二分定案);provider 原始回复 = 单条
|
|
619
|
+
// [thinking?, text?, tool_use…] 消息,合并重放(P-D)过审。合并口径:
|
|
620
|
+
// - 相邻 assistant(toolCall) 聚合(同 turn 多 tool_use 单条);thinking 取首条附加;
|
|
621
|
+
// - 紧邻前驱为 assistant 纯文本消息 → 弹回合并为 [thinking?, text, tool_use…];
|
|
622
|
+
// - 无相邻文本的 toolCall 消息形态不变([thinking?, tool_use])——非工具环链逐字节兼容(D-T5)。
|
|
623
|
+
let pendingTu = null;
|
|
624
|
+
const flushTu = () => {
|
|
625
|
+
if (!pendingTu)
|
|
626
|
+
return;
|
|
627
|
+
const prev = turns[turns.length - 1];
|
|
628
|
+
const { thinkingBlocks, toolCalls } = pendingTu;
|
|
629
|
+
const th = thinkingBlocks ?? [];
|
|
630
|
+
if (prev && prev.role === 'assistant' && typeof prev.content === 'string') {
|
|
631
|
+
turns.pop();
|
|
632
|
+
turns.push({ role: 'assistant', content: [...th, { type: 'text', text: prev.content }, ...toolCalls] });
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
turns.push({ role: 'assistant', content: [...th, ...toolCalls] });
|
|
636
|
+
}
|
|
637
|
+
pendingTu = null;
|
|
638
|
+
};
|
|
609
639
|
for (const m of req.messages) {
|
|
610
640
|
if (m.role === 'system') {
|
|
611
641
|
system.push(typeof m.content === 'string' ? m.content : JSON.stringify(m.content));
|
|
612
642
|
continue;
|
|
613
643
|
}
|
|
614
644
|
if (m.role === 'toolResult') {
|
|
645
|
+
flushTu(); // tool_result 前 = 同轮 assistant 消息收口([text?,tu…] 先于 tool_result 出站)
|
|
615
646
|
const p = m.content;
|
|
616
647
|
pendingToolResults.push({
|
|
617
648
|
type: 'tool_result',
|
|
@@ -621,25 +652,38 @@ function toAnthropic(req, apiKey, cache) {
|
|
|
621
652
|
});
|
|
622
653
|
continue;
|
|
623
654
|
}
|
|
624
|
-
flushToolResults();
|
|
625
655
|
if (m.role === 'assistant' && m.content != null && typeof m.content === 'object' && 'toolCall' in m.content) {
|
|
626
656
|
const tc = m.content.toolCall;
|
|
627
657
|
// 1.21(R-TOKENHUB-1 / D-T4):工具环回传——投影层附加的 thinking(同 turn 原始 assistant
|
|
628
|
-
// 消息的 thinking
|
|
629
|
-
//
|
|
630
|
-
//
|
|
658
|
+
// 消息的 thinking 块)前置重放。1.21.1:thinking 块随合并缓冲进同轮单条消息(见 flushTu 注记);
|
|
659
|
+
// 无 thinking = 1.20 形态。1.22(D-B2/D-B3):投影双形态消费——单块三元组(1.21 形态,字节
|
|
660
|
+
// 兼容线)/ 多块 blocks 数组(每块独立签名按序展开前置;redacted 混合块序保真)。
|
|
631
661
|
const th = m.content.thinking;
|
|
632
|
-
const
|
|
633
|
-
|
|
662
|
+
const thinkingBlocks = [];
|
|
663
|
+
if (th?.blocks?.length) {
|
|
664
|
+
for (const b of th.blocks) {
|
|
665
|
+
if (!b.text?.length)
|
|
666
|
+
continue;
|
|
667
|
+
thinkingBlocks.push(b.redacted
|
|
668
|
+
? { type: 'redacted_thinking', data: b.text }
|
|
669
|
+
: { type: 'thinking', thinking: b.text, ...(b.signature ? { signature: b.signature } : {}) });
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
else if (th?.text?.length) {
|
|
673
|
+
thinkingBlocks.push(th.redacted
|
|
634
674
|
? { type: 'redacted_thinking', data: th.text }
|
|
635
|
-
: { type: 'thinking', thinking: th.text, ...(th.signature ? { signature: th.signature } : {}) }
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
675
|
+
: { type: 'thinking', thinking: th.text, ...(th.signature ? { signature: th.signature } : {}) });
|
|
676
|
+
}
|
|
677
|
+
if (!pendingTu)
|
|
678
|
+
pendingTu = { toolCalls: [], ...(thinkingBlocks.length ? { thinkingBlocks } : {}) };
|
|
679
|
+
pendingTu.toolCalls.push({ type: 'tool_use', id: tc.id, name: tc.tool, input: tc.args ?? {} });
|
|
680
|
+
continue;
|
|
641
681
|
}
|
|
682
|
+
flushTu();
|
|
683
|
+
flushToolResults();
|
|
684
|
+
turns.push({ role: m.role, content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content) });
|
|
642
685
|
}
|
|
686
|
+
flushTu();
|
|
643
687
|
flushToolResults();
|
|
644
688
|
// 1.20-K1(D-48 P2):滚动断点在白名单命中时挂尾部消息(缺省 1 个)——system 断点(P1)
|
|
645
689
|
// 与消息断点独立,off 时两者俱灭(rollingCacheAllowed 内已连坐)
|
|
@@ -716,8 +760,14 @@ async function* parseAnthropicSseStream(body, model, adapterId) {
|
|
|
716
760
|
if (block?.type === 'tool_use') {
|
|
717
761
|
yield { toolCallDelta: { index: evt.index, id: block.id, name: block.name } };
|
|
718
762
|
}
|
|
763
|
+
else if (block?.type === 'thinking') {
|
|
764
|
+
// 1.22(D-B1 多块):thinking 块开始信号——消费方(chatStep)以累积非空判封板,
|
|
765
|
+
// 单块流亦发此信号但落链形态不变(单块 meta 无 blockIndex)
|
|
766
|
+
yield { thinkingBlockStart: evt.index };
|
|
767
|
+
}
|
|
719
768
|
else if (block?.type === 'redacted_thinking' && typeof block.data === 'string' && block.data.length) {
|
|
720
|
-
// 1.21(R-TOKENHUB-1 / D-T1):redacted_thinking 全文单发(回传形态 {type:'redacted_thinking',data}
|
|
769
|
+
// 1.21(R-TOKENHUB-1 / D-T1):redacted_thinking 全文单发(回传形态 {type:'redacted_thinking',data});
|
|
770
|
+
// 1.22:消费方将 redacted 封为独立块(原「后块覆盖前块」缺陷随多块硬化消除)
|
|
721
771
|
yield { thinkingRedacted: block.data };
|
|
722
772
|
}
|
|
723
773
|
}
|
|
@@ -92,6 +92,9 @@ export interface LlmChunk {
|
|
|
92
92
|
thinkingSignatureDelta?: string;
|
|
93
93
|
/** redacted_thinking 块 data 全文(content_block_start 单发;回传形态 {type:'redacted_thinking',data}) */
|
|
94
94
|
thinkingRedacted?: string;
|
|
95
|
+
/** 1.22(D-B1 多块):thinking 块开始信号(content_block_start type='thinking',值为块 evt.index)——
|
|
96
|
+
* 消费方(chatStep)以「累积非空时封板」判块边界;单块流亦发此信号,落链形态不受影响(单块 meta 无 blockIndex) */
|
|
97
|
+
thinkingBlockStart?: number;
|
|
95
98
|
}
|
|
96
99
|
/** Provider 适配器(ACL,C-02):统一签名,消解 Provider 差异 */
|
|
97
100
|
export interface LlmAdapter {
|
package/dist/sbom.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bomFormat": "CAR-SBOM",
|
|
3
3
|
"specVersion": "0.1",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.22.0",
|
|
5
5
|
"components": [
|
|
6
6
|
{
|
|
7
7
|
"type": "file",
|
|
@@ -161,7 +161,7 @@
|
|
|
161
161
|
{
|
|
162
162
|
"type": "file",
|
|
163
163
|
"path": "src/runtime-core/chatStep.ts",
|
|
164
|
-
"sha256": "
|
|
164
|
+
"sha256": "8847c49264abcb451bb9587c1c15abb06c940038be8f95ddcf8a8ba776b58d03"
|
|
165
165
|
},
|
|
166
166
|
{
|
|
167
167
|
"type": "file",
|
|
@@ -176,7 +176,7 @@
|
|
|
176
176
|
{
|
|
177
177
|
"type": "file",
|
|
178
178
|
"path": "src/runtime-core/llm.ts",
|
|
179
|
-
"sha256": "
|
|
179
|
+
"sha256": "8e8e255b0de192c6118d5972a62e30a4812ce72f8d3acd5641f8241b63c842f6"
|
|
180
180
|
},
|
|
181
181
|
{
|
|
182
182
|
"type": "file",
|
|
@@ -201,7 +201,7 @@
|
|
|
201
201
|
{
|
|
202
202
|
"type": "file",
|
|
203
203
|
"path": "src/runtime-core/types.ts",
|
|
204
|
-
"sha256": "
|
|
204
|
+
"sha256": "fbe2d03167420169ebe601bd425e641f3df5ad518d109995ff5302b839a82480"
|
|
205
205
|
},
|
|
206
206
|
{
|
|
207
207
|
"type": "file",
|
|
@@ -251,7 +251,7 @@
|
|
|
251
251
|
{
|
|
252
252
|
"type": "file",
|
|
253
253
|
"path": "src/session/log.ts",
|
|
254
|
-
"sha256": "
|
|
254
|
+
"sha256": "e87fdaaeecb3ad71924664bd565369b8bfb7347500cd2d97c51c22c5c68ab8be"
|
|
255
255
|
},
|
|
256
256
|
{
|
|
257
257
|
"type": "file",
|
|
@@ -271,7 +271,7 @@
|
|
|
271
271
|
{
|
|
272
272
|
"type": "file",
|
|
273
273
|
"path": "package.json",
|
|
274
|
-
"sha256": "
|
|
274
|
+
"sha256": "95a85844d77cb6aab1dc9de4cce906fdd447702381f68fa4afda9a521b86c77c"
|
|
275
275
|
},
|
|
276
276
|
{
|
|
277
277
|
"type": "file",
|
package/dist/session/log.js
CHANGED
|
@@ -122,24 +122,27 @@ export class SessionLog {
|
|
|
122
122
|
const out = [];
|
|
123
123
|
if (compactEvent)
|
|
124
124
|
out.push({ role: 'system', content: (compactEvent.payload.summary) });
|
|
125
|
-
// 1.21(R-TOKENHUB-1 / D-T3
|
|
126
|
-
// toolCall
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
|
|
125
|
+
// 1.21(R-TOKENHUB-1 / D-T3)→ 1.22(D-B2 多块):thinking 投影——同 turn 内 thinking 事件
|
|
126
|
+
// (一块一事件)按序聚合为块列表,附加到首个后续 toolCall 消息:单块 = 1.21 三元组形态
|
|
127
|
+
// (text/signature?/redacted?,投影逐字节不变——D-T5 兼容线);多块 = blocks 数组(顶层
|
|
128
|
+
// text/signature 键缺席,消费方 toAnthropic 双形态展开)。standalone(无后续 toolCall)/
|
|
129
|
+
// 被 user·system 隔断 / 跨 turn 不投影(实证:普通两轮历史不要求回传);assistant(text)
|
|
130
|
+
// 同 turn 不隔断(链序 thinking→assistant→toolCall);无 thinking 事件投影逐字节不变
|
|
131
|
+
// (N1 快照自洽)。
|
|
132
|
+
let pendingThinkingTurn = null;
|
|
133
|
+
let pendingBlocks = [];
|
|
131
134
|
for (const e of projected) {
|
|
132
|
-
if (
|
|
133
|
-
|
|
135
|
+
if (pendingBlocks.length && (e.turnId !== pendingThinkingTurn || e.kind === 'user' || e.kind === 'system'))
|
|
136
|
+
pendingBlocks = [];
|
|
134
137
|
if (e.kind === 'thinking') {
|
|
135
138
|
const p = typeof e.payload === 'string' ? e.payload : '';
|
|
136
139
|
if (p.length || e.meta?.redacted === true) {
|
|
137
|
-
|
|
138
|
-
|
|
140
|
+
pendingThinkingTurn = e.turnId;
|
|
141
|
+
pendingBlocks.push({
|
|
139
142
|
text: p,
|
|
140
143
|
...(typeof e.meta?.signature === 'string' && e.meta.signature ? { signature: e.meta.signature } : {}),
|
|
141
144
|
...(e.meta?.redacted === true ? { redacted: true } : {}),
|
|
142
|
-
};
|
|
145
|
+
});
|
|
143
146
|
}
|
|
144
147
|
continue; // thinking 不单独成消息(无独立回传语义)
|
|
145
148
|
}
|
|
@@ -151,13 +154,18 @@ export class SessionLog {
|
|
|
151
154
|
out.push({ role: 'assistant', content: e.payload });
|
|
152
155
|
else if (e.kind === 'toolCall') {
|
|
153
156
|
const msg = { role: 'assistant', toolCall: e.payload };
|
|
154
|
-
if (
|
|
157
|
+
if (pendingBlocks.length === 1) {
|
|
158
|
+
const b = pendingBlocks[0];
|
|
155
159
|
msg.thinking = {
|
|
156
|
-
text:
|
|
157
|
-
...(
|
|
158
|
-
...(
|
|
160
|
+
text: b.text,
|
|
161
|
+
...(b.signature ? { signature: b.signature } : {}),
|
|
162
|
+
...(b.redacted ? { redacted: true } : {}),
|
|
159
163
|
};
|
|
160
|
-
|
|
164
|
+
pendingBlocks = []; // 首 toolCall 消费即清——同 turn 多 toolCall = 同一原始消息,单块重放
|
|
165
|
+
}
|
|
166
|
+
else if (pendingBlocks.length > 1) {
|
|
167
|
+
msg.thinking = { blocks: pendingBlocks }; // 1.22(D-B2):多块形态(provider 原始多块回复的按序重放)
|
|
168
|
+
pendingBlocks = [];
|
|
161
169
|
}
|
|
162
170
|
out.push(msg);
|
|
163
171
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lqc123qwe/car-runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.0",
|
|
4
4
|
"description": "Composable Agent Runtime (CAR) - microkernel plugin system with sandboxed PTC, append-only hashed session log, and MCP host bridge",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -53,8 +53,13 @@ export interface ChatStepOptions {
|
|
|
53
53
|
* 同纪律);同请求同名只回调一次;
|
|
54
54
|
* - 纯渲染提示:不落链、不持久、不影响 ModelStep 与 N1(事实本体仍以落盘行为准,
|
|
55
55
|
* assistant 事件到达前 UI 呈现的增量属临时态);缺省(undefined)= 零行为变化。
|
|
56
|
+
* 1.22(D-C1/D-C2):+thinkingDelta = 思考流式上屏数据源(桌面批消费)——掩蔽流
|
|
57
|
+
* (独立 StreamRedactor 实例,与 assistant 文本同脱敏纪律;链侧 thinking 禁改写不变,
|
|
58
|
+
* 审计面原文唯一事实源 = 链);渲染提示级(同 toolName,无对拍红线——1.19 红线面
|
|
59
|
+
* 不被 thinking 破坏,D-T6 延续);内核 spec 内断言:thinkingDelta 之和 + flush
|
|
60
|
+
* ≡ 掩蔽(thinking 事件 payload 之和)。
|
|
56
61
|
*/
|
|
57
|
-
onDelta?: (d: { textDelta?: string; toolName?: string }) => void
|
|
62
|
+
onDelta?: (d: { textDelta?: string; toolName?: string; thinkingDelta?: string }) => void
|
|
58
63
|
}
|
|
59
64
|
|
|
60
65
|
/** ModelStep 加法扩展:脱敏计数留痕(S15 secretsRedacted 同名口径) */
|
|
@@ -96,11 +101,22 @@ export async function chatStep(opts: ChatStepOptions): Promise<ChatStepResult> {
|
|
|
96
101
|
const redactor = new StreamRedactor()
|
|
97
102
|
let text = ''
|
|
98
103
|
const calls = new Map<number, { id?: string; name?: string; argsBuf: string }>()
|
|
99
|
-
// 1.21(R-TOKENHUB-1 / D-T1/D-T2
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
// 1.21(R-TOKENHUB-1 / D-T1/D-T2)→ 1.22(D-B1 多块硬化):thinking 捕获累积——禁改写
|
|
105
|
+
// (回传签名完整性 > 脱敏改写),provider 事实字节保真。单累加器升级为块数组:
|
|
106
|
+
// thinkingBlockStart 且累积非空 = 封板前块(签名随块独立,不再跨块拼接);redacted =
|
|
107
|
+
// 封板 + 独立块(原「后块覆盖前块」缺陷消除)。单块流形态与 1.21.1 逐字节等价。
|
|
108
|
+
type ThinkingBlock = { text: string; signature?: string; redacted?: boolean }
|
|
109
|
+
const thinkingBlocks: ThinkingBlock[] = []
|
|
110
|
+
let thCurText = ''
|
|
111
|
+
let thCurSig = ''
|
|
112
|
+
const sealThinkingBlock = () => {
|
|
113
|
+
if (thCurText.length) thinkingBlocks.push({ text: thCurText, ...(thCurSig ? { signature: thCurSig } : {}) })
|
|
114
|
+
thCurText = ''
|
|
115
|
+
thCurSig = ''
|
|
116
|
+
}
|
|
117
|
+
// 1.22(D-C1):思考掩蔽流——独立 StreamRedactor 实例(与 assistant 文本同脱敏纪律;
|
|
118
|
+
// 链侧禁改写不变,UI 显示面与审计原文面分离)
|
|
119
|
+
const thinkingRedactor = new StreamRedactor()
|
|
104
120
|
let stopReason: ModelStep['stopReason'] | undefined
|
|
105
121
|
let errorDetail: string | undefined
|
|
106
122
|
let usage: LlmUsage | undefined
|
|
@@ -136,10 +152,25 @@ export async function chatStep(opts: ChatStepOptions): Promise<ChatStepResult> {
|
|
|
136
152
|
if (chunk.toolCallDelta.argumentsDelta) cur.argsBuf += chunk.toolCallDelta.argumentsDelta
|
|
137
153
|
calls.set(idx, cur)
|
|
138
154
|
}
|
|
139
|
-
// 1.21(
|
|
140
|
-
|
|
141
|
-
if (chunk.
|
|
142
|
-
if (chunk.
|
|
155
|
+
// 1.21(D-T1)→ 1.22(D-B1 多块):thinking 三面捕获——块数组累积(签名随块独立)+
|
|
156
|
+
// 掩蔽流回调(D-C1:独立 redactor,masked 非空才回调)
|
|
157
|
+
if (chunk.thinkingBlockStart !== undefined) sealThinkingBlock()
|
|
158
|
+
if (chunk.thinkingDelta !== undefined) {
|
|
159
|
+
thCurText += chunk.thinkingDelta
|
|
160
|
+
if (opts.onDelta) {
|
|
161
|
+
const masked = thinkingRedactor.push(chunk.thinkingDelta)
|
|
162
|
+
if (masked) opts.onDelta({ thinkingDelta: masked })
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (chunk.thinkingSignatureDelta !== undefined) thCurSig += chunk.thinkingSignatureDelta
|
|
166
|
+
if (chunk.thinkingRedacted !== undefined) {
|
|
167
|
+
sealThinkingBlock() // redacted = 独立块(不与前文本块拼接)
|
|
168
|
+
thinkingBlocks.push({ text: chunk.thinkingRedacted, redacted: true })
|
|
169
|
+
if (opts.onDelta) {
|
|
170
|
+
const masked = thinkingRedactor.push(chunk.thinkingRedacted)
|
|
171
|
+
if (masked) opts.onDelta({ thinkingDelta: masked })
|
|
172
|
+
}
|
|
173
|
+
}
|
|
143
174
|
if (chunk.error) errorDetail = chunk.error.message
|
|
144
175
|
if (chunk.usage) usage = chunk.usage // D-33:附着于最后一个 chunk——后到覆盖
|
|
145
176
|
if (chunk.finishReason !== undefined) stopReason = chunk.finishReason === 'aborted' ? 'error' : chunk.finishReason
|
|
@@ -155,6 +186,12 @@ export async function chatStep(opts: ChatStepOptions): Promise<ChatStepResult> {
|
|
|
155
186
|
const tail = redactor.flush()
|
|
156
187
|
if (tail && opts.onDelta) opts.onDelta({ textDelta: tail })
|
|
157
188
|
text += tail
|
|
189
|
+
// 1.22(D-B1/D-C1):流尾封板末块 + 思考掩蔽流 flush 残段(渲染提示面,先于 finish 兜底——flush 不抛错)
|
|
190
|
+
sealThinkingBlock()
|
|
191
|
+
{
|
|
192
|
+
const thTail = thinkingRedactor.flush()
|
|
193
|
+
if (thTail && opts.onDelta) opts.onDelta({ thinkingDelta: thTail })
|
|
194
|
+
}
|
|
158
195
|
|
|
159
196
|
// 1.11-S2(D-33 / 计量设计 §3.3):请求级 usage 事实落链(拿到 usage 的最后一个 chunk 即请求
|
|
160
197
|
// 收尾;撞限/异常 turn 照常落——截断前已完成请求的 usage 事实不吞)。缺失 = provider 未回,
|
|
@@ -173,19 +210,31 @@ export async function chatStep(opts: ChatStepOptions): Promise<ChatStepResult> {
|
|
|
173
210
|
})
|
|
174
211
|
}
|
|
175
212
|
|
|
176
|
-
// 5a. 1.21(R-TOKENHUB-1 / D-T2):thinking
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
// redacted 形态 payload = data
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
213
|
+
// 5a. 1.21(R-TOKENHUB-1 / D-T2)→ 1.22(D-B1):thinking 事件落链——一块一事件(append-only
|
|
214
|
+
// 最窄面,审计/投影按序聚合自然成立)。actor='model',先于 assistant/toolCall(投影层按同
|
|
215
|
+
// turn 首 toolCall 附加回传)。payload = 块原文禁改写(签名完整性 > 脱敏改写——改写即回传
|
|
216
|
+
// 校验失败);secretsRedacted 仅计数留痕(审计信号,不复写);redacted 形态 payload = data
|
|
217
|
+
// 全文(meta.redacted=true)。**单块链(含 redacted 单块)meta 无 blockIndex = 与 1.21.1
|
|
218
|
+
// 逐字节同形(D-B1 兼容线);多块链每块带 blockIndex(0 起块序)**。无 thinking 块 = 零新
|
|
219
|
+
// 事件(D-T5 字节兼容,链形态与 1.20 全等)。
|
|
220
|
+
if (thinkingBlocks.length === 1) {
|
|
221
|
+
const b = thinkingBlocks[0]!
|
|
222
|
+
const secretsInThinking = scanSecrets(b.text).hits.length
|
|
223
|
+
log.append('model', 'thinking', turnId, b.text, {
|
|
224
|
+
...(b.redacted ? { redacted: true } : {}),
|
|
225
|
+
...(b.signature ? { signature: b.signature } : {}),
|
|
187
226
|
...(secretsInThinking ? { secretsRedacted: secretsInThinking } : {}),
|
|
188
227
|
})
|
|
228
|
+
} else if (thinkingBlocks.length > 1) {
|
|
229
|
+
thinkingBlocks.forEach((b, i) => {
|
|
230
|
+
const secretsInThinking = scanSecrets(b.text).hits.length
|
|
231
|
+
log.append('model', 'thinking', turnId, b.text, {
|
|
232
|
+
...(b.redacted ? { redacted: true } : {}),
|
|
233
|
+
...(b.signature ? { signature: b.signature } : {}),
|
|
234
|
+
...(secretsInThinking ? { secretsRedacted: secretsInThinking } : {}),
|
|
235
|
+
blockIndex: i,
|
|
236
|
+
})
|
|
237
|
+
})
|
|
189
238
|
}
|
|
190
239
|
|
|
191
240
|
// 5. assistant 文本落 M7(脱敏后 + 计数留痕;空文本不产事件)
|
package/src/runtime-core/llm.ts
CHANGED
|
@@ -387,8 +387,14 @@ async function* parseSseStream(body: AsyncIterable<Uint8Array>, model: string, a
|
|
|
387
387
|
}))
|
|
388
388
|
: []
|
|
389
389
|
const text = typeof delta.content === 'string' && delta.content.length ? delta.content : undefined
|
|
390
|
+
// 1.22(D-A2):openai 形 thinking 捕获——delta.reasoning_content(DeepSeek 官方 + new-api
|
|
391
|
+
// 家族标准形态)→ thinkingDelta chunk(复用 1.21 anthropic 捕获字段,chatStep 零改动)。
|
|
392
|
+
// 回传面不做(D-A1):已知 openai 形上游零需求且 DeepSeek 官方拒绝收回传(输入含
|
|
393
|
+
// reasoning_content → 400);enforce 契约网关真出现时按 1.21 模式另立项。
|
|
394
|
+
const reasoningContent =
|
|
395
|
+
typeof delta.reasoning_content === 'string' && delta.reasoning_content.length ? delta.reasoning_content : undefined
|
|
390
396
|
// LlmChunk 单 toolCallDelta 口径:同事件多条 tool_calls 顺序展开为多 chunk
|
|
391
|
-
if (!text && !toolCallDeltas.length && finish === undefined) {
|
|
397
|
+
if (!text && reasoningContent === undefined && !toolCallDeltas.length && finish === undefined) {
|
|
392
398
|
// 空事件但携 usage(部分 compat 网关形态):usage 不随空事件丢失
|
|
393
399
|
if (usage) yield { usage }
|
|
394
400
|
continue
|
|
@@ -396,6 +402,7 @@ async function* parseSseStream(body: AsyncIterable<Uint8Array>, model: string, a
|
|
|
396
402
|
const chunks: LlmChunk[] = []
|
|
397
403
|
if (toolCallDeltas.length === 0) {
|
|
398
404
|
chunks.push({
|
|
405
|
+
...(reasoningContent !== undefined ? { thinkingDelta: reasoningContent } : {}),
|
|
399
406
|
...(text !== undefined ? { delta: text } : {}),
|
|
400
407
|
...(finish !== undefined
|
|
401
408
|
? { finishReason: finish, ...(finish === 'error' ? { error: { code: 'B080001', message: `未映射的 finish_reason "${raw}"` } } : {}) }
|
|
@@ -405,6 +412,7 @@ async function* parseSseStream(body: AsyncIterable<Uint8Array>, model: string, a
|
|
|
405
412
|
for (let i = 0; i < toolCallDeltas.length; i++) {
|
|
406
413
|
const last = i === toolCallDeltas.length - 1
|
|
407
414
|
chunks.push({
|
|
415
|
+
...(i === 0 && reasoningContent !== undefined ? { thinkingDelta: reasoningContent } : {}),
|
|
408
416
|
...(i === 0 && text !== undefined ? { delta: text } : {}),
|
|
409
417
|
toolCallDelta: toolCallDeltas[i],
|
|
410
418
|
...(last && finish !== undefined
|
|
@@ -655,12 +663,34 @@ function toAnthropic(req: LlmRequest, apiKey: string, cache: { rolling: boolean;
|
|
|
655
663
|
turns.push({ role: 'user', content: pendingToolResults })
|
|
656
664
|
pendingToolResults = []
|
|
657
665
|
}
|
|
666
|
+
// 1.21.1(R-TOKENHUB-1 二分实证):同轮拆分重放合并——投影形态 [assistant(text)][assistant(toolCall)…]
|
|
667
|
+
// 在 tools 声明在场时被 tokenhub 网关严格路径拒绝(400 reasoning_content must be passed back,
|
|
668
|
+
// 与 thinking 是否已在 wire 无关——P-B/P-C vs P-D 四探针二分定案);provider 原始回复 = 单条
|
|
669
|
+
// [thinking?, text?, tool_use…] 消息,合并重放(P-D)过审。合并口径:
|
|
670
|
+
// - 相邻 assistant(toolCall) 聚合(同 turn 多 tool_use 单条);thinking 取首条附加;
|
|
671
|
+
// - 紧邻前驱为 assistant 纯文本消息 → 弹回合并为 [thinking?, text, tool_use…];
|
|
672
|
+
// - 无相邻文本的 toolCall 消息形态不变([thinking?, tool_use])——非工具环链逐字节兼容(D-T5)。
|
|
673
|
+
let pendingTu: { toolCalls: Array<{ type: 'tool_use'; id: string; name: string; input: unknown }>; thinkingBlocks?: Array<Record<string, unknown>> } | null = null
|
|
674
|
+
const flushTu = () => {
|
|
675
|
+
if (!pendingTu) return
|
|
676
|
+
const prev = turns[turns.length - 1]
|
|
677
|
+
const { thinkingBlocks, toolCalls } = pendingTu
|
|
678
|
+
const th = thinkingBlocks ?? []
|
|
679
|
+
if (prev && prev.role === 'assistant' && typeof prev.content === 'string') {
|
|
680
|
+
turns.pop()
|
|
681
|
+
turns.push({ role: 'assistant', content: [...th, { type: 'text', text: prev.content }, ...toolCalls] })
|
|
682
|
+
} else {
|
|
683
|
+
turns.push({ role: 'assistant', content: [...th, ...toolCalls] })
|
|
684
|
+
}
|
|
685
|
+
pendingTu = null
|
|
686
|
+
}
|
|
658
687
|
for (const m of req.messages) {
|
|
659
688
|
if (m.role === 'system') {
|
|
660
689
|
system.push(typeof m.content === 'string' ? m.content : JSON.stringify(m.content))
|
|
661
690
|
continue
|
|
662
691
|
}
|
|
663
692
|
if (m.role === 'toolResult') {
|
|
693
|
+
flushTu() // tool_result 前 = 同轮 assistant 消息收口([text?,tu…] 先于 tool_result 出站)
|
|
664
694
|
const p = m.content as { id?: string; result?: unknown; error?: string }
|
|
665
695
|
pendingToolResults.push({
|
|
666
696
|
type: 'tool_result',
|
|
@@ -670,24 +700,41 @@ function toAnthropic(req: LlmRequest, apiKey: string, cache: { rolling: boolean;
|
|
|
670
700
|
})
|
|
671
701
|
continue
|
|
672
702
|
}
|
|
673
|
-
flushToolResults()
|
|
674
703
|
if (m.role === 'assistant' && m.content != null && typeof m.content === 'object' && 'toolCall' in (m.content as object)) {
|
|
675
704
|
const tc = (m.content as { toolCall: { id: string; tool: string; args: unknown } }).toolCall
|
|
676
705
|
// 1.21(R-TOKENHUB-1 / D-T4):工具环回传——投影层附加的 thinking(同 turn 原始 assistant
|
|
677
|
-
// 消息的 thinking
|
|
678
|
-
//
|
|
679
|
-
//
|
|
680
|
-
const th = (m.content as {
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
706
|
+
// 消息的 thinking 块)前置重放。1.21.1:thinking 块随合并缓冲进同轮单条消息(见 flushTu 注记);
|
|
707
|
+
// 无 thinking = 1.20 形态。1.22(D-B2/D-B3):投影双形态消费——单块三元组(1.21 形态,字节
|
|
708
|
+
// 兼容线)/ 多块 blocks 数组(每块独立签名按序展开前置;redacted 混合块序保真)。
|
|
709
|
+
const th = (m.content as {
|
|
710
|
+
thinking?: { text?: string; signature?: string; redacted?: boolean; blocks?: Array<{ text: string; signature?: string; redacted?: boolean }> }
|
|
711
|
+
}).thinking
|
|
712
|
+
const thinkingBlocks: Array<Record<string, unknown>> = []
|
|
713
|
+
if (th?.blocks?.length) {
|
|
714
|
+
for (const b of th.blocks) {
|
|
715
|
+
if (!b.text?.length) continue
|
|
716
|
+
thinkingBlocks.push(
|
|
717
|
+
b.redacted
|
|
718
|
+
? { type: 'redacted_thinking', data: b.text }
|
|
719
|
+
: { type: 'thinking', thinking: b.text, ...(b.signature ? { signature: b.signature } : {}) },
|
|
720
|
+
)
|
|
721
|
+
}
|
|
722
|
+
} else if (th?.text?.length) {
|
|
723
|
+
thinkingBlocks.push(
|
|
724
|
+
th.redacted
|
|
725
|
+
? { type: 'redacted_thinking', data: th.text }
|
|
726
|
+
: { type: 'thinking', thinking: th.text, ...(th.signature ? { signature: th.signature } : {}) },
|
|
727
|
+
)
|
|
728
|
+
}
|
|
729
|
+
if (!pendingTu) pendingTu = { toolCalls: [], ...(thinkingBlocks.length ? { thinkingBlocks } : {}) }
|
|
730
|
+
pendingTu.toolCalls.push({ type: 'tool_use', id: tc.id, name: tc.tool, input: tc.args ?? {} })
|
|
731
|
+
continue
|
|
689
732
|
}
|
|
733
|
+
flushTu()
|
|
734
|
+
flushToolResults()
|
|
735
|
+
turns.push({ role: m.role, content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content) })
|
|
690
736
|
}
|
|
737
|
+
flushTu()
|
|
691
738
|
flushToolResults()
|
|
692
739
|
// 1.20-K1(D-48 P2):滚动断点在白名单命中时挂尾部消息(缺省 1 个)——system 断点(P1)
|
|
693
740
|
// 与消息断点独立,off 时两者俱灭(rollingCacheAllowed 内已连坐)
|
|
@@ -756,8 +803,13 @@ async function* parseAnthropicSseStream(body: AsyncIterable<Uint8Array>, model:
|
|
|
756
803
|
const block = evt.content_block
|
|
757
804
|
if (block?.type === 'tool_use') {
|
|
758
805
|
yield { toolCallDelta: { index: evt.index, id: block.id, name: block.name } }
|
|
806
|
+
} else if (block?.type === 'thinking') {
|
|
807
|
+
// 1.22(D-B1 多块):thinking 块开始信号——消费方(chatStep)以累积非空判封板,
|
|
808
|
+
// 单块流亦发此信号但落链形态不变(单块 meta 无 blockIndex)
|
|
809
|
+
yield { thinkingBlockStart: evt.index }
|
|
759
810
|
} else if (block?.type === 'redacted_thinking' && typeof block.data === 'string' && block.data.length) {
|
|
760
|
-
// 1.21(R-TOKENHUB-1 / D-T1):redacted_thinking 全文单发(回传形态 {type:'redacted_thinking',data}
|
|
811
|
+
// 1.21(R-TOKENHUB-1 / D-T1):redacted_thinking 全文单发(回传形态 {type:'redacted_thinking',data});
|
|
812
|
+
// 1.22:消费方将 redacted 封为独立块(原「后块覆盖前块」缺陷随多块硬化消除)
|
|
761
813
|
yield { thinkingRedacted: block.data }
|
|
762
814
|
}
|
|
763
815
|
} else if (type === 'content_block_delta') {
|
|
@@ -84,6 +84,9 @@ export interface LlmChunk {
|
|
|
84
84
|
thinkingSignatureDelta?: string
|
|
85
85
|
/** redacted_thinking 块 data 全文(content_block_start 单发;回传形态 {type:'redacted_thinking',data}) */
|
|
86
86
|
thinkingRedacted?: string
|
|
87
|
+
/** 1.22(D-B1 多块):thinking 块开始信号(content_block_start type='thinking',值为块 evt.index)——
|
|
88
|
+
* 消费方(chatStep)以「累积非空时封板」判块边界;单块流亦发此信号,落链形态不受影响(单块 meta 无 blockIndex) */
|
|
89
|
+
thinkingBlockStart?: number
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
/** Provider 适配器(ACL,C-02):统一签名,消解 Provider 差异 */
|
package/src/session/log.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { createHash } from 'node:crypto'
|
|
|
11
11
|
import { readFileSync } from 'node:fs'
|
|
12
12
|
import { decodeLogBuffer, splitJsonlLines } from './format.ts'
|
|
13
13
|
|
|
14
|
-
export type EventKind = 'user' | 'assistant' | 'toolCall' | 'toolResult' | 'turnEnd' | 'goalUpdate' | 'hostRaw' | 'fork' | 'system' | 'usage' | 'compact' | 'routing' | 'memory' | 'thinking' // M3-S11 加法扩展:多宿主归一化降级通道(pattern 未命中留痕,零静默);M5-DEC4 加法扩展:跨宿主 fork 标记事件;1.4-S2 加法扩展:system prompt 落链(§3.5.5:新模型可见输入 = 新事件类型);1.11-S2 加法扩展:usage 计量事实(D-33,actor='runtime'、model_visible=0 不进模型消息流,deriveMessages 不投影);六值 TurnEndReason 不变;1.14-S2 加法扩展(K-MP-2 / D-40):历史压缩事件(actor='runtime',append-only 只追加——payload={summary, compactedUpTo, ...},投影按 compactedUpTo 前缀折叠为摘要,原事件链不改写);1.14-S4 加法扩展(K-POOL-1 / D-42):模型池路由决策(actor='runtime',payload.type='decide',selected/reason/retries/attempts——禁静默换模型;model_visible=0 不进模型消息流,deriveMessages 不投影——同 usage 纪律);1.15-S1 加法扩展(K-MEM-1 / D-46):白盒记忆操作事件(actor='user' 宿主代理用户操作,turnId='memory' 会话级标识同 'compaction' 先例,payload.type='write'|'edit'|'delete'|'rollback'——审计链同源差异化面,链即版本库〔rollback 恢复数据源=链上 payload.before/after 全文〕;model_visible=0 不进模型消息流——记忆注入走宿主装配层 system ctx 行,deriveMessages 不投影);1.21 加法扩展(R-TOKENHUB-1 / D-T2):thinking 事件(actor='model',payload=thinking 原文禁改写,meta={signature?, redacted?, secretsRedacted?}——先于 assistant/toolCall 落链;投影 = 同 turn 首个 toolCall 消息附加回传(工具环 reasoning_content 契约,Anthropic thinking+tool_use 规范同款);standalone/隔断/跨 turn 不投影;无 thinking
|
|
14
|
+
export type EventKind = 'user' | 'assistant' | 'toolCall' | 'toolResult' | 'turnEnd' | 'goalUpdate' | 'hostRaw' | 'fork' | 'system' | 'usage' | 'compact' | 'routing' | 'memory' | 'thinking' // M3-S11 加法扩展:多宿主归一化降级通道(pattern 未命中留痕,零静默);M5-DEC4 加法扩展:跨宿主 fork 标记事件;1.4-S2 加法扩展:system prompt 落链(§3.5.5:新模型可见输入 = 新事件类型);1.11-S2 加法扩展:usage 计量事实(D-33,actor='runtime'、model_visible=0 不进模型消息流,deriveMessages 不投影);六值 TurnEndReason 不变;1.14-S2 加法扩展(K-MP-2 / D-40):历史压缩事件(actor='runtime',append-only 只追加——payload={summary, compactedUpTo, ...},投影按 compactedUpTo 前缀折叠为摘要,原事件链不改写);1.14-S4 加法扩展(K-POOL-1 / D-42):模型池路由决策(actor='runtime',payload.type='decide',selected/reason/retries/attempts——禁静默换模型;model_visible=0 不进模型消息流,deriveMessages 不投影——同 usage 纪律);1.15-S1 加法扩展(K-MEM-1 / D-46):白盒记忆操作事件(actor='user' 宿主代理用户操作,turnId='memory' 会话级标识同 'compaction' 先例,payload.type='write'|'edit'|'delete'|'rollback'——审计链同源差异化面,链即版本库〔rollback 恢复数据源=链上 payload.before/after 全文〕;model_visible=0 不进模型消息流——记忆注入走宿主装配层 system ctx 行,deriveMessages 不投影);1.21 加法扩展(R-TOKENHUB-1 / D-T2):thinking 事件(actor='model',payload=thinking 原文禁改写,meta={signature?, redacted?, secretsRedacted?}——先于 assistant/toolCall 落链;投影 = 同 turn 首个 toolCall 消息附加回传(工具环 reasoning_content 契约,Anthropic thinking+tool_use 规范同款);standalone/隔断/跨 turn 不投影;无 thinking 事件链投影逐字节不变;1.22 加法扩展(1.22 迭代规划 D-B1):多块语义——一块一事件(多块链每事件 meta.blockIndex=块序,单块链 meta 与 1.21 逐字节同形),投影单块 = 1.21 三元组、多块 = blocks 数组(D-B2,消费方 toAnthropic 双形态展开));
|
|
15
15
|
export type Actor = 'user' | 'model' | 'plugin' | 'runtime'
|
|
16
16
|
export interface SessionEvent {
|
|
17
17
|
seq: number
|
|
@@ -146,23 +146,26 @@ export class SessionLog {
|
|
|
146
146
|
}
|
|
147
147
|
const out: Array<{ role: string; [k: string]: unknown }> = []
|
|
148
148
|
if (compactEvent) out.push({ role: 'system', content: ((compactEvent.payload as { summary: string }).summary) })
|
|
149
|
-
// 1.21(R-TOKENHUB-1 / D-T3
|
|
150
|
-
// toolCall
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
|
|
149
|
+
// 1.21(R-TOKENHUB-1 / D-T3)→ 1.22(D-B2 多块):thinking 投影——同 turn 内 thinking 事件
|
|
150
|
+
// (一块一事件)按序聚合为块列表,附加到首个后续 toolCall 消息:单块 = 1.21 三元组形态
|
|
151
|
+
// (text/signature?/redacted?,投影逐字节不变——D-T5 兼容线);多块 = blocks 数组(顶层
|
|
152
|
+
// text/signature 键缺席,消费方 toAnthropic 双形态展开)。standalone(无后续 toolCall)/
|
|
153
|
+
// 被 user·system 隔断 / 跨 turn 不投影(实证:普通两轮历史不要求回传);assistant(text)
|
|
154
|
+
// 同 turn 不隔断(链序 thinking→assistant→toolCall);无 thinking 事件投影逐字节不变
|
|
155
|
+
// (N1 快照自洽)。
|
|
156
|
+
let pendingThinkingTurn: string | null = null
|
|
157
|
+
let pendingBlocks: Array<{ text: string; signature?: string; redacted?: boolean }> = []
|
|
155
158
|
for (const e of projected) {
|
|
156
|
-
if (
|
|
159
|
+
if (pendingBlocks.length && (e.turnId !== pendingThinkingTurn || e.kind === 'user' || e.kind === 'system')) pendingBlocks = []
|
|
157
160
|
if (e.kind === 'thinking') {
|
|
158
161
|
const p = typeof e.payload === 'string' ? e.payload : ''
|
|
159
162
|
if (p.length || e.meta?.redacted === true) {
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
pendingThinkingTurn = e.turnId
|
|
164
|
+
pendingBlocks.push({
|
|
162
165
|
text: p,
|
|
163
166
|
...(typeof e.meta?.signature === 'string' && e.meta.signature ? { signature: e.meta.signature } : {}),
|
|
164
167
|
...(e.meta?.redacted === true ? { redacted: true } : {}),
|
|
165
|
-
}
|
|
168
|
+
})
|
|
166
169
|
}
|
|
167
170
|
continue // thinking 不单独成消息(无独立回传语义)
|
|
168
171
|
}
|
|
@@ -171,13 +174,17 @@ export class SessionLog {
|
|
|
171
174
|
else if (e.kind === 'assistant') out.push({ role: 'assistant', content: e.payload })
|
|
172
175
|
else if (e.kind === 'toolCall') {
|
|
173
176
|
const msg: { role: string; [k: string]: unknown } = { role: 'assistant', toolCall: e.payload }
|
|
174
|
-
if (
|
|
177
|
+
if (pendingBlocks.length === 1) {
|
|
178
|
+
const b = pendingBlocks[0]!
|
|
175
179
|
msg.thinking = {
|
|
176
|
-
text:
|
|
177
|
-
...(
|
|
178
|
-
...(
|
|
180
|
+
text: b.text,
|
|
181
|
+
...(b.signature ? { signature: b.signature } : {}),
|
|
182
|
+
...(b.redacted ? { redacted: true } : {}),
|
|
179
183
|
}
|
|
180
|
-
|
|
184
|
+
pendingBlocks = [] // 首 toolCall 消费即清——同 turn 多 toolCall = 同一原始消息,单块重放
|
|
185
|
+
} else if (pendingBlocks.length > 1) {
|
|
186
|
+
msg.thinking = { blocks: pendingBlocks } // 1.22(D-B2):多块形态(provider 原始多块回复的按序重放)
|
|
187
|
+
pendingBlocks = []
|
|
181
188
|
}
|
|
182
189
|
out.push(msg)
|
|
183
190
|
}
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"base64Signature":"MEQCIEr84YFIo6UQdCBqDYqzEn5iofitA9Wtuxx9AqUbuNGZAiBdNvJTODyumJazgvvJunU8HC/jVNGcHjUM9u7quHIyOg==","cert":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUc1ekNDQm0yZ0F3SUJBZ0lVYWV0eWY3L29XeUE3RlVhb1RuV0k0QjYzVU1Vd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpZeE1URTBNRE16TlRNM1doY05Nall4TVRFME1ETTBOVE0zV2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVpdlNPYnBEY1ZHZjd3Vm0yTWhUajlqbTdmQ0Z2ZGFZeGYrVTcKS2ljbzJLbUdNdWRXRUk4KzJuYmxtQmN6Q0tYNWoyWGMrNDRHTTk0bW5EUkF3OTdZT0tPQ0JZd3dnZ1dJTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWZCZ05WSFNNRUdEQVdnQlRmCjArblBWaVFSbHZtbzJPa29WYUxHTGhoa1B6QmlCZ05WSFJFQkFmOEVXREJXaGxSb2RIUndjem92TDJkcGRHaDEKWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHpMM0psYkdWaApjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakl4TGpBd09RWUtLd1lCQkFHRHZ6QUJBUVFyYUhSMGNITTZMeTkwCmIydGxiaTVoWTNScGIyNXpMbWRwZEdoMVluVnpaWEpqYjI1MFpXNTBMbU52YlRBVkJnb3JCZ0VFQVlPL01BRUMKQkFkeVpXeGxZWE5sTURZR0Npc0dBUVFCZzc4d0FRTUVLRFZsWW1Fd1pHTXpNRGhpT1dWak1qSTVNR1l4Tm1GbApabUV5TVdNNVlUVXlPR1UzTkRReU9EQXdGUVlLS3dZQkJBR0R2ekFCQkFRSGNtVnNaV0Z6WlRBZ0Jnb3JCZ0VFCkFZTy9NQUVGQkJKc2NXTTJNalF2WTJGeUxYSjFiblJwYldVd0hnWUtLd1lCQkFHRHZ6QUJCZ1FRY21WbWN5OTAKWVdkekx6RXVNakV1TURBN0Jnb3JCZ0VFQVlPL01BRUlCQzBNSzJoMGRIQnpPaTh2ZEc5clpXNHVZV04wYVc5dQpjeTVuYVhSb2RXSjFjMlZ5WTI5dWRHVnVkQzVqYjIwd1pBWUtLd1lCQkFHRHZ6QUJDUVJXREZSb2RIUndjem92CkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHoKTDNKbGJHVmhjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakl4TGpBd09BWUtLd1lCQkFHRHZ6QUJDZ1FxRENnMQpaV0poTUdSak16QTRZamxsWXpJeU9UQm1NVFpoWldaaE1qRmpPV0UxTWpobE56UTBNamd3TUIwR0Npc0dBUVFCCmc3OHdBUXNFRHd3TloybDBhSFZpTFdodmMzUmxaREExQmdvckJnRUVBWU8vTUFFTUJDY01KV2gwZEhCek9pOHYKWjJsMGFIVmlMbU52YlM5c2NXTTJNalF2WTJGeUxYSjFiblJwYldVd09BWUtLd1lCQkFHRHZ6QUJEUVFxRENnMQpaV0poTUdSak16QTRZamxsWXpJeU9UQm1NVFpoWldaaE1qRmpPV0UxTWpobE56UTBNamd3TUNBR0Npc0dBUVFCCmc3OHdBUTRFRWd3UWNtVm1jeTkwWVdkekx6RXVNakV1TURBYUJnb3JCZ0VFQVlPL01BRVBCQXdNQ2pFek5qRXgKT1RJM01UUXdLUVlLS3dZQkJBR0R2ekFCRUFRYkRCbG9kSFJ3Y3pvdkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMApNQmdHQ2lzR0FRUUJnNzh3QVJFRUNnd0lOamt5TXpRMU5qUXdaQVlLS3dZQkJBR0R2ekFCRWdSV0RGUm9kSFJ3CmN6b3ZMMmRwZEdoMVlpNWpiMjB2YkhGak5qSTBMMk5oY2kxeWRXNTBhVzFsTHk1bmFYUm9kV0l2ZDI5eWEyWnMKYjNkekwzSmxiR1ZoYzJVdWVXMXNRSEpsWm5NdmRHRm5jeTh4TGpJeExqQXdPQVlLS3dZQkJBR0R2ekFCRXdRcQpEQ2cxWldKaE1HUmpNekE0WWpsbFl6SXlPVEJtTVRaaFpXWmhNakZqT1dFMU1qaGxOelEwTWpnd01CY0dDaXNHCkFRUUJnNzh3QVJRRUNRd0hjbVZzWldGelpUQlpCZ29yQmdFRUFZTy9NQUVWQkVzTVNXaDBkSEJ6T2k4dloybDAKYUhWaUxtTnZiUzlzY1dNMk1qUXZZMkZ5TFhKMWJuUnBiV1V2WVdOMGFXOXVjeTl5ZFc1ekx6UXpOVFV5TkRFMwpPVFE0TDJGMGRHVnRjSFJ6THpFd0ZnWUtLd1lCQkFHRHZ6QUJGZ1FJREFad2RXSnNhV013VUFZS0t3WUJCQUdECnZ6QUJHQVJDREVCeVpYQnZPbXh4WXpZeU5FQTJPVEl6TkRVMk5DOWpZWEl0Y25WdWRHbHRaVUF4TXpZeE1Ua3kKTnpFME9uSmxaanB5WldaekwzUmhaM012TVM0eU1TNHdNSUdLQmdvckJnRUVBZFo1QWdRQ0JId0VlZ0I0QUhZQQozVDB3YXNiSEVUSmpHUjRjbVdjM0FxSktYcmplUEszL2g0cHlnQzhwN280QUFBR2gyQi85K0FBQUJBTUFSekJGCkFpRUE2QlpwRnVTK3Y5WVVqZXNxWk02WGFyTXcydDVNbmUxaldSOStkYXVJQ0dJQ0lBSWhPL2h4b0NUQitCdlgKbkVRRmlmNzZvanVtbHlLeWYvckF3V1Rzc3VPMk1Bb0dDQ3FHU000OUJBTURBMmdBTUdVQ01HK2R4dS9BV2tMOQo4QUtiSlhXSXYzMFlGNjk5UGp5cWFDcVhTSUllY25VRzdPZHFXTzRYK2dwb1RNVEc1bXRJcVFJeEFOT0xZRGFZCndTNUhoU0RNcXVLU1M2ODRjL1U2bTlLc0syWmN2RGFrRlZOL1BiZHhCc1Y5cE1ySzZFeEVMblpEb3c9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==","rekorBundle":{"SignedEntryTimestamp":"MEUCIB04W7cJqnNa2clZD6iGQQPWdN+4NyyrSfjpxuDJ5cWIAiEAlr/UsHUN8IVr0S/5WeyxAYNKIpQUnHcPyToMjqgz+HA=","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI4ZDliZDFmYTRkNDQ3YjI1NWFlNjY4YTUxYmI0NzMzOGJkZThlMzVhZDhjY2FjOTdhYzcyZDJjODkzNjY0MTE1In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FUUNJRXI4NFlGSW82VVFkQ0JxRFlxekVuNWlvZml0QTlXdHV4eDlBcVVidU5HWkFpQmROdkpUT0R5dW1KYXpndnZKdW5VOEhDL2pWTkdjSGpVTTl1N3F1SEl5T2c9PSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVYzFla05EUW0weVowRjNTVUpCWjBsVllXVjBlV1kzTDI5WGVVRTNSbFZoYjFSdVYwazBRall6VlUxVmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFVUlRCTlJFMTZUbFJOTTFkb1kwNU5hbGw0VFZSRk1FMUVUVEJPVkUwelYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZwZGxOUFluQkVZMVpIWmpkM1ZtMHlUV2hVYWpscWJUZG1RMFoyWkdGWmVHWXJWVGNLUzJsamJ6SkxiVWROZFdSWFJVazRLekp1WW14dFFtTjZRMHRZTldveVdHTXJORFJIVFRrMGJXNUVVa0YzT1RkWlQwdFBRMEpaZDNkbloxZEpUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFtbENaMDVXU0ZKRlFrRm1PRVZYUkVKWGFHeFNiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmlTRVpxVG1wSk1Fd3lUbWhqYVRGNVpGYzFNR0ZYTVd4TWVUVnVZVmhTYjJSWFNYWmtNamw1WVRKYWMySXpaSHBNTTBwc1lrZFdhQXBqTWxWMVpWY3hjMUZJU214YWJrMTJaRWRHYm1ONU9IaE1ha2w0VEdwQmQwOVJXVXRMZDFsQ1FrRkhSSFo2UVVKQlVWRnlZVWhTTUdOSVRUWk1lVGt3Q21JeWRHeGlhVFZvV1ROU2NHSXlOWHBNYldSd1pFZG9NVmx1Vm5wYVdFcHFZakkxTUZwWE5UQk1iVTUyWWxSQlZrSm5iM0pDWjBWRlFWbFBMMDFCUlVNS1FrRmtlVnBYZUd4WldFNXNUVVJaUjBOcGMwZEJVVkZDWnpjNGQwRlJUVVZMUkZac1dXMUZkMXBIVFhwTlJHaHBUMWRXYWsxcVNUVk5SMWw0VG0xR2JBcGFiVVY1VFZkTk5WbFVWWGxQUjFVelRrUlJlVTlFUVhkR1VWbExTM2RaUWtKQlIwUjJla0ZDUWtGUlNHTnRWbk5hVjBaNldsUkJaMEpuYjNKQ1owVkZDa0ZaVHk5TlFVVkdRa0pLYzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMGhuV1V0TGQxbENRa0ZIUkhaNlFVSkNaMUZSWTIxV2JXTjVPVEFLV1Zka2VreDZSWFZOYWtWMVRVUkJOMEpuYjNKQ1owVkZRVmxQTDAxQlJVbENRekJOU3pKb01HUklRbnBQYVRoMlpFYzVjbHBYTkhWWlYwNHdZVmM1ZFFwamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcVlqSXdkMXBCV1V0TGQxbENRa0ZIUkhaNlFVSkRVVkpYUkVaU2IyUklVbmRqZW05MkNrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUV3eVRtaGphVEY1WkZjMU1HRlhNV3hNZVRWdVlWaFNiMlJYU1haa01qbDVZVEphYzJJelpIb0tURE5LYkdKSFZtaGpNbFYxWlZjeGMxRklTbXhhYmsxMlpFZEdibU41T0hoTWFrbDRUR3BCZDA5QldVdExkMWxDUWtGSFJIWjZRVUpEWjFGeFJFTm5NUXBhVjBwb1RVZFNhazE2UVRSWmFteHNXWHBKZVU5VVFtMU5WRnBvV2xkYWFFMXFSbXBQVjBVeFRXcG9iRTU2VVRCTmFtZDNUVUl3UjBOcGMwZEJVVkZDQ21jM09IZEJVWE5GUkhkM1Rsb3liREJoU0ZacFRGZG9kbU16VW14YVJFRXhRbWR2Y2tKblJVVkJXVTh2VFVGRlRVSkRZMDFLVjJnd1pFaENlazlwT0hZS1dqSnNNR0ZJVm1sTWJVNTJZbE01YzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMDlCV1V0TGQxbENRa0ZIUkhaNlFVSkVVVkZ4UkVObk1RcGFWMHBvVFVkU2FrMTZRVFJaYW14c1dYcEplVTlVUW0xTlZGcG9XbGRhYUUxcVJtcFBWMFV4VFdwb2JFNTZVVEJOYW1kM1RVTkJSME5wYzBkQlVWRkNDbWMzT0hkQlVUUkZSV2QzVVdOdFZtMWplVGt3V1Zka2VreDZSWFZOYWtWMVRVUkJZVUpuYjNKQ1owVkZRVmxQTDAxQlJWQkNRWGROUTJwRmVrNXFSWGdLVDFSSk0wMVVVWGRMVVZsTFMzZFpRa0pCUjBSMmVrRkNSVUZSWWtSQ2JHOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUFwTlFtZEhRMmx6UjBGUlVVSm5OemgzUVZKRlJVTm5kMGxPYW10NVRYcFJNVTVxVVhkYVFWbExTM2RaUWtKQlIwUjJla0ZDUldkU1YwUkdVbTlrU0ZKM0NtTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJZa2hHYWs1cVNUQk1NazVvWTJreGVXUlhOVEJoVnpGc1RIazFibUZZVW05a1YwbDJaREk1ZVdFeVduTUtZak5rZWt3elNteGlSMVpvWXpKVmRXVlhNWE5SU0Vwc1dtNU5kbVJIUm01amVUaDRUR3BKZUV4cVFYZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JYZFJjUXBFUTJjeFdsZEthRTFIVW1wTmVrRTBXV3BzYkZsNlNYbFBWRUp0VFZSYWFGcFhXbWhOYWtacVQxZEZNVTFxYUd4T2VsRXdUV3BuZDAxQ1kwZERhWE5IQ2tGUlVVSm5OemgzUVZKUlJVTlJkMGhqYlZaeldsZEdlbHBVUWxwQ1oyOXlRbWRGUlVGWlR5OU5RVVZXUWtWelRWTlhhREJrU0VKNlQyazRkbG95YkRBS1lVaFdhVXh0VG5aaVV6bHpZMWROTWsxcVVYWlpNa1o1VEZoS01XSnVVbkJpVjFWMldWZE9NR0ZYT1hWamVUbDVaRmMxZWt4NlVYcE9WRlY1VGtSRk13cFBWRkUwVERKR01HUkhWblJqU0ZKNlRIcEZkMFpuV1V0TGQxbENRa0ZIUkhaNlFVSkdaMUZKUkVGYWQyUlhTbk5oVjAxM1ZVRlpTMHQzV1VKQ1FVZEVDblo2UVVKSFFWSkRSRVZDZVZwWVFuWlBiWGg0V1hwWmVVNUZRVEpQVkVsNlRrUlZNazVET1dwWldFbDBZMjVXZFdSSGJIUmFWVUY0VFhwWmVFMVVhM2tLVG5wRk1FOXVTbXhhYW5CNVdsZGFla3d6VW1oYU0wMTJUVk0wZVUxVE5IZE5TVWRMUW1kdmNrSm5SVVZCWkZvMVFXZFJRMEpJZDBWbFowSTBRVWhaUVFvelZEQjNZWE5pU0VWVVNtcEhValJqYlZkak0wRnhTa3RZY21wbFVFc3pMMmcwY0hsblF6aHdOMjgwUVVGQlIyZ3lRaTg1SzBGQlFVSkJUVUZTZWtKR0NrRnBSVUUyUWxwd1JuVlRLM1k1V1ZWcVpYTnhXazAyV0dGeVRYY3lkRFZOYm1VeGFsZFNPU3RrWVhWSlEwZEpRMGxCU1doUEwyaDRiME5VUWl0Q2RsZ0tia1ZSUm1sbU56WnZhblZ0YkhsTGVXWXZja0YzVjFSemMzVlBNazFCYjBkRFEzRkhVMDAwT1VKQlRVUkJNbWRCVFVkVlEwMUhLMlI0ZFM5QlYydE1PUW80UVV0aVNsaFhTWFl6TUZsR05qazVVR3A1Y1dGRGNWaFRTVWxsWTI1VlJ6ZFBaSEZYVHpSWUsyZHdiMVJOVkVjMWJYUkpjVkZKZUVGT1QweFpSR0ZaQ25kVE5VaG9VMFJOY1hWTFUxTTJPRFJqTDFVMmJUbExjMHN5V21OMlJHRnJSbFpPTDFCaVpIaENjMVk1Y0UxeVN6WkZlRVZNYmxwRWIzYzlQUW90TFMwdExVVk9SQ0JEUlZKVVNVWkpRMEZVUlMwdExTMHRDZz09In19fX0=","integratedTime":1794627338,"logIndex":3868826566,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}
|