Skip to content

Add interpolated-intent and fallback-list render modes#1015

Open
lorisleiva wants to merge 1 commit into
06-24-add_display_value_formatting_and_provide_inject_resolutionfrom
06-25-add_interpolated-intent_and_fallback-list_render_modes
Open

Add interpolated-intent and fallback-list render modes#1015
lorisleiva wants to merge 1 commit into
06-24-add_display_value_formatting_and_provide_inject_resolutionfrom
06-25-add_interpolated-intent_and_fallback-list_render_modes

Conversation

@lorisleiva

Copy link
Copy Markdown
Member

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.

@changeset-bot

changeset-bot Bot commented Jun 25, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 68a6c47

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

lorisleiva commented Jun 25, 2026

Copy link
Copy Markdown
Member Author

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.
Learn more

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));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If i'm not mistaken, DisplaySkip could be imported from import { type DisplaySkip } from 'codama';

Suggested change
skip: 'always' | 'never' | 'whenInjected' | undefined,
skip: DisplaySkip | undefined,

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 + resolveDefinedType support to thread instruction/data/accounts/provides through display helpers.
  • Adds interpolateIntent and listFallback render modes plus formatArgumentValue/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.

Comment on lines +100 to +107
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));
}
Comment on lines +14 to +16
* 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));

@mikhd mikhd Jun 26, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 } }

@lorisleiva lorisleiva force-pushed the 06-25-add_interpolated-intent_and_fallback-list_render_modes branch from 10776b0 to 8480e88 Compare July 7, 2026 09:49
@lorisleiva lorisleiva force-pushed the 06-24-add_display_value_formatting_and_provide_inject_resolution branch from 7bb6f3f to 47131a5 Compare July 7, 2026 09:49
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.
@lorisleiva lorisleiva force-pushed the 06-25-add_interpolated-intent_and_fallback-list_render_modes branch from 8480e88 to 68a6c47 Compare July 8, 2026 08:25
@lorisleiva lorisleiva force-pushed the 06-24-add_display_value_formatting_and_provide_inject_resolution branch from 47131a5 to b15ad3e Compare July 8, 2026 08:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants