@lqc123qwe/car-runtime 1.23.0 → 1.24.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.24.0.tgz +0 -0
- package/dist/car-runtime-1.24.0.tgz.sig.bundle +1 -0
- package/dist/loop/recover.js +4 -0
- package/dist/loop/settlement.d.ts +39 -0
- package/dist/loop/settlement.js +76 -0
- package/dist/loop/stop.js +7 -2
- package/dist/release-audit.jsonl +4 -4
- package/dist/sbom.json +10 -5
- package/dist/session/log.js +5 -0
- package/package.json +1 -1
- package/src/loop/recover.ts +4 -0
- package/src/loop/settlement.ts +107 -0
- package/src/loop/stop.ts +7 -2
- package/src/session/log.ts +5 -1
- package/dist/car-runtime-1.23.0.tgz +0 -0
- package/dist/car-runtime-1.23.0.tgz.sig.bundle +0 -1
package/dist/SHA256SUMS
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
aa80b65782ac20a0d01289545992a9f89c745fd342eeb5c2c4f41bd84e0ff920 car-runtime-1.24.0.tgz
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"base64Signature":"MEYCIQDiF46jsQyUu5MC5YYxG9m3lolFgWHYy/ZYkf4k3oG0DgIhAJVfUldLgNqb/5Ie8OhzH11EUeulKuNL1ZHufvANg8/R","cert":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUc2RENDQm02Z0F3SUJBZ0lVRVhTRjZBSjNXOS9vK2x4V2xzbjVoUTFpcThZd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpZeE1URTFNRGsxT0RNeldoY05Nall4TVRFMU1UQXdPRE16V2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVuZUJGeFprRHRCWDBFVHNsNXlnMEg1Y1BJMGJRYTA1QW5RSkwKWHdTRTlPMUtyWmpIYjc3UnN1TTdCT3lNWEliTHoxbDcyR2pZdTRsM0I2bm9HNS9YZEtPQ0JZMHdnZ1dKTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWZCZ05WSFNNRUdEQVdnQlRmCjArblBWaVFSbHZtbzJPa29WYUxHTGhoa1B6QmlCZ05WSFJFQkFmOEVXREJXaGxSb2RIUndjem92TDJkcGRHaDEKWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHpMM0psYkdWaApjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakkwTGpBd09RWUtLd1lCQkFHRHZ6QUJBUVFyYUhSMGNITTZMeTkwCmIydGxiaTVoWTNScGIyNXpMbWRwZEdoMVluVnpaWEpqYjI1MFpXNTBMbU52YlRBVkJnb3JCZ0VFQVlPL01BRUMKQkFkeVpXeGxZWE5sTURZR0Npc0dBUVFCZzc4d0FRTUVLR1ZqT1RKak1XRm1ZbVpsTldKbE16ZGlZVEEyWW1ReQpOVGhrWWpGbE1qRTNZVFptWmpaaU4yTXdGUVlLS3dZQkJBR0R2ekFCQkFRSGNtVnNaV0Z6WlRBZ0Jnb3JCZ0VFCkFZTy9NQUVGQkJKc2NXTTJNalF2WTJGeUxYSjFiblJwYldVd0hnWUtLd1lCQkFHRHZ6QUJCZ1FRY21WbWN5OTAKWVdkekx6RXVNalF1TURBN0Jnb3JCZ0VFQVlPL01BRUlCQzBNSzJoMGRIQnpPaTh2ZEc5clpXNHVZV04wYVc5dQpjeTVuYVhSb2RXSjFjMlZ5WTI5dWRHVnVkQzVqYjIwd1pBWUtLd1lCQkFHRHZ6QUJDUVJXREZSb2RIUndjem92CkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHoKTDNKbGJHVmhjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakkwTGpBd09BWUtLd1lCQkFHRHZ6QUJDZ1FxRENobApZemt5WXpGaFptSm1aVFZpWlRNM1ltRXdObUprTWpVNFpHSXhaVEl4TjJFMlptWTJZamRqTUIwR0Npc0dBUVFCCmc3OHdBUXNFRHd3TloybDBhSFZpTFdodmMzUmxaREExQmdvckJnRUVBWU8vTUFFTUJDY01KV2gwZEhCek9pOHYKWjJsMGFIVmlMbU52YlM5c2NXTTJNalF2WTJGeUxYSjFiblJwYldVd09BWUtLd1lCQkFHRHZ6QUJEUVFxRENobApZemt5WXpGaFptSm1aVFZpWlRNM1ltRXdObUprTWpVNFpHSXhaVEl4TjJFMlptWTJZamRqTUNBR0Npc0dBUVFCCmc3OHdBUTRFRWd3UWNtVm1jeTkwWVdkekx6RXVNalF1TURBYUJnb3JCZ0VFQVlPL01BRVBCQXdNQ2pFek5qRXgKT1RJM01UUXdLUVlLS3dZQkJBR0R2ekFCRUFRYkRCbG9kSFJ3Y3pvdkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMApNQmdHQ2lzR0FRUUJnNzh3QVJFRUNnd0lOamt5TXpRMU5qUXdaQVlLS3dZQkJBR0R2ekFCRWdSV0RGUm9kSFJ3CmN6b3ZMMmRwZEdoMVlpNWpiMjB2YkhGak5qSTBMMk5oY2kxeWRXNTBhVzFsTHk1bmFYUm9kV0l2ZDI5eWEyWnMKYjNkekwzSmxiR1ZoYzJVdWVXMXNRSEpsWm5NdmRHRm5jeTh4TGpJMExqQXdPQVlLS3dZQkJBR0R2ekFCRXdRcQpEQ2hsWXpreVl6RmhabUptWlRWaVpUTTNZbUV3Tm1Ka01qVTRaR0l4WlRJeE4yRTJabVkyWWpkak1CY0dDaXNHCkFRUUJnNzh3QVJRRUNRd0hjbVZzWldGelpUQlpCZ29yQmdFRUFZTy9NQUVWQkVzTVNXaDBkSEJ6T2k4dloybDAKYUhWaUxtTnZiUzlzY1dNMk1qUXZZMkZ5TFhKMWJuUnBiV1V2WVdOMGFXOXVjeTl5ZFc1ekx6UXpOekF4TnpnNApNRE0yTDJGMGRHVnRjSFJ6THpFd0ZnWUtLd1lCQkFHRHZ6QUJGZ1FJREFad2RXSnNhV013VUFZS0t3WUJCQUdECnZ6QUJHQVJDREVCeVpYQnZPbXh4WXpZeU5FQTJPVEl6TkRVMk5DOWpZWEl0Y25WdWRHbHRaVUF4TXpZeE1Ua3kKTnpFME9uSmxaanB5WldaekwzUmhaM012TVM0eU5DNHdNSUdMQmdvckJnRUVBZFo1QWdRQ0JIMEVld0I1QUhjQQozVDB3YXNiSEVUSmpHUjRjbVdjM0FxSktYcmplUEszL2g0cHlnQzhwN280QUFBR2gzcVR1bEFBQUJBTUFTREJHCkFpRUE2TnI0Z2VIQUh4cVN0K1cwenJKVXdCMk1ReFQ2Yjh4NVI1OVBoc1IvN2FvQ0lRQ1FvT1JWTFgrc0RmMzkKbVRiZklJYkpaQktEMGtPYnZJY0dMTllHWEhFdDl6QUtCZ2dxaGtqT1BRUURBd05vQURCbEFqQUpWSGZsQ2JNZApMWWtDWndDTmMzVTRGcUVwVzFsQ3JmcTdyMDNJUW9aajM3eUJUTDhWVkZYSFlEQlczUmtGNTBZQ01RQ25COTROCk9LVkhXRkJGM3E5TFlSRjhXN1ZnTkdJbE1rOUdXb2tFbm50R3FIWVBGVGF2WVJhWGxQWmNCN2dYbytrPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==","rekorBundle":{"SignedEntryTimestamp":"MEUCIQDl3bXOX15YpnZ1dQThXg/rqc4GueDfrRcJ9xfgTb4HTgIgfiTDW3QOsmV4fWzLGKtxSDvM64AG/1HJkNoDDnxIJ58=","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJhYTgwYjY1NzgyYWMyMGEwZDAxMjg5NTQ1OTkyYTlmODljNzQ1ZmQzNDJlZWI1YzJjNGY0MWJkODRlMGZmOTIwIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FWUNJUURpRjQ2anNReVV1NU1DNVlZeEc5bTNsb2xGZ1dIWXkvWllrZjRrM29HMERnSWhBSlZmVWxkTGdOcWIvNUllOE9oekgxMUVVZXVsS3VOTDFaSHVmdkFOZzgvUiIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVYzJSRU5EUW0wMlowRjNTVUpCWjBsVlJWaFRSalpCU2pOWE9TOXZLMng0VjJ4emJqVm9VVEZwY1RoWmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFVUlRGTlJHc3hUMFJOZWxkb1kwNU5hbGw0VFZSRk1VMVVRWGRQUkUxNlYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZ1WlVKR2VGcHJSSFJDV0RCRlZITnNOWGxuTUVnMVkxQkpNR0pSWVRBMVFXNVJTa3dLV0hkVFJUbFBNVXR5V21wSVlqYzNVbk4xVFRkQ1QzbE5XRWxpVEhveGJEY3lSMnBaZFRSc00wSTJibTlITlM5WVpFdFBRMEpaTUhkbloxZEtUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFtbENaMDVXU0ZKRlFrRm1PRVZYUkVKWGFHeFNiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmlTRVpxVG1wSk1Fd3lUbWhqYVRGNVpGYzFNR0ZYTVd4TWVUVnVZVmhTYjJSWFNYWmtNamw1WVRKYWMySXpaSHBNTTBwc1lrZFdhQXBqTWxWMVpWY3hjMUZJU214YWJrMTJaRWRHYm1ONU9IaE1ha2t3VEdwQmQwOVJXVXRMZDFsQ1FrRkhSSFo2UVVKQlVWRnlZVWhTTUdOSVRUWk1lVGt3Q21JeWRHeGlhVFZvV1ROU2NHSXlOWHBNYldSd1pFZG9NVmx1Vm5wYVdFcHFZakkxTUZwWE5UQk1iVTUyWWxSQlZrSm5iM0pDWjBWRlFWbFBMMDFCUlVNS1FrRmtlVnBYZUd4WldFNXNUVVJaUjBOcGMwZEJVVkZDWnpjNGQwRlJUVVZMUjFacVQxUkthazFYUm0xWmJWcHNUbGRLYkUxNlpHbFpWRUV5V1cxUmVRcE9WR2hyV1dwR2JFMXFSVE5aVkZwdFdtcGFhVTR5VFhkR1VWbExTM2RaUWtKQlIwUjJla0ZDUWtGUlNHTnRWbk5hVjBaNldsUkJaMEpuYjNKQ1owVkZDa0ZaVHk5TlFVVkdRa0pLYzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMGhuV1V0TGQxbENRa0ZIUkhaNlFVSkNaMUZSWTIxV2JXTjVPVEFLV1Zka2VreDZSWFZOYWxGMVRVUkJOMEpuYjNKQ1owVkZRVmxQTDAxQlJVbENRekJOU3pKb01HUklRbnBQYVRoMlpFYzVjbHBYTkhWWlYwNHdZVmM1ZFFwamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcVlqSXdkMXBCV1V0TGQxbENRa0ZIUkhaNlFVSkRVVkpYUkVaU2IyUklVbmRqZW05MkNrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUV3eVRtaGphVEY1WkZjMU1HRlhNV3hNZVRWdVlWaFNiMlJYU1haa01qbDVZVEphYzJJelpIb0tURE5LYkdKSFZtaGpNbFYxWlZjeGMxRklTbXhhYmsxMlpFZEdibU41T0hoTWFra3dUR3BCZDA5QldVdExkMWxDUWtGSFJIWjZRVUpEWjFGeFJFTm9iQXBaZW10NVdYcEdhRnB0U20xYVZGWnBXbFJOTTFsdFJYZE9iVXByVFdwVk5GcEhTWGhhVkVsNFRqSkZNbHB0V1RKWmFtUnFUVUl3UjBOcGMwZEJVVkZDQ21jM09IZEJVWE5GUkhkM1Rsb3liREJoU0ZacFRGZG9kbU16VW14YVJFRXhRbWR2Y2tKblJVVkJXVTh2VFVGRlRVSkRZMDFLVjJnd1pFaENlazlwT0hZS1dqSnNNR0ZJVm1sTWJVNTJZbE01YzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMDlCV1V0TGQxbENRa0ZIUkhaNlFVSkVVVkZ4UkVOb2JBcFplbXQ1V1hwR2FGcHRTbTFhVkZacFdsUk5NMWx0UlhkT2JVcHJUV3BWTkZwSFNYaGFWRWw0VGpKRk1scHRXVEpaYW1ScVRVTkJSME5wYzBkQlVWRkNDbWMzT0hkQlVUUkZSV2QzVVdOdFZtMWplVGt3V1Zka2VreDZSWFZOYWxGMVRVUkJZVUpuYjNKQ1owVkZRVmxQTDAxQlJWQkNRWGROUTJwRmVrNXFSWGdLVDFSSk0wMVVVWGRMVVZsTFMzZFpRa0pCUjBSMmVrRkNSVUZSWWtSQ2JHOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUFwTlFtZEhRMmx6UjBGUlVVSm5OemgzUVZKRlJVTm5kMGxPYW10NVRYcFJNVTVxVVhkYVFWbExTM2RaUWtKQlIwUjJla0ZDUldkU1YwUkdVbTlrU0ZKM0NtTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJZa2hHYWs1cVNUQk1NazVvWTJreGVXUlhOVEJoVnpGc1RIazFibUZZVW05a1YwbDJaREk1ZVdFeVduTUtZak5rZWt3elNteGlSMVpvWXpKVmRXVlhNWE5SU0Vwc1dtNU5kbVJIUm01amVUaDRUR3BKTUV4cVFYZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JYZFJjUXBFUTJoc1dYcHJlVmw2Um1oYWJVcHRXbFJXYVZwVVRUTlpiVVYzVG0xS2EwMXFWVFJhUjBsNFdsUkplRTR5UlRKYWJWa3lXV3BrYWsxQ1kwZERhWE5IQ2tGUlVVSm5OemgzUVZKUlJVTlJkMGhqYlZaeldsZEdlbHBVUWxwQ1oyOXlRbWRGUlVGWlR5OU5RVVZXUWtWelRWTlhhREJrU0VKNlQyazRkbG95YkRBS1lVaFdhVXh0VG5aaVV6bHpZMWROTWsxcVVYWlpNa1o1VEZoS01XSnVVbkJpVjFWMldWZE9NR0ZYT1hWamVUbDVaRmMxZWt4NlVYcE9la0Y0VG5wbk5BcE5SRTB5VERKR01HUkhWblJqU0ZKNlRIcEZkMFpuV1V0TGQxbENRa0ZIUkhaNlFVSkdaMUZKUkVGYWQyUlhTbk5oVjAxM1ZVRlpTMHQzV1VKQ1FVZEVDblo2UVVKSFFWSkRSRVZDZVZwWVFuWlBiWGg0V1hwWmVVNUZRVEpQVkVsNlRrUlZNazVET1dwWldFbDBZMjVXZFdSSGJIUmFWVUY0VFhwWmVFMVVhM2tLVG5wRk1FOXVTbXhhYW5CNVdsZGFla3d6VW1oYU0wMTJUVk0wZVU1RE5IZE5TVWRNUW1kdmNrSm5SVVZCWkZvMVFXZFJRMEpJTUVWbGQwSTFRVWhqUVFvelZEQjNZWE5pU0VWVVNtcEhValJqYlZkak0wRnhTa3RZY21wbFVFc3pMMmcwY0hsblF6aHdOMjgwUVVGQlIyZ3pjVlIxYkVGQlFVSkJUVUZUUkVKSENrRnBSVUUyVG5JMFoyVklRVWg0Y1ZOMEsxY3dlbkpLVlhkQ01rMVJlRlEyWWpoNE5WSTFPVkJvYzFJdk4yRnZRMGxSUTFGdlQxSldURmdyYzBSbU16a0tiVlJpWmtsSllrcGFRa3RFTUd0UFluWkpZMGRNVGxsSFdFaEZkRGw2UVV0Q1oyZHhhR3RxVDFCUlVVUkJkMDV2UVVSQ2JFRnFRVXBXU0dac1EySk5aQXBNV1d0RFduZERUbU16VlRSR2NVVndWekZzUTNKbWNUZHlNRE5KVVc5YWFqTTNlVUpVVERoV1ZrWllTRmxFUWxjelVtdEdOVEJaUTAxUlEyNUNPVFJPQ2s5TFZraFhSa0pHTTNFNVRGbFNSamhYTjFablRrZEpiRTFyT1VkWGIydEZibTUwUjNGSVdWQkdWR0YyV1ZKaFdHeFFXbU5DTjJkWWJ5dHJQUW90TFMwdExVVk9SQ0JEUlZKVVNVWkpRMEZVUlMwdExTMHRDZz09In19fX0=","integratedTime":1794736714,"logIndex":3899685861,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}
|
package/dist/loop/recover.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { appendSettlement } from './settlement.js';
|
|
1
2
|
/** 扫描日志中未闭合的 turn(有 turnStart 语义的用户事件但没有 turnEnd)与未配对 toolCall */
|
|
2
3
|
export function recoverInterrupted(log) {
|
|
3
4
|
const report = { turnsClosed: 0, pairedCalls: 0 };
|
|
@@ -31,7 +32,10 @@ export function recoverInterrupted(log) {
|
|
|
31
32
|
report.pairedCalls++;
|
|
32
33
|
}
|
|
33
34
|
// 未闭合 turn → 补记 turnEnd=interrupted(不可与 aborted 混用)
|
|
35
|
+
// 1.24-W2(D-W2-2):补记前先落 settlement——部分链对账 = hasUnknownOutcomes 主战场
|
|
36
|
+
// (上方成对补记的 recovered:true 合成结果在结算里按「结果不明」显式记账,不丢信号)
|
|
34
37
|
for (const turnId of openTurns) {
|
|
38
|
+
appendSettlement(log, turnId, { reason: 'interrupted', recovered: true });
|
|
35
39
|
log.append('runtime', 'turnEnd', turnId, null, { reason: 'interrupted', recovered: true });
|
|
36
40
|
report.turnsClosed++;
|
|
37
41
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 1.24-W2 · 回合结算回执(settlement receipt)
|
|
3
|
+
*
|
|
4
|
+
* 口径(《Qwen-Code 对照分析》§2.3/§5 / 借鉴四篇裁决记录 Q-W2 / 迭代规划 D-W2-1~6):
|
|
5
|
+
* - 「结算必留回执」:任何 turn 无论成败都有一张结构化凭据——观测 / 恢复 / 审计消费同一张
|
|
6
|
+
* - 落链形态 = kind:'system' + payload.type:'settlement'(EventKind 零新增;payload.type 扩展
|
|
7
|
+
* 沿 routing 'decide' / memory 'write|edit|delete|rollback' 先例);一 turn 一张,llm 面与
|
|
8
|
+
* tool 节合并(D-W2-1)
|
|
9
|
+
* - 产出点仅两处:runTurn closeTurn(turnEnd 之前——turnEnd 保持终止标记语义)与
|
|
10
|
+
* recoverInterrupted 补记(部分链对账);authz 台账 turnEnd 与 facade sessionStop 不经
|
|
11
|
+
* closeTurn、不触发(D-W2-2 登记)
|
|
12
|
+
* - 事实源 = 链(非运行时状态):两本账按链上 toolCall/toolResult payload.id 对账;
|
|
13
|
+
* permissionDenialCount = toolResult error:'authorization-denied' 且 granted===false;
|
|
14
|
+
* hasUnknownOutcomes = 无配对 toolResult 或配对结果 recovered:true(副作用状态未知显式记账);
|
|
15
|
+
* bounded = aborted-before-dispatch 补记形态在链(取消落在派发边界,未打断在途执行)
|
|
16
|
+
* - 字段 CAR 化:outcome 由 reason 映射(complete|interrupted|failed);failureKind = 1.23
|
|
17
|
+
* meta.kind 诚实缺键;assistantSeq 代 Qwen assistantMessageUuid;Qwen nextMaxOutputTokens
|
|
18
|
+
* 在 CAR 无对应机制 → 诚实缺键不预埋(D-W2-3 偏差登记)
|
|
19
|
+
* - turnEnd meta 零变化:settlement 是独立事件非 meta 尾键(D-W2-4,s78-16 字节兼容锚不动);
|
|
20
|
+
* stopRequested 经 closeTurn hints 传递不落 meta
|
|
21
|
+
* - kill-switch:CAR_SETTLEMENT=off 跳过 append(K1 env 逐 turn 求值先例);缺省开(D-W2-5)
|
|
22
|
+
* - 链量纪律(R-W2):定长小 payload——账本数组 cap 64 + truncated 标记;内容类信息不进链
|
|
23
|
+
*/
|
|
24
|
+
import type { SessionLog } from '../session/log.ts';
|
|
25
|
+
export type SettlementOutcome = 'complete' | 'interrupted' | 'failed';
|
|
26
|
+
/** 账本数组上限(超出截断 + ledgerTruncated 标记——防病态长 turn 链量失控) */
|
|
27
|
+
export declare const SETTLEMENT_LEDGER_CAP = 64;
|
|
28
|
+
export interface SettlementHints {
|
|
29
|
+
/** terminate 型收口(工具主动 stop 语义,stop.ts closeTurn hints——不落 turnEnd meta) */
|
|
30
|
+
stopRequested?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/** TurnEndReason → settlement outcome 映射(completed/max-tokens=complete;aborted/interrupted=interrupted;error/blocked=failed) */
|
|
33
|
+
export declare function outcomeFromReason(reason: string): SettlementOutcome;
|
|
34
|
+
/**
|
|
35
|
+
* 结算回执落链(closeTurn / recover 共用单点)。meta = 同 turn turnEnd 将携带的 meta
|
|
36
|
+
* (reason/kind 等事实同源);usage/hints 缺省时从链自证(requestSent 由 usage 事件或
|
|
37
|
+
* assistant 在场推导)。
|
|
38
|
+
*/
|
|
39
|
+
export declare function appendSettlement(log: SessionLog, turnId: string, meta: Record<string, unknown>, hints?: SettlementHints): void;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** 账本数组上限(超出截断 + ledgerTruncated 标记——防病态长 turn 链量失控) */
|
|
2
|
+
export const SETTLEMENT_LEDGER_CAP = 64;
|
|
3
|
+
/** TurnEndReason → settlement outcome 映射(completed/max-tokens=complete;aborted/interrupted=interrupted;error/blocked=failed) */
|
|
4
|
+
export function outcomeFromReason(reason) {
|
|
5
|
+
if (reason === 'completed' || reason === 'max-tokens')
|
|
6
|
+
return 'complete';
|
|
7
|
+
if (reason === 'aborted' || reason === 'interrupted')
|
|
8
|
+
return 'interrupted';
|
|
9
|
+
return 'failed';
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 结算回执落链(closeTurn / recover 共用单点)。meta = 同 turn turnEnd 将携带的 meta
|
|
13
|
+
* (reason/kind 等事实同源);usage/hints 缺省时从链自证(requestSent 由 usage 事件或
|
|
14
|
+
* assistant 在场推导)。
|
|
15
|
+
*/
|
|
16
|
+
export function appendSettlement(log, turnId, meta, hints) {
|
|
17
|
+
if (process.env.CAR_SETTLEMENT === 'off')
|
|
18
|
+
return;
|
|
19
|
+
const reason = typeof meta.reason === 'string' ? meta.reason : 'error';
|
|
20
|
+
const kind = typeof meta.kind === 'string' ? meta.kind : undefined;
|
|
21
|
+
// 单次链扫描:两本账 + 拒绝计数 + unknown/bounded 事实 + requestSent 事实 + assistantSeq
|
|
22
|
+
const declared = [];
|
|
23
|
+
const resultById = new Map();
|
|
24
|
+
let denialCount = 0;
|
|
25
|
+
let bounded = false;
|
|
26
|
+
let usageRequests = 0;
|
|
27
|
+
let assistantSeq;
|
|
28
|
+
for (const e of log.events) {
|
|
29
|
+
if (e.turnId !== turnId)
|
|
30
|
+
continue;
|
|
31
|
+
const p = (e.payload ?? {});
|
|
32
|
+
if (e.kind === 'toolCall') {
|
|
33
|
+
if (typeof p.id === 'string')
|
|
34
|
+
declared.push(p.id);
|
|
35
|
+
}
|
|
36
|
+
else if (e.kind === 'toolResult') {
|
|
37
|
+
if (typeof p.id === 'string') {
|
|
38
|
+
resultById.set(p.id, p); // 1.6-S1 last-wins 同款口径
|
|
39
|
+
if (p.error === 'authorization-denied' && p.granted === false)
|
|
40
|
+
denialCount++;
|
|
41
|
+
if (p.error === 'aborted-before-dispatch')
|
|
42
|
+
bounded = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else if (e.kind === 'usage') {
|
|
46
|
+
usageRequests++;
|
|
47
|
+
}
|
|
48
|
+
else if (e.kind === 'assistant') {
|
|
49
|
+
assistantSeq = e.seq;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const dispatched = [...resultById.keys()];
|
|
53
|
+
const unknownIds = declared.filter((id) => {
|
|
54
|
+
const res = resultById.get(id);
|
|
55
|
+
return !res || res.recovered === true;
|
|
56
|
+
});
|
|
57
|
+
const cap = (arr) => (arr.length > SETTLEMENT_LEDGER_CAP ? arr.slice(0, SETTLEMENT_LEDGER_CAP) : arr);
|
|
58
|
+
const ledgerTruncated = declared.length > SETTLEMENT_LEDGER_CAP || dispatched.length > SETTLEMENT_LEDGER_CAP;
|
|
59
|
+
log.append('runtime', 'system', turnId, {
|
|
60
|
+
type: 'settlement',
|
|
61
|
+
outcome: outcomeFromReason(reason),
|
|
62
|
+
...(kind ? { failureKind: kind } : {}),
|
|
63
|
+
requestSent: usageRequests > 0 || assistantSeq !== undefined,
|
|
64
|
+
...(assistantSeq !== undefined ? { assistantSeq } : {}),
|
|
65
|
+
declaredToolUseIds: cap(declared),
|
|
66
|
+
dispatchedToolUseIds: cap(dispatched),
|
|
67
|
+
...(ledgerTruncated ? { ledgerTruncated: true } : {}),
|
|
68
|
+
tool: {
|
|
69
|
+
permissionDenialCount: denialCount,
|
|
70
|
+
hasUnknownOutcomes: unknownIds.length > 0,
|
|
71
|
+
...(unknownIds.length ? { unknownToolUseIds: cap(unknownIds) } : {}),
|
|
72
|
+
stopRequested: hints?.stopRequested === true,
|
|
73
|
+
bounded,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}
|
package/dist/loop/stop.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CarM8Error } from '../runtime-core/errors.js';
|
|
2
|
+
import { appendSettlement } from './settlement.js';
|
|
2
3
|
/**
|
|
3
4
|
* 1.23-W1(D-W1-6):取消时机标注(W-0 审计 F-W0-3——aborted 三路径链上不区分)——
|
|
4
5
|
* 'before-request' = 请求未发出(runTurn 循环头 / chatStep 零 chunk 流结束检查);
|
|
@@ -55,13 +56,16 @@ export async function runTurn(opts) {
|
|
|
55
56
|
let steps = 0;
|
|
56
57
|
// 1.11-S2(D-33):turnEnd 落链单点包装——聚合本 turn usage 事件(无 usage 不带键,
|
|
57
58
|
// 缺省=未采集向后兼容);reason 保持 meta 首键,usage 恒为加法尾键
|
|
58
|
-
|
|
59
|
+
// 1.24-W2(D-W2-2):turnEnd 之前先落 settlement 结算回执(turnEnd 保持终止标记语义;
|
|
60
|
+
// hints 仅 terminate 收口传递 stopRequested——不落 turnEnd meta,D-W2-4)
|
|
61
|
+
const closeTurn = (meta, hints) => {
|
|
59
62
|
const usage = turnUsageFrom(log, turnId);
|
|
60
63
|
// 1.18.2-K8(R-K7-2):计量缺失 fail-visible——商汤网关实测 20% 概率 message_delta
|
|
61
64
|
// 不带 usage(流正常回复但计量整条缺席)→ 缺失口径纪律不落半条事实(turnUsageFrom
|
|
62
65
|
// undefined),缺失本身在此显式标注:本 turn 存在 assistant 事件(模型有可见输出 ⇒
|
|
63
66
|
// 必有请求)而无 usage 聚合时带 usageMissing: true(加法尾键,与 usage 同语义位)
|
|
64
67
|
const hasAssistant = log.events.some((e) => e.kind === 'assistant' && e.turnId === turnId);
|
|
68
|
+
appendSettlement(log, turnId, meta, hints);
|
|
65
69
|
return log.append('runtime', 'turnEnd', turnId, null, {
|
|
66
70
|
...meta,
|
|
67
71
|
...(usage ? { usage } : hasAssistant ? { usageMissing: true } : {}),
|
|
@@ -237,7 +241,8 @@ export async function runTurn(opts) {
|
|
|
237
241
|
const agg = preset.aggregate ?? {};
|
|
238
242
|
const abortedNow = (agg.terminate ?? 'all') === 'any' ? batch.terminateVotes > 0 : batch.terminateAll;
|
|
239
243
|
if (abortedNow) { // terminate 收口:默认 AND(整批),可配置 any
|
|
240
|
-
|
|
244
|
+
// 1.24-W2:工具主动 stop 语义 → settlement stopRequested=true(hints 不落 meta,D-W2-4)
|
|
245
|
+
const seq = closeTurn({ reason: 'aborted' }, { stopRequested: true }).seq;
|
|
241
246
|
trail.push({ seq, reason: 'aborted' });
|
|
242
247
|
return { reason: 'aborted', steps, endReasonTrail: trail };
|
|
243
248
|
}
|
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":"
|
|
4
|
-
{"stage":"cosign-keyless","detail":"signed car-runtime-1.
|
|
1
|
+
{"stage":"archive","detail":"git archive HEAD → car-runtime-1.24.0.tgz(455869 bytes,树哈希锚定)","ts":1794736712665}
|
|
2
|
+
{"stage":"sha256sums","detail":"SHA256SUMS aa80b65782ac20a0…(裸字节复核通过)","ts":1794736712666}
|
|
3
|
+
{"stage":"sbom","detail":"56 个组件(运行时依赖 0 项)","ts":1794736712672}
|
|
4
|
+
{"stage":"cosign-keyless","detail":"signed car-runtime-1.24.0.tgz (keyless OIDC + Rekor)","ts":1794736714665}
|
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.24.0",
|
|
5
5
|
"components": [
|
|
6
6
|
{
|
|
7
7
|
"type": "file",
|
|
@@ -101,12 +101,17 @@
|
|
|
101
101
|
{
|
|
102
102
|
"type": "file",
|
|
103
103
|
"path": "src/loop/recover.ts",
|
|
104
|
-
"sha256": "
|
|
104
|
+
"sha256": "28f3ee3c244380b91ea5f037bb7920c55c2979ea5e818f77827ab2c473e1578a"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"type": "file",
|
|
108
|
+
"path": "src/loop/settlement.ts",
|
|
109
|
+
"sha256": "07b9da93f216f5bee4dc7e034e7e194e9a209449599e71371255c7cd388f4c3a"
|
|
105
110
|
},
|
|
106
111
|
{
|
|
107
112
|
"type": "file",
|
|
108
113
|
"path": "src/loop/stop.ts",
|
|
109
|
-
"sha256": "
|
|
114
|
+
"sha256": "7e185d31c4c65ee4ba1d43135a609572e677a70f93110c183e34d593d8aaf0a6"
|
|
110
115
|
},
|
|
111
116
|
{
|
|
112
117
|
"type": "file",
|
|
@@ -251,7 +256,7 @@
|
|
|
251
256
|
{
|
|
252
257
|
"type": "file",
|
|
253
258
|
"path": "src/session/log.ts",
|
|
254
|
-
"sha256": "
|
|
259
|
+
"sha256": "7cecb0ef745d27bd5c1a8935b19f2f2b54546cab0b0865c29b0826aad32bcd11"
|
|
255
260
|
},
|
|
256
261
|
{
|
|
257
262
|
"type": "file",
|
|
@@ -271,7 +276,7 @@
|
|
|
271
276
|
{
|
|
272
277
|
"type": "file",
|
|
273
278
|
"path": "package.json",
|
|
274
|
-
"sha256": "
|
|
279
|
+
"sha256": "4c74e9d524e6d57a89b85936fc67b7d454a947c22686d87a0d7a09a1afade230"
|
|
275
280
|
},
|
|
276
281
|
{
|
|
277
282
|
"type": "file",
|
package/dist/session/log.js
CHANGED
|
@@ -132,6 +132,11 @@ export class SessionLog {
|
|
|
132
132
|
let pendingThinkingTurn = null;
|
|
133
133
|
let pendingBlocks = [];
|
|
134
134
|
for (const e of projected) {
|
|
135
|
+
// 1.24-W2(D-W2-1):settlement 回执不投影(model_visible=0 同 usage 纪律——结算凭据是
|
|
136
|
+
// 审计面事实非模型上下文;system kind 语义位但 payload.type 判别排除,先于 thinking
|
|
137
|
+
// 隔断检查,杜绝任何投影面影响;无 settlement 链投影逐字节不变)
|
|
138
|
+
if (e.kind === 'system' && e.payload?.type === 'settlement')
|
|
139
|
+
continue;
|
|
135
140
|
if (pendingBlocks.length && (e.turnId !== pendingThinkingTurn || e.kind === 'user' || e.kind === 'system'))
|
|
136
141
|
pendingBlocks = [];
|
|
137
142
|
if (e.kind === 'thinking') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lqc123qwe/car-runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.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",
|
package/src/loop/recover.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - 副作用审计:补记事件带 recovered=true 标记(副作用是否落地由恢复层显式声明为未知)
|
|
8
8
|
*/
|
|
9
9
|
import type { SessionLog, SessionEvent } from '../session/log.ts'
|
|
10
|
+
import { appendSettlement } from './settlement.ts'
|
|
10
11
|
|
|
11
12
|
export interface RecoveryReport {
|
|
12
13
|
/** 补记 interrupted 的 turn 数 */
|
|
@@ -39,7 +40,10 @@ export function recoverInterrupted(log: SessionLog): RecoveryReport {
|
|
|
39
40
|
report.pairedCalls++
|
|
40
41
|
}
|
|
41
42
|
// 未闭合 turn → 补记 turnEnd=interrupted(不可与 aborted 混用)
|
|
43
|
+
// 1.24-W2(D-W2-2):补记前先落 settlement——部分链对账 = hasUnknownOutcomes 主战场
|
|
44
|
+
// (上方成对补记的 recovered:true 合成结果在结算里按「结果不明」显式记账,不丢信号)
|
|
42
45
|
for (const turnId of openTurns) {
|
|
46
|
+
appendSettlement(log, turnId, { reason: 'interrupted', recovered: true })
|
|
43
47
|
log.append('runtime', 'turnEnd', turnId, null, { reason: 'interrupted', recovered: true })
|
|
44
48
|
report.turnsClosed++
|
|
45
49
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 1.24-W2 · 回合结算回执(settlement receipt)
|
|
3
|
+
*
|
|
4
|
+
* 口径(《Qwen-Code 对照分析》§2.3/§5 / 借鉴四篇裁决记录 Q-W2 / 迭代规划 D-W2-1~6):
|
|
5
|
+
* - 「结算必留回执」:任何 turn 无论成败都有一张结构化凭据——观测 / 恢复 / 审计消费同一张
|
|
6
|
+
* - 落链形态 = kind:'system' + payload.type:'settlement'(EventKind 零新增;payload.type 扩展
|
|
7
|
+
* 沿 routing 'decide' / memory 'write|edit|delete|rollback' 先例);一 turn 一张,llm 面与
|
|
8
|
+
* tool 节合并(D-W2-1)
|
|
9
|
+
* - 产出点仅两处:runTurn closeTurn(turnEnd 之前——turnEnd 保持终止标记语义)与
|
|
10
|
+
* recoverInterrupted 补记(部分链对账);authz 台账 turnEnd 与 facade sessionStop 不经
|
|
11
|
+
* closeTurn、不触发(D-W2-2 登记)
|
|
12
|
+
* - 事实源 = 链(非运行时状态):两本账按链上 toolCall/toolResult payload.id 对账;
|
|
13
|
+
* permissionDenialCount = toolResult error:'authorization-denied' 且 granted===false;
|
|
14
|
+
* hasUnknownOutcomes = 无配对 toolResult 或配对结果 recovered:true(副作用状态未知显式记账);
|
|
15
|
+
* bounded = aborted-before-dispatch 补记形态在链(取消落在派发边界,未打断在途执行)
|
|
16
|
+
* - 字段 CAR 化:outcome 由 reason 映射(complete|interrupted|failed);failureKind = 1.23
|
|
17
|
+
* meta.kind 诚实缺键;assistantSeq 代 Qwen assistantMessageUuid;Qwen nextMaxOutputTokens
|
|
18
|
+
* 在 CAR 无对应机制 → 诚实缺键不预埋(D-W2-3 偏差登记)
|
|
19
|
+
* - turnEnd meta 零变化:settlement 是独立事件非 meta 尾键(D-W2-4,s78-16 字节兼容锚不动);
|
|
20
|
+
* stopRequested 经 closeTurn hints 传递不落 meta
|
|
21
|
+
* - kill-switch:CAR_SETTLEMENT=off 跳过 append(K1 env 逐 turn 求值先例);缺省开(D-W2-5)
|
|
22
|
+
* - 链量纪律(R-W2):定长小 payload——账本数组 cap 64 + truncated 标记;内容类信息不进链
|
|
23
|
+
*/
|
|
24
|
+
import type { SessionLog } from '../session/log.ts'
|
|
25
|
+
|
|
26
|
+
export type SettlementOutcome = 'complete' | 'interrupted' | 'failed'
|
|
27
|
+
|
|
28
|
+
/** 账本数组上限(超出截断 + ledgerTruncated 标记——防病态长 turn 链量失控) */
|
|
29
|
+
export const SETTLEMENT_LEDGER_CAP = 64
|
|
30
|
+
|
|
31
|
+
export interface SettlementHints {
|
|
32
|
+
/** terminate 型收口(工具主动 stop 语义,stop.ts closeTurn hints——不落 turnEnd meta) */
|
|
33
|
+
stopRequested?: boolean
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** TurnEndReason → settlement outcome 映射(completed/max-tokens=complete;aborted/interrupted=interrupted;error/blocked=failed) */
|
|
37
|
+
export function outcomeFromReason(reason: string): SettlementOutcome {
|
|
38
|
+
if (reason === 'completed' || reason === 'max-tokens') return 'complete'
|
|
39
|
+
if (reason === 'aborted' || reason === 'interrupted') return 'interrupted'
|
|
40
|
+
return 'failed'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 结算回执落链(closeTurn / recover 共用单点)。meta = 同 turn turnEnd 将携带的 meta
|
|
45
|
+
* (reason/kind 等事实同源);usage/hints 缺省时从链自证(requestSent 由 usage 事件或
|
|
46
|
+
* assistant 在场推导)。
|
|
47
|
+
*/
|
|
48
|
+
export function appendSettlement(
|
|
49
|
+
log: SessionLog,
|
|
50
|
+
turnId: string,
|
|
51
|
+
meta: Record<string, unknown>,
|
|
52
|
+
hints?: SettlementHints,
|
|
53
|
+
): void {
|
|
54
|
+
if (process.env.CAR_SETTLEMENT === 'off') return
|
|
55
|
+
const reason = typeof meta.reason === 'string' ? meta.reason : 'error'
|
|
56
|
+
const kind = typeof meta.kind === 'string' ? meta.kind : undefined
|
|
57
|
+
|
|
58
|
+
// 单次链扫描:两本账 + 拒绝计数 + unknown/bounded 事实 + requestSent 事实 + assistantSeq
|
|
59
|
+
const declared: string[] = []
|
|
60
|
+
const resultById = new Map<string, Record<string, unknown>>()
|
|
61
|
+
let denialCount = 0
|
|
62
|
+
let bounded = false
|
|
63
|
+
let usageRequests = 0
|
|
64
|
+
let assistantSeq: number | undefined
|
|
65
|
+
for (const e of log.events) {
|
|
66
|
+
if (e.turnId !== turnId) continue
|
|
67
|
+
const p = (e.payload ?? {}) as Record<string, unknown>
|
|
68
|
+
if (e.kind === 'toolCall') {
|
|
69
|
+
if (typeof p.id === 'string') declared.push(p.id)
|
|
70
|
+
} else if (e.kind === 'toolResult') {
|
|
71
|
+
if (typeof p.id === 'string') {
|
|
72
|
+
resultById.set(p.id, p) // 1.6-S1 last-wins 同款口径
|
|
73
|
+
if (p.error === 'authorization-denied' && p.granted === false) denialCount++
|
|
74
|
+
if (p.error === 'aborted-before-dispatch') bounded = true
|
|
75
|
+
}
|
|
76
|
+
} else if (e.kind === 'usage') {
|
|
77
|
+
usageRequests++
|
|
78
|
+
} else if (e.kind === 'assistant') {
|
|
79
|
+
assistantSeq = e.seq
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const dispatched = [...resultById.keys()]
|
|
83
|
+
const unknownIds = declared.filter((id) => {
|
|
84
|
+
const res = resultById.get(id)
|
|
85
|
+
return !res || res.recovered === true
|
|
86
|
+
})
|
|
87
|
+
const cap = (arr: string[]) => (arr.length > SETTLEMENT_LEDGER_CAP ? arr.slice(0, SETTLEMENT_LEDGER_CAP) : arr)
|
|
88
|
+
const ledgerTruncated = declared.length > SETTLEMENT_LEDGER_CAP || dispatched.length > SETTLEMENT_LEDGER_CAP
|
|
89
|
+
|
|
90
|
+
log.append('runtime', 'system', turnId, {
|
|
91
|
+
type: 'settlement',
|
|
92
|
+
outcome: outcomeFromReason(reason),
|
|
93
|
+
...(kind ? { failureKind: kind } : {}),
|
|
94
|
+
requestSent: usageRequests > 0 || assistantSeq !== undefined,
|
|
95
|
+
...(assistantSeq !== undefined ? { assistantSeq } : {}),
|
|
96
|
+
declaredToolUseIds: cap(declared),
|
|
97
|
+
dispatchedToolUseIds: cap(dispatched),
|
|
98
|
+
...(ledgerTruncated ? { ledgerTruncated: true } : {}),
|
|
99
|
+
tool: {
|
|
100
|
+
permissionDenialCount: denialCount,
|
|
101
|
+
hasUnknownOutcomes: unknownIds.length > 0,
|
|
102
|
+
...(unknownIds.length ? { unknownToolUseIds: cap(unknownIds) } : {}),
|
|
103
|
+
stopRequested: hints?.stopRequested === true,
|
|
104
|
+
bounded,
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
}
|
package/src/loop/stop.ts
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import type { SessionLog } from '../session/log.ts'
|
|
18
18
|
import { CarM8Error } from '../runtime-core/errors.ts'
|
|
19
|
+
import { appendSettlement } from './settlement.ts'
|
|
19
20
|
|
|
20
21
|
export type StepOutcome = 'completed' | 'max-tokens' | 'null'
|
|
21
22
|
export type TurnEndReason = 'completed' | 'max-tokens' | 'aborted' | 'error' | 'blocked' | 'interrupted'
|
|
@@ -129,13 +130,16 @@ export async function runTurn(opts: {
|
|
|
129
130
|
|
|
130
131
|
// 1.11-S2(D-33):turnEnd 落链单点包装——聚合本 turn usage 事件(无 usage 不带键,
|
|
131
132
|
// 缺省=未采集向后兼容);reason 保持 meta 首键,usage 恒为加法尾键
|
|
132
|
-
|
|
133
|
+
// 1.24-W2(D-W2-2):turnEnd 之前先落 settlement 结算回执(turnEnd 保持终止标记语义;
|
|
134
|
+
// hints 仅 terminate 收口传递 stopRequested——不落 turnEnd meta,D-W2-4)
|
|
135
|
+
const closeTurn = (meta: Record<string, unknown>, hints?: { stopRequested?: boolean }) => {
|
|
133
136
|
const usage = turnUsageFrom(log, turnId)
|
|
134
137
|
// 1.18.2-K8(R-K7-2):计量缺失 fail-visible——商汤网关实测 20% 概率 message_delta
|
|
135
138
|
// 不带 usage(流正常回复但计量整条缺席)→ 缺失口径纪律不落半条事实(turnUsageFrom
|
|
136
139
|
// undefined),缺失本身在此显式标注:本 turn 存在 assistant 事件(模型有可见输出 ⇒
|
|
137
140
|
// 必有请求)而无 usage 聚合时带 usageMissing: true(加法尾键,与 usage 同语义位)
|
|
138
141
|
const hasAssistant = log.events.some((e) => e.kind === 'assistant' && e.turnId === turnId)
|
|
142
|
+
appendSettlement(log, turnId, meta, hints)
|
|
139
143
|
return log.append('runtime', 'turnEnd', turnId, null, {
|
|
140
144
|
...meta,
|
|
141
145
|
...(usage ? { usage } : hasAssistant ? { usageMissing: true } : {}),
|
|
@@ -301,7 +305,8 @@ export async function runTurn(opts: {
|
|
|
301
305
|
const agg = preset.aggregate ?? {}
|
|
302
306
|
const abortedNow = (agg.terminate ?? 'all') === 'any' ? batch.terminateVotes > 0 : batch.terminateAll
|
|
303
307
|
if (abortedNow) { // terminate 收口:默认 AND(整批),可配置 any
|
|
304
|
-
|
|
308
|
+
// 1.24-W2:工具主动 stop 语义 → settlement stopRequested=true(hints 不落 meta,D-W2-4)
|
|
309
|
+
const seq = closeTurn({ reason: 'aborted' }, { stopRequested: true }).seq
|
|
305
310
|
trail.push({ seq, reason: 'aborted' })
|
|
306
311
|
return { reason: 'aborted', steps, endReasonTrail: trail }
|
|
307
312
|
}
|
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 事件链投影逐字节不变;1.22 加法扩展(1.22 迭代规划 D-B1):多块语义——一块一事件(多块链每事件 meta.blockIndex=块序,单块链 meta 与 1.21 逐字节同形),投影单块 = 1.21 三元组、多块 = blocks 数组(D-B2,消费方 toAnthropic
|
|
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 双形态展开);1.24-W2 加法扩展(Q-W2 / D-W2-1):system kind payload.type='settlement' 回合结算回执(actor='runtime',一 turn 一张——closeTurn〔turnEnd 之前〕与 recoverInterrupted 补记两产出点,字段见 loop/settlement.ts,CAR_SETTLEMENT=off 可关;model_visible=0 白名单不投影同 usage 纪律));
|
|
15
15
|
export type Actor = 'user' | 'model' | 'plugin' | 'runtime'
|
|
16
16
|
export interface SessionEvent {
|
|
17
17
|
seq: number
|
|
@@ -156,6 +156,10 @@ export class SessionLog {
|
|
|
156
156
|
let pendingThinkingTurn: string | null = null
|
|
157
157
|
let pendingBlocks: Array<{ text: string; signature?: string; redacted?: boolean }> = []
|
|
158
158
|
for (const e of projected) {
|
|
159
|
+
// 1.24-W2(D-W2-1):settlement 回执不投影(model_visible=0 同 usage 纪律——结算凭据是
|
|
160
|
+
// 审计面事实非模型上下文;system kind 语义位但 payload.type 判别排除,先于 thinking
|
|
161
|
+
// 隔断检查,杜绝任何投影面影响;无 settlement 链投影逐字节不变)
|
|
162
|
+
if (e.kind === 'system' && (e.payload as { type?: unknown } | null)?.type === 'settlement') continue
|
|
159
163
|
if (pendingBlocks.length && (e.turnId !== pendingThinkingTurn || e.kind === 'user' || e.kind === 'system')) pendingBlocks = []
|
|
160
164
|
if (e.kind === 'thinking') {
|
|
161
165
|
const p = typeof e.payload === 'string' ? e.payload : ''
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"base64Signature":"MEYCIQDW2ZdCjKblGFqrvmJOVOwajIkbcz3Y5rSVCO/xoU0CgwIhALOUpcq1yOaJXrvFJPepFRLaUqz1gAcNINk5Ix81rKrv","cert":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUc2VENDQm02Z0F3SUJBZ0lVVUhrY0dRTEVYcnFOWFdNSzN0TnQxaE01R3ljd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpZeE1URTFNRGN5TXpBeVdoY05Nall4TVRFMU1EY3pNekF5V2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVIWU1COWxHSExQelVFd291cFB1S2s5OExENnpsZzlyUURaY3oKR2g2YzhZY0N0a0VUVnZnN0g2eU5UL3VudjA3VG0raEdSVVNoUHBkVTFxekNCT1A3NWFPQ0JZMHdnZ1dKTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWZCZ05WSFNNRUdEQVdnQlRmCjArblBWaVFSbHZtbzJPa29WYUxHTGhoa1B6QmlCZ05WSFJFQkFmOEVXREJXaGxSb2RIUndjem92TDJkcGRHaDEKWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHpMM0psYkdWaApjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakl6TGpBd09RWUtLd1lCQkFHRHZ6QUJBUVFyYUhSMGNITTZMeTkwCmIydGxiaTVoWTNScGIyNXpMbWRwZEdoMVluVnpaWEpqYjI1MFpXNTBMbU52YlRBVkJnb3JCZ0VFQVlPL01BRUMKQkFkeVpXeGxZWE5sTURZR0Npc0dBUVFCZzc4d0FRTUVLRFUwTURWa1lqbGlaR0U0TURaak0yTXpaV1ZrWVRVMwpOV014WldJMFlXVTBPREE0WWpWaE16SXdGUVlLS3dZQkJBR0R2ekFCQkFRSGNtVnNaV0Z6WlRBZ0Jnb3JCZ0VFCkFZTy9NQUVGQkJKc2NXTTJNalF2WTJGeUxYSjFiblJwYldVd0hnWUtLd1lCQkFHRHZ6QUJCZ1FRY21WbWN5OTAKWVdkekx6RXVNak11TURBN0Jnb3JCZ0VFQVlPL01BRUlCQzBNSzJoMGRIQnpPaTh2ZEc5clpXNHVZV04wYVc5dQpjeTVuYVhSb2RXSjFjMlZ5WTI5dWRHVnVkQzVqYjIwd1pBWUtLd1lCQkFHRHZ6QUJDUVJXREZSb2RIUndjem92CkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHoKTDNKbGJHVmhjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakl6TGpBd09BWUtLd1lCQkFHRHZ6QUJDZ1FxRENnMQpOREExWkdJNVltUmhPREEyWXpOak0yVmxaR0UxTnpWak1XVmlOR0ZsTkRnd09HSTFZVE15TUIwR0Npc0dBUVFCCmc3OHdBUXNFRHd3TloybDBhSFZpTFdodmMzUmxaREExQmdvckJnRUVBWU8vTUFFTUJDY01KV2gwZEhCek9pOHYKWjJsMGFIVmlMbU52YlM5c2NXTTJNalF2WTJGeUxYSjFiblJwYldVd09BWUtLd1lCQkFHRHZ6QUJEUVFxRENnMQpOREExWkdJNVltUmhPREEyWXpOak0yVmxaR0UxTnpWak1XVmlOR0ZsTkRnd09HSTFZVE15TUNBR0Npc0dBUVFCCmc3OHdBUTRFRWd3UWNtVm1jeTkwWVdkekx6RXVNak11TURBYUJnb3JCZ0VFQVlPL01BRVBCQXdNQ2pFek5qRXgKT1RJM01UUXdLUVlLS3dZQkJBR0R2ekFCRUFRYkRCbG9kSFJ3Y3pvdkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMApNQmdHQ2lzR0FRUUJnNzh3QVJFRUNnd0lOamt5TXpRMU5qUXdaQVlLS3dZQkJBR0R2ekFCRWdSV0RGUm9kSFJ3CmN6b3ZMMmRwZEdoMVlpNWpiMjB2YkhGak5qSTBMMk5oY2kxeWRXNTBhVzFsTHk1bmFYUm9kV0l2ZDI5eWEyWnMKYjNkekwzSmxiR1ZoYzJVdWVXMXNRSEpsWm5NdmRHRm5jeTh4TGpJekxqQXdPQVlLS3dZQkJBR0R2ekFCRXdRcQpEQ2cxTkRBMVpHSTVZbVJoT0RBMll6TmpNMlZsWkdFMU56VmpNV1ZpTkdGbE5EZ3dPR0kxWVRNeU1CY0dDaXNHCkFRUUJnNzh3QVJRRUNRd0hjbVZzWldGelpUQlpCZ29yQmdFRUFZTy9NQUVWQkVzTVNXaDBkSEJ6T2k4dloybDAKYUhWaUxtTnZiUzlzY1dNMk1qUXZZMkZ5TFhKMWJuUnBiV1V2WVdOMGFXOXVjeTl5ZFc1ekx6UXpOamc1TmpnNApNekV3TDJGMGRHVnRjSFJ6THpFd0ZnWUtLd1lCQkFHRHZ6QUJGZ1FJREFad2RXSnNhV013VUFZS0t3WUJCQUdECnZ6QUJHQVJDREVCeVpYQnZPbXh4WXpZeU5FQTJPVEl6TkRVMk5DOWpZWEl0Y25WdWRHbHRaVUF4TXpZeE1Ua3kKTnpFME9uSmxaanB5WldaekwzUmhaM012TVM0eU15NHdNSUdMQmdvckJnRUVBZFo1QWdRQ0JIMEVld0I1QUhjQQozVDB3YXNiSEVUSmpHUjRjbVdjM0FxSktYcmplUEszL2g0cHlnQzhwN280QUFBR2gzaGFQbmdBQUJBTUFTREJHCkFpRUF2Wkp2ZFdYdHZXc2VxOWR5MGRjWU43L0F3Q1BJZ0dRV3FMME1oTWZZb0xnQ0lRRDdYTk1sVnZ4VGE2ZUQKZVZ3ZEczcGhjZWh4NVhrTTZqVTdyRkY4VmpTdyt6QUtCZ2dxaGtqT1BRUURBd05wQURCbUFqRUFnaUptNlBGQwprWjV5bHNDaW42a0pFQkFHVjZyRW1QV0xxQW5yak5seDRUVnRZSnBHMm5UQThJNFBRRkFrV0ROdUFqRUF6dlJqCmg3dEhTNVQzYWlBVXZvVmlMZmZnSlgzMk52dk5RdFJCWndZQlBya3F2RW40OU0weFBoa0VqQWZ5TVdiQwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==","rekorBundle":{"SignedEntryTimestamp":"MEQCIDFX1LK6tAMq5Zen3TbpVZE22INBCyh2O1gxEqUxIE8MAiA6L4cok518P7smZs+PnaPqiaXNB3zTFGx8g3v3hJW4/g==","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI2ZTYyZGMxNmZlNjEyYjdiYjUyNGE4MjMzYzYwNDI4YjFhNmY3NjY4NWRkOWQ5ZGE3NWRjNzc0OWVhZGQwY2YwIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FWUNJUURXMlpkQ2pLYmxHRnFydm1KT1ZPd2FqSWtiY3ozWTVyU1ZDTy94b1UwQ2d3SWhBTE9VcGNxMXlPYUpYcnZGSlBlcEZSTGFVcXoxZ0FjTklOazVJeDgxcktydiIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVYzJWRU5EUW0wMlowRjNTVUpCWjBsVlZVaHJZMGRSVEVWWWNuRk9XRmROU3pOMFRuUXhhRTAxUjNsamQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFVUlRGTlJHTjVUWHBCZVZkb1kwNU5hbGw0VFZSRk1VMUVZM3BOZWtGNVYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZJV1UxQ09XeEhTRXhRZWxWRmQyOTFjRkIxUzJzNU9FeEVObnBzWnpseVVVUmFZM29LUjJnMll6aFpZME4wYTBWVVZuWm5OMGcyZVU1VUwzVnVkakEzVkcwcmFFZFNWVk5vVUhCa1ZURnhla05DVDFBM05XRlBRMEpaTUhkbloxZEtUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFtbENaMDVXU0ZKRlFrRm1PRVZYUkVKWGFHeFNiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmlTRVpxVG1wSk1Fd3lUbWhqYVRGNVpGYzFNR0ZYTVd4TWVUVnVZVmhTYjJSWFNYWmtNamw1WVRKYWMySXpaSHBNTTBwc1lrZFdhQXBqTWxWMVpWY3hjMUZJU214YWJrMTJaRWRHYm1ONU9IaE1ha2w2VEdwQmQwOVJXVXRMZDFsQ1FrRkhSSFo2UVVKQlVWRnlZVWhTTUdOSVRUWk1lVGt3Q21JeWRHeGlhVFZvV1ROU2NHSXlOWHBNYldSd1pFZG9NVmx1Vm5wYVdFcHFZakkxTUZwWE5UQk1iVTUyWWxSQlZrSm5iM0pDWjBWRlFWbFBMMDFCUlVNS1FrRmtlVnBYZUd4WldFNXNUVVJaUjBOcGMwZEJVVkZDWnpjNGQwRlJUVVZMUkZVd1RVUldhMWxxYkdsYVIwVTBUVVJhYWsweVRYcGFWMVpyV1ZSVk13cE9WMDE0V2xkSk1GbFhWVEJQUkVFMFdXcFdhRTE2U1hkR1VWbExTM2RaUWtKQlIwUjJla0ZDUWtGUlNHTnRWbk5hVjBaNldsUkJaMEpuYjNKQ1owVkZDa0ZaVHk5TlFVVkdRa0pLYzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMGhuV1V0TGQxbENRa0ZIUkhaNlFVSkNaMUZSWTIxV2JXTjVPVEFLV1Zka2VreDZSWFZOYWsxMVRVUkJOMEpuYjNKQ1owVkZRVmxQTDAxQlJVbENRekJOU3pKb01HUklRbnBQYVRoMlpFYzVjbHBYTkhWWlYwNHdZVmM1ZFFwamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcVlqSXdkMXBCV1V0TGQxbENRa0ZIUkhaNlFVSkRVVkpYUkVaU2IyUklVbmRqZW05MkNrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUV3eVRtaGphVEY1WkZjMU1HRlhNV3hNZVRWdVlWaFNiMlJYU1haa01qbDVZVEphYzJJelpIb0tURE5LYkdKSFZtaGpNbFYxWlZjeGMxRklTbXhhYmsxMlpFZEdibU41T0hoTWFrbDZUR3BCZDA5QldVdExkMWxDUWtGSFJIWjZRVUpEWjFGeFJFTm5NUXBPUkVFeFdrZEpOVmx0VW1oUFJFRXlXWHBPYWsweVZteGFSMFV4VG5wV2FrMVhWbWxPUjBac1RrUm5kMDlIU1RGWlZFMTVUVUl3UjBOcGMwZEJVVkZDQ21jM09IZEJVWE5GUkhkM1Rsb3liREJoU0ZacFRGZG9kbU16VW14YVJFRXhRbWR2Y2tKblJVVkJXVTh2VFVGRlRVSkRZMDFLVjJnd1pFaENlazlwT0hZS1dqSnNNR0ZJVm1sTWJVNTJZbE01YzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMDlCV1V0TGQxbENRa0ZIUkhaNlFVSkVVVkZ4UkVObk1RcE9SRUV4V2tkSk5WbHRVbWhQUkVFeVdYcE9hazB5Vm14YVIwVXhUbnBXYWsxWFZtbE9SMFpzVGtSbmQwOUhTVEZaVkUxNVRVTkJSME5wYzBkQlVWRkNDbWMzT0hkQlVUUkZSV2QzVVdOdFZtMWplVGt3V1Zka2VreDZSWFZOYWsxMVRVUkJZVUpuYjNKQ1owVkZRVmxQTDAxQlJWQkNRWGROUTJwRmVrNXFSWGdLVDFSSk0wMVVVWGRMVVZsTFMzZFpRa0pCUjBSMmVrRkNSVUZSWWtSQ2JHOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUFwTlFtZEhRMmx6UjBGUlVVSm5OemgzUVZKRlJVTm5kMGxPYW10NVRYcFJNVTVxVVhkYVFWbExTM2RaUWtKQlIwUjJla0ZDUldkU1YwUkdVbTlrU0ZKM0NtTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJZa2hHYWs1cVNUQk1NazVvWTJreGVXUlhOVEJoVnpGc1RIazFibUZZVW05a1YwbDJaREk1ZVdFeVduTUtZak5rZWt3elNteGlSMVpvWXpKVmRXVlhNWE5SU0Vwc1dtNU5kbVJIUm01amVUaDRUR3BKZWt4cVFYZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JYZFJjUXBFUTJjeFRrUkJNVnBIU1RWWmJWSm9UMFJCTWxsNlRtcE5NbFpzV2tkRk1VNTZWbXBOVjFacFRrZEdiRTVFWjNkUFIwa3hXVlJOZVUxQ1kwZERhWE5IQ2tGUlVVSm5OemgzUVZKUlJVTlJkMGhqYlZaeldsZEdlbHBVUWxwQ1oyOXlRbWRGUlVGWlR5OU5RVVZXUWtWelRWTlhhREJrU0VKNlQyazRkbG95YkRBS1lVaFdhVXh0VG5aaVV6bHpZMWROTWsxcVVYWlpNa1o1VEZoS01XSnVVbkJpVjFWMldWZE9NR0ZYT1hWamVUbDVaRmMxZWt4NlVYcE9hbWMxVG1wbk5BcE5la1YzVERKR01HUkhWblJqU0ZKNlRIcEZkMFpuV1V0TGQxbENRa0ZIUkhaNlFVSkdaMUZKUkVGYWQyUlhTbk5oVjAxM1ZVRlpTMHQzV1VKQ1FVZEVDblo2UVVKSFFWSkRSRVZDZVZwWVFuWlBiWGg0V1hwWmVVNUZRVEpQVkVsNlRrUlZNazVET1dwWldFbDBZMjVXZFdSSGJIUmFWVUY0VFhwWmVFMVVhM2tLVG5wRk1FOXVTbXhhYW5CNVdsZGFla3d6VW1oYU0wMTJUVk0wZVUxNU5IZE5TVWRNUW1kdmNrSm5SVVZCWkZvMVFXZFJRMEpJTUVWbGQwSTFRVWhqUVFvelZEQjNZWE5pU0VWVVNtcEhValJqYlZkak0wRnhTa3RZY21wbFVFc3pMMmcwY0hsblF6aHdOMjgwUVVGQlIyZ3phR0ZRYm1kQlFVSkJUVUZUUkVKSENrRnBSVUYyV2twMlpGZFlkSFpYYzJWeE9XUjVNR1JqV1U0M0wwRjNRMUJKWjBkUlYzRk1NRTFvVFdaWmIweG5RMGxSUkRkWVRrMXNWblo0VkdFMlpVUUtaVlozWkVjemNHaGpaV2g0TlZoclRUWnFWVGR5UmtZNFZtcFRkeXQ2UVV0Q1oyZHhhR3RxVDFCUlVVUkJkMDV3UVVSQ2JVRnFSVUZuYVVwdE5sQkdRd3ByV2pWNWJITkRhVzQyYTBwRlFrRkhWalp5UlcxUVYweHhRVzV5YWs1c2VEUlVWblJaU25CSE1tNVVRVGhKTkZCUlJrRnJWMFJPZFVGcVJVRjZkbEpxQ21nM2RFaFROVlF6WVdsQlZYWnZWbWxNWm1ablNsZ3pNazUyZGs1UmRGSkNXbmRaUWxCeWEzRjJSVzQwT1Uwd2VGQm9hMFZxUVdaNVRWZGlRd290TFMwdExVVk9SQ0JEUlZKVVNVWkpRMEZVUlMwdExTMHRDZz09In19fX0=","integratedTime":1794727383,"logIndex":3896882215,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}
|