@lqc123qwe/car-runtime 1.20.0 → 1.21.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 CHANGED
@@ -1 +1 @@
1
- 4546ebcc06ccdb9f33754d2d98ee413b25937f61e6bd3fe06a6cff60fa7ae541 car-runtime-1.20.0.tgz
1
+ 8d9bd1fa4d447b255ae668a51bb47338bde8e35ad8ccac97ac72d2c893664115 car-runtime-1.21.0.tgz
Binary file
@@ -0,0 +1 @@
1
+ {"base64Signature":"MEQCIEr84YFIo6UQdCBqDYqzEn5iofitA9Wtuxx9AqUbuNGZAiBdNvJTODyumJazgvvJunU8HC/jVNGcHjUM9u7quHIyOg==","cert":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUc1ekNDQm0yZ0F3SUJBZ0lVYWV0eWY3L29XeUE3RlVhb1RuV0k0QjYzVU1Vd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpZeE1URTBNRE16TlRNM1doY05Nall4TVRFME1ETTBOVE0zV2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVpdlNPYnBEY1ZHZjd3Vm0yTWhUajlqbTdmQ0Z2ZGFZeGYrVTcKS2ljbzJLbUdNdWRXRUk4KzJuYmxtQmN6Q0tYNWoyWGMrNDRHTTk0bW5EUkF3OTdZT0tPQ0JZd3dnZ1dJTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWZCZ05WSFNNRUdEQVdnQlRmCjArblBWaVFSbHZtbzJPa29WYUxHTGhoa1B6QmlCZ05WSFJFQkFmOEVXREJXaGxSb2RIUndjem92TDJkcGRHaDEKWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHpMM0psYkdWaApjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakl4TGpBd09RWUtLd1lCQkFHRHZ6QUJBUVFyYUhSMGNITTZMeTkwCmIydGxiaTVoWTNScGIyNXpMbWRwZEdoMVluVnpaWEpqYjI1MFpXNTBMbU52YlRBVkJnb3JCZ0VFQVlPL01BRUMKQkFkeVpXeGxZWE5sTURZR0Npc0dBUVFCZzc4d0FRTUVLRFZsWW1Fd1pHTXpNRGhpT1dWak1qSTVNR1l4Tm1GbApabUV5TVdNNVlUVXlPR1UzTkRReU9EQXdGUVlLS3dZQkJBR0R2ekFCQkFRSGNtVnNaV0Z6WlRBZ0Jnb3JCZ0VFCkFZTy9NQUVGQkJKc2NXTTJNalF2WTJGeUxYSjFiblJwYldVd0hnWUtLd1lCQkFHRHZ6QUJCZ1FRY21WbWN5OTAKWVdkekx6RXVNakV1TURBN0Jnb3JCZ0VFQVlPL01BRUlCQzBNSzJoMGRIQnpPaTh2ZEc5clpXNHVZV04wYVc5dQpjeTVuYVhSb2RXSjFjMlZ5WTI5dWRHVnVkQzVqYjIwd1pBWUtLd1lCQkFHRHZ6QUJDUVJXREZSb2RIUndjem92CkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHoKTDNKbGJHVmhjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakl4TGpBd09BWUtLd1lCQkFHRHZ6QUJDZ1FxRENnMQpaV0poTUdSak16QTRZamxsWXpJeU9UQm1NVFpoWldaaE1qRmpPV0UxTWpobE56UTBNamd3TUIwR0Npc0dBUVFCCmc3OHdBUXNFRHd3TloybDBhSFZpTFdodmMzUmxaREExQmdvckJnRUVBWU8vTUFFTUJDY01KV2gwZEhCek9pOHYKWjJsMGFIVmlMbU52YlM5c2NXTTJNalF2WTJGeUxYSjFiblJwYldVd09BWUtLd1lCQkFHRHZ6QUJEUVFxRENnMQpaV0poTUdSak16QTRZamxsWXpJeU9UQm1NVFpoWldaaE1qRmpPV0UxTWpobE56UTBNamd3TUNBR0Npc0dBUVFCCmc3OHdBUTRFRWd3UWNtVm1jeTkwWVdkekx6RXVNakV1TURBYUJnb3JCZ0VFQVlPL01BRVBCQXdNQ2pFek5qRXgKT1RJM01UUXdLUVlLS3dZQkJBR0R2ekFCRUFRYkRCbG9kSFJ3Y3pvdkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMApNQmdHQ2lzR0FRUUJnNzh3QVJFRUNnd0lOamt5TXpRMU5qUXdaQVlLS3dZQkJBR0R2ekFCRWdSV0RGUm9kSFJ3CmN6b3ZMMmRwZEdoMVlpNWpiMjB2YkhGak5qSTBMMk5oY2kxeWRXNTBhVzFsTHk1bmFYUm9kV0l2ZDI5eWEyWnMKYjNkekwzSmxiR1ZoYzJVdWVXMXNRSEpsWm5NdmRHRm5jeTh4TGpJeExqQXdPQVlLS3dZQkJBR0R2ekFCRXdRcQpEQ2cxWldKaE1HUmpNekE0WWpsbFl6SXlPVEJtTVRaaFpXWmhNakZqT1dFMU1qaGxOelEwTWpnd01CY0dDaXNHCkFRUUJnNzh3QVJRRUNRd0hjbVZzWldGelpUQlpCZ29yQmdFRUFZTy9NQUVWQkVzTVNXaDBkSEJ6T2k4dloybDAKYUhWaUxtTnZiUzlzY1dNMk1qUXZZMkZ5TFhKMWJuUnBiV1V2WVdOMGFXOXVjeTl5ZFc1ekx6UXpOVFV5TkRFMwpPVFE0TDJGMGRHVnRjSFJ6THpFd0ZnWUtLd1lCQkFHRHZ6QUJGZ1FJREFad2RXSnNhV013VUFZS0t3WUJCQUdECnZ6QUJHQVJDREVCeVpYQnZPbXh4WXpZeU5FQTJPVEl6TkRVMk5DOWpZWEl0Y25WdWRHbHRaVUF4TXpZeE1Ua3kKTnpFME9uSmxaanB5WldaekwzUmhaM012TVM0eU1TNHdNSUdLQmdvckJnRUVBZFo1QWdRQ0JId0VlZ0I0QUhZQQozVDB3YXNiSEVUSmpHUjRjbVdjM0FxSktYcmplUEszL2g0cHlnQzhwN280QUFBR2gyQi85K0FBQUJBTUFSekJGCkFpRUE2QlpwRnVTK3Y5WVVqZXNxWk02WGFyTXcydDVNbmUxaldSOStkYXVJQ0dJQ0lBSWhPL2h4b0NUQitCdlgKbkVRRmlmNzZvanVtbHlLeWYvckF3V1Rzc3VPMk1Bb0dDQ3FHU000OUJBTURBMmdBTUdVQ01HK2R4dS9BV2tMOQo4QUtiSlhXSXYzMFlGNjk5UGp5cWFDcVhTSUllY25VRzdPZHFXTzRYK2dwb1RNVEc1bXRJcVFJeEFOT0xZRGFZCndTNUhoU0RNcXVLU1M2ODRjL1U2bTlLc0syWmN2RGFrRlZOL1BiZHhCc1Y5cE1ySzZFeEVMblpEb3c9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==","rekorBundle":{"SignedEntryTimestamp":"MEUCIB04W7cJqnNa2clZD6iGQQPWdN+4NyyrSfjpxuDJ5cWIAiEAlr/UsHUN8IVr0S/5WeyxAYNKIpQUnHcPyToMjqgz+HA=","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI4ZDliZDFmYTRkNDQ3YjI1NWFlNjY4YTUxYmI0NzMzOGJkZThlMzVhZDhjY2FjOTdhYzcyZDJjODkzNjY0MTE1In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FUUNJRXI4NFlGSW82VVFkQ0JxRFlxekVuNWlvZml0QTlXdHV4eDlBcVVidU5HWkFpQmROdkpUT0R5dW1KYXpndnZKdW5VOEhDL2pWTkdjSGpVTTl1N3F1SEl5T2c9PSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVYzFla05EUW0weVowRjNTVUpCWjBsVllXVjBlV1kzTDI5WGVVRTNSbFZoYjFSdVYwazBRall6VlUxVmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFVUlRCTlJFMTZUbFJOTTFkb1kwNU5hbGw0VFZSRk1FMUVUVEJPVkUwelYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZwZGxOUFluQkVZMVpIWmpkM1ZtMHlUV2hVYWpscWJUZG1RMFoyWkdGWmVHWXJWVGNLUzJsamJ6SkxiVWROZFdSWFJVazRLekp1WW14dFFtTjZRMHRZTldveVdHTXJORFJIVFRrMGJXNUVVa0YzT1RkWlQwdFBRMEpaZDNkbloxZEpUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFtbENaMDVXU0ZKRlFrRm1PRVZYUkVKWGFHeFNiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmlTRVpxVG1wSk1Fd3lUbWhqYVRGNVpGYzFNR0ZYTVd4TWVUVnVZVmhTYjJSWFNYWmtNamw1WVRKYWMySXpaSHBNTTBwc1lrZFdhQXBqTWxWMVpWY3hjMUZJU214YWJrMTJaRWRHYm1ONU9IaE1ha2w0VEdwQmQwOVJXVXRMZDFsQ1FrRkhSSFo2UVVKQlVWRnlZVWhTTUdOSVRUWk1lVGt3Q21JeWRHeGlhVFZvV1ROU2NHSXlOWHBNYldSd1pFZG9NVmx1Vm5wYVdFcHFZakkxTUZwWE5UQk1iVTUyWWxSQlZrSm5iM0pDWjBWRlFWbFBMMDFCUlVNS1FrRmtlVnBYZUd4WldFNXNUVVJaUjBOcGMwZEJVVkZDWnpjNGQwRlJUVVZMUkZac1dXMUZkMXBIVFhwTlJHaHBUMWRXYWsxcVNUVk5SMWw0VG0xR2JBcGFiVVY1VFZkTk5WbFVWWGxQUjFVelRrUlJlVTlFUVhkR1VWbExTM2RaUWtKQlIwUjJla0ZDUWtGUlNHTnRWbk5hVjBaNldsUkJaMEpuYjNKQ1owVkZDa0ZaVHk5TlFVVkdRa0pLYzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMGhuV1V0TGQxbENRa0ZIUkhaNlFVSkNaMUZSWTIxV2JXTjVPVEFLV1Zka2VreDZSWFZOYWtWMVRVUkJOMEpuYjNKQ1owVkZRVmxQTDAxQlJVbENRekJOU3pKb01HUklRbnBQYVRoMlpFYzVjbHBYTkhWWlYwNHdZVmM1ZFFwamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcVlqSXdkMXBCV1V0TGQxbENRa0ZIUkhaNlFVSkRVVkpYUkVaU2IyUklVbmRqZW05MkNrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUV3eVRtaGphVEY1WkZjMU1HRlhNV3hNZVRWdVlWaFNiMlJYU1haa01qbDVZVEphYzJJelpIb0tURE5LYkdKSFZtaGpNbFYxWlZjeGMxRklTbXhhYmsxMlpFZEdibU41T0hoTWFrbDRUR3BCZDA5QldVdExkMWxDUWtGSFJIWjZRVUpEWjFGeFJFTm5NUXBhVjBwb1RVZFNhazE2UVRSWmFteHNXWHBKZVU5VVFtMU5WRnBvV2xkYWFFMXFSbXBQVjBVeFRXcG9iRTU2VVRCTmFtZDNUVUl3UjBOcGMwZEJVVkZDQ21jM09IZEJVWE5GUkhkM1Rsb3liREJoU0ZacFRGZG9kbU16VW14YVJFRXhRbWR2Y2tKblJVVkJXVTh2VFVGRlRVSkRZMDFLVjJnd1pFaENlazlwT0hZS1dqSnNNR0ZJVm1sTWJVNTJZbE01YzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMDlCV1V0TGQxbENRa0ZIUkhaNlFVSkVVVkZ4UkVObk1RcGFWMHBvVFVkU2FrMTZRVFJaYW14c1dYcEplVTlVUW0xTlZGcG9XbGRhYUUxcVJtcFBWMFV4VFdwb2JFNTZVVEJOYW1kM1RVTkJSME5wYzBkQlVWRkNDbWMzT0hkQlVUUkZSV2QzVVdOdFZtMWplVGt3V1Zka2VreDZSWFZOYWtWMVRVUkJZVUpuYjNKQ1owVkZRVmxQTDAxQlJWQkNRWGROUTJwRmVrNXFSWGdLVDFSSk0wMVVVWGRMVVZsTFMzZFpRa0pCUjBSMmVrRkNSVUZSWWtSQ2JHOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUFwTlFtZEhRMmx6UjBGUlVVSm5OemgzUVZKRlJVTm5kMGxPYW10NVRYcFJNVTVxVVhkYVFWbExTM2RaUWtKQlIwUjJla0ZDUldkU1YwUkdVbTlrU0ZKM0NtTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJZa2hHYWs1cVNUQk1NazVvWTJreGVXUlhOVEJoVnpGc1RIazFibUZZVW05a1YwbDJaREk1ZVdFeVduTUtZak5rZWt3elNteGlSMVpvWXpKVmRXVlhNWE5SU0Vwc1dtNU5kbVJIUm01amVUaDRUR3BKZUV4cVFYZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JYZFJjUXBFUTJjeFdsZEthRTFIVW1wTmVrRTBXV3BzYkZsNlNYbFBWRUp0VFZSYWFGcFhXbWhOYWtacVQxZEZNVTFxYUd4T2VsRXdUV3BuZDAxQ1kwZERhWE5IQ2tGUlVVSm5OemgzUVZKUlJVTlJkMGhqYlZaeldsZEdlbHBVUWxwQ1oyOXlRbWRGUlVGWlR5OU5RVVZXUWtWelRWTlhhREJrU0VKNlQyazRkbG95YkRBS1lVaFdhVXh0VG5aaVV6bHpZMWROTWsxcVVYWlpNa1o1VEZoS01XSnVVbkJpVjFWMldWZE9NR0ZYT1hWamVUbDVaRmMxZWt4NlVYcE9WRlY1VGtSRk13cFBWRkUwVERKR01HUkhWblJqU0ZKNlRIcEZkMFpuV1V0TGQxbENRa0ZIUkhaNlFVSkdaMUZKUkVGYWQyUlhTbk5oVjAxM1ZVRlpTMHQzV1VKQ1FVZEVDblo2UVVKSFFWSkRSRVZDZVZwWVFuWlBiWGg0V1hwWmVVNUZRVEpQVkVsNlRrUlZNazVET1dwWldFbDBZMjVXZFdSSGJIUmFWVUY0VFhwWmVFMVVhM2tLVG5wRk1FOXVTbXhhYW5CNVdsZGFla3d6VW1oYU0wMTJUVk0wZVUxVE5IZE5TVWRMUW1kdmNrSm5SVVZCWkZvMVFXZFJRMEpJZDBWbFowSTBRVWhaUVFvelZEQjNZWE5pU0VWVVNtcEhValJqYlZkak0wRnhTa3RZY21wbFVFc3pMMmcwY0hsblF6aHdOMjgwUVVGQlIyZ3lRaTg1SzBGQlFVSkJUVUZTZWtKR0NrRnBSVUUyUWxwd1JuVlRLM1k1V1ZWcVpYTnhXazAyV0dGeVRYY3lkRFZOYm1VeGFsZFNPU3RrWVhWSlEwZEpRMGxCU1doUEwyaDRiME5VUWl0Q2RsZ0tia1ZSUm1sbU56WnZhblZ0YkhsTGVXWXZja0YzVjFSemMzVlBNazFCYjBkRFEzRkhVMDAwT1VKQlRVUkJNbWRCVFVkVlEwMUhLMlI0ZFM5QlYydE1PUW80UVV0aVNsaFhTWFl6TUZsR05qazVVR3A1Y1dGRGNWaFRTVWxsWTI1VlJ6ZFBaSEZYVHpSWUsyZHdiMVJOVkVjMWJYUkpjVkZKZUVGT1QweFpSR0ZaQ25kVE5VaG9VMFJOY1hWTFUxTTJPRFJqTDFVMmJUbExjMHN5V21OMlJHRnJSbFpPTDFCaVpIaENjMVk1Y0UxeVN6WkZlRVZNYmxwRWIzYzlQUW90TFMwdExVVk9SQ0JEUlZKVVNVWkpRMEZVUlMwdExTMHRDZz09In19fX0=","integratedTime":1794627338,"logIndex":3868826566,"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.0.tgz(436516 bytes,树哈希锚定)","ts":1794627336025}
2
+ {"stage":"sha256sums","detail":"SHA256SUMS 8d9bd1fa4d447b25…(裸字节复核通过)","ts":1794627336026}
3
+ {"stage":"sbom","detail":"55 个组件(运行时依赖 0 项)","ts":1794627336033}
4
+ {"stage":"cosign-keyless","detail":"signed car-runtime-1.21.0.tgz (keyless OIDC + Rekor)","ts":1794627338842}
@@ -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;
@@ -624,7 +624,17 @@ function toAnthropic(req, apiKey, cache) {
624
624
  flushToolResults();
625
625
  if (m.role === 'assistant' && m.content != null && typeof m.content === 'object' && 'toolCall' in m.content) {
626
626
  const tc = m.content.toolCall;
627
- turns.push({ role: 'assistant', content: [{ type: 'tool_use', id: tc.id, name: tc.tool, input: tc.args ?? {} }] });
627
+ // 1.21(R-TOKENHUB-1 / D-T4):工具环回传——投影层附加的 thinking(同 turn 原始 assistant
628
+ // 消息的 thinking 块)前置重放(Anthropic 规范:thinking 须位于同消息 text/tool_use 之前;
629
+ // tokenhub 等网关对缺回传 400——R-TOKENHUB-1 实证)。无 thinking = 形态与 1.20 逐字节一致
630
+ // (D-T5 兼容线,golden 不动)。
631
+ const th = m.content.thinking;
632
+ const thinkingBlock = th?.text?.length
633
+ ? th.redacted
634
+ ? { type: 'redacted_thinking', data: th.text }
635
+ : { type: 'thinking', thinking: th.text, ...(th.signature ? { signature: th.signature } : {}) }
636
+ : undefined;
637
+ turns.push({ role: 'assistant', content: [...(thinkingBlock ? [thinkingBlock] : []), { type: 'tool_use', id: tc.id, name: tc.tool, input: tc.args ?? {} }] });
628
638
  }
629
639
  else {
630
640
  turns.push({ role: m.role, content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content) });
@@ -706,6 +716,10 @@ async function* parseAnthropicSseStream(body, model, adapterId) {
706
716
  if (block?.type === 'tool_use') {
707
717
  yield { toolCallDelta: { index: evt.index, id: block.id, name: block.name } };
708
718
  }
719
+ 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})
721
+ yield { thinkingRedacted: block.data };
722
+ }
709
723
  }
