Skip to content

Commit 9cdb046

Browse files
committed
fix: update v0.3 proto converter to handle raw binary payloads instead of base64 strings
1 parent 35964f8 commit 9cdb046

8 files changed

Lines changed: 86 additions & 145 deletions

File tree

docs/compatibility-v0_3.md

Lines changed: 48 additions & 88 deletions
Large diffs are not rendered by default.

docs/migration-guide.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,6 @@ switch (part.content?.$case) {
7979
| `FilePart.file.uri` | `Part.content` with `$case: 'url'` |
8080
| `FilePart.file.bytes` | `Part.content` with `$case: 'raw'` |
8181

82-
> **Encoding difference.** In v0.3 the SDK exposed file bytes as a
83-
> base64-encoded string (`FilePart.file.bytes: string`); user code was
84-
> expected to `atob(...)` / `Buffer.from(bytes, 'base64')` to recover the
85-
> payload. In v1.0 `Part.content.value` for `$case: 'raw'` is a `Uint8Array`
86-
> (or Node `Buffer`) of raw decoded bytes — no explicit decode step. If your
87-
> migration mixes v1.0 and v0.3 peers and you exchange raw binary payloads
88-
> over gRPC or HTTP+JSON, read the [`file_with_bytes` wire encoding section](compatibility-v0_3.md#file_with_bytes-wire-encoding)
89-
> of the v0.3 compat guide for the wire-shape considerations.
90-
9182
### 1.2 `kind` Discriminator Removed
9283

9384
The `kind` field has been removed from `Message`, `Task`,

itk/scenarios.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@
6363
"behavior": "resubscribe"
6464
},
6565
{
66-
"name": "Current vs Python v03 - Send Message (Non-Streaming)",
67-
"sdks": ["current", "python_v03"],
66+
"name": "Current vs TS v03 - Send Message (Non-Streaming)",
67+
"sdks": ["current", "ts_v03"],
6868
"traversal": "euler",
6969
"edges": ["0->1", "1->0"],
7070
"protocols": [
@@ -75,8 +75,8 @@
7575
"behavior": "send_message"
7676
},
7777
{
78-
"name": "Current vs Python v03 - Send Message (Streaming)",
79-
"sdks": ["current", "python_v03"],
78+
"name": "Current vs TS v03 - Send Message (Streaming)",
79+
"sdks": ["current", "ts_v03"],
8080
"traversal": "euler",
8181
"edges": ["0->1", "1->0"],
8282
"protocols": [
@@ -88,8 +88,8 @@
8888
"behavior": "send_message"
8989
},
9090
{
91-
"name": "Current vs Python v03 - Push Notification",
92-
"sdks": ["current", "python_v03"],
91+
"name": "Current vs TS v03 - Push Notification",
92+
"sdks": ["current", "ts_v03"],
9393
"traversal": "euler",
9494
"edges": ["0->1", "1->0"],
9595
"protocols": [
@@ -100,8 +100,8 @@
100100
"behavior": "push_notification"
101101
},
102102
{
103-
"name": "Current vs Python v03 - Resubscribe",
104-
"sdks": ["current", "python_v03"],
103+
"name": "Current vs TS v03 - Resubscribe",
104+
"sdks": ["current", "ts_v03"],
105105
"traversal": "euler",
106106
"edges": ["0->1", "1->0"],
107107
"protocols": [

itk/scenarios_full.json

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,7 @@
5656
"traversal": "euler",
5757
"edges": ["0->1", "1->0"],
5858
"protocols": [
59-
"jsonrpc",
60-
"grpc",
61-
"http_json"
59+
"jsonrpc"
6260
],
6361
"behavior": "send_message"
6462
},
@@ -68,9 +66,7 @@
6866
"traversal": "euler",
6967
"edges": ["0->1", "1->0"],
7068
"protocols": [
71-
"jsonrpc",
72-
"grpc",
73-
"http_json"
69+
"jsonrpc"
7470
],
7571
"streaming": true,
7672
"behavior": "send_message"
@@ -81,9 +77,7 @@
8177
"traversal": "euler",
8278
"edges": ["0->1", "1->0"],
8379
"protocols": [
84-
"jsonrpc",
85-
"grpc",
86-
"http_json"
80+
"jsonrpc"
8781
],
8882
"behavior": "push_notification"
8983
},
@@ -93,9 +87,7 @@
9387
"traversal": "euler",
9488
"edges": ["0->1", "1->0"],
9589
"protocols": [
96-
"jsonrpc",
97-
"grpc",
98-
"http_json"
90+
"jsonrpc"
9991
],
10092
"streaming": true,
10193
"behavior": "resubscribe"
@@ -156,8 +148,7 @@
156148
"traversal": "euler",
157149
"edges": ["0->1", "1->0"],
158150
"protocols": [
159-
"jsonrpc",
160-
"grpc"
151+
"jsonrpc"
161152
],
162153
"behavior": "send_message"
163154
},
@@ -167,8 +158,7 @@
167158
"traversal": "euler",
168159
"edges": ["0->1", "1->0"],
169160
"protocols": [
170-
"jsonrpc",
171-
"grpc"
161+
"jsonrpc"
172162
],
173163
"streaming": true,
174164
"behavior": "send_message"
@@ -179,8 +169,7 @@
179169
"traversal": "euler",
180170
"edges": ["0->1", "1->0"],
181171
"protocols": [
182-
"jsonrpc",
183-
"grpc"
172+
"jsonrpc"
184173
],
185174
"behavior": "push_notification"
186175
},
@@ -190,8 +179,7 @@
190179
"traversal": "euler",
191180
"edges": ["0->1", "1->0"],
192181
"protocols": [
193-
"jsonrpc",
194-
"grpc"
182+
"jsonrpc"
195183
],
196184
"streaming": true,
197185
"behavior": "resubscribe"
@@ -252,7 +240,9 @@
252240
"traversal": "euler",
253241
"edges": ["0->1", "1->0"],
254242
"protocols": [
255-
"jsonrpc"
243+
"jsonrpc",
244+
"grpc",
245+
"http_json"
256246
],
257247
"behavior": "send_message"
258248
},
@@ -262,7 +252,9 @@
262252
"traversal": "euler",
263253
"edges": ["0->1", "1->0"],
264254
"protocols": [
265-
"jsonrpc"
255+
"jsonrpc",
256+
"grpc",
257+
"http_json"
266258
],
267259
"streaming": true,
268260
"behavior": "send_message"
@@ -273,7 +265,9 @@
273265
"traversal": "euler",
274266
"edges": ["0->1", "1->0"],
275267
"protocols": [
276-
"jsonrpc"
268+
"jsonrpc",
269+
"grpc",
270+
"http_json"
277271
],
278272
"behavior": "push_notification"
279273
},
@@ -283,7 +277,9 @@
283277
"traversal": "euler",
284278
"edges": ["0->1", "1->0"],
285279
"protocols": [
286-
"jsonrpc"
280+
"jsonrpc",
281+
"grpc",
282+
"http_json"
287283
],
288284
"streaming": true,
289285
"behavior": "resubscribe"

