@lqc123qwe/car-runtime 1.20.0 → 1.21.1

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 CHANGED
@@ -1 +1 @@
1
- 4546ebcc06ccdb9f33754d2d98ee413b25937f61e6bd3fe06a6cff60fa7ae541 car-runtime-1.20.0.tgz
1
+ 66bbea0d771ff0a416ece86c703d25f39a4e9e78af767610ba336b01bdb1c9ac car-runtime-1.21.1.tgz
Binary file
@@ -0,0 +1 @@
1
+ {"base64Signature":"MEUCIQDKONgEM8eAPTGlklJnk7tc5wNDrs/vZpp39jeG81yWtwIgR+tCPl3Djrl8Nk9gpNSZJ+FPXI4ZFp7773VAdr+Fpck=","cert":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUc2RENDQm02Z0F3SUJBZ0lVZEJmS0N4OVhLZllnM3QrVExBMlQzQ3M3WHBJd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpZeE1URTBNRFF5TURNMldoY05Nall4TVRFME1EUXpNRE0yV2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVSTG9jQzRXNFpuV0ZzMjIvYjA3cllRaW5LMHBVQWhLejFidW4KRFM4ZG02QlVhc2FqUHltK0VVcjBNZWQ5aUJlcjF5cXZuNHFiaHRJQWFkYmtpUXk1emFPQ0JZMHdnZ1dKTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWZCZ05WSFNNRUdEQVdnQlRmCjArblBWaVFSbHZtbzJPa29WYUxHTGhoa1B6QmlCZ05WSFJFQkFmOEVXREJXaGxSb2RIUndjem92TDJkcGRHaDEKWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHpMM0psYkdWaApjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakl4TGpFd09RWUtLd1lCQkFHRHZ6QUJBUVFyYUhSMGNITTZMeTkwCmIydGxiaTVoWTNScGIyNXpMbWRwZEdoMVluVnpaWEpqYjI1MFpXNTBMbU52YlRBVkJnb3JCZ0VFQVlPL01BRUMKQkFkeVpXeGxZWE5sTURZR0Npc0dBUVFCZzc4d0FRTUVLRGc1TURObFpEQTJaVEJoTW1KallqYzVPV1V6TkdJMgpPREE0TldZellqUTFObUZoWWpFM09UZ3dGUVlLS3dZQkJBR0R2ekFCQkFRSGNtVnNaV0Z6WlRBZ0Jnb3JCZ0VFCkFZTy9NQUVGQkJKc2NXTTJNalF2WTJGeUxYSjFiblJwYldVd0hnWUtLd1lCQkFHRHZ6QUJCZ1FRY21WbWN5OTAKWVdkekx6RXVNakV1TVRBN0Jnb3JCZ0VFQVlPL01BRUlCQzBNSzJoMGRIQnpPaTh2ZEc5clpXNHVZV04wYVc5dQpjeTVuYVhSb2RXSjFjMlZ5WTI5dWRHVnVkQzVqYjIwd1pBWUtLd1lCQkFHRHZ6QUJDUVJXREZSb2RIUndjem92CkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHoKTDNKbGJHVmhjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakl4TGpFd09BWUtLd1lCQkFHRHZ6QUJDZ1FxRENnNApPVEF6WldRd05tVXdZVEppWTJJM09UbGxNelJpTmpnd09EVm1NMkkwTlRaaFlXSXhOems0TUIwR0Npc0dBUVFCCmc3OHdBUXNFRHd3TloybDBhSFZpTFdodmMzUmxaREExQmdvckJnRUVBWU8vTUFFTUJDY01KV2gwZEhCek9pOHYKWjJsMGFIVmlMbU52YlM5c2NXTTJNalF2WTJGeUxYSjFiblJwYldVd09BWUtLd1lCQkFHRHZ6QUJEUVFxRENnNApPVEF6WldRd05tVXdZVEppWTJJM09UbGxNelJpTmpnd09EVm1NMkkwTlRaaFlXSXhOems0TUNBR0Npc0dBUVFCCmc3OHdBUTRFRWd3UWNtVm1jeTkwWVdkekx6RXVNakV1TVRBYUJnb3JCZ0VFQVlPL01BRVBCQXdNQ2pFek5qRXgKT1RJM01UUXdLUVlLS3dZQkJBR0R2ekFCRUFRYkRCbG9kSFJ3Y3pvdkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMApNQmdHQ2lzR0FRUUJnNzh3QVJFRUNnd0lOamt5TXpRMU5qUXdaQVlLS3dZQkJBR0R2ekFCRWdSV0RGUm9kSFJ3CmN6b3ZMMmRwZEdoMVlpNWpiMjB2YkhGak5qSTBMMk5oY2kxeWRXNTBhVzFsTHk1bmFYUm9kV0l2ZDI5eWEyWnMKYjNkekwzSmxiR1ZoYzJVdWVXMXNRSEpsWm5NdmRHRm5jeTh4TGpJeExqRXdPQVlLS3dZQkJBR0R2ekFCRXdRcQpEQ2c0T1RBelpXUXdObVV3WVRKaVkySTNPVGxsTXpSaU5qZ3dPRFZtTTJJME5UWmhZV0l4TnprNE1CY0dDaXNHCkFRUUJnNzh3QVJRRUNRd0hjbVZzWldGelpUQlpCZ29yQmdFRUFZTy9NQUVWQkVzTVNXaDBkSEJ6T2k4dloybDAKYUhWaUxtTnZiUzlzY1dNMk1qUXZZMkZ5TFhKMWJuUnBiV1V2WVdOMGFXOXVjeTl5ZFc1ekx6UXpOVFUyTVRNNQpNak16TDJGMGRHVnRjSFJ6THpFd0ZnWUtLd1lCQkFHRHZ6QUJGZ1FJREFad2RXSnNhV013VUFZS0t3WUJCQUdECnZ6QUJHQVJDREVCeVpYQnZPbXh4WXpZeU5FQTJPVEl6TkRVMk5DOWpZWEl0Y25WdWRHbHRaVUF4TXpZeE1Ua3kKTnpFME9uSmxaanB5WldaekwzUmhaM012TVM0eU1TNHhNSUdMQmdvckJnRUVBZFo1QWdRQ0JIMEVld0I1QUhjQQozVDB3YXNiSEVUSmpHUjRjbVdjM0FxSktYcmplUEszL2g0cHlnQzhwN280QUFBR2gyRWtyQkFBQUJBTUFTREJHCkFpRUE0eUtpR25lWUhUS1JicjZjNHEwYmM4NXU5RU1FUU1obUtSZWprUlo2dytRQ0lRRFhQMGRRTEVjNEFhV1EKMkhXb002aEZKRE15a291aGJIajE3UHZnVHd5UGJEQUtCZ2dxaGtqT1BRUURBd05vQURCbEFqQk8vdU41VlRxQQpkb3YxcFFFQVFkR3hCNDVKZEw2VHRPRmNMbEd5d0RpWWdsT2RCYnZtZkdkdHlqaDF5V0dXVUtZQ01RQzcrSGJTCmttTHREeGNwOU5TMGZMZkFMNTg5eUtiMXNsOEtVR0FBdlFidEVjNVUvVWNWRmJheXp2c3FBSkZFZGNvPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==","rekorBundle":{"SignedEntryTimestamp":"MEUCICgbmt4S7KuZIcHFx5zOZBAs/O7cmqRY9neWpULg0ib6AiEA/O0LtpinJBhb30rjXIzOagiD8H59yhnPAcUqQXIJwec=","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI2NmJiZWEwZDc3MWZmMGE0MTZlY2U4NmM3MDNkMjVmMzlhNGU5ZTc4YWY3Njc2MTBiYTMzNmIwMWJkYjFjOWFjIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUURLT05nRU04ZUFQVEdsa2xKbms3dGM1d05EcnMvdlpwcDM5amVHODF5V3R3SWdSK3RDUGwzRGpybDhOazlncE5TWkorRlBYSTRaRnA3NzczVkFkcitGcGNrPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVYzJSRU5EUW0wMlowRjNTVUpCWjBsVlpFSm1TME40T1ZoTFpsbG5NM1FyVkV4Qk1sUXpRM00zV0hCSmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFVUlRCTlJGRjVUVVJOTWxkb1kwNU5hbGw0VFZSRk1FMUVVWHBOUkUweVYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZTVEc5alF6UlhORnB1VjBaek1qSXZZakEzY2xsUmFXNUxNSEJWUVdoTGVqRmlkVzRLUkZNNFpHMDJRbFZoYzJGcVVIbHRLMFZWY2pCTlpXUTVhVUpsY2pGNWNYWnVOSEZpYUhSSlFXRmtZbXRwVVhrMWVtRlBRMEpaTUhkbloxZEtUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFtbENaMDVXU0ZKRlFrRm1PRVZYUkVKWGFHeFNiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmlTRVpxVG1wSk1Fd3lUbWhqYVRGNVpGYzFNR0ZYTVd4TWVUVnVZVmhTYjJSWFNYWmtNamw1WVRKYWMySXpaSHBNTTBwc1lrZFdhQXBqTWxWMVpWY3hjMUZJU214YWJrMTJaRWRHYm1ONU9IaE1ha2w0VEdwRmQwOVJXVXRMZDFsQ1FrRkhSSFo2UVVKQlVWRnlZVWhTTUdOSVRUWk1lVGt3Q21JeWRHeGlhVFZvV1ROU2NHSXlOWHBNYldSd1pFZG9NVmx1Vm5wYVdFcHFZakkxTUZwWE5UQk1iVTUyWWxSQlZrSm5iM0pDWjBWRlFWbFBMMDFCUlVNS1FrRmtlVnBYZUd4WldFNXNUVVJaUjBOcGMwZEJVVkZDWnpjNGQwRlJUVVZMUkdjMVRVUk9iRnBFUVRKYVZFSm9UVzFLYWxscVl6VlBWMVY2VGtkSk1ncFBSRUUwVGxkWmVsbHFVVEZPYlVab1dXcEZNMDlVWjNkR1VWbExTM2RaUWtKQlIwUjJla0ZDUWtGUlNHTnRWbk5hVjBaNldsUkJaMEpuYjNKQ1owVkZDa0ZaVHk5TlFVVkdRa0pLYzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMGhuV1V0TGQxbENRa0ZIUkhaNlFVSkNaMUZSWTIxV2JXTjVPVEFLV1Zka2VreDZSWFZOYWtWMVRWUkJOMEpuYjNKQ1owVkZRVmxQTDAxQlJVbENRekJOU3pKb01HUklRbnBQYVRoMlpFYzVjbHBYTkhWWlYwNHdZVmM1ZFFwamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcVlqSXdkMXBCV1V0TGQxbENRa0ZIUkhaNlFVSkRVVkpYUkVaU2IyUklVbmRqZW05MkNrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUV3eVRtaGphVEY1WkZjMU1HRlhNV3hNZVRWdVlWaFNiMlJYU1haa01qbDVZVEphYzJJelpIb0tURE5LYkdKSFZtaGpNbFYxWlZjeGMxRklTbXhhYmsxMlpFZEdibU41T0hoTWFrbDRUR3BGZDA5QldVdExkMWxDUWtGSFJIWjZRVUpEWjFGeFJFTm5OQXBQVkVGNldsZFJkMDV0VlhkWlZFcHBXVEpKTTA5VWJHeE5lbEpwVG1wbmQwOUVWbTFOTWtrd1RsUmFhRmxYU1hoT2VtczBUVUl3UjBOcGMwZEJVVkZDQ21jM09IZEJVWE5GUkhkM1Rsb3liREJoU0ZacFRGZG9kbU16VW14YVJFRXhRbWR2Y2tKblJVVkJXVTh2VFVGRlRVSkRZMDFLVjJnd1pFaENlazlwT0hZS1dqSnNNR0ZJVm1sTWJVNTJZbE01YzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMDlCV1V0TGQxbENRa0ZIUkhaNlFVSkVVVkZ4UkVObk5BcFBWRUY2V2xkUmQwNXRWWGRaVkVwcFdUSkpNMDlVYkd4TmVsSnBUbXBuZDA5RVZtMU5Na2t3VGxSYWFGbFhTWGhPZW1zMFRVTkJSME5wYzBkQlVWRkNDbWMzT0hkQlVUUkZSV2QzVVdOdFZtMWplVGt3V1Zka2VreDZSWFZOYWtWMVRWUkJZVUpuYjNKQ1owVkZRVmxQTDAxQlJWQkNRWGROUTJwRmVrNXFSWGdLVDFSSk0wMVVVWGRMVVZsTFMzZFpRa0pCUjBSMmVrRkNSVUZSWWtSQ2JHOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUFwTlFtZEhRMmx6UjBGUlVVSm5OemgzUVZKRlJVTm5kMGxPYW10NVRYcFJNVTVxVVhkYVFWbExTM2RaUWtKQlIwUjJla0ZDUldkU1YwUkdVbTlrU0ZKM0NtTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJZa2hHYWs1cVNUQk1NazVvWTJreGVXUlhOVEJoVnpGc1RIazFibUZZVW05a1YwbDJaREk1ZVdFeVduTUtZak5rZWt3elNteGlSMVpvWXpKVmRXVlhNWE5SU0Vwc1dtNU5kbVJIUm01amVUaDRUR3BKZUV4cVJYZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JYZFJjUXBFUTJjMFQxUkJlbHBYVVhkT2JWVjNXVlJLYVZreVNUTlBWR3hzVFhwU2FVNXFaM2RQUkZadFRUSkpNRTVVV21oWlYwbDRUbnByTkUxQ1kwZERhWE5IQ2tGUlVVSm5OemgzUVZKUlJVTlJkMGhqYlZaeldsZEdlbHBVUWxwQ1oyOXlRbWRGUlVGWlR5OU5RVVZXUWtWelRWTlhhREJrU0VKNlQyazRkbG95YkRBS1lVaFdhVXh0VG5aaVV6bHpZMWROTWsxcVVYWlpNa1o1VEZoS01XSnVVbkJpVjFWMldWZE9NR0ZYT1hWamVUbDVaRmMxZWt4NlVYcE9WRlV5VFZSTk5RcE5hazE2VERKR01HUkhWblJqU0ZKNlRIcEZkMFpuV1V0TGQxbENRa0ZIUkhaNlFVSkdaMUZKUkVGYWQyUlhTbk5oVjAxM1ZVRlpTMHQzV1VKQ1FVZEVDblo2UVVKSFFWSkRSRVZDZVZwWVFuWlBiWGg0V1hwWmVVNUZRVEpQVkVsNlRrUlZNazVET1dwWldFbDBZMjVXZFdSSGJIUmFWVUY0VFhwWmVFMVVhM2tLVG5wRk1FOXVTbXhhYW5CNVdsZGFla3d6VW1oYU0wMTJUVk0wZVUxVE5IaE5TVWRNUW1kdmNrSm5SVVZCWkZvMVFXZFJRMEpJTUVWbGQwSTFRVWhqUVFvelZEQjNZWE5pU0VWVVNtcEhValJqYlZkak0wRnhTa3RZY21wbFVFc3pMMmcwY0hsblF6aHdOMjgwUVVGQlIyZ3lSV3R5UWtGQlFVSkJUVUZUUkVKSENrRnBSVUUwZVV0cFIyNWxXVWhVUzFKaWNqWmpOSEV3WW1NNE5YVTVSVTFGVVUxb2JVdFNaV3ByVWxvMmR5dFJRMGxSUkZoUU1HUlJURVZqTkVGaFYxRUtNa2hYYjAwMmFFWktSRTE1YTI5MWFHSklhakUzVUhablZIZDVVR0pFUVV0Q1oyZHhhR3RxVDFCUlVVUkJkMDV2UVVSQ2JFRnFRazh2ZFU0MVZsUnhRUXBrYjNZeGNGRkZRVkZrUjNoQ05EVktaRXcyVkhSUFJtTk1iRWQ1ZDBScFdXZHNUMlJDWW5adFprZGtkSGxxYURGNVYwZFhWVXRaUTAxUlF6Y3JTR0pUQ210dFRIUkVlR053T1U1VE1HWk1aa0ZNTlRnNWVVdGlNWE5zT0V0VlIwRkJkbEZpZEVWak5WVXZWV05XUm1KaGVYcDJjM0ZCU2taRlpHTnZQUW90TFMwdExVVk9SQ0JEUlZKVVNVWkpRMEZVUlMwdExTMHRDZz09In19fX0=","integratedTime":1794630037,"logIndex":3869485684,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}
@@ -1,4 +1,4 @@
1
- {"stage":"archive","detail":"git archive HEAD → car-runtime-1.20.0.tgz(430265 bytes,树哈希锚定)","ts":1794037383291}
2
- {"stage":"sha256sums","detail":"SHA256SUMS 4546ebcc06ccdb9f…(裸字节复核通过)","ts":1794037383292}
3
- {"stage":"sbom","detail":"55 个组件(运行时依赖 0 项)","ts":1794037383299}
4
- {"stage":"cosign-keyless","detail":"signed car-runtime-1.20.0.tgz (keyless OIDC + Rekor)","ts":1794037385104}
1
+ {"stage":"archive","detail":"git archive HEAD → car-runtime-1.21.1.tgz(437655 bytes,树哈希锚定)","ts":1794630034700}
2
+ {"stage":"sha256sums","detail":"SHA256SUMS 66bbea0d771ff0a4…(裸字节复核通过)","ts":1794630034701}
3
+ {"stage":"sbom","detail":"55 个组件(运行时依赖 0 项)","ts":1794630034707}
4
+ {"stage":"cosign-keyless","detail":"signed car-runtime-1.21.1.tgz (keyless OIDC + Rekor)","ts":1794630037965}
@@ -21,13 +21,25 @@ export async function chatStep(opts) {
21
21
  const messages = log.deriveMessages(undefined, { activeTurnId: turnId }).map(m => ({
22
22
  role: m.role,
23
23
  content: m.toolCall !== undefined
24
- ? { toolCall: m.toolCall }
24
+ ? {
25
+ toolCall: m.toolCall,
26
+ // 1.21(R-TOKENHUB-1 / D-T3/D-T4):投影层附加的同 turn thinking 三元组随 toolCall
27
+ // 载荷透传(适配器回传消费——toAnthropic 前置 thinking 块;openai 形忽略该键)
28
+ ...(m.thinking !== undefined
29
+ ? { thinking: m.thinking }
30
+ : {}),
31
+ }
25
32
  : m.content,
26
33
  }));
27
34
  // 4. 流式消费(3. 凭据解析在适配器首块前,A080001 由此传播)
28
35
  const redactor = new StreamRedactor();
29
36
  let text = '';
30
37
  const calls = new Map();
38
+ // 1.21(R-TOKENHUB-1 / D-T1/D-T2):thinking 捕获累积——禁改写(回传签名完整性 > 脱敏
39
+ // 改写),provider 事实字节保真;redacted_thinking = data 全文单发覆盖
40
+ let thinkingText = '';
41
+ let thinkingSignature = '';
42
+ let thinkingRedacted;
31
43
  let stopReason;
32
44
  let errorDetail;
33
45
  let usage;
@@ -67,6 +79,13 @@ export async function chatStep(opts) {
67
79
  cur.argsBuf += chunk.toolCallDelta.argumentsDelta;
68
80
  calls.set(idx, cur);
69
81
  }
82
+ // 1.21(R-TOKENHUB-1 / D-T1):thinking 三面捕获(text/signature 增量累积、redacted 单发覆盖)
83
+ if (chunk.thinkingDelta !== undefined)
84
+ thinkingText += chunk.thinkingDelta;
85
+ if (chunk.thinkingSignatureDelta !== undefined)
86
+ thinkingSignature += chunk.thinkingSignatureDelta;
87
+ if (chunk.thinkingRedacted !== undefined)
88
+ thinkingRedacted = chunk.thinkingRedacted;
70
89
  if (chunk.error)
71
90
  errorDetail = chunk.error.message;
72
91
  if (chunk.usage)
@@ -103,6 +122,20 @@ export async function chatStep(opts) {
103
122
  providerRaw: usage.providerRaw,
104
123
  });
105
124
  }
