@openapi-flow/langchain 0.3.18 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/README.md +21 -0
  2. package/dist/arguments/analyze-api-input-answers.js +34 -6
  3. package/dist/arguments/api-argument-planning-error.d.ts +11 -0
  4. package/dist/arguments/api-argument-planning-error.js +32 -0
  5. package/dist/arguments/assert-api-argument-generation-source.d.ts +4 -0
  6. package/dist/arguments/assert-api-argument-generation-source.js +16 -0
  7. package/dist/arguments/attribute-api-literal-generation-sources.d.ts +4 -0
  8. package/dist/arguments/attribute-api-literal-generation-sources.js +16 -0
  9. package/dist/arguments/create-api-argument-rejection.d.ts +3 -0
  10. package/dist/arguments/create-api-argument-rejection.js +38 -0
  11. package/dist/arguments/fingerprint-api-argument-source.d.ts +4 -0
  12. package/dist/arguments/fingerprint-api-argument-source.js +13 -0
  13. package/dist/arguments/generate-api-arguments.js +108 -40
  14. package/dist/arguments/interpret-api-argument-enums.js +1 -0
  15. package/dist/arguments/resolve-api-literal-generation-output.d.ts +3 -0
  16. package/dist/arguments/resolve-api-literal-generation-output.js +14 -0
  17. package/dist/bindings/plan-api-bindings-by-call.js +12 -3
  18. package/dist/bindings/plan-api-call-bindings.js +30 -9
  19. package/dist/bindings/select-api-binding-sources.js +32 -8
  20. package/dist/model/invoke-structured-model.js +32 -6
  21. package/dist/prompts/api-arguments-prompt.d.ts +2 -1
  22. package/dist/prompts/api-arguments-prompt.js +11 -1
  23. package/dist/prompts/api-input-answers-prompt.d.ts +1 -1
  24. package/dist/prompts/api-input-answers-prompt.js +8 -7
  25. package/dist/prompts/api-material-repair-prompt.d.ts +1 -0
  26. package/dist/prompts/api-material-repair-prompt.js +1 -0
  27. package/dist/prompts/incremental-workflow-connections-prompt.d.ts +2 -2
  28. package/dist/prompts/incremental-workflow-connections-prompt.js +5 -4
  29. package/dist/prompts/native-instance-selection-review-prompt.d.ts +1 -0
  30. package/dist/prompts/native-instance-selection-review-prompt.js +9 -0
  31. package/dist/prompts/native-node-planning-prompt.d.ts +1 -1
  32. package/dist/prompts/native-node-planning-prompt.js +2 -0
  33. package/dist/prompts/workflow-connection-goal-recovery-prompt.d.ts +1 -0
  34. package/dist/prompts/workflow-connection-goal-recovery-prompt.js +8 -0
  35. package/dist/prompts/workflow-connection-goal-review-prompt.d.ts +1 -0
  36. package/dist/prompts/workflow-connection-goal-review-prompt.js +7 -0
  37. package/dist/prompts/workflow-connection-native-repair-prompt.d.ts +1 -0
  38. package/dist/prompts/workflow-connection-native-repair-prompt.js +1 -0
  39. package/dist/prompts/workflow-connection-outline-prompt.d.ts +1 -0
  40. package/dist/prompts/workflow-connection-outline-prompt.js +6 -0
  41. package/dist/prompts/workflow-connection-revision-prompt.d.ts +1 -0
  42. package/dist/prompts/workflow-connection-revision-prompt.js +10 -0
  43. package/dist/public-api.d.ts +28 -0
  44. package/dist/public-api.js +21 -0
  45. package/dist/schemas/api-argument-rejection-schema.d.ts +28 -0
  46. package/dist/schemas/api-argument-rejection-schema.js +20 -0
  47. package/dist/schemas/api-input-answer-source-schema.d.ts +5 -5
  48. package/dist/schemas/api-input-answer-source-schema.js +14 -6
  49. package/dist/schemas/api-literal-generation-output-schema.d.ts +35 -4
  50. package/dist/schemas/api-literal-generation-output-schema.js +49 -14
  51. package/dist/schemas/create-connection-material-repair-choice-schema.d.ts +4 -0
  52. package/dist/schemas/create-connection-material-repair-choice-schema.js +23 -0
  53. package/dist/schemas/model-signal-schema.d.ts +3 -0
  54. package/dist/schemas/model-signal-schema.js +3 -0
  55. package/dist/schemas/native-node-parameter-contract.js +2 -0
  56. package/dist/schemas/native-node-planning-contract.js +30 -23
  57. package/dist/schemas/native-planning-rejection-schema.d.ts +11 -0
  58. package/dist/schemas/native-planning-rejection-schema.js +8 -0
  59. package/dist/schemas/workflow-connection-goal-recovery-schema.d.ts +4 -0
  60. package/dist/schemas/workflow-connection-goal-recovery-schema.js +16 -0
  61. package/dist/schemas/workflow-connection-goal-rejection-schema.d.ts +76 -0
  62. package/dist/schemas/workflow-connection-goal-rejection-schema.js +2 -1
  63. package/dist/schemas/workflow-connection-goal-review-schema.d.ts +4 -0
  64. package/dist/schemas/workflow-connection-goal-review-schema.js +26 -0
  65. package/dist/schemas/workflow-connection-goals-schema.d.ts +4 -2
  66. package/dist/schemas/workflow-connection-outline-rejection-schema.d.ts +25 -0
  67. package/dist/schemas/workflow-connection-outline-rejection-schema.js +21 -0
  68. package/dist/schemas/workflow-connection-outline-schema.d.ts +3 -0
  69. package/dist/schemas/workflow-connection-outline-schema.js +25 -0
  70. package/dist/schemas/workflow-connection-revision-rejection-schema.d.ts +113 -0
  71. package/dist/schemas/workflow-connection-revision-rejection-schema.js +23 -0
  72. package/dist/schemas/workflow-connection-revision-schema.d.ts +4 -0
  73. package/dist/schemas/workflow-connection-revision-schema.js +23 -0
  74. package/dist/schemas/workflow-connection-step-schema.d.ts +5 -3
  75. package/dist/schemas/workflow-connection-step-schema.js +62 -31
  76. package/dist/types/api-call-binding-planning.d.ts +2 -1
  77. package/dist/types/api-input-answers.d.ts +3 -6
  78. package/dist/types/argument-generation.d.ts +37 -12
  79. package/dist/types/incremental-connection-planning.d.ts +10 -3
  80. package/dist/types/native-instance-selection-review.d.ts +12 -0
  81. package/dist/types/native-instance-selection-review.js +1 -0
  82. package/dist/types/native-node-planning.d.ts +10 -2
  83. package/dist/types/native-planning-rejection.d.ts +21 -0
  84. package/dist/types/native-planning-rejection.js +1 -0
  85. package/dist/types/workflow-connection-goal-recovery.d.ts +22 -0
  86. package/dist/types/workflow-connection-goal-recovery.js +1 -0
  87. package/dist/types/workflow-connection-goal-review.d.ts +13 -0
  88. package/dist/types/workflow-connection-goal-review.js +1 -0
  89. package/dist/types/workflow-connection-native-repair.d.ts +16 -0
  90. package/dist/types/workflow-connection-native-repair.js +1 -0
  91. package/dist/types/workflow-connection-outline.d.ts +22 -0
  92. package/dist/types/workflow-connection-outline.js +1 -0
  93. package/dist/types/workflow-connection-revision.d.ts +34 -0
  94. package/dist/types/workflow-connection-revision.js +1 -0
  95. package/dist/workflow/connections/create-workflow-connection-goal-rejection.js +8 -2
  96. package/dist/workflow/connections/create-workflow-connection-outline-rejection.d.ts +3 -0
  97. package/dist/workflow/connections/create-workflow-connection-outline-rejection.js +28 -0
  98. package/dist/workflow/connections/create-workflow-connection-revision-rejection.d.ts +3 -0
  99. package/dist/workflow/connections/create-workflow-connection-revision-rejection.js +32 -0
  100. package/dist/workflow/connections/describe-workflow-connection-outline-request.d.ts +3 -0
  101. package/dist/workflow/connections/describe-workflow-connection-outline-request.js +30 -0
  102. package/dist/workflow/connections/generate-workflow-connection-native-parameters.d.ts +4 -0
  103. package/dist/workflow/connections/generate-workflow-connection-native-parameters.js +80 -0
  104. package/dist/workflow/connections/invoke-connection-planning-model.js +3 -0
  105. package/dist/workflow/connections/plan-workflow-connection-goal-recovery.d.ts +3 -0
  106. package/dist/workflow/connections/plan-workflow-connection-goal-recovery.js +111 -0
  107. package/dist/workflow/connections/plan-workflow-connection-goals.js +35 -16
  108. package/dist/workflow/connections/plan-workflow-connection-native-dependencies.d.ts +4 -0
  109. package/dist/workflow/connections/plan-workflow-connection-native-dependencies.js +73 -0
  110. package/dist/workflow/connections/plan-workflow-connection-outline.d.ts +4 -0
  111. package/dist/workflow/connections/plan-workflow-connection-outline.js +93 -0
  112. package/dist/workflow/connections/plan-workflow-connection-revision.d.ts +3 -0
  113. package/dist/workflow/connections/plan-workflow-connection-revision.js +163 -0
  114. package/dist/workflow/connections/plan-workflow-connection-step.js +75 -29
  115. package/dist/workflow/connections/resolve-connection-selections.d.ts +6 -0
  116. package/dist/workflow/connections/resolve-connection-selections.js +28 -0
  117. package/dist/workflow/connections/review-workflow-connection-goals.d.ts +4 -0
  118. package/dist/workflow/connections/review-workflow-connection-goals.js +64 -0
  119. package/dist/workflow/connections/validate-workflow-goal-review-feedback.d.ts +4 -0
  120. package/dist/workflow/connections/validate-workflow-goal-review-feedback.js +22 -0
  121. package/dist/workflow/connections/workflow-connection-native-repair-error.d.ts +6 -0
  122. package/dist/workflow/connections/workflow-connection-native-repair-error.js +18 -0
  123. package/dist/workflow/connections/workflow-connection-planning-error.d.ts +1 -0
  124. package/dist/workflow/connections/workflow-connection-planning-error.js +2 -0
  125. package/dist/workflow/native-selection/create-native-planning-rejection.d.ts +4 -0
  126. package/dist/workflow/native-selection/create-native-planning-rejection.js +45 -0
  127. package/dist/workflow/native-selection/describe-native-planning-request.d.ts +5 -0
  128. package/dist/workflow/native-selection/describe-native-planning-request.js +26 -0
  129. package/dist/workflow/native-selection/native-instance-selection-review-error.d.ts +6 -0
  130. package/dist/workflow/native-selection/native-instance-selection-review-error.js +18 -0
  131. package/dist/workflow/native-selection/review-native-instance-selection.d.ts +4 -0
  132. package/dist/workflow/native-selection/review-native-instance-selection.js +97 -0
  133. package/dist/workflow/native-selection/validate-native-planning-rejections.d.ts +2 -0
  134. package/dist/workflow/native-selection/validate-native-planning-rejections.js +14 -0
  135. package/dist/workflow/resolve-native-node-planning-output.js +3 -1
  136. package/dist/workflow/select-native-node-instances.js +44 -17
  137. package/package.json +2 -2
