Add interpolated-intent and fallback-list render modes#1015
Conversation
|
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
| return value.toString(); | ||
| } | ||
| if (isObjectRecord(value) && typeof value.__kind === 'string') return titleCase(value.__kind); | ||
| return JSON.stringify(value, (_key, v: unknown) => (typeof v === 'bigint' ? v.toString() : v)); |
There was a problem hiding this comment.
Just in case, there is safeStringify in shared/util.
However, not sure it will be acceptable in this case to return non-serializable <value_type> instead of throwing and error when JSON.stringify fails.
| * (its value is surfaced elsewhere through the provide/inject graph); `'never'`/absent shows. | ||
| */ | ||
| function isSkipped( | ||
| skip: 'always' | 'never' | 'whenInjected' | undefined, |
There was a problem hiding this comment.
If i'm not mistaken, DisplaySkip could be imported from import { type DisplaySkip } from 'codama';
| skip: 'always' | 'never' | 'whenInjected' | undefined, | |
| skip: DisplaySkip | undefined, |
There was a problem hiding this comment.
Pull request overview
Adds new internal display-layer building blocks for dynamic instructions, enabling (1) interpolated intent sentence rendering and (2) a structured fallback list of labelled fields, all driven by a unified DisplayContext and a new formatArgumentValue bridge for type-aware formatting (amount/date-time/duration/string/enums + defined-type link following). Test utilities and display tests are updated/added to validate these behaviors.
Changes:
- Introduces
DisplayContext+resolveDefinedTypesupport to thread instruction/data/accounts/provides through display helpers. - Adds
interpolateIntentandlistFallbackrender modes plusformatArgumentValue/resolveDisplayType. - Expands the display test suite and centralizes test context creation.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/dynamic-instructions/test/test-utils.ts | Adds a shared displayContext helper for display-layer tests. |
| packages/dynamic-instructions/test/display/resolve-injected-value.test.ts | Updates tests to use the shared displayContext helper. |
| packages/dynamic-instructions/test/display/list-fallback.test.ts | New tests covering fallback list ordering, labels, skip rules, and struct flattening. |
| packages/dynamic-instructions/test/display/interpolate-intent.test.ts | New tests for interpolated intent rendering and null/fallback behavior. |
| packages/dynamic-instructions/test/display/format-value.test.ts | Updates tests to use the shared displayContext helper. |
| packages/dynamic-instructions/test/display/format-argument-value.test.ts | New tests for formatArgumentValue formatting and defined-type link resolution. |
| packages/dynamic-instructions/src/display/types.ts | Replaces DisplayResolutionContext with a richer DisplayContext and adds display-layer types/helpers. |
| packages/dynamic-instructions/src/display/resolve-injected-value.ts | Adapts injected-value resolution to the new DisplayContext type. |
| packages/dynamic-instructions/src/display/list-fallback.ts | Implements the structured fallback list render mode. |
| packages/dynamic-instructions/src/display/interpolate-intent.ts | Implements interpolated intent template rendering. |
| packages/dynamic-instructions/src/display/index.ts | Re-exports newly added display helpers for internal consumption. |
| packages/dynamic-instructions/src/display/format-value.ts | Updates formatter signatures to accept DisplayContext. |
| packages/dynamic-instructions/src/display/format-argument-value.ts | Adds the value-to-display bridge plus defined-type link resolution helper. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function rawValue(value: unknown): string { | ||
| if (typeof value === 'string') return value; | ||
| if (typeof value === 'bigint' || typeof value === 'number' || typeof value === 'boolean') { | ||
| return value.toString(); | ||
| } | ||
| if (isObjectRecord(value) && typeof value.__kind === 'string') return titleCase(value.__kind); | ||
| return JSON.stringify(value, (_key, v: unknown) => (typeof v === 'bigint' ? v.toString() : v)); | ||
| } |
| * Returns `null` when the instruction has no `interpolatedIntent`, or when any placeholder | ||
| * cannot be resolved (an unknown name, or a value whose formatting fails). A `null` result | ||
| * signals the caller to fall back to the structured field list. |
| return value.toString(); | ||
| } | ||
| if (isObjectRecord(value) && typeof value.__kind === 'string') return titleCase(value.__kind); | ||
| return JSON.stringify(value, (_key, v: unknown) => (typeof v === 'bigint' ? v.toString() : v)); |
There was a problem hiding this comment.
I think when value: unknown is undefined, then JSON.stringify(undefined) would return undefined instead of desired string.
I guess, this could happen when some key of context data is set to undefined - i.e.
displayContext { data: { decimals: undefined } }
10776b0 to
8480e88
Compare
7bb6f3f to
47131a5
Compare
This PR adds the two clear-signing render modes on top of the value layer (sRFC 39). interpolateIntent renders an instruction's interpolatedIntent template by substituting flat ${data.<argument>} and ${accounts.<account>} placeholders, returning null when the template is absent or a referenced name cannot be resolved so the caller can fall back. listFallback builds the structured fallback list of labelled fields for the instruction's arguments and accounts, honouring skip strategies (including whenInjected), label overrides, and struct flattening with prefixes. Both consume a new formatArgumentValue bridge that maps a decoded value to its type's display node — dispatching to the amount, date-time, duration, and string formatters, resolving linked enums to their variant labels, and degrading to a raw form when no display metadata applies. Defined-type links are followed through a single shared resolveDisplayType helper, and the whole display layer threads one flat DisplayContext (instruction, decoded data, account addresses, provide/inject graph, account fetching, and link resolution) so every piece stays unit-testable ahead of the orchestration PR. These remain internal building blocks, not yet exported from the package. No changeset is included, consistent with the rest of the 1.7.0 stack.
8480e88 to
68a6c47
Compare
47131a5 to
b15ad3e
Compare

This PR adds the two clear-signing render modes on top of the value layer (sRFC 39). interpolateIntent renders an instruction's interpolatedIntent template by substituting flat ${data.} and ${accounts.} placeholders, returning null when the template is absent or a referenced name cannot be resolved so the caller can fall back. listFallback builds the structured fallback list of labelled fields for the instruction's arguments and accounts, honouring skip strategies (including whenInjected), label overrides, and struct flattening with prefixes. Both consume a new formatArgumentValue bridge that maps a decoded value to its type's display node — dispatching to the amount, date-time, duration, and string formatters, resolving linked enums to their variant labels, and degrading to a raw form when no display metadata applies. Defined-type links are followed through a single shared resolveDisplayType helper, and the whole display layer threads one flat DisplayContext (instruction, decoded data, account addresses, provide/inject graph, account fetching, and link resolution) so every piece stays unit-testable ahead of the orchestration PR. These remain internal building blocks, not yet exported from the package. No changeset is included, consistent with the rest of the 1.7.0 stack.