125
+ // 5a. 1.21(R-TOKENHUB-1 / D-T2):thinking 事件落链(actor='model',先于 assistant/toolCall
126
+ // ——投影层按同 turn 首 toolCall 附加回传)。payload = thinking 原文禁改写(签名完整性 >
127
+ // 脱敏改写——改写即回传校验失败);secretsRedacted 仅计数留痕(审计信号,不复写);
128
+ // redacted 形态 payload = data 全文(meta.redacted=true)。无 thinking chunk = 零新事件
129
+ // (D-T5 字节兼容,链形态与 1.20 全等)。
130
+ if (thinkingText.length || thinkingRedacted !== undefined) {
131
+ const thinkingPayload = thinkingRedacted ?? thinkingText;
132
+ const secretsInThinking = scanSecrets(thinkingPayload).hits.length;
133
+ log.append('model', 'thinking', turnId, thinkingPayload, {
134
+ ...(thinkingRedacted !== undefined ? { redacted: true } : {}),
135
+ ...(thinkingSignature ? { signature: thinkingSignature } : {}),
136
+ ...(secretsInThinking ? { secretsRedacted: secretsInThinking } : {}),
137
+ });
138
+ }
106
139
  // 5. assistant 文本落 M7(脱敏后 + 计数留痕;空文本不产事件)