@@ -0,0 +1,93 @@
1
+ import { isDeepStrictEqual } from 'node:util';
2
+ import { HumanMessage, SystemMessage } from '@langchain/core/messages';
3
+ import { createWorkflowConnectionOutline, runOpenApiFlowOperation, } from '@openapi-flow/core';
4
+ import { createWorkflowConnectionOutlineSchema } from '../../schemas/workflow-connection-outline-schema.js';
5
+ import { workflowConnectionOutlinePrompt } from '../../prompts/workflow-connection-outline-prompt.js';
6
+ import { modelSignalSchema } from '../../schemas/model-signal-schema.js';
7
+ import { workflowConnectionOutlineRejectionSchema } from '../../schemas/workflow-connection-outline-rejection-schema.js';
8
+ import { describeWorkflowConnectionOutlineRequest } from './describe-workflow-connection-outline-request.js';
9
+ import { invokeConnectionPlanningModel } from './invoke-connection-planning-model.js';
10
+ import { validateConnectionProposal, WorkflowConnectionPlanningError, } from './workflow-connection-planning-error.js';
11
+ /** One outline proposal; the host owns selection, retry, checkpoints and adoption. */
12
+ export async function planWorkflowConnectionOutline(input) {
13
+ const operation = 'planWorkflowConnectionOutline';
14
+ const { description, previousOutline, requestFingerprint, rejectedSnapshot } = runOpenApiFlowOperation({
15
+ owner: 'langchain',
16
+ operation,
17
+ stage: 'input-validation',
18
+ code: 'PLANNING_INPUT_INVALID',
19
+ }, () => {
20
+ modelSignalSchema.parse(input.signal);
21
+ const request = describeWorkflowConnectionOutlineRequest(input);
22
+ if (input.rejectedProposals !== undefined) {
23
+ if (!Array.isArray(input.rejectedProposals))
24
+ throw new Error('Outline rejectedProposals must be an array when supplied');
25
+ for (const rejection of input.rejectedProposals) {
26
+ const parsed = workflowConnectionOutlineRejectionSchema.parse(rejection);
27
+ if (!isDeepStrictEqual(parsed, rejection) ||
28
+ parsed.requestFingerprint !== request.requestFingerprint ||
29
+ !isDeepStrictEqual(parsed.expected, request.description.expected))
30
+ throw new Error('Outline feedback must belong to this exact source, session, goals, revision and previous outline');
31
+ }
32
+ }
33
+ return {
34
+ ...request,
35
+ rejectedSnapshot: input.rejectedProposals === undefined
36
+ ? undefined
37
+ : structuredClone(input.rejectedProposals),
38
+ };
39
+ });
40
+ const checkCurrent = (output, originalFailure) => validateConnectionProposal({
41
+ operation,
42
+ stage: 'input-validation',
43
+ code: 'PLANNING_INPUT_INVALID',
44
+ output,
45
+ sourceFingerprint: description.expected.sourceFingerprint,
46
+ requestFingerprint,
47
+ }, () => {
48
+ try {
49
+ if (!isDeepStrictEqual(describeWorkflowConnectionOutlineRequest(input)
50
+ .requestFingerprint, requestFingerprint) ||
51
+ !isDeepStrictEqual(input.rejectedProposals, rejectedSnapshot))
52
+ throw new Error('Outline source, session, previous outline or feedback changed during model invocation');
53
+ }
54
+ catch (error) {
55
+ if (originalFailure !== undefined)
56
+ throw new AggregateError([originalFailure, error], 'Outline input changed while an invalid output was received', { cause: error });
57
+ throw error;
58
+ }
59
+ });
60
+ const output = await invokeConnectionPlanningModel({
61
+ model: input.model,
62
+ operation,
63
+ name: 'plan_workflow_connection_outline',
64
+ schema: createWorkflowConnectionOutlineSchema(description),
65
+ sourceFingerprint: description.expected.sourceFingerprint,
66
+ requestFingerprint,
67
+ messages: [
68
+ new SystemMessage(workflowConnectionOutlinePrompt),
69
+ new HumanMessage(JSON.stringify({
70
+ ...description,
71
+ ...(previousOutline === undefined ? {} : { previousOutline }),
72
+ ...(rejectedSnapshot === undefined
73
+ ? {}
74
+ : { rejectedProposals: rejectedSnapshot }),
75
+ })),
76
+ ],
77
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
78
+ }).catch((error) => {
79
+ if (error instanceof WorkflowConnectionPlanningError &&
80
+ error.diagnostic.stage === 'model-output')
81
+ checkCurrent(error.output, error);
82
+ throw error;
83
+ });
84
+ checkCurrent(output);
85
+ return validateConnectionProposal({
86
+ operation,
87
+ stage: 'contract-validation',
88
+ code: 'WORKFLOW_GRAPH_PLANNING_FAILED',
89
+ output,
90
+ sourceFingerprint: description.expected.sourceFingerprint,
91
+ requestFingerprint,
92
+ }, () => createWorkflowConnectionOutline({ ...input, proposal: output }));
93
+ }
@@ -0,0 +1,3 @@
1
+ import type { PlanWorkflowConnectionRevisionInput, PlanWorkflowConnectionRevisionResult } from '../../types/workflow-connection-revision.js';
2
+ /** One originating-stage decision. The caller owns repetition, material generation, budgets and adoption. */
3
+ export declare function planWorkflowConnectionRevision(input: PlanWorkflowConnectionRevisionInput): Promise<PlanWorkflowConnectionRevisionResult>;
@@ -0,0 +1,163 @@
1
+ import { isDeepStrictEqual } from 'node:util';
2
+ import { HumanMessage, SystemMessage } from '@langchain/core/messages';
3
+ import { describeWorkflowConnectionRevision, applyWorkflowConnectionRevision, validateWorkflowConnectionMaterialRepairRequest, validateWorkflowConnectionMaterialRepairReceipt, runOpenApiFlowOperation, workflowConnectionRejectedProposalSchema, validateWorkflowConnectionRevision, validateWorkflowConnectionGoalReview, } from '@openapi-flow/core';
4
+ import { createWorkflowConnectionRevisionSchema } from '../../schemas/workflow-connection-revision-schema.js';
5
+ import { modelSignalSchema } from '../../schemas/model-signal-schema.js';
6
+ import { workflowConnectionRevisionRejectionSchema } from '../../schemas/workflow-connection-revision-rejection-schema.js';
7
+ import { workflowConnectionRevisionPrompt } from '../../prompts/workflow-connection-revision-prompt.js';
8
+ import { invokeConnectionPlanningModel } from './invoke-connection-planning-model.js';
9
+ import { validateConnectionProposal, WorkflowConnectionPlanningError, } from './workflow-connection-planning-error.js';
10
+ import { resolveConnectionGoalSelections, resolveConnectionEdgeSelections, resolveConnectionEndpointSelections, } from './resolve-connection-selections.js';
11
+ /** One originating-stage decision. The caller owns repetition, material generation, budgets and adoption. */
12
+ export async function planWorkflowConnectionRevision(input) {
13
+ const operation = 'planWorkflowConnectionRevision';
14
+ const { description, schema, rejectedProposals, rejectedConnections, rejectedGoalReviews, } = runOpenApiFlowOperation({
15
+ owner: 'langchain',
16
+ operation,
17
+ stage: 'input-validation',
18
+ code: 'PLANNING_INPUT_INVALID',
19
+ }, () => {
20
+ modelSignalSchema.parse(input.signal);
21
+ const description = describeWorkflowConnectionRevision(input);
22
+ if (input.rejectedConnections !== undefined) {
23
+ if (!Array.isArray(input.rejectedConnections))
24
+ throw new Error('rejectedConnections must be an array when supplied');
25
+ for (const rejection of input.rejectedConnections) {
26
+ const checked = workflowConnectionRejectedProposalSchema.parse(rejection);
27
+ if (!isDeepStrictEqual(checked, rejection) ||
28
+ !isDeepStrictEqual(rejection.expected, description.before.expected))
29
+ throw new Error('Rejected connection evidence must belong to the current original session/revision');
30
+ }
31
+ }
32
+ if (input.rejectedGoalReviews !== undefined) {
33
+ if (!Array.isArray(input.rejectedGoalReviews))
34
+ throw new Error('rejectedGoalReviews must be an array when supplied');
35
+ for (const candidate of input.rejectedGoalReviews) {
36
+ validateWorkflowConnectionRevision({
37
+ ...input,
38
+ proposal: candidate.revision.proposal,
39
+ revision: candidate.revision,
40
+ });
41
+ validateWorkflowConnectionGoalReview({
42
+ ...input.after,
43
+ ...candidate.revision.sourceUpdate,
44
+ session: candidate.revision.session,
45
+ review: candidate.review,
46
+ });
47
+ if (candidate.review.accepted)
48
+ throw new Error('Revision rejection history cannot contain an accepted goal review');
49
+ }
50
+ }
51
+ if (input.rejectedProposals !== undefined) {
52
+ if (!Array.isArray(input.rejectedProposals))
53
+ throw new Error('rejectedProposals must be an array when supplied');
54
+ for (const rejection of input.rejectedProposals) {
55
+ const checked = workflowConnectionRevisionRejectionSchema.parse(rejection);
56
+ if (!isDeepStrictEqual(checked, rejection) ||
57
+ rejection.sourceFingerprint !== description.sourceFingerprint ||
58
+ !isDeepStrictEqual(rejection.expected, description.before.expected))
59
+ throw new Error('Rejected revisions must belong to the unchanged source epochs and original session');
60
+ }
61
+ }
62
+ return {
63
+ description,
64
+ schema: createWorkflowConnectionRevisionSchema(description),
65
+ rejectedProposals: input.rejectedProposals === undefined
66
+ ? undefined
67
+ : structuredClone(input.rejectedProposals),
68
+ rejectedConnections: input.rejectedConnections === undefined
69
+ ? undefined
70
+ : structuredClone(input.rejectedConnections),
71
+ rejectedGoalReviews: input.rejectedGoalReviews === undefined
72
+ ? undefined
73
+ : structuredClone(input.rejectedGoalReviews),
74
+ };
75
+ });
76
+ const checkCurrentInput = (output, rejectedOutputError) => {
77
+ validateConnectionProposal({
78
+ operation,
79
+ stage: 'input-validation',
80
+ code: 'PLANNING_INPUT_INVALID',
81
+ output,
82
+ sourceFingerprint: description.sourceFingerprint,
83
+ }, () => {
84
+ try {
85
+ if (!isDeepStrictEqual(describeWorkflowConnectionRevision(input), description) ||
86
+ !isDeepStrictEqual(input.rejectedProposals, rejectedProposals) ||
87
+ !isDeepStrictEqual(input.rejectedConnections, rejectedConnections) ||
88
+ !isDeepStrictEqual(input.rejectedGoalReviews, rejectedGoalReviews))
89
+ throw new Error('Connection revision source, session or rejection evidence changed during model invocation', { cause: rejectedOutputError });
90
+ }
91
+ catch (error) {
92
+ if (rejectedOutputError !== undefined)
93
+ throw new AggregateError([rejectedOutputError, error], 'Connection revision input changed while invalid model output was received', { cause: error });
94
+ throw error;
95
+ }
96
+ });
97
+ };
98
+ const output = await invokeConnectionPlanningModel({
99
+ model: input.model,
100
+ operation,
101
+ name: 'plan_workflow_connection_revision',
102
+ schema,
103
+ sourceFingerprint: description.sourceFingerprint,
104
+ messages: [
105
+ new SystemMessage(workflowConnectionRevisionPrompt),
106
+ new HumanMessage(JSON.stringify({
107
+ ...description,
108
+ ...(rejectedProposals === undefined ? {} : { rejectedProposals }),
109
+ ...(rejectedConnections === undefined ? {} : { rejectedConnections }),
110
+ ...(rejectedGoalReviews === undefined ? {} : { rejectedGoalReviews }),
111
+ })),
112
+ ],
113
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
114
+ }).catch((error) => {
115
+ // A malformed model response must not skip the input guard and become retryable after a concurrent edit.
116
+ if (error instanceof WorkflowConnectionPlanningError &&
117
+ error.diagnostic.stage === 'model-output')
118
+ checkCurrentInput(error.output, error);
119
+ throw error;
120
+ });
121
+ checkCurrentInput(output);
122
+ return validateConnectionProposal({
123
+ operation,
124
+ stage: 'contract-validation',
125
+ code: 'WORKFLOW_GRAPH_PLANNING_FAILED',
126
+ output,
127
+ sourceFingerprint: description.sourceFingerprint,
128
+ }, () => {
129
+ if (output.decision.kind === 'replan-materials') {
130
+ validateWorkflowConnectionMaterialRepairRequest({
131
+ ...input,
132
+ request: output.decision,
133
+ });
134
+ const receipt = {
135
+ kind: 'replan-materials',
136
+ expected: {
137
+ before: structuredClone(description.before.expected),
138
+ afterSourceFingerprint: description.after.sourceFingerprint,
139
+ revisionSourceFingerprint: description.sourceFingerprint,
140
+ },
141
+ request: output.decision,
142
+ };
143
+ validateWorkflowConnectionMaterialRepairReceipt({ ...input, receipt });
144
+ return receipt;
145
+ }
146
+ const addEdges = resolveConnectionEdgeSelections(output.decision.graphChange.addEdges, description.after.context.nodes);
147
+ const revision = applyWorkflowConnectionRevision({
148
+ ...input,
149
+ proposal: {
150
+ goals: resolveConnectionGoalSelections(output.decision.goals, description.after.context.nodes),
151
+ graphChange: {
152
+ ...output.decision.graphChange,
153
+ addEdges,
154
+ addTerminals: resolveConnectionEndpointSelections(output.decision.graphChange.addTerminals, description.after.context.nodes),
155
+ removeTerminals: resolveConnectionEndpointSelections(output.decision.graphChange.removeTerminals, description.before.context.nodes),
156
+ },
157
+ },
158
+ });
159
+ if (rejectedGoalReviews?.some((candidate) => candidate.revision.session.id === revision.session.id))
160
+ throw new Error('Connection revision repeats a candidate already rejected by the configured goal review');
161
+ return { kind: 'revised-connections', revision };
162
+ });
163
+ }
@@ -1,20 +1,29 @@
1
1
  import { isDeepStrictEqual } from 'node:util';