710
724
  else if (type === 'content_block_delta') {
711
725
  const d = evt.delta;
@@ -715,7 +729,14 @@ async function* parseAnthropicSseStream(body, model, adapterId) {
715
729
  else if (d?.type === 'input_json_delta' && typeof d.partial_json === 'string' && d.partial_json.length) {
716
730
  yield { toolCallDelta: { index: evt.index, argumentsDelta: d.partial_json } };
717
731
  }
718
- // thinking_delta / citations_delta 等非 CAR 消费面:容错跳过
732
+ else if (d?.type === 'thinking_delta' && typeof d.thinking === 'string' && d.thinking.length) {
733
+ // 1.21(R-TOKENHUB-1 / D-T1):thinking 文本增量捕获(原容错跳过 → 落链 + 工具环回传)
734
+ yield { thinkingDelta: d.thinking };
735
+ }
736
+ else if (d?.type === 'signature_delta' && typeof d.signature === 'string' && d.signature.length) {
737
+ yield { thinkingSignatureDelta: d.signature };
738
+ }
739
+ // citations_delta 等其余非 CAR 消费面:容错跳过
719
740
  }
720
741
  else if (type === 'message_start') {
721
742
  // 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.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": "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": "71bf8926b162fc8ae05343953405a225b5630ba85196dc71727524de18196cc3"
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": "a6ae52801faedf9b64c49d0be8c5a7c22204697bf22d78c7253494bf28677b9d"
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.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",
@@ -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
@@ -673,7 +673,17 @@ function toAnthropic(req: LlmRequest, apiKey: string, cache: { rolling: boolean;
673
673
  flushToolResults()
674
674
  if (m.role === 'assistant' && m.content != null && typeof m.content === 'object' && 'toolCall' in (m.content as object)) {
675
675
  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 ?? {} }] })
676
+ // 1.21(R-TOKENHUB-1 / D-T4):工具环回传——投影层附加的 thinking(同 turn 原始 assistant
677
+ // 消息的 thinking 块)前置重放(Anthropic 规范:thinking 须位于同消息 text/tool_use 之前;
678
+ // tokenhub 等网关对缺回传 400——R-TOKENHUB-1 实证)。无 thinking = 形态与 1.20 逐字节一致
679
+ // (D-T5 兼容线,golden 不动)。
680
+ const th = (m.content as { thinking?: { text?: string; signature?: string; redacted?: boolean } }).thinking
681
+ const thinkingBlock = th?.text?.length
682
+ ? th.redacted
683
+ ? { type: 'redacted_thinking', data: th.text }
684
+ : { type: 'thinking', thinking: th.text, ...(th.signature ? { signature: th.signature } : {}) }
685
+ : undefined
686
+ turns.push({ role: 'assistant', content: [...(thinkingBlock ? [thinkingBlock] : []), { type: 'tool_use', id: tc.id, name: tc.tool, input: tc.args ?? {} }] })
677
687
  } else {
678
688
  turns.push({ role: m.role, content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content) })