107
140
  // flush 后兜底复扫只计数不复写:流式遮蔽已生效,>0 即流式边界逃逸的审计信号
108
141
  let secretsRedacted = 0;
@@ -606,12 +606,35 @@ function toAnthropic(req, apiKey, cache) {
606
606
  turns.push({ role: 'user', content: pendingToolResults });
607
607
  pendingToolResults = [];
608
608
  };
609
+ // 1.21.1(R-TOKENHUB-1 二分实证):同轮拆分重放合并——投影形态 [assistant(text)][assistant(toolCall)…]
610
+ // 在 tools 声明在场时被 tokenhub 网关严格路径拒绝(400 reasoning_content must be passed back,
611
+ // 与 thinking 是否已在 wire 无关——P-B/P-C vs P-D 四探针二分定案);provider 原始回复 = 单条
612
+ // [thinking?, text?, tool_use…] 消息,合并重放(P-D)过审。合并口径:
613
+ // - 相邻 assistant(toolCall) 聚合(同 turn 多 tool_use 单条);thinking 取首条附加;
614
+ // - 紧邻前驱为 assistant 纯文本消息 → 弹回合并为 [thinking?, text, tool_use…];
615
+ // - 无相邻文本的 toolCall 消息形态不变([thinking?, tool_use])——非工具环链逐字节兼容(D-T5)。
616
+ let pendingTu = null;
617
+ const flushTu = () => {
618
+ if (!pendingTu)
619
+ return;
620
+ const prev = turns[turns.length - 1];
621
+ const { thinkingBlock, toolCalls } = pendingTu;
622
+ if (prev && prev.role === 'assistant' && typeof prev.content === 'string') {
623
+ turns.pop();
624
+ turns.push({ role: 'assistant', content: [...(thinkingBlock ? [thinkingBlock] : []), { type: 'text', text: prev.content }, ...toolCalls] });
625
+ }
626
+ else {
627
+ turns.push({ role: 'assistant', content: [...(thinkingBlock ? [thinkingBlock] : []), ...toolCalls] });
628
+ }
629
+ pendingTu = null;
630
+ };
609
631
  for (const m of req.messages) {
610
632
  if (m.role === 'system') {
611
633
  system.push(typeof m.content === 'string' ? m.content : JSON.stringify(m.content));
612
634
  continue;
613
635
  }
614
636
  if (m.role === 'toolResult') {
637
+ flushTu(); // tool_result 前 = 同轮 assistant 消息收口([text?,tu…] 先于 tool_result 出站)
615
638
  const p = m.content;
616
639
  pendingToolResults.push({
617
640
  type: 'tool_result',
@@ -621,15 +644,27 @@ function toAnthropic(req, apiKey, cache) {
621
644
  });
622
645
  continue;
623
646
  }
624
- flushToolResults();
625
647
  if (m.role === 'assistant' && m.content != null && typeof m.content === 'object' && 'toolCall' in m.content) {
626
648
  const tc = m.content.toolCall;
627
- turns.push({ role: 'assistant', content: [{ type: 'tool_use', id: tc.id, name: tc.tool, input: tc.args ?? {} }] });
628
- }
629
- else {
630
- turns.push({ role: m.role, content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content) });
649
+ // 1.21(R-TOKENHUB-1 / D-T4):工具环回传——投影层附加的 thinking(同 turn 原始 assistant
650
+ // 消息的 thinking 块)前置重放。1.21.1:thinking 块随合并缓冲进同轮单条消息(见 flushTu 注记);
651
+ // 无 thinking = 1.20 形态。
652
+ const th = m.content.thinking;
653
+ const thinkingBlock = th?.text?.length
654
+ ? th.redacted
655
+ ? { type: 'redacted_thinking', data: th.text }
656
+ : { type: 'thinking', thinking: th.text, ...(th.signature ? { signature: th.signature } : {}) }
657
+ : undefined;
658
+ if (!pendingTu)
659
+ pendingTu = { toolCalls: [], ...(thinkingBlock ? { thinkingBlock } : {}) };
660
+ pendingTu.toolCalls.push({ type: 'tool_use', id: tc.id, name: tc.tool, input: tc.args ?? {} });
661
+ continue;
631
662
  }
663
+ flushTu();
664
+ flushToolResults();
665
+ turns.push({ role: m.role, content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content) });
632
666
  }
