@@ -5,7 +5,7 @@ import { tmpdir } from 'node:os';
55import { join } from 'node:path' ;
66
77import { grpcFrame } from '../src/grpc.js' ;
8- import { writeBoolField , writeMessageField , writeStringField , writeVarintField } from '../src/proto.js' ;
8+ import { writeBoolField , writeBytesField , writeMessageField , writeStringField , writeVarintField } from '../src/proto.js' ;
99import { buildSendCascadeMessageRequest } from '../src/windsurf.js' ;
1010import {
1111 _resetProtoTraceForTests ,
@@ -139,6 +139,36 @@ describe('proto trace', () => {
139139 assert . ok ( grep . bytes > 0 ) ;
140140 } ) ;
141141
142+ it ( 'summarizes unknown native tool config fields for web matrix experiments' , ( ) => {
143+ process . env . WINDSURFAPI_PROTO_TRACE = '1' ;
144+ const toolConfig = Buffer . concat ( [
145+ writeMessageField ( 42 , writeStringField ( 1 , 'web' ) ) ,
146+ writeBytesField ( 40 , Buffer . alloc ( 0 ) ) ,
147+ writeStringField ( 32 , 'search_web' ) ,
148+ writeStringField ( 32 , 'read_url_content' ) ,
149+ ] ) ;
150+ const planner = writeMessageField ( 13 , toolConfig ) ;
151+ const cascadeConfig = writeMessageField ( 1 , planner ) ;
152+ const proto = writeMessageField ( 5 , cascadeConfig ) ;
153+
154+ traceGrpcPayload ( {
155+ port : 42100 ,
156+ path : '/exa.language_server_pb.LanguageServerService/SendUserCascadeMessage' ,
157+ direction : 'request' ,
158+ body : grpcFrame ( proto ) ,
159+ transport : 'grpc' ,
160+ framed : true ,
161+ } ) ;
162+
163+ const file = join ( dir , `ls-proto-${ process . pid } -SendUserCascadeMessage.jsonl` ) ;
164+ const rec = JSON . parse ( readFileSync ( file , 'utf8' ) . trim ( ) ) ;
165+ assert . deepEqual ( rec . semantic . nativeToolConfig . allowlist , [ 'search_web' , 'read_url_content' ] ) ;
166+ assert . deepEqual ( rec . semantic . nativeToolConfig . subconfigFields , [ ] ) ;
167+ assert . deepEqual ( rec . semantic . nativeToolConfig . unknownFields . map ( f => f . field ) , [ 42 , 40 ] ) ;
168+ assert . deepEqual ( rec . semantic . nativeToolConfig . unknownFields [ 0 ] . summary . fieldNumbers , [ 1 ] ) ;
169+ assert . equal ( rec . semantic . nativeToolConfig . unknownFields [ 1 ] . bytes , 0 ) ;
170+ } ) ;
171+
142172 it ( 'adds semantic GetCascadeTrajectorySteps native oneof summaries' , ( ) => {
143173 process . env . WINDSURFAPI_PROTO_TRACE = '1' ;
144174 const grepBody = Buffer . concat ( [
@@ -172,6 +202,57 @@ describe('proto trace', () => {
172202 assert . equal ( rec . semantic . steps [ 0 ] . nativeOneofs [ 0 ] . body . rawOutputBytes , 'README.md\n' . length ) ;
173203 } ) ;
174204
205+ it ( 'summarizes web trajectory payload shapes for protocol diffing' , ( ) => {
206+ process . env . WINDSURFAPI_PROTO_TRACE = '1' ;
207+ const doc = Buffer . concat ( [
208+ writeStringField ( 1 , 'title' ) ,
209+ writeStringField ( 2 , 'https://example.com/' ) ,
210+ ] ) ;
211+ const searchBody = Buffer . concat ( [
212+ writeStringField ( 1 , 'WindsurfAPI native bridge' ) ,
213+ writeMessageField ( 2 , doc ) ,
214+ writeStringField ( 3 , 'example.com' ) ,
215+ writeStringField ( 5 , 'summary' ) ,
216+ ] ) ;
217+ const fetchBody = Buffer . concat ( [
218+ writeStringField ( 1 , 'https://example.com/' ) ,
219+ writeMessageField ( 2 , doc ) ,
220+ writeStringField ( 5 , 'body summary' ) ,
221+ ] ) ;
222+ const response = Buffer . concat ( [
223+ writeMessageField ( 1 , Buffer . concat ( [
224+ writeVarintField ( 1 , 42 ) ,
225+ writeVarintField ( 4 , 3 ) ,
226+ writeMessageField ( 42 , searchBody ) ,
227+ ] ) ) ,
228+ writeMessageField ( 1 , Buffer . concat ( [
229+ writeVarintField ( 1 , 40 ) ,
230+ writeVarintField ( 4 , 3 ) ,
231+ writeMessageField ( 40 , fetchBody ) ,
232+ ] ) ) ,
233+ ] ) ;
234+ traceGrpcPayload ( {
235+ port : 42100 ,
236+ path : '/exa.language_server_pb.LanguageServerService/GetCascadeTrajectorySteps' ,
237+ direction : 'response' ,
238+ body : response ,
239+ transport : 'grpc' ,
240+ framed : false ,
241+ } ) ;
242+
243+ const file = join ( dir , `ls-proto-${ process . pid } -GetCascadeTrajectorySteps.jsonl` ) ;
244+ const rec = JSON . parse ( readFileSync ( file , 'utf8' ) . trim ( ) ) ;
245+ const search = rec . semantic . steps [ 0 ] . nativeOneofs [ 0 ] ;
246+ assert . equal ( search . kind , 'search_web' ) ;
247+ assert . equal ( search . body . webDocumentCount , 1 ) ;
248+ assert . deepEqual ( search . body . fieldNumbers , [ 1 , 2 , 3 , 5 ] ) ;
249+ assert . equal ( search . body . messageFields [ 0 ] . field , 2 ) ;
250+ const fetch = rec . semantic . steps [ 1 ] . nativeOneofs [ 0 ] ;
251+ assert . equal ( fetch . kind , 'read_url_content' ) ;
252+ assert . deepEqual ( fetch . body . fieldNumbers , [ 1 , 2 , 5 ] ) ;
253+ assert . equal ( fetch . body . messageFields [ 0 ] . field , 2 ) ;
254+ } ) ;
255+
175256 it ( 'summarizes non-oneof step message fields for protocol diffing' , ( ) => {
176257 process . env . WINDSURFAPI_PROTO_TRACE = '1' ;
177258 const viewWrapper = Buffer . concat ( [
0 commit comments