2
2
  import { HumanMessage, SystemMessage } from '@langchain/core/messages';
3
- import { describeWorkflowConnectionStep, workflowConnectionPlanningDecisionSchema, workflowConnectionRejectedProposalSchema, runOpenApiFlowOperation, } from '@openapi-flow/core';
3
+ import { describeWorkflowConnectionStep, workflowConnectionPlanningDecisionSchema, workflowConnectionRejectedProposalSchema, runOpenApiFlowOperation, describeWorkflowConnectionOutlineBundle, } from '@openapi-flow/core';
4
4
  import { createWorkflowConnectionStepSchema } from '../../schemas/workflow-connection-step-schema.js';
5
5
  import { workflowConnectionStepPrompt } from '../../prompts/incremental-workflow-connections-prompt.js';
6
6
  import { invokeConnectionPlanningModel } from './invoke-connection-planning-model.js';
7
- import { resolveConnectionPortSelection } from './resolve-connection-port-selection.js';
8
- import { validateConnectionProposal } from './workflow-connection-planning-error.js';
7
+ import { resolveConnectionEdgeSelections, resolveConnectionEndpointSelections, } from './resolve-connection-selections.js';
8
+ import { validateConnectionProposal, WorkflowConnectionPlanningError, } from './workflow-connection-planning-error.js';
9
9
  export async function planWorkflowConnectionStep(input) {
10
10
  const operation = 'planWorkflowConnectionStep';
11
- const { description, capabilities, capabilityIndex, schema } = runOpenApiFlowOperation({
11
+ const { description, capabilities, capabilityIndex, schema, outlineContext, rejectedSnapshot, } = runOpenApiFlowOperation({
12
12
  owner: 'langchain',
13
13
  operation,
14
14
  stage: 'input-validation',
15
15
  code: 'PLANNING_INPUT_INVALID',
16
16
  }, () => {
17
17
  const description = describeWorkflowConnectionStep(input);
18
+ if ((input.outline === undefined) !== (input.bundleId === undefined))
19
+ throw new Error('Connection outline and bundleId must be supplied together');
20
+ const outlineContext = input.outline === undefined
21
+ ? undefined
22
+ : describeWorkflowConnectionOutlineBundle({
23
+ ...input,
24
+ outline: input.outline,
25
+ bundleId: input.bundleId,
26
+ });
18
27
  if (input.rejectedProposals !== undefined) {
19
28
  if (!Array.isArray(input.rejectedProposals))
20
29
  throw new Error('rejectedProposals must be an array when supplied');
@@ -31,14 +40,50 @@ export async function planWorkflowConnectionStep(input) {
31
40
  const capabilities = input.capabilities === undefined ? [] : input.capabilities;
32
41
  return {
33
42
  description,
43
+ outlineContext,
44
+ rejectedSnapshot: input.rejectedProposals === undefined
45
+ ? undefined
46
+ : structuredClone(input.rejectedProposals),
34
47
  capabilities,
35
48
  capabilityIndex: capabilities.map(({ name, description }) => ({
36
49
  name,
37
50
  description,
38
51
  })),
39
- schema: createWorkflowConnectionStepSchema(description, capabilities),
52
+ schema: createWorkflowConnectionStepSchema(description, capabilities, outlineContext),
40
53
  };
41
54
  });
55
+ const checkCurrent = (output, originalFailure) => validateConnectionProposal({
56
+ operation,
57
+ stage: 'input-validation',
58
+ code: 'PLANNING_INPUT_INVALID',
59
+ output,
60
+ sourceFingerprint: description.expected.sourceFingerprint,
61
+ }, () => {
62
+ try {
63
+ if ((input.outline === undefined) !== (input.bundleId === undefined))
64
+ throw new Error('Connection outline and bundleId changed during model invocation');
65
+ const currentOutline = input.outline === undefined
66
+ ? undefined
67
+ : describeWorkflowConnectionOutlineBundle({
68
+ ...input,
69
+ outline: input.outline,
70
+ bundleId: input.bundleId,
71
+ });
72
+ if (!isDeepStrictEqual(describeWorkflowConnectionStep(input), description) ||
73
+ !isDeepStrictEqual(currentOutline, outlineContext) ||
74
+ !isDeepStrictEqual(input.rejectedProposals, rejectedSnapshot) ||
75
+ !isDeepStrictEqual(capabilities.map(({ name, description }) => ({
76
+ name,
77
+ description,
78
+ })), capabilityIndex))
79
+ throw new Error('Connection source, session, outline, feedback or native capabilities changed during model invocation');
80
+ }
81
+ catch (error) {
82
+ if (originalFailure !== undefined)
83
+ throw new AggregateError([originalFailure, error], 'Planning input changed while an invalid connection output was received', { cause: error });
84
+ throw error;
85
+ }
86
+ });
42
87
  const output = await invokeConnectionPlanningModel({
43
88
  model: input.model,
44
89
  operation,
@@ -48,47 +93,48 @@ export async function planWorkflowConnectionStep(input) {
48
93
  new SystemMessage(workflowConnectionStepPrompt),
49
94
  new HumanMessage(JSON.stringify({
50
95
  ...description,
96
+ ...(outlineContext === undefined
97
+ ? {}
98
+ : {
99
+ planningOutline: {
100
+ outline: outlineContext.outline,
101
+ bundles: outlineContext.bundles,
102
+ selectedBundle: outlineContext.bundle,
103
+ requiredProducerIds: outlineContext.requiredProducerIds,
104
+ crossingEdges: outlineContext.crossingEdges,
105
+ },
106
+ }),
51
107
  availableNativeCapabilities: capabilityIndex,
52
- ...(input.rejectedProposals === undefined
108
+ ...(rejectedSnapshot === undefined
53
109
  ? {}
54
- : { rejectedProposals: input.rejectedProposals }),
110
+ : { rejectedProposals: rejectedSnapshot }),
55
111
  })),
56
112
  ],
57
113
  ...(input.signal === undefined ? {} : { signal: input.signal }),
114
+ }).catch((error) => {
115
+ if (error instanceof WorkflowConnectionPlanningError &&
116
+ error.diagnostic.stage === 'model-output')
117
+ checkCurrent(error.output, error);
118
+ throw error;
58
119
  });
120
+ checkCurrent(output);
59
121
  return validateConnectionProposal({
60
122
  operation,
61
123
  stage: 'contract-validation',
62
124
  code: 'WORKFLOW_GRAPH_PLANNING_FAILED',
63
125
  output,
64
126
  }, () => {
65
- if (!isDeepStrictEqual(describeWorkflowConnectionStep(input), description))
66
- throw new Error('Connection session or source changed during model invocation');
67
- if (!isDeepStrictEqual(capabilities.map(({ name, description }) => ({ name, description })), capabilityIndex))
68
- throw new Error('Available native capabilities changed during model invocation');
69
127
  const raw = output.decision;
128
+ const addEdges = raw.kind === 'patch'
129
+ ? resolveConnectionEdgeSelections(raw.addEdges, description.context.nodes)
130
+ : [];
70
131
  const decision = raw.kind !== 'patch'
71
132
  ? raw
72
133
  : {
73
134
  ...raw,
74
- addEdges: raw.addEdges.map((edge) => ({
75
- from: edge.source.nodeId,
76
- output: resolveConnectionPortSelection(edge.source, description.context.nodes, 'outputs'),
77
- to: edge.target.nodeId,
78
- input: resolveConnectionPortSelection(edge.target, description.context.nodes, 'inputs'),
79
- })),
80
- addTerminals: raw.addTerminals.map((selection) => ({
81
- nodeId: selection.nodeId,
82
- output: resolveConnectionPortSelection(selection, description.context.nodes, 'outputs'),
83
- })),
84
- removeTerminals: raw.removeTerminals.map((selection) => ({
85
- nodeId: selection.nodeId,
86
- output: resolveConnectionPortSelection(selection, description.context.nodes.map((node) => ({
87
- ...node,
88
- outputs: node.outputs.filter((port) => description.terminals.some((terminal) => terminal.nodeId === node.id &&
89
- terminal.output === port)),
90
- })), 'outputs'),
91
- })),
135
+ addEdges,
136
+ addTerminals: resolveConnectionEndpointSelections(raw.addTerminals, description.context.nodes),
137
+ removeTerminals: resolveConnectionEndpointSelections(raw.removeTerminals, description.context.nodes),
92
138
  };
93
139
  return {
94
140
  expected: structuredClone(description.expected),
@@ -0,0 +1,6 @@
1
+ import type { WorkflowConnectionGoalProposal, WorkflowPlanNodeContract, WorkflowPlanEdge, WorkflowConnectionPatch } from '@openapi-flow/core';
2
+ import type { WorkflowConnectionGoalSelection, WorkflowConnectionEdgeSelection, WorkflowConnectionEndpointSelection } from '../../types/incremental-connection-planning.js';
3
+ export declare function resolveConnectionGoalSelections(selections: WorkflowConnectionGoalSelection[], nodes: WorkflowPlanNodeContract[]): WorkflowConnectionGoalProposal[];
4
+ /** Endpoint intent is model-owned; a unique declared output port is code-owned. */
5
+ export declare function resolveConnectionEndpointSelections(selections: WorkflowConnectionEndpointSelection[], nodes: WorkflowPlanNodeContract[]): WorkflowConnectionPatch['addTerminals'];
6
+ export declare function resolveConnectionEdgeSelections(selections: WorkflowConnectionEdgeSelection[], nodes: WorkflowPlanNodeContract[]): WorkflowPlanEdge[];
@@ -0,0 +1,28 @@
1
+ import { resolveConnectionPortSelection } from './resolve-connection-port-selection.js';
2
+ export function resolveConnectionGoalSelections(selections, nodes) {
3
+ return selections.map((goal) => goal.kind !== 'route'
4
+ ? goal
5
+ : {
6
+ kind: goal.kind,
7
+ from: goal.source.nodeId,
8
+ to: goal.to,
9
+ factIds: goal.factIds,
10
+ reason: goal.reason,
11
+ output: resolveConnectionPortSelection(goal.source, nodes, 'outputs'),
12
+ });
13
+ }
14
+ /** Endpoint intent is model-owned; a unique declared output port is code-owned. */
15
+ export function resolveConnectionEndpointSelections(selections, nodes) {
16
+ return selections.map((selection) => ({
17
+ nodeId: selection.nodeId,
18
+ output: resolveConnectionPortSelection(selection, nodes, 'outputs'),
19
+ }));
20
+ }
21
+ export function resolveConnectionEdgeSelections(selections, nodes) {
22
+ return selections.map((edge) => ({
23
+ from: edge.source.nodeId,
24
+ output: resolveConnectionPortSelection(edge.source, nodes, 'outputs'),
25
+ to: edge.target.nodeId,
26
+ input: resolveConnectionPortSelection(edge.target, nodes, 'inputs'),
27
+ }));
28
+ }
@@ -0,0 +1,4 @@
1
+ import type { WorkflowConnectionGoalReview } from '@openapi-flow/core';
2
+ import type { ReviewWorkflowConnectionGoalsInput } from '../../types/workflow-connection-goal-review.js';
3
+ /** One independent judgment; the host owns whether and how to replan rejected goals/material. */
4
+ export declare function reviewWorkflowConnectionGoals(input: ReviewWorkflowConnectionGoalsInput): Promise<WorkflowConnectionGoalReview>;
@@ -0,0 +1,64 @@
1
+ import { isDeepStrictEqual } from 'node:util';
2
+ import { HumanMessage, SystemMessage } from '@langchain/core/messages';
3
+ import { describeWorkflowConnectionGoalReview, createWorkflowConnectionGoalReview, runOpenApiFlowOperation, } from '@openapi-flow/core';
4
+ import { createWorkflowConnectionGoalReviewSchema } from '../../schemas/workflow-connection-goal-review-schema.js';
5
+ import { modelSignalSchema } from '../../schemas/model-signal-schema.js';
6
+ import { workflowConnectionGoalReviewPrompt } from '../../prompts/workflow-connection-goal-review-prompt.js';
7
+ import { invokeConnectionPlanningModel } from './invoke-connection-planning-model.js';
8
+ import { WorkflowConnectionPlanningError, validateConnectionProposal, } from './workflow-connection-planning-error.js';
9
+ /** One independent judgment; the host owns whether and how to replan rejected goals/material. */
10
+ export async function reviewWorkflowConnectionGoals(input) {
11
+ const operation = 'reviewWorkflowConnectionGoals';
12
+ const description = runOpenApiFlowOperation({
13
+ owner: 'langchain',
14
+ operation,
15
+ stage: 'input-validation',
16
+ code: 'PLANNING_INPUT_INVALID',
17
+ }, () => {
18
+ modelSignalSchema.parse(input.signal);
19
+ return describeWorkflowConnectionGoalReview(input);
20
+ });
21
+ const checkCurrent = (output) => validateConnectionProposal({
22
+ operation,
23
+ stage: 'input-validation',
24
+ code: 'PLANNING_INPUT_INVALID',
25
+ output,
26
+ sourceFingerprint: description.sourceFingerprint,
27
+ }, () => {
28
+ if (!isDeepStrictEqual(description, describeWorkflowConnectionGoalReview(input)))
29
+ throw new Error('Goal review source or candidate changed during model invocation');
30
+ });
31
+ const output = await invokeConnectionPlanningModel({
32
+ model: input.model,
33
+ operation,
34
+ name: 'review_workflow_connection_goals',
35
+ schema: createWorkflowConnectionGoalReviewSchema(description),
36
+ sourceFingerprint: description.sourceFingerprint,
37
+ messages: [
38
+ new SystemMessage(workflowConnectionGoalReviewPrompt),
39
+ new HumanMessage(JSON.stringify(description)),
40
+ ],
41
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
42
+ }).catch((error) => {
43
+ if (error instanceof WorkflowConnectionPlanningError &&
44
+ error.diagnostic.stage === 'model-output')
45
+ checkCurrent(error.output);
46
+ throw error;
47
+ });
48
+ checkCurrent(output);
49
+ return validateConnectionProposal({
50
+ operation,
51
+ stage: 'contract-validation',
52
+ code: 'WORKFLOW_GRAPH_PLANNING_FAILED',
53
+ output,
54
+ sourceFingerprint: description.sourceFingerprint,
55
+ }, () => createWorkflowConnectionGoalReview({
56
+ ...input,
57
+ proposal: {
58
+ assessments: description.requirements.map((fact) => ({
59
+ factId: fact.id,
60
+ ...output.assessments[fact.id],
61
+ })),
62
+ },
63
+ }));
64
+ }
@@ -0,0 +1,4 @@
1
+ import type { WorkflowReviewedGoalCandidate } from '@openapi-flow/core';
2
+ import type { ValidateWorkflowGoalReviewFeedbackInput } from '../../types/workflow-connection-goal-review.js';
3
+ /** Verify exact negative judgments against actual current material; never turn them into user intent. */
4
+ export declare function validateWorkflowGoalReviewFeedback(input: ValidateWorkflowGoalReviewFeedbackInput): WorkflowReviewedGoalCandidate[];
@@ -0,0 +1,22 @@
1
+ import { isDeepStrictEqual } from 'node:util';
2
+ import { validateWorkflowConnectionGoalReview, workflowReviewedGoalCandidateSchema, } from '@openapi-flow/core';
3
+ /** Verify exact negative judgments against actual current material; never turn them into user intent. */
4
+ export function validateWorkflowGoalReviewFeedback(input) {
5
+ if (input.rejectedGoalReviews === undefined)
6
+ return [];
7
+ if (!Array.isArray(input.rejectedGoalReviews))
8
+ throw new Error('rejectedGoalReviews must be an array when supplied');
9
+ for (const candidate of input.rejectedGoalReviews) {
10
+ const checked = workflowReviewedGoalCandidateSchema.parse(candidate);
11
+ if (!isDeepStrictEqual(checked, candidate))
12
+ throw new Error('Goal review feedback must preserve its exact candidate');
13
+ validateWorkflowConnectionGoalReview({
14
+ ...input,
15
+ session: candidate.session,
16
+ review: candidate.review,
17
+ });
18
+ if (candidate.review.accepted)
19
+ throw new Error('Accepted goal review is not rejection feedback');
20
+ }
21
+ return structuredClone(input.rejectedGoalReviews);
22
+ }
@@ -0,0 +1,6 @@
1
+ import { OpenApiFlowError } from '@openapi-flow/core';
2
+ import type { WorkflowConnectionNativeRepairFailure } from '../../types/workflow-connection-native-repair.js';
3
+ export declare class WorkflowConnectionNativeRepairError extends OpenApiFlowError {
4
+ readonly failure: WorkflowConnectionNativeRepairFailure;
5
+ constructor(failure: WorkflowConnectionNativeRepairFailure, cause: Error);
6
+ }
@@ -0,0 +1,18 @@
1
+ import { OpenApiFlowError } from '@openapi-flow/core';
2
+ export class WorkflowConnectionNativeRepairError extends OpenApiFlowError {
3
+ failure;
4
+ constructor(failure, cause) {
5
+ super({
6
+ message: cause.message,
7
+ diagnostic: {
8
+ owner: 'langchain',
9
+ operation: failure.operation,
10
+ stage: 'contract-validation',
11
+ code: 'NATIVE_NODE_PLANNING_FAILED',
12
+ },
13
+ cause,
14
+ });
15
+ this.name = 'WorkflowConnectionNativeRepairError';
16
+ this.failure = failure;
17
+ }
18
+ }
@@ -4,6 +4,7 @@ import type { WorkflowConnectionPlanningFailure } from '../../types/incremental-
4
4
  export declare class WorkflowConnectionPlanningError extends OpenApiFlowError {
5
5
  readonly output: unknown;
6
6
  readonly sourceFingerprint: string | undefined;
7
+ readonly requestFingerprint: string | undefined;
7
8
  constructor(failure: WorkflowConnectionPlanningFailure, cause: unknown);
8
9
  }
9
10
  export declare function validateConnectionProposal<Result>(failure: WorkflowConnectionPlanningFailure, execute: () => Result): Result;
@@ -3,6 +3,7 @@ import { OpenApiFlowError } from '@openapi-flow/core';
3
3
  export class WorkflowConnectionPlanningError extends OpenApiFlowError {
4
4
  output;
5
5
  sourceFingerprint;
6
+ requestFingerprint;
6
7
  constructor(failure, cause) {
7
8
  super({
8
9
  message: cause instanceof Error ? cause.message : failure.operation,
@@ -16,6 +17,7 @@ export class WorkflowConnectionPlanningError extends OpenApiFlowError {
16
17
  });
17
18
  this.output = failure.output;
18
19
  this.sourceFingerprint = failure.sourceFingerprint;
20
+ this.requestFingerprint = failure.requestFingerprint;
19
21
  }
20
22
  }
21
23
  export function validateConnectionProposal(failure, execute) {
@@ -0,0 +1,4 @@
1
+ import type { CreateNativeSelectionRejectionInput, CreateNativeSelectionReviewRejectionInput, NativePlanningRejectedProposal } from '../../types/native-planning-rejection.js';
2
+ /** Only unchanged, source-bound output failures are eligible; transport/configuration failures are not proposals. */
3
+ export declare function createNativeSelectionRejection(input: CreateNativeSelectionRejectionInput): NativePlanningRejectedProposal | undefined;
4
+ export declare function createNativeSelectionReviewRejection(input: CreateNativeSelectionReviewRejectionInput): NativePlanningRejectedProposal | undefined;