(apiKey, cascadeId, text, modelEnum, modelUid, sessionId, { toolPreamble, images, additionalSteps, nativeMode, nativeAllowlist, nativeEnvironment } = {})
| 329 | * sees the next user turn. See src/cascade-native-bridge.js. |
| 330 | */ |
| 331 | export function buildSendCascadeMessageRequest(apiKey, cascadeId, text, modelEnum, modelUid, sessionId, { toolPreamble, images, additionalSteps, nativeMode, nativeAllowlist, nativeEnvironment } = {}) { |
| 332 | const parts = []; |
| 333 | |
| 334 | // Field 1: cascade_id |
| 335 | parts.push(writeStringField(1, cascadeId)); |
| 336 | |
| 337 | // Field 2: TextOrScopeItem { text = 1 } |
| 338 | parts.push(writeMessageField(2, writeStringField(1, text))); |
| 339 | |
| 340 | // Field 3: metadata |
| 341 | parts.push(writeMessageField(3, buildMetadata(apiKey, undefined, sessionId))); |
| 342 | |
| 343 | // Field 5: cascade_config |
| 344 | // DEFAULT mode enables vision but also activates Cascade's built-in tools |
| 345 | // which conflict with our emulated tools. We force DEFAULT in two cases: |
| 346 | // - vision: images are attached AND no client tools are present. |
| 347 | // - native bridge: the caller's tools[] all map onto cascade-native |
| 348 | // IDE tools and v2.0.65 wants the planner's IDE agent loop alive |
| 349 | // (see src/cascade-native-bridge.js for rationale). |
| 350 | const forceDefault = !!nativeMode || (!!images?.length && !toolPreamble); |
| 351 | // v2.0.66 partition mode: when nativeMode is on AND a non-empty |
| 352 | // toolPreamble was provided, the caller has unmapped tools that need |
| 353 | // emulation alongside the mapped-tool native bridge. Pass toolPreamble |
| 354 | // through so additional_instructions_section still carries those tool |
| 355 | // definitions even though planner_mode is DEFAULT. |
| 356 | const cascadeConfig = buildCascadeConfig(modelEnum, modelUid, { |
| 357 | toolPreamble: toolPreamble || '', |
| 358 | forceDefault, |
| 359 | nativeMode: !!nativeMode, |
| 360 | nativeAllowlist: nativeAllowlist || null, |
| 361 | nativeEnvironment: nativeEnvironment || '', |
| 362 | }); |
| 363 | parts.push(writeMessageField(5, cascadeConfig)); |
| 364 | |
| 365 | // Field 6: images — repeated ImageData { base64_data=1, mime_type=2 } |
| 366 | if (images?.length) { |
| 367 | for (const img of images) { |
| 368 | const imgMsg = Buffer.concat([ |
| 369 | writeStringField(1, img.base64_data), |
| 370 | writeStringField(2, img.mime_type || 'image/png'), |
| 371 | ]); |
| 372 | parts.push(writeMessageField(6, imgMsg)); |
| 373 | } |
| 374 | } |
| 375 | |
| 376 | // Field 9: additional_steps — repeated CortexTrajectoryStep. The native |
| 377 | // bridge fills this with "we already executed view_file/run_command/... |
| 378 | // and here are the results" steps so the planner reasons from the |
| 379 | // post-tool state directly. |
| 380 | if (Array.isArray(additionalSteps) && additionalSteps.length) { |
| 381 | for (const stepBuf of additionalSteps) { |
| 382 | if (!stepBuf || !Buffer.isBuffer(stepBuf) || stepBuf.length === 0) continue; |
| 383 | parts.push(writeMessageField(9, stepBuf)); |
| 384 | } |
| 385 | } |
| 386 | |
| 387 | return Buffer.concat(parts); |
| 388 | } |
no test coverage detected