exchange-format: Add buildExchangeFormatDirect() sender for 2.1.1
The orchestrator currently synthesises a wrapped Z7 inside WFCodeImpl.evaluate() solely to feed it to convertWrappedZObjectToExchangeFormat(), which then immediately walks back out through theFunction.Z8K4.K1.Z14K3.Z16K2.Z6K1, calls findFunctionIdentity() on the same synthesised Z8, etc., to produce a flat exchange-format request. That costly round-trip — including a fullImplementation.asZObject() deep materialisation whose only consumer is this serialisation — is paid on every Z14 evaluator call.
Add a sibling builder, buildExchangeFormatDirect(), that accepts orchestrator-native inputs (functionName, codeString, codingLanguage, returnTypeJSON, argumentEntries) and produces a bit-identical exchange-format request. The wire format is unchanged; this is a sender-side cleanup only, so recoverRequestFromExchangeFormat() and the evaluator side need no changes.
To keep the two builders identical by construction:
- Factor maybeGetSerializer() in exchangeFormatUtils.js into a sibling maybeGetSerializerFromReturnType(returnTypeJSON, programmingLanguage); the old name now delegates and stays exported.
- Extract the per-argument loop body in exchange-format-2.1.1.js into a private appendArgumentToExchangeFormat() helper used by both convertWrappedZObjectToExchangeFormat() and the new builder.
Tests: three parity cases (one per existing fixture) build the request both ways from the same source and deepEqual the results; a serializer-absence case and an empty-argumentEntries edge case round it out.
Also, rev. the format to 2.1.1 for T416161.