679
689
  }
@@ -746,6 +756,9 @@ async function* parseAnthropicSseStream(body: AsyncIterable<Uint8Array>, model:
746
756
  const block = evt.content_block
747
757
  if (block?.type === 'tool_use') {
748
758
  yield { toolCallDelta: { index: evt.index, id: block.id, name: block.name } }
759
+ } 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})
761
+ yield { thinkingRedacted: block.data }
749
762
  }
750
763
  } else if (type === 'content_block_delta') {
751
764
  const d = evt.delta
@@ -753,8 +766,13 @@ async function* parseAnthropicSseStream(body: AsyncIterable<Uint8Array>, model:
753
766
  yield { delta: d.text }
754
767
  } else if (d?.type === 'input_json_delta' && typeof d.partial_json === 'string' && d.partial_json.length) {
755
768
  yield { toolCallDelta: { index: evt.index, argumentsDelta: d.partial_json } }
769
+ } else if (d?.type === 'thinking_delta' && typeof d.thinking === 'string' && d.thinking.length) {
770
+ // 1.21(R-TOKENHUB-1 / D-T1):thinking 文本增量捕获(原容错跳过 → 落链 + 工具环回传)
771
+ yield { thinkingDelta: d.thinking }
772
+ } else if (d?.type === 'signature_delta' && typeof d.signature === 'string' && d.signature.length) {
773
+ yield { thinkingSignatureDelta: d.signature }
756
774
  }
757
- // thinking_delta / citations_delta 等非 CAR 消费面:容错跳过
775
+ // citations_delta 等其余非 CAR 消费面:容错跳过
758
776
  } else if (type === 'message_start') {
759
777
  // 1.11-S1(D-33):input 侧采集(usage 嵌套在 message 下)
760
778
  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"}}}