diff --git a/packages/agentscope/package.json b/packages/agentscope/package.json index b6b3603..4ec957a 100644 --- a/packages/agentscope/package.json +++ b/packages/agentscope/package.json @@ -1,6 +1,6 @@ { "name": "@agentscope-ai/agentscope", - "version": "0.0.6", + "version": "0.0.7", "description": "", "exports": { "./message": { diff --git a/packages/agentscope/src/message/append-event.test.ts b/packages/agentscope/src/message/append-event.test.ts index 811ec5f..b01249b 100644 --- a/packages/agentscope/src/message/append-event.test.ts +++ b/packages/agentscope/src/message/append-event.test.ts @@ -265,20 +265,29 @@ describe('appendEvent', () => { ]) ); + // Use independently base64-encoded chunks whose raw byte lengths + // aren't multiples of 3 — each chunk's base64 carries its own '=' + // padding. The accumulated base64 must equal base64(concat(raw + // bytes)), NOT string-concat of the per-chunk base64 (which would + // splice padding into the middle of the stream and corrupt it). + const DATA_CHUNK_1 = Buffer.from([0x01, 0x02]).toString('base64'); // "AQI=" + const DATA_CHUNK_2 = Buffer.from([0x03]).toString('base64'); // "Aw==" + const DATA_MERGED = Buffer.from([0x01, 0x02, 0x03]).toString('base64'); // "AQID" + events.push({ id: '10', created_at: '', type: EventType.DATA_BLOCK_DELTA, reply_id: REPLY_ID, block_id: B_DATA, - data: 'abc', + data: DATA_CHUNK_1, media_type: 'image/png', }); groundTruths.push( base([ tb(B_TEXT, 'Hello World'), thb(B_THINK, 'Let me think'), - dbB64(B_DATA, 'abc', 'image/png'), + dbB64(B_DATA, DATA_CHUNK_1, 'image/png'), ]) ); @@ -288,14 +297,14 @@ describe('appendEvent', () => { type: EventType.DATA_BLOCK_DELTA, reply_id: REPLY_ID, block_id: B_DATA, - data: 'def', + data: DATA_CHUNK_2, media_type: 'image/png', }); groundTruths.push( base([ tb(B_TEXT, 'Hello World'), thb(B_THINK, 'Let me think'), - dbB64(B_DATA, 'abcdef', 'image/png'), + dbB64(B_DATA, DATA_MERGED, 'image/png'), ]) ); @@ -310,7 +319,7 @@ describe('appendEvent', () => { base([ tb(B_TEXT, 'Hello World'), thb(B_THINK, 'Let me think'), - dbB64(B_DATA, 'abcdef', 'image/png'), + dbB64(B_DATA, DATA_MERGED, 'image/png'), ]) ); @@ -318,7 +327,7 @@ describe('appendEvent', () => { const s4Prefix = [ tb(B_TEXT, 'Hello World'), thb(B_THINK, 'Let me think'), - dbB64(B_DATA, 'abcdef', 'image/png'), + dbB64(B_DATA, DATA_MERGED, 'image/png'), ]; events.push({ diff --git a/packages/agentscope/src/message/message.ts b/packages/agentscope/src/message/message.ts index 6c1bc1c..30583d5 100644 --- a/packages/agentscope/src/message/message.ts +++ b/packages/agentscope/src/message/message.ts @@ -329,7 +329,14 @@ export function appendEvent(msg: Msg, event: AgentEvent): Msg { if (!block) { console.warn(`DataBlock "${event.block_id}" not found, skipping.`); } else if (event.data) { - ((block as DataBlock).source as Base64Source).data += event.data; + // Each delta is an independently base64-encoded chunk (with + // its own padding); naive string concat would inject '=' into + // the middle of the byte stream and corrupt it. Decode, concat + // bytes, re-encode. + const src = (block as DataBlock).source as Base64Source; + const existing = src.data ? Buffer.from(src.data, 'base64') : Buffer.alloc(0); + const incoming = Buffer.from(event.data, 'base64'); + src.data = Buffer.concat([existing, incoming]).toString('base64'); } break; }