667
+ flushTu();
633
668
  flushToolResults();
634
669
  // 1.20-K1(D-48 P2):滚动断点在白名单命中时挂尾部消息(缺省 1 个)——system 断点(P1)
635
670
  // 与消息断点独立,off 时两者俱灭(rollingCacheAllowed 内已连坐)
@@ -706,6 +741,10 @@ async function* parseAnthropicSseStream(body, model, adapterId) {
706
741
  if (block?.type === 'tool_use') {
707
742
  yield { toolCallDelta: { index: evt.index, id: block.id, name: block.name } };
708
743
  }
744
+ else if (block?.type === 'redacted_thinking' && typeof block.data === 'string' && block.data.length) {
745
+ // 1.21(R-TOKENHUB-1 / D-T1):redacted_thinking 全文单发(回传形态 {type:'redacted_thinking',data})
746
+ yield { thinkingRedacted: block.data };
747
+ }
709
748
  }
710
749
  else if (type === 'content_block_delta') {
711
750
  const d = evt.delta;
@@ -715,7 +754,14 @@ async function* parseAnthropicSseStream(body, model, adapterId) {
715
754
  else if (d?.type === 'input_json_delta' && typeof d.partial_json === 'string' && d.partial_json.length) {
716
755
  yield { toolCallDelta: { index: evt.index, argumentsDelta: d.partial_json } };
717
756
  }
718
- // thinking_delta / citations_delta 等非 CAR 消费面:容错跳过
757
+ else if (d?.type === 'thinking_delta' && typeof d.thinking === 'string' && d.thinking.length) {
758
+ // 1.21(R-TOKENHUB-1 / D-T1):thinking 文本增量捕获(原容错跳过 → 落链 + 工具环回传)
759
+ yield { thinkingDelta: d.thinking };
760
+ }
761
+ else if (d?.type === 'signature_delta' && typeof d.signature === 'string' && d.signature.length) {
762
+ yield { thinkingSignatureDelta: d.signature };
763
+ }
764
+ // citations_delta 等其余非 CAR 消费面:容错跳过
719
765
  }
720
766
  else if (type === 'message_start') {
721
767
  // 1.11-S1(D-33):input 侧采集(usage 嵌套在 message 下)
@@ -86,6 +86,12 @@ export interface LlmChunk {
86
86
  };
87
87
  /** 1.11-S1(D-33):每次请求最后一个 chunk 附带归一化用量;缺失 = provider 未回,禁补造 */
88
88
  usage?: LlmUsage;
89
+ /** thinking 块文本增量(content_block_delta.thinking_delta) */
90
+ thinkingDelta?: string;
91
+ /** thinking 块签名增量(signature_delta——真 Anthropic thinking 块回传须携签名) */
92
+ thinkingSignatureDelta?: string;
93
+ /** redacted_thinking 块 data 全文(content_block_start 单发;回传形态 {type:'redacted_thinking',data}) */
94
+ thinkingRedacted?: string;
89
95
  }
90
96
  /** Provider 适配器(ACL,C-02):统一签名,消解 Provider 差异 */
91
97
  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.20.0",
4
+ "version": "1.21.1",
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": "da87f5e0231a9d0dc8455bac6057ce7f5d45eeffa7534b9ae44be7c0a42e64f4"
164
+ "sha256": "b7cf35ba06ebaae339a89da0e4df08b5ae310a60a97b5201de54f092fc8758ab"
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": "ea7d8f9c9e8b79d5f073df06e7e8cc8af1819500222108061ff07b60aa29695a"
179
+ "sha256": "9e481456aa224c468ccdf6b577ce1e1d0c2b91aeeaa2c0f195ee40c779b7da02"
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": "15229f894f8432ce29e8c1b3dcefded54a1e1220e0c6da93c5f24a68213147df"
204
+ "sha256": "d9ff638ea4de9b89d56238f2d7fd65c07dd29323fcb9906e72b6877618a360a6"
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": "435fc7336e5de1b96688d3c973aa1129ae39e7347a324d5f15aaabe77a6e1a71"
254
+ "sha256": "9b3a081bfa60e046166cce11203848402f52d4e9b9d0f94ad2e9dc1f0ebadd9c"
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": "29ba6c8cb059bcb1429d80a909ca79573c644ae1429f870a6065903c898d2816"
274
+ "sha256": "707102222be862dbc4f2d6d5aa3168472401d186934edf95ef21d6cc950ca998"
275
275
  },
