feat(workflow-executor): handle polymorphic relations in load-related (skip + follow) [PRD-493]#1647
Conversation
… (skip + follow) [PRD-493]
The load-related step now handles polymorphic BelongsTo relations (e.g. Rails
`commentable`), which carry no single static target. A relation is followable
when it has a relatedCollectionName OR a polymorphicTypeField; unfollowable ones
are no longer offered to the AI or in the awaiting-input card.
For a polymorphic relation the concrete target is resolved per record: the
target type is read from the raw JSON:API linkage (data.relationships.<rel>.data
= { type, id }) — not a discriminator column, which Forest does not expose as a
field — then mapped to one of polymorphicReferencedModels (exact, then
case-insensitive). resolveTargetCollection centralises static + polymorphic
resolution and is used by buildRelationCandidates, buildTarget and the Branch A
re-entry path.
Depends on the orchestrator exposing polymorphicTypeField /
polymorphicReferencedModels (forestadmin-server PRD-493).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2 new issues
|
|
|
||
| const body = (await response.json()) as { | ||
| data?: { relationships?: Record<string, { data?: { type?: string; id?: string } | null }> }; | ||
| }; |
There was a problem hiding this comment.
🟡 Medium adapters/agent-client-agent-port.ts:276
resolvePolymorphicType returns { type, id: "undefined" } when the agent returns a linkage with type but no id (e.g., { type: 'orders' }). String(linkage.id) produces the string "undefined" rather than null, unlike getSingleRelatedData which guards against missing id. Downstream fetches will fail when trying to retrieve record "undefined". Consider adding the same guard: return null unless both type and id are present.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/workflow-executor/src/adapters/agent-client-agent-port.ts around line 276:
`resolvePolymorphicType` returns `{ type, id: "undefined" }` when the agent returns a linkage with `type` but no `id` (e.g., `{ type: 'orders' }`). `String(linkage.id)` produces the string `"undefined"` rather than `null`, unlike `getSingleRelatedData` which guards against missing `id`. Downstream fetches will fail when trying to retrieve record `"undefined"`. Consider adding the same guard: return `null` unless both `type` and `id` are present.
Evidence trail:
packages/workflow-executor/src/adapters/agent-client-agent-port.ts lines 274-279 (resolvePolymorphicType: no guard on linkage.id), lines 178-180 (getSingleRelatedData: guards with `if (!linkage || !packedId) return null`). JavaScript spec: String(undefined) === "undefined".
|
Coverage Impact This PR will not change total coverage. Modified Files with Diff Coverage (3)
🛟 Help
|
# @forestadmin/workflow-executor [1.1.0](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/workflow-executor@1.0.1...@forestadmin/workflow-executor@1.1.0) (2026-06-10) ### Features * **workflow-executor:** handle polymorphic relations in load-related (skip + follow) [PRD-493] ([#1647](#1647)) ([f7eef97](f7eef97))

What
Handle polymorphic
BelongsTorelations (e.g. Railscommentable→Author/Library/ …) in the load-related-record step. These relations carry no single static target, so they were previously unfollowable. The step can now both skip them when unresolvable and follow them by resolving the concrete target per record.Rebased onto
main— supersedes #1640, which targeted the now-mergedfeat/prd-214-server-step-mapperand predatedmain'sRelationCandidaterefactor of the relation-selection model.Why
A polymorphic relation has no
relatedCollectionName(the orchestrator omits it). Two things were needed:The discriminator column (e.g.
commentable_type) is not exposed as a Forest field, so it can't be read via a projection. The target type is instead read from the raw JSON:API linkage (data.relationships.<rel>.data = { type, id }), which the agent-client deserializer drops — then mapped to one ofpolymorphicReferencedModels(exact, then case-insensitive, which aligns with Rails model-name = Forest collection-name).Changes
collection.ts— schema: optionalpolymorphicTypeField+polymorphicReferencedModels.agent-port.ts/agent-client-agent-port.ts— newresolvePolymorphicType(raw linkage fetch);mintTokenextracted for reuse.agent-with-log.ts— unaudited passthrough (metadata probe; the actual load is audited separately).load-related-record-step-executor.ts—isFollowableRelation+resolveTargetCollection(static + polymorphic), wired intobuildRelationCandidates(resolves per record),buildTarget, and the Branch A re-entry path.Tests
AgentWithLog: unaudited passthrough.998 tests / 45 suites passing, lint clean.
Dependency
Requires the orchestrator exposing
polymorphicTypeField/polymorphicReferencedModels(forestadmin-server PRD-493).fixes PRD-493
🤖 Generated with Claude Code
Note
Handle polymorphic relations in load-related step executor skip and follow logic
resolvePolymorphicTypeto theAgentPortinterface and implements it inAgentClientAgentPortby fetching JSON:API linkage for a relation from the agent's by-id route, returning{ type, id }or null.LoadRelatedRecordStepExecutorto resolve the concrete target collection for polymorphic relations per record using the new method, mapping the discriminator type to one ofpolymorphicReferencedModelscase-insensitively.FieldSchemaSchemazod schema with optionalpolymorphicTypeFieldandpolymorphicReferencedModelsfields to carry polymorphic relation metadata.StepStateErrorinstead of proceeding when a relation target cannot be determined.📊 Macroscope summarized 8cd54ab. 5 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted
🗂️ Filtered Issues
No issues evaluated.