src/compat/v0_3/types/converters/from_proto.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ export class FromProto {
188188
return {
189189
kind: 'file',
190190
file: {
191-
bytes: Buffer.from(filePart.file.value).toString('utf8'),
191+
bytes: Buffer.from(filePart.file.value).toString('base64'),
192192
mimeType: filePart.mimeType,
193193
},
194194
};

src/compat/v0_3/types/converters/to_proto.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ export class ToProto {
517517
};
518518
} else if ('bytes' in part.file) {
519519
filePart = {
520-
file: { $case: 'fileWithBytes', value: Buffer.from(part.file.bytes, 'utf8') },
520+
file: { $case: 'fileWithBytes', value: Buffer.from(part.file.bytes, 'base64') },
521521
mimeType: part.file.mimeType ?? '',
522522
};
523523
} else {

test/compat/v0_3/types/converters/from_proto.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,13 @@ describe('FromProto', () => {
186186
});
187187
});
188188

189-
it('should convert a file part with bytes (v0.3 wire convention)', () => {
190-
const base64Bytes = Buffer.from('file content').toString('base64');
191-
const wireBytes = Buffer.from(base64Bytes, 'utf8');
189+
it('should convert a file part with bytes (proto3-compliant raw payload)', () => {
190+
const rawPayload = Buffer.from('file content');
191+
const base64Bytes = rawPayload.toString('base64');
192192
const part: proto.Part = {
193193
part: {
194194
$case: 'file',
195-
value: { file: { $case: 'fileWithBytes', value: wireBytes }, mimeType: 'text/plain' },
195+
value: { file: { $case: 'fileWithBytes', value: rawPayload }, mimeType: 'text/plain' },
196196
},
197197
};
198198
const result = FromProto.part(part);

test/compat/v0_3/types/converters/to_proto.spec.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,9 @@ describe('ToProto', () => {
117117
});
118118
});
119119

120-
it('should convert a file part with bytes (v0.3 wire convention)', () => {
121-
// Per v0.3 SDK interop: `file_with_bytes` over gRPC carries the
122-
// base64 string's UTF-8 bytes (NOT the decoded raw payload).
123-
// a2a-go v0.3 emits `[]byte(fc.Bytes)` where `fc.Bytes` is the
124-
// base64 string; a2a-python v0.3 does the equivalent. The proto
125-
// spec says raw bytes, but the de-facto wire format across the
126-
// v0.3 reference SDKs is base64-string-as-bytes, so we match it
127-
// here for cross-SDK interop.
128-
const base64Bytes = Buffer.from('file content').toString('base64');
120+
it('should convert a file part with bytes (proto3-compliant raw payload)', () => {
121+
const rawPayload = Buffer.from('file content');
122+
const base64Bytes = rawPayload.toString('base64');
129123
const part: types.Part = {
130124
kind: 'file',
131125
file: { bytes: base64Bytes, mimeType: 'application/octet-stream' },
@@ -135,7 +129,7 @@ describe('ToProto', () => {
135129
part: {
136130
$case: 'file',
137131
value: {
138-
file: { $case: 'fileWithBytes', value: Buffer.from(base64Bytes, 'utf8') },
132+
file: { $case: 'fileWithBytes', value: rawPayload },
139133
mimeType: 'application/octet-stream',
140134
},
141135
},

0 commit comments

Comments
 (0)