276
276
  {
277
277
  "type": "file",
@@ -1,4 +1,4 @@
1
- export type EventKind = 'user' | 'assistant' | 'toolCall' | 'toolResult' | 'turnEnd' | 'goalUpdate' | 'hostRaw' | 'fork' | 'system' | 'usage' | 'compact' | 'routing' | 'memory';
1
+ export type EventKind = 'user' | 'assistant' | 'toolCall' | 'toolResult' | 'turnEnd' | 'goalUpdate' | 'hostRaw' | 'fork' | 'system' | 'usage' | 'compact' | 'routing' | 'memory' | 'thinking';
2
2
  export type Actor = 'user' | 'model' | 'plugin' | 'runtime';
3
3
  export interface SessionEvent {
4
4
  seq: number;
@@ -122,15 +122,45 @@ 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):thinking 投影——同 turn 内 thinking 事件附加到首个后续
126
+ // toolCall 消息(原始 provider assistant 消息 = [thinking, ...tool_use] 的重放形态);
127
+ // standalone(无后续 toolCall)/ 被 user·system 隔断 / 跨 turn 不投影(实证:普通两轮
128
+ // 历史不要求回传);assistant(text) 同 turn 不隔断(链序 thinking→assistant→toolCall);
129
+ // 无 thinking 事件投影逐字节不变(D-T5 兼容线,N1 快照自洽)。
130
+ let pendingThinking = null;
125
131
  for (const e of projected) {
132
+ if (pendingThinking && (e.turnId !== pendingThinking.turnId || e.kind === 'user' || e.kind === 'system'))
133
+ pendingThinking = null;
134
+ if (e.kind === 'thinking') {
135
+ const p = typeof e.payload === 'string' ? e.payload : '';
136
+ if (p.length || e.meta?.redacted === true) {
137
+ pendingThinking = {
138
+ turnId: e.turnId,
139
+ text: p,
140
+ ...(typeof e.meta?.signature === 'string' && e.meta.signature ? { signature: e.meta.signature } : {}),
141
+ ...(e.meta?.redacted === true ? { redacted: true } : {}),
142
+ };
143
+ }
144
+ continue; // thinking 不单独成消息(无独立回传语义)
145
+ }
126
146
  if (e.kind === 'system')
127
147
  out.push({ role: 'system', content: e.payload });
128
148
  else if (e.kind === 'user')
129
149
  out.push({ role: 'user', content: e.payload });
130
150
  else if (e.kind === 'assistant')
131
151
  out.push({ role: 'assistant', content: e.payload });
132
- else if (e.kind === 'toolCall')
133
- out.push({ role: 'assistant', toolCall: e.payload });
152
+ else if (e.kind === 'toolCall') {
153
+ const msg = { role: 'assistant', toolCall: e.payload };
154
+ if (pendingThinking) {
155
+ msg.thinking = {
156
+ text: pendingThinking.text,
157
+ ...(pendingThinking.signature ? { signature: pendingThinking.signature } : {}),
158
+ ...(pendingThinking.redacted ? { redacted: true } : {}),
159
+ };
160
+ pendingThinking = null; // 首 toolCall 消费即清——同 turn 多 toolCall = 同一原始消息,单块重放
161
+ }
162
+ out.push(msg);
163
+ }
134
164
  else if (e.kind === 'toolResult') {
135
165
  const id = e.payload?.id;
136
166
  if (typeof id === 'string' && lastSeqById.get(id) !== e.seq)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lqc123qwe/car-runtime",
3
- "version": "1.20.0",
3
+ "version": "1.21.1",
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",
@@ -81,7 +81,14 @@ export async function chatStep(opts: ChatStepOptions): Promise<ChatStepResult> {
81
81
  const messages = log.deriveMessages(undefined, { activeTurnId: turnId }).map(m => ({
82
82
  role: m.role as 'system' | 'user' | 'assistant' | 'toolResult',
83
83
  content: (m as unknown as { toolCall?: unknown }).toolCall !== undefined
84
- ? { toolCall: (m as unknown as { toolCall: unknown }).toolCall }
84
+ ? {
85
+ toolCall: (m as unknown as { toolCall: unknown }).toolCall,
86
+ // 1.21(R-TOKENHUB-1 / D-T3/D-T4):投影层附加的同 turn thinking 三元组随 toolCall
87
+ // 载荷透传(适配器回传消费——toAnthropic 前置 thinking 块;openai 形忽略该键)
88
+ ...((m as unknown as { thinking?: unknown }).thinking !== undefined
89
+ ? { thinking: (m as unknown as { thinking: unknown }).thinking }
90
+ : {}),
91
+ }
85
92
  : m.content,
86
93
  }))
87
94
 
@@ -89,6 +96,11 @@ export async function chatStep(opts: ChatStepOptions): Promise<ChatStepResult> {
89
96
  const redactor = new StreamRedactor()
90
97
  let text = ''
91
98
  const calls = new Map<number, { id?: string; name?: string; argsBuf: string }>()
99
+ // 1.21(R-TOKENHUB-1 / D-T1/D-T2):thinking 捕获累积——禁改写(回传签名完整性 > 脱敏
100
+ // 改写),provider 事实字节保真;redacted_thinking = data 全文单发覆盖
101
+ let thinkingText = ''
102
+ let thinkingSignature = ''
103
+ let thinkingRedacted: string | undefined
92
104
  let stopReason: ModelStep['stopReason'] | undefined
93
105
  let errorDetail: string | undefined
94
106
  let usage: LlmUsage | undefined
@@ -124,6 +136,10 @@ export async function chatStep(opts: ChatStepOptions): Promise<ChatStepResult> {
124
136
  if (chunk.toolCallDelta.argumentsDelta) cur.argsBuf += chunk.toolCallDelta.argumentsDelta
125
137
  calls.set(idx, cur)
126
138
  }
139
+ // 1.21(R-TOKENHUB-1 / D-T1):thinking 三面捕获(text/signature 增量累积、redacted 单发覆盖)
140
+ if (chunk.thinkingDelta !== undefined) thinkingText += chunk.thinkingDelta
141
+ if (chunk.thinkingSignatureDelta !== undefined) thinkingSignature += chunk.thinkingSignatureDelta
142
+ if (chunk.thinkingRedacted !== undefined) thinkingRedacted = chunk.thinkingRedacted
127
143
  if (chunk.error) errorDetail = chunk.error.message
128
144
  if (chunk.usage) usage = chunk.usage // D-33:附着于最后一个 chunk——后到覆盖
129
145
  if (chunk.finishReason !== undefined) stopReason = chunk.finishReason === 'aborted' ? 'error' : chunk.finishReason
@@ -157,6 +173,21 @@ export async function chatStep(opts: ChatStepOptions): Promise<ChatStepResult> {
157
173
  })
158
174
  }
159
175
 
176
+ // 5a. 1.21(R-TOKENHUB-1 / D-T2):thinking 事件落链(actor='model',先于 assistant/toolCall
177
+ // ——投影层按同 turn 首 toolCall 附加回传)。payload = thinking 原文禁改写(签名完整性 >
178
+ // 脱敏改写——改写即回传校验失败);secretsRedacted 仅计数留痕(审计信号,不复写);
179
+ // redacted 形态 payload = data 全文(meta.redacted=true)。无 thinking chunk = 零新事件
180
+ // (D-T5 字节兼容,链形态与 1.20 全等)。
181
+ if (thinkingText.length || thinkingRedacted !== undefined) {
182
+ const thinkingPayload = thinkingRedacted ?? thinkingText
183
+ const secretsInThinking = scanSecrets(thinkingPayload).hits.length
184
+ log.append('model', 'thinking', turnId, thinkingPayload, {
185
+ ...(thinkingRedacted !== undefined ? { redacted: true } : {}),
186
+ ...(thinkingSignature ? { signature: thinkingSignature } : {}),
187
+ ...(secretsInThinking ? { secretsRedacted: secretsInThinking } : {}),
188
+ })
189
+ }
190
+
160
191
  // 5. assistant 文本落 M7(脱敏后 + 计数留痕;空文本不产事件)
161
192
  // flush 后兜底复扫只计数不复写:流式遮蔽已生效,>0 即流式边界逃逸的审计信号
162
193
  let secretsRedacted = 0
@@ -655,12 +655,33 @@ function toAnthropic(req: LlmRequest, apiKey: string, cache: { rolling: boolean;
655
655
  turns.push({ role: 'user', content: pendingToolResults })
656
656
  pendingToolResults = []
657
657
  }
658
+ // 1.21.1(R-TOKENHUB-1 二分实证):同轮拆分重放合并——投影形态 [assistant(text)][assistant(toolCall)…]
659
+ // 在 tools 声明在场时被 tokenhub 网关严格路径拒绝(400 reasoning_content must be passed back,
660
+ // 与 thinking 是否已在 wire 无关——P-B/P-C vs P-D 四探针二分定案);provider 原始回复 = 单条
661
+ // [thinking?, text?, tool_use…] 消息,合并重放(P-D)过审。合并口径:
662
+ // - 相邻 assistant(toolCall) 聚合(同 turn 多 tool_use 单条);thinking 取首条附加;
663
+ // - 紧邻前驱为 assistant 纯文本消息 → 弹回合并为 [thinking?, text, tool_use…];
664
+ // - 无相邻文本的 toolCall 消息形态不变([thinking?, tool_use])——非工具环链逐字节兼容(D-T5)。
665
+ let pendingTu: { toolCalls: Array<{ type: 'tool_use'; id: string; name: string; input: unknown }>; thinkingBlock?: Record<string, unknown> } | null = null
666
+ const flushTu = () => {
667
+ if (!pendingTu) return
668
+ const prev = turns[turns.length - 1]
669
+ const { thinkingBlock, toolCalls } = pendingTu
670
+ if (prev && prev.role === 'assistant' && typeof prev.content === 'string') {
671
+ turns.pop()
672
+ turns.push({ role: 'assistant', content: [...(thinkingBlock ? [thinkingBlock] : []), { type: 'text', text: prev.content }, ...toolCalls] })
673
+ } else {
674
+ turns.push({ role: 'assistant', content: [...(thinkingBlock ? [thinkingBlock] : []), ...toolCalls] })
675
+ }
676
+ pendingTu = null
677
+ }
658
678
  for (const m of req.messages) {
659
679
  if (m.role === 'system') {
660
680
  system.push(typeof m.content === 'string' ? m.content : JSON.stringify(m.content))
661
681
  continue
662
682
  }
663
683
  if (m.role === 'toolResult') {
684
+ flushTu() // tool_result 前 = 同轮 assistant 消息收口([text?,tu…] 先于 tool_result 出站)
664
685
  const p = m.content as { id?: string; result?: unknown; error?: string }
665
686
  pendingToolResults.push({
666
687
  type: 'tool_result',
@@ -670,14 +691,26 @@ function toAnthropic(req: LlmRequest, apiKey: string, cache: { rolling: boolean;
670
691
  })
671
692
  continue
672
693
  }
673
- flushToolResults()
674
694
  if (m.role === 'assistant' && m.content != null && typeof m.content === 'object' && 'toolCall' in (m.content as object)) {
675
695
  const tc = (m.content as { toolCall: { id: string; tool: string; args: unknown } }).toolCall
676
- turns.push({ role: 'assistant', content: [{ type: 'tool_use', id: tc.id, name: tc.tool, input: tc.args ?? {} }] })
677
- } else {
678
- turns.push({ role: m.role, content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content) })
696
+ // 1.21(R-TOKENHUB-1 / D-T4):工具环回传——投影层附加的 thinking(同 turn 原始 assistant
697
+ // 消息的 thinking 块)前置重放。1.21.1:thinking 块随合并缓冲进同轮单条消息(见 flushTu 注记);
698
+ // 无 thinking = 1.20 形态。
699
+ const th = (m.content as { thinking?: { text?: string; signature?: string; redacted?: boolean } }).thinking
700
+ const thinkingBlock = th?.text?.length
701
+ ? th.redacted
702
+ ? { type: 'redacted_thinking', data: th.text }
703
+ : { type: 'thinking', thinking: th.text, ...(th.signature ? { signature: th.signature } : {}) }
704
+ : undefined
705
+ if (!pendingTu) pendingTu = { toolCalls: [], ...(thinkingBlock ? { thinkingBlock } : {}) }
706
+ pendingTu.toolCalls.push({ type: 'tool_use', id: tc.id, name: tc.tool, input: tc.args ?? {} })
707
+ continue
679
708
  }
709
+ flushTu()
710
+ flushToolResults()
711
+ turns.push({ role: m.role, content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content) })
680
712
  }
713
+ flushTu()
681
714
  flushToolResults()
682
715
  // 1.20-K1(D-48 P2):滚动断点在白名单命中时挂尾部消息(缺省 1 个)——system 断点(P1)
683
716
  // 与消息断点独立,off 时两者俱灭(rollingCacheAllowed 内已连坐)
@@ -746,6 +779,9 @@ async function* parseAnthropicSseStream(body: AsyncIterable<Uint8Array>, model:
746
779
  const block = evt.content_block
747
780
  if (block?.type === 'tool_use') {
748
781
  yield { toolCallDelta: { index: evt.index, id: block.id, name: block.name } }
782
+ } else if (block?.type === 'redacted_thinking' && typeof block.data === 'string' && block.data.length) {
783
+ // 1.21(R-TOKENHUB-1 / D-T1):redacted_thinking 全文单发(回传形态 {type:'redacted_thinking',data})
784
+ yield { thinkingRedacted: block.data }
749
785
  }
750
786
  } else if (type === 'content_block_delta') {
751
787
  const d = evt.delta
@@ -753,8 +789,13 @@ async function* parseAnthropicSseStream(body: AsyncIterable<Uint8Array>, model:
753
789
  yield { delta: d.text }
754
790
  } else if (d?.type === 'input_json_delta' && typeof d.partial_json === 'string' && d.partial_json.length) {
755
791
  yield { toolCallDelta: { index: evt.index, argumentsDelta: d.partial_json } }
792
+ } else if (d?.type === 'thinking_delta' && typeof d.thinking === 'string' && d.thinking.length) {
793
+ // 1.21(R-TOKENHUB-1 / D-T1):thinking 文本增量捕获(原容错跳过 → 落链 + 工具环回传)
794
+ yield { thinkingDelta: d.thinking }
795
+ } else if (d?.type === 'signature_delta' && typeof d.signature === 'string' && d.signature.length) {
796
+ yield { thinkingSignatureDelta: d.signature }
756
797
  }
757
- // thinking_delta / citations_delta 等非 CAR 消费面:容错跳过
798
+ // citations_delta 等其余非 CAR 消费面:容错跳过
758
799
  } else if (type === 'message_start') {
759
800
  // 1.11-S1(D-33):input 侧采集(usage 嵌套在 message 下)
760
801
  const u = (evt.message as Record<string, unknown> | undefined)?.usage
@@ -76,6 +76,14 @@ export interface LlmChunk {
76
76
  error?: { code: string; message: string }
77
77
  /** 1.11-S1(D-33):每次请求最后一个 chunk 附带归一化用量;缺失 = provider 未回,禁补造 */
78
78
  usage?: LlmUsage
79
+ // —— 1.21(R-TOKENHUB-1 / D-T1)thinking 捕获加法——anthropic SSE thinking 面捕获;
80
+ // 禁改写(回传签名完整性 > 脱敏改写);缺失 = provider 未发 thinking,禁补造
81
+ /** thinking 块文本增量(content_block_delta.thinking_delta) */
82
+ thinkingDelta?: string
83
+ /** thinking 块签名增量(signature_delta——真 Anthropic thinking 块回传须携签名) */
84
+ thinkingSignatureDelta?: string
85
+ /** redacted_thinking 块 data 全文(content_block_start 单发;回传形态 {type:'redacted_thinking',data}) */
86
+ thinkingRedacted?: string
79
87
  }
80
88
 
81
89
  /** Provider 适配器(ACL,C-02):统一签名,消解 Provider 差异 */
@@ -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' // 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 不投影);
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 事件链投影逐字节不变);
15
15
  export type Actor = 'user' | 'model' | 'plugin' | 'runtime'
16
16
  export interface SessionEvent {
17
17
  seq: number
@@ -146,11 +146,41 @@ 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):thinking 投影——同 turn 内 thinking 事件附加到首个后续
150
+ // toolCall 消息(原始 provider assistant 消息 = [thinking, ...tool_use] 的重放形态);
151
+ // standalone(无后续 toolCall)/ 被 user·system 隔断 / 跨 turn 不投影(实证:普通两轮
152
+ // 历史不要求回传);assistant(text) 同 turn 不隔断(链序 thinking→assistant→toolCall);
153
+ // 无 thinking 事件投影逐字节不变(D-T5 兼容线,N1 快照自洽)。
154
+ let pendingThinking: { turnId: string; text: string; signature?: string; redacted?: boolean } | null = null
149
155
  for (const e of projected) {
156
+ if (pendingThinking && (e.turnId !== pendingThinking.turnId || e.kind === 'user' || e.kind === 'system')) pendingThinking = null
157
+ if (e.kind === 'thinking') {
158
+ const p = typeof e.payload === 'string' ? e.payload : ''
159
+ if (p.length || e.meta?.redacted === true) {
160
+ pendingThinking = {
161
+ turnId: e.turnId,
162
+ text: p,
163
+ ...(typeof e.meta?.signature === 'string' && e.meta.signature ? { signature: e.meta.signature } : {}),
164
+ ...(e.meta?.redacted === true ? { redacted: true } : {}),
165
+ }
166
+ }
167
+ continue // thinking 不单独成消息(无独立回传语义)
168
+ }
150
169
  if (e.kind === 'system') out.push({ role: 'system', content: e.payload })
151
170
  else if (e.kind === 'user') out.push({ role: 'user', content: e.payload })
152
171
  else if (e.kind === 'assistant') out.push({ role: 'assistant', content: e.payload })
153
- else if (e.kind === 'toolCall') out.push({ role: 'assistant', toolCall: e.payload })
172
+ else if (e.kind === 'toolCall') {
173
+ const msg: { role: string; [k: string]: unknown } = { role: 'assistant', toolCall: e.payload }
174
+ if (pendingThinking) {
175
+ msg.thinking = {
176
+ text: pendingThinking.text,
177
+ ...(pendingThinking.signature ? { signature: pendingThinking.signature } : {}),
178
+ ...(pendingThinking.redacted ? { redacted: true } : {}),
179
+ }
180
+ pendingThinking = null // 首 toolCall 消费即清——同 turn 多 toolCall = 同一原始消息,单块重放
181
+ }
182
+ out.push(msg)
183
+ }
154
184
  else if (e.kind === 'toolResult') {
155
185
  const id = (e.payload as { id?: unknown } | null)?.id
156
186
  if (typeof id === 'string' && lastSeqById.get(id) !== e.seq) continue // D-23:后续有同 id 最终结果,本条为授权中间记录
Binary file
@@ -1 +0,0 @@
1
- {"base64Signature":"MEYCIQCbYahnJCIA6I3JiR78DqF448xO747Dj5VSDZa+DjrhBwIhAOWOh2Ax0tWvzwsaV+OjU2P/tU5+zZ63vwIRgHQ+gSD4","cert":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUc1ekNDQm0yZ0F3SUJBZ0lVQm5MRi9MSmhtbDh6b2p3Q3NIM1Z3aGtzWGJnd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpZeE1UQTNNRGMwTXpBMFdoY05Nall4TVRBM01EYzFNekEwV2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUV2WkJzSDB0WlFzZkh0VzNhZUordVVKaVA2dWJKT0lVSlZnbisKRjFkaWNuK2xlQVo4Uk80UDFUVm5QemFMdlNVNkdaL3dZcGtZWjlPZ0RDOGt2bWk5SDZPQ0JZd3dnZ1dJTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWZCZ05WSFNNRUdEQVdnQlRmCjArblBWaVFSbHZtbzJPa29WYUxHTGhoa1B6QmlCZ05WSFJFQkFmOEVXREJXaGxSb2RIUndjem92TDJkcGRHaDEKWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHpMM0psYkdWaApjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakl3TGpBd09RWUtLd1lCQkFHRHZ6QUJBUVFyYUhSMGNITTZMeTkwCmIydGxiaTVoWTNScGIyNXpMbWRwZEdoMVluVnpaWEpqYjI1MFpXNTBMbU52YlRBVkJnb3JCZ0VFQVlPL01BRUMKQkFkeVpXeGxZWE5sTURZR0Npc0dBUVFCZzc4d0FRTUVLR1l6TUdVME5qaGxNRFEyTkRjNVl6QmxOMkUyWm1VdwpaVFE0WVdNeVpUVmhNbUUzTlRoaVpEa3dGUVlLS3dZQkJBR0R2ekFCQkFRSGNtVnNaV0Z6WlRBZ0Jnb3JCZ0VFCkFZTy9NQUVGQkJKc2NXTTJNalF2WTJGeUxYSjFiblJwYldVd0hnWUtLd1lCQkFHRHZ6QUJCZ1FRY21WbWN5OTAKWVdkekx6RXVNakF1TURBN0Jnb3JCZ0VFQVlPL01BRUlCQzBNSzJoMGRIQnpPaTh2ZEc5clpXNHVZV04wYVc5dQpjeTVuYVhSb2RXSjFjMlZ5WTI5dWRHVnVkQzVqYjIwd1pBWUtLd1lCQkFHRHZ6QUJDUVJXREZSb2RIUndjem92CkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHoKTDNKbGJHVmhjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakl3TGpBd09BWUtLd1lCQkFHRHZ6QUJDZ1FxRENobQpNekJsTkRZNFpUQTBOalEzT1dNd1pUZGhObVpsTUdVME9HRmpNbVUxWVRKaE56VTRZbVE1TUIwR0Npc0dBUVFCCmc3OHdBUXNFRHd3TloybDBhSFZpTFdodmMzUmxaREExQmdvckJnRUVBWU8vTUFFTUJDY01KV2gwZEhCek9pOHYKWjJsMGFIVmlMbU52YlM5c2NXTTJNalF2WTJGeUxYSjFiblJwYldVd09BWUtLd1lCQkFHRHZ6QUJEUVFxRENobQpNekJsTkRZNFpUQTBOalEzT1dNd1pUZGhObVpsTUdVME9HRmpNbVUxWVRKaE56VTRZbVE1TUNBR0Npc0dBUVFCCmc3OHdBUTRFRWd3UWNtVm1jeTkwWVdkekx6RXVNakF1TURBYUJnb3JCZ0VFQVlPL01BRVBCQXdNQ2pFek5qRXgKT1RJM01UUXdLUVlLS3dZQkJBR0R2ekFCRUFRYkRCbG9kSFJ3Y3pvdkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMApNQmdHQ2lzR0FRUUJnNzh3QVJFRUNnd0lOamt5TXpRMU5qUXdaQVlLS3dZQkJBR0R2ekFCRWdSV0RGUm9kSFJ3CmN6b3ZMMmRwZEdoMVlpNWpiMjB2YkhGak5qSTBMMk5oY2kxeWRXNTBhVzFsTHk1bmFYUm9kV0l2ZDI5eWEyWnMKYjNkekwzSmxiR1ZoYzJVdWVXMXNRSEpsWm5NdmRHRm5jeTh4TGpJd0xqQXdPQVlLS3dZQkJBR0R2ekFCRXdRcQpEQ2htTXpCbE5EWTRaVEEwTmpRM09XTXdaVGRoTm1abE1HVTBPR0ZqTW1VMVlUSmhOelU0WW1RNU1CY0dDaXNHCkFRUUJnNzh3QVJRRUNRd0hjbVZzWldGelpUQlpCZ29yQmdFRUFZTy9NQUVWQkVzTVNXaDBkSEJ6T2k4dloybDAKYUhWaUxtTnZiUzlzY1dNMk1qUXZZMkZ5TFhKMWJuUnBiV1V2WVdOMGFXOXVjeTl5ZFc1ekx6UXlNelV5TkRJeApPRFl4TDJGMGRHVnRjSFJ6THpFd0ZnWUtLd1lCQkFHRHZ6QUJGZ1FJREFad2RXSnNhV013VUFZS0t3WUJCQUdECnZ6QUJHQVJDREVCeVpYQnZPbXh4WXpZeU5FQTJPVEl6TkRVMk5DOWpZWEl0Y25WdWRHbHRaVUF4TXpZeE1Ua3kKTnpFME9uSmxaanB5WldaekwzUmhaM012TVM0eU1DNHdNSUdLQmdvckJnRUVBZFo1QWdRQ0JId0VlZ0I0QUhZQQozVDB3YXNiSEVUSmpHUjRjbVdjM0FxSktYcmplUEszL2g0cHlnQzhwN280QUFBR2h0UFlEeXdBQUJBTUFSekJGCkFpRUFrQlNnbEJvOThmMVZNMFMyUGhaUnlQWG0yZ1pFWUFSREZnY1JsenlObXprQ0lDUWc2NUgxL1diUjJHUEkKYmk0MlFDVGdhKzlsMDduYU1rTG8zTm5NbDN6eE1Bb0dDQ3FHU000OUJBTURBMmdBTUdVQ01RRGxjdWNsQjhvTwpzVE0reGJ0ems3Z0hEbXhOZ2gzbEEwaHk4NUFaWUdIZG5PSUI5N0JLMGtjcWFWMnhPSUg1SVRnQ01FQTNmU293CkppaUUxbXNVNUlRSGc5V2pDcTB5dkpoNmc1VW5LVDFwY1RFN3FNSCtIYVU0WE0wWHVYK3dHWWpjNGc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==","rekorBundle":{"SignedEntryTimestamp":"MEUCIQDB6YqP2KWVy4Fo7LbSrDV7nIEb4z/smHLueDq0QzfuQQIgc0BoLANFB0BT/TS7PHukqcqBjRM0g3tV9AA+Kbq5Jvo=","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI0NTQ2ZWJjYzA2Y2NkYjlmMzM3NTRkMmQ5OGVlNDEzYjI1OTM3ZjYxZTZiZDNmZTA2YTZjZmY2MGZhN2FlNTQxIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FWUNJUUNiWWFobkpDSUE2STNKaVI3OERxRjQ0OHhPNzQ3RGo1VlNEWmErRGpyaEJ3SWhBT1dPaDJBeDB0V3Z6d3NhVitPalUyUC90VTUrelo2M3Z3SVJnSFErZ1NENCIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVYzFla05EUW0weVowRjNTVUpCWjBsVlFtNU1SaTlNU21odGJEaDZiMnAzUTNOSU0xWjNhR3R6V0dKbmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFVUVROTlJHTXdUWHBCTUZkb1kwNU5hbGw0VFZSQk0wMUVZekZOZWtFd1YycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVYyV2tKelNEQjBXbEZ6WmtoMFZ6TmhaVW9yZFZWS2FWQTJkV0pLVDBsVlNsWm5iaXNLUmpGa2FXTnVLMnhsUVZvNFVrODBVREZVVm01UWVtRk1kbE5WTmtkYUwzZFpjR3RaV2psUFowUkRPR3QyYldrNVNEWlBRMEpaZDNkbloxZEpUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFtbENaMDVXU0ZKRlFrRm1PRVZYUkVKWGFHeFNiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmlTRVpxVG1wSk1Fd3lUbWhqYVRGNVpGYzFNR0ZYTVd4TWVUVnVZVmhTYjJSWFNYWmtNamw1WVRKYWMySXpaSHBNTTBwc1lrZFdhQXBqTWxWMVpWY3hjMUZJU214YWJrMTJaRWRHYm1ONU9IaE1ha2wzVEdwQmQwOVJXVXRMZDFsQ1FrRkhSSFo2UVVKQlVWRnlZVWhTTUdOSVRUWk1lVGt3Q21JeWRHeGlhVFZvV1ROU2NHSXlOWHBNYldSd1pFZG9NVmx1Vm5wYVdFcHFZakkxTUZwWE5UQk1iVTUyWWxSQlZrSm5iM0pDWjBWRlFWbFBMMDFCUlVNS1FrRmtlVnBYZUd4WldFNXNUVVJaUjBOcGMwZEJVVkZDWnpjNGQwRlJUVVZMUjFsNlRVZFZNRTVxYUd4TlJGRXlUa1JqTlZsNlFteE9Na1V5V20xVmR3cGFWRkUwV1ZkTmVWcFVWbWhOYlVVelRsUm9hVnBFYTNkR1VWbExTM2RaUWtKQlIwUjJla0ZDUWtGUlNHTnRWbk5hVjBaNldsUkJaMEpuYjNKQ1owVkZDa0ZaVHk5TlFVVkdRa0pLYzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMGhuV1V0TGQxbENRa0ZIUkhaNlFVSkNaMUZSWTIxV2JXTjVPVEFLV1Zka2VreDZSWFZOYWtGMVRVUkJOMEpuYjNKQ1owVkZRVmxQTDAxQlJVbENRekJOU3pKb01HUklRbnBQYVRoMlpFYzVjbHBYTkhWWlYwNHdZVmM1ZFFwamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcVlqSXdkMXBCV1V0TGQxbENRa0ZIUkhaNlFVSkRVVkpYUkVaU2IyUklVbmRqZW05MkNrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUV3eVRtaGphVEY1WkZjMU1HRlhNV3hNZVRWdVlWaFNiMlJYU1haa01qbDVZVEphYzJJelpIb0tURE5LYkdKSFZtaGpNbFYxWlZjeGMxRklTbXhhYmsxMlpFZEdibU41T0hoTWFrbDNUR3BCZDA5QldVdExkMWxDUWtGSFJIWjZRVUpEWjFGeFJFTm9iUXBOZWtKc1RrUlpORnBVUVRCT2FsRXpUMWROZDFwVVpHaE9iVnBzVFVkVk1FOUhSbXBOYlZVeFdWUkthRTU2VlRSWmJWRTFUVUl3UjBOcGMwZEJVVkZDQ21jM09IZEJVWE5GUkhkM1Rsb3liREJoU0ZacFRGZG9kbU16VW14YVJFRXhRbWR2Y2tKblJVVkJXVTh2VFVGRlRVSkRZMDFLVjJnd1pFaENlazlwT0hZS1dqSnNNR0ZJVm1sTWJVNTJZbE01YzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMDlCV1V0TGQxbENRa0ZIUkhaNlFVSkVVVkZ4UkVOb2JRcE5la0pzVGtSWk5GcFVRVEJPYWxFelQxZE5kMXBVWkdoT2JWcHNUVWRWTUU5SFJtcE5iVlV4V1ZSS2FFNTZWVFJaYlZFMVRVTkJSME5wYzBkQlVWRkNDbWMzT0hkQlVUUkZSV2QzVVdOdFZtMWplVGt3V1Zka2VreDZSWFZOYWtGMVRVUkJZVUpuYjNKQ1owVkZRVmxQTDAxQlJWQkNRWGROUTJwRmVrNXFSWGdLVDFSSk0wMVVVWGRMVVZsTFMzZFpRa0pCUjBSMmVrRkNSVUZSWWtSQ2JHOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUFwTlFtZEhRMmx6UjBGUlVVSm5OemgzUVZKRlJVTm5kMGxPYW10NVRYcFJNVTVxVVhkYVFWbExTM2RaUWtKQlIwUjJla0ZDUldkU1YwUkdVbTlrU0ZKM0NtTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJZa2hHYWs1cVNUQk1NazVvWTJreGVXUlhOVEJoVnpGc1RIazFibUZZVW05a1YwbDJaREk1ZVdFeVduTUtZak5rZWt3elNteGlSMVpvWXpKVmRXVlhNWE5SU0Vwc1dtNU5kbVJIUm01amVUaDRUR3BKZDB4cVFYZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JYZFJjUXBFUTJodFRYcENiRTVFV1RSYVZFRXdUbXBSTTA5WFRYZGFWR1JvVG0xYWJFMUhWVEJQUjBacVRXMVZNVmxVU21oT2VsVTBXVzFSTlUxQ1kwZERhWE5IQ2tGUlVVSm5OemgzUVZKUlJVTlJkMGhqYlZaeldsZEdlbHBVUWxwQ1oyOXlRbWRGUlVGWlR5OU5RVVZXUWtWelRWTlhhREJrU0VKNlQyazRkbG95YkRBS1lVaFdhVXh0VG5aaVV6bHpZMWROTWsxcVVYWlpNa1o1VEZoS01XSnVVbkJpVjFWMldWZE9NR0ZYT1hWamVUbDVaRmMxZWt4NlVYbE5lbFY1VGtSSmVBcFBSRmw0VERKR01HUkhWblJqU0ZKNlRIcEZkMFpuV1V0TGQxbENRa0ZIUkhaNlFVSkdaMUZKUkVGYWQyUlhTbk5oVjAxM1ZVRlpTMHQzV1VKQ1FVZEVDblo2UVVKSFFWSkRSRVZDZVZwWVFuWlBiWGg0V1hwWmVVNUZRVEpQVkVsNlRrUlZNazVET1dwWldFbDBZMjVXZFdSSGJIUmFWVUY0VFhwWmVFMVVhM2tLVG5wRk1FOXVTbXhhYW5CNVdsZGFla3d6VW1oYU0wMTJUVk0wZVUxRE5IZE5TVWRMUW1kdmNrSm5SVVZCWkZvMVFXZFJRMEpJZDBWbFowSTBRVWhaUVFvelZEQjNZWE5pU0VWVVNtcEhValJqYlZkak0wRnhTa3RZY21wbFVFc3pMMmcwY0hsblF6aHdOMjgwUVVGQlIyaDBVRmxFZVhkQlFVSkJUVUZTZWtKR0NrRnBSVUZyUWxObmJFSnZPVGhtTVZaTk1GTXlVR2hhVW5sUVdHMHlaMXBGV1VGU1JFWm5ZMUpzZW5sT2JYcHJRMGxEVVdjMk5VZ3hMMWRpVWpKSFVFa0tZbWswTWxGRFZHZGhLemxzTURkdVlVMXJURzh6VG01TmJETjZlRTFCYjBkRFEzRkhVMDAwT1VKQlRVUkJNbWRCVFVkVlEwMVJSR3hqZFdOc1FqaHZUd3B6VkUwcmVHSjBlbXMzWjBoRWJYaE9aMmd6YkVFd2FIazROVUZhV1VkSVpHNVBTVUk1TjBKTE1HdGpjV0ZXTW5oUFNVZzFTVlJuUTAxRlFUTm1VMjkzQ2twcGFVVXhiWE5WTlVsUlNHYzVWMnBEY1RCNWRrcG9ObWMxVlc1TFZERndZMVJGTjNGTlNDdElZVlUwV0Uwd1dIVllLM2RIV1dwak5HYzlQUW90TFMwdExVVk9SQ0JEUlZKVVNVWkpRMEZVUlMwdExTMHRDZz09In19fX0=","integratedTime":1794037384,"logIndex":3732640096,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}