mirror of
https://github.com/simstudioai/sim.git
synced 2026-10-31 03:47:12 +08:00
fix(copilot): name a count-parallel's branch count count in the model's read view (#7082)
sanitizeForCopilot builds the workflow JSON the model reads before editing. For a loop it emits `iterations` from `block.data.count`, which is right: the loop write contract (components/blocks/loop.json) declares `iterations`, and the edit path reads `params.inputs.iterations` back into `data.count`. The parallel branch copied that line without renaming the field. But the parallel write contract (components/blocks/parallel.json) declares `count`, and the edit path reads `params.inputs.count` — so the model was shown a branch count under a name its own write contract does not define. Echoing it back drops the value silently: neither addSubflowConfig nor the update path looks for `iterations` on a parallel. Scoped to the copilot read/edit round-trip. sanitizeForExport is unaffected — it preserves state.blocks wholesale, so JSON export and folder backup/restore always carried the real data.count. The sanitizer had zero parallelType coverage, which is how this drifted. Adds three cases pinning both contracts and the collection variant; the parallel one fails against the old code.
This commit is contained in:
@@ -184,6 +184,58 @@ describe('sanitizeForCopilot product-gated block inputs', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('sanitizeForCopilot subflow config', () => {
|
||||
/**
|
||||
* The model's read view has to use the same field names as the write contract it is
|
||||
* given, or an echoed-back edit is silently dropped. `components/blocks/parallel.json`
|
||||
* declares `count`; `components/blocks/loop.json` declares `iterations`.
|
||||
*/
|
||||
it("names a count-parallel's branch count `count`, matching the parallel write contract", () => {
|
||||
const state = makeSingleBlockWorkflow('parallel-1', {
|
||||
type: 'parallel',
|
||||
name: 'Parallel 1',
|
||||
enabled: true,
|
||||
subBlocks: {},
|
||||
data: { parallelType: 'count', count: 5 },
|
||||
})
|
||||
|
||||
expect(sanitizeForCopilot(state).blocks['parallel-1'].inputs).toEqual({
|
||||
parallelType: 'count',
|
||||
count: 5,
|
||||
})
|
||||
})
|
||||
|
||||
it("names a for-loop's trip count `iterations`, matching the loop write contract", () => {
|
||||
const state = makeSingleBlockWorkflow('loop-1', {
|
||||
type: 'loop',
|
||||
name: 'Loop 1',
|
||||
enabled: true,
|
||||
subBlocks: {},
|
||||
data: { loopType: 'for', count: 3 },
|
||||
})
|
||||
|
||||
expect(sanitizeForCopilot(state).blocks['loop-1'].inputs).toEqual({
|
||||
loopType: 'for',
|
||||
iterations: 3,
|
||||
})
|
||||
})
|
||||
|
||||
it('exports a collection parallel without a branch count', () => {
|
||||
const state = makeSingleBlockWorkflow('parallel-2', {
|
||||
type: 'parallel',
|
||||
name: 'Parallel 2',
|
||||
enabled: true,
|
||||
subBlocks: {},
|
||||
data: { parallelType: 'collection', collection: '<start.items>' },
|
||||
})
|
||||
|
||||
expect(sanitizeForCopilot(state).blocks['parallel-2'].inputs).toEqual({
|
||||
parallelType: 'collection',
|
||||
collection: '<start.items>',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/** Builds a one-block workflow for webhook-URL synthesis tests. */
|
||||
function makeSingleBlockWorkflow(blockId: string, block: Record<string, unknown>): WorkflowState {
|
||||
return {
|
||||
|
||||
@@ -591,7 +591,11 @@ export function sanitizeForCopilot(
|
||||
loopInputs.parallelType = parallelType
|
||||
// Only export fields relevant to the current parallelType
|
||||
if (parallelType === 'count' && block.data?.count !== undefined) {
|
||||
loopInputs.iterations = block.data.count
|
||||
// `count`, not `iterations`: the parallel schema the model is given names this
|
||||
// field `count` and the edit path reads it back under that name. A loop's
|
||||
// equivalent field really is called `iterations` on both sides — copying that
|
||||
// line here made the model's read view disagree with its own write contract.
|
||||
loopInputs.count = block.data.count
|
||||
}
|
||||
if (parallelType === 'collection' && block.data?.collection !== undefined) {
|
||||
loopInputs.collection = block.data.collection
|
||||
|
||||
Reference in New Issue
Block a user