@openapi-flow/langchain 0.0.0-stage → 0.2.0

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 (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +32 -2
  3. package/THIRD_PARTY_NOTICES.md +3 -0
  4. package/dist/arguments/generate-api-arguments.d.ts +3 -0
  5. package/dist/arguments/generate-api-arguments.js +45 -0
  6. package/dist/arguments/select-api-request-media-type.d.ts +2 -0
  7. package/dist/arguments/select-api-request-media-type.js +39 -0
  8. package/dist/bindings/plan-api-bindings.d.ts +3 -0
  9. package/dist/bindings/plan-api-bindings.js +43 -0
  10. package/dist/legacy/planning/operation-plan-inputs.d.ts +3 -0
  11. package/dist/legacy/planning/operation-plan-inputs.js +17 -0
  12. package/dist/legacy/planning/parse-structured-output.d.ts +2 -0
  13. package/dist/legacy/planning/parse-structured-output.js +9 -0
  14. package/dist/legacy/planning/propose-catalog-scenario.d.ts +3 -0
  15. package/dist/legacy/planning/propose-catalog-scenario.js +136 -0
  16. package/dist/legacy/planning/select-operation.d.ts +4 -0
  17. package/dist/legacy/planning/select-operation.js +43 -0
  18. package/dist/legacy/schemas/catalog-selection-schema.d.ts +19 -0
  19. package/dist/legacy/schemas/catalog-selection-schema.js +39 -0
  20. package/dist/legacy/schemas/catalog-step-schema.d.ts +16 -0
  21. package/dist/legacy/schemas/catalog-step-schema.js +39 -0
  22. package/dist/legacy/schemas/operation-selection-schema.d.ts +6 -0
  23. package/dist/legacy/schemas/operation-selection-schema.js +14 -0
  24. package/dist/legacy-api.d.ts +9 -0
  25. package/dist/legacy-api.js +7 -0
  26. package/dist/prompts/api-arguments-prompt.d.ts +1 -0
  27. package/dist/prompts/api-arguments-prompt.js +1 -0
  28. package/dist/prompts/api-bindings-prompt.d.ts +1 -0
  29. package/dist/prompts/api-bindings-prompt.js +12 -0
  30. package/dist/prompts/api-request-media-type-prompt.d.ts +1 -0
  31. package/dist/prompts/api-request-media-type-prompt.js +1 -0
  32. package/dist/prompts/native-node-planning-prompt.d.ts +1 -0
  33. package/dist/prompts/native-node-planning-prompt.js +9 -0
  34. package/dist/prompts/operation-selection-prompt.d.ts +1 -0
  35. package/dist/prompts/operation-selection-prompt.js +1 -0
  36. package/dist/prompts/reviewable-workflow-graph-prompt.d.ts +1 -0
  37. package/dist/prompts/reviewable-workflow-graph-prompt.js +7 -0
  38. package/dist/prompts/workflow-connections-prompt.d.ts +1 -0
  39. package/dist/prompts/workflow-connections-prompt.js +9 -0
  40. package/dist/prompts/workflow-graph-prompt.d.ts +1 -0
  41. package/dist/prompts/workflow-graph-prompt.js +13 -0
  42. package/dist/public-api.d.ts +20 -0
  43. package/dist/public-api.js +12 -0
  44. package/dist/schemas/api-binding-plan-schema.d.ts +3 -0
  45. package/dist/schemas/api-binding-plan-schema.js +49 -0
  46. package/dist/schemas/api-request-media-type-schema.d.ts +3 -0
  47. package/dist/schemas/api-request-media-type-schema.js +11 -0
  48. package/dist/schemas/api-selection-schema.d.ts +12 -0
  49. package/dist/schemas/api-selection-schema.js +30 -0
  50. package/dist/schemas/native-node-plan-schema.d.ts +4 -0
  51. package/dist/schemas/native-node-plan-schema.js +26 -0
  52. package/dist/schemas/reviewable-workflow-graph-schema.d.ts +4 -0
  53. package/dist/schemas/reviewable-workflow-graph-schema.js +63 -0
  54. package/dist/schemas/workflow-graph-proposal-schema.d.ts +4 -0
  55. package/dist/schemas/workflow-graph-proposal-schema.js +38 -0
  56. package/dist/selection/select-api-operations.d.ts +3 -0
  57. package/dist/selection/select-api-operations.js +51 -0
  58. package/dist/types/argument-generation.d.ts +7 -0
  59. package/dist/types/argument-generation.js +1 -0
  60. package/dist/types/binding-planning.d.ts +8 -0
  61. package/dist/types/binding-planning.js +1 -0
  62. package/dist/types/legacy/catalog-planning.d.ts +16 -0
  63. package/dist/types/legacy/catalog-planning.js +1 -0
  64. package/dist/types/legacy/planning.d.ts +5 -0
  65. package/dist/types/legacy/planning.js +1 -0
  66. package/dist/types/native-node-planning.d.ts +25 -0
  67. package/dist/types/native-node-planning.js +1 -0
  68. package/dist/types/operation-selection.d.ts +10 -0
  69. package/dist/types/operation-selection.js +1 -0
  70. package/dist/types/request-media-selection.d.ts +10 -0
  71. package/dist/types/request-media-selection.js +1 -0
  72. package/dist/types/reviewable-workflow-planning.d.ts +19 -0
  73. package/dist/types/reviewable-workflow-planning.js +1 -0
  74. package/dist/types/workflow-orchestration.d.ts +23 -0
  75. package/dist/types/workflow-orchestration.js +1 -0
  76. package/dist/types/workflow-planning.d.ts +23 -0
  77. package/dist/types/workflow-planning.js +1 -0
  78. package/dist/workflow/assemble-native-node-materials.d.ts +3 -0
  79. package/dist/workflow/assemble-native-node-materials.js +8 -0
  80. package/dist/workflow/complete-reviewable-workflow-graph-proposal.d.ts +4 -0
  81. package/dist/workflow/complete-reviewable-workflow-graph-proposal.js +13 -0
  82. package/dist/workflow/create-prepared-native-node-materials.d.ts +4 -0
  83. package/dist/workflow/create-prepared-native-node-materials.js +15 -0
  84. package/dist/workflow/native-node-planning-error.d.ts +5 -0
  85. package/dist/workflow/native-node-planning-error.js +10 -0
  86. package/dist/workflow/orchestrate-workflow.d.ts +4 -0
  87. package/dist/workflow/orchestrate-workflow.js +31 -0
  88. package/dist/workflow/plan-native-nodes.d.ts +2 -0
  89. package/dist/workflow/plan-native-nodes.js +99 -0
  90. package/dist/workflow/plan-reviewable-workflow-graph.d.ts +3 -0
  91. package/dist/workflow/plan-reviewable-workflow-graph.js +101 -0
  92. package/dist/workflow/plan-workflow-connections.d.ts +3 -0
  93. package/dist/workflow/plan-workflow-connections.js +62 -0
  94. package/dist/workflow/plan-workflow-graph.d.ts +3 -0
  95. package/dist/workflow/plan-workflow-graph.js +99 -0
  96. package/dist/workflow/prepare-workflow-connection-materials.d.ts +3 -0
  97. package/dist/workflow/prepare-workflow-connection-materials.js +66 -0
  98. package/dist/workflow/reviewable-workflow-graph-planning-error.d.ts +5 -0
  99. package/dist/workflow/reviewable-workflow-graph-planning-error.js +8 -0
  100. package/dist/workflow/workflow-graph-planning-error.d.ts +5 -0
  101. package/dist/workflow/workflow-graph-planning-error.js +10 -0
  102. package/package.json +44 -4
@@ -0,0 +1,19 @@
1
+ import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
2
+ import type { ReviewableWorkflowGraphProposal, ReviewableWorkflowPlanningContext, WorkflowReviewGap, PlannedNativeNode } from '@openapi-flow/core';
3
+ export interface PlanReviewableWorkflowGraphInput extends ReviewableWorkflowPlanningContext {
4
+ scenario: string;
5
+ model: BaseChatModel;
6
+ gaps: WorkflowReviewGap[];
7
+ preparedNativeNodes?: PlannedNativeNode[];
8
+ }
9
+ export type ReviewableWorkflowGraphPlanningFailure = {
10
+ stage: 'proposal-schema';
11
+ output: unknown;
12
+ } | {
13
+ stage: 'graph-validation';
14
+ output: ReviewableWorkflowGraphOutput;
15
+ };
16
+ export type ReviewableWorkflowGraphOutput = Omit<ReviewableWorkflowGraphProposal, 'nativeNodes' | 'blockedCalls'> & {
17
+ additionalNativeNodes?: ReviewableWorkflowGraphProposal['nativeNodes'];
18
+ blockedCalls?: ReviewableWorkflowGraphProposal['blockedCalls'];
19
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
2
+ import type { ReviewableWorkflowApiMaterial, PlannedNativeNode, WorkflowCapability, WorkflowPlanEdge, WorkflowReviewGap, WorkflowPlanNodeContract } from '@openapi-flow/core';
3
+ export interface PlanWorkflowConnectionsInput {
4
+ scenario: string;
5
+ model: BaseChatModel;
6
+ materials?: ReviewableWorkflowApiMaterial[];
7
+ capabilities?: WorkflowCapability[];
8
+ nativeNodes?: PlannedNativeNode[];
9
+ gaps?: WorkflowReviewGap[];
10
+ edges?: WorkflowPlanEdge[];
11
+ }
12
+ export interface OrchestrateWorkflowInput extends Omit<PlanWorkflowConnectionsInput, 'nativeNodes'> {
13
+ workflowId: string;
14
+ preparedNativeNodes?: PlannedNativeNode[];
15
+ }
16
+ export interface WorkflowConnectionMaterials {
17
+ materials: ReviewableWorkflowApiMaterial[];
18
+ capabilities: WorkflowCapability[];
19
+ nativeNodes: PlannedNativeNode[];
20
+ gaps: WorkflowReviewGap[];
21
+ edges: WorkflowPlanEdge[];
22
+ contracts: WorkflowPlanNodeContract[];
23
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
2
+ import type { WorkflowApiMaterial, WorkflowCapability, WorkflowGraphProposal, PlannedNativeNode } from '@openapi-flow/core';
3
+ export interface PlanWorkflowGraphInput {
4
+ scenario: string;
5
+ model: BaseChatModel;
6
+ materials: WorkflowApiMaterial[];
7
+ capabilities: WorkflowCapability[];
8
+ preparedNativeNodes?: PlannedNativeNode[];
9
+ }
10
+ export interface PreparedNativeNodeMaterial extends PlannedNativeNode {
11
+ inputPorts: string[];
12
+ outputPorts: string[];
13
+ }
14
+ export type WorkflowGraphOutput = Omit<WorkflowGraphProposal, 'nativeNodes'> & {
15
+ additionalNativeNodes: PlannedNativeNode[];
16
+ };
17
+ export type WorkflowGraphPlanningFailure = {
18
+ stage: 'proposal-schema';
19
+ output: unknown;
20
+ } | {
21
+ stage: 'graph-validation';
22
+ output: WorkflowGraphOutput;
23
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { PlannedNativeNode } from '@openapi-flow/core';
2
+ /** Prepared values belong to the host; model output contains only additions. */
3
+ export declare function assembleNativeNodeMaterials(prepared: PlannedNativeNode[], additional: PlannedNativeNode[]): PlannedNativeNode[];
@@ -0,0 +1,8 @@
1
+ /** Prepared values belong to the host; model output contains only additions. */
2
+ export function assembleNativeNodeMaterials(prepared, additional) {
3
+ const preparedIds = new Set(prepared.map((node) => node.id));
4
+ for (const node of additional)
5
+ if (preparedIds.has(node.id))
6
+ throw new Error(`additionalNativeNodes[${node.id}] duplicates preparedNativeNodes; return only new nodes, not existing materials`);
7
+ return [...prepared, ...additional];
8
+ }
@@ -0,0 +1,4 @@
1
+ import type { ReviewableWorkflowGraphProposal } from '@openapi-flow/core';
2
+ import type { ReviewableWorkflowGraphOutput } from '../types/reviewable-workflow-planning.js';
3
+ /** Complete only fields fixed by the supplied planning context, not model errors. */
4
+ export declare function completeReviewableWorkflowGraphProposal(output: ReviewableWorkflowGraphOutput, capabilityCount: number, readyCallCount: number): ReviewableWorkflowGraphProposal;
@@ -0,0 +1,13 @@
1
+ /** Complete only fields fixed by the supplied planning context, not model errors. */
2
+ export function completeReviewableWorkflowGraphProposal(output, capabilityCount, readyCallCount) {
3
+ if (capabilityCount > 0 && output.additionalNativeNodes === undefined)
4
+ throw new Error('model reviewable workflow graph.additionalNativeNodes is required');
5
+ if (readyCallCount > 0 && output.blockedCalls === undefined)
6
+ throw new Error('model reviewable workflow graph.blockedCalls is required');
7
+ const { additionalNativeNodes, ...proposal } = output;
8
+ return {
9
+ ...proposal,
10
+ nativeNodes: capabilityCount === 0 ? [] : additionalNativeNodes,
11
+ blockedCalls: readyCallCount === 0 ? [] : output.blockedCalls,
12
+ };
13
+ }
@@ -0,0 +1,4 @@
1
+ import type { PlannedNativeNode, WorkflowCapability } from '@openapi-flow/core';
2
+ import type { PreparedNativeNodeMaterial } from '../types/workflow-planning.js';
3
+ /** Expose existing implementation-owned ports, not descriptions for the model to guess. */
4
+ export declare function createPreparedNativeNodeMaterials(nodes: PlannedNativeNode[], capabilities: WorkflowCapability[]): PreparedNativeNodeMaterial[];
@@ -0,0 +1,15 @@
1
+ import { parseNativeNodeParameters } from '@openapi-flow/core';
2
+ /** Expose existing implementation-owned ports, not descriptions for the model to guess. */
3
+ export function createPreparedNativeNodeMaterials(nodes, capabilities) {
4
+ return nodes.map((planned) => {
5
+ const capability = capabilities.find((item) => item.name === planned.capability);
6
+ if (!capability)
7
+ throw new Error(`prepared node ${planned.id}: unknown capability ${planned.capability}`);
8
+ const parameters = parseNativeNodeParameters(planned, capability);
9
+ return {
10
+ ...planned,
11
+ inputPorts: capability.inputPorts(parameters),
12
+ outputPorts: capability.outputPorts(parameters),
13
+ };
14
+ });
15
+ }
@@ -0,0 +1,5 @@
1
+ import type { NativeNodePlanningFailure } from '../types/native-node-planning.js';
2
+ export declare class NativeNodePlanningError extends Error {
3
+ readonly failure: NativeNodePlanningFailure;
4
+ constructor(failure: NativeNodePlanningFailure, cause: Error);
5
+ }
@@ -0,0 +1,10 @@
1
+ export class NativeNodePlanningError extends Error {
2
+ failure;
3
+ constructor(failure, cause) {
4
+ super(`Native node planning failed at ${failure.stage}: ${cause.message}`, {
5
+ cause,
6
+ });
7
+ this.name = 'NativeNodePlanningError';
8
+ this.failure = failure;
9
+ }
10
+ }
@@ -0,0 +1,4 @@
1
+ import type { ReviewableWorkflowGraphPlan } from '@openapi-flow/core';
2
+ import type { OrchestrateWorkflowInput } from '../types/workflow-orchestration.js';
3
+ /** Optional material groups mean absence, never an implicit capability registry. */
4
+ export declare function orchestrateWorkflow(input: OrchestrateWorkflowInput): Promise<ReviewableWorkflowGraphPlan>;
@@ -0,0 +1,31 @@
1
+ import { planNativeNodes } from './plan-native-nodes.js';
2
+ import { planWorkflowConnections } from './plan-workflow-connections.js';
3
+ import { assembleNativeNodeMaterials } from './assemble-native-node-materials.js';
4
+ import { prepareWorkflowConnectionMaterials } from './prepare-workflow-connection-materials.js';
5
+ /** Optional material groups mean absence, never an implicit capability registry. */
6
+ export async function orchestrateWorkflow(input) {
7
+ if (!input.workflowId?.trim())
8
+ throw new Error('orchestrateWorkflow.workflowId is required');
9
+ prepareWorkflowConnectionMaterials({
10
+ ...input,
11
+ nativeNodes: input.preparedNativeNodes,
12
+ });
13
+ const nativePlan = await planNativeNodes({
14
+ planId: `${input.workflowId}-native`,
15
+ scenario: input.scenario,
16
+ model: input.model,
17
+ capabilities: input.capabilities,
18
+ preparedNativeNodes: input.preparedNativeNodes,
19
+ apiMaterials: input.materials?.map((material) => ({
20
+ callId: material.status === 'ready'
21
+ ? material.arguments.callId
22
+ : material.callId,
23
+ operation: material.operation,
24
+ })),
25
+ });
26
+ return planWorkflowConnections({
27
+ ...input,
28
+ nativeNodes: assembleNativeNodeMaterials(input.preparedNativeNodes ?? [], nativePlan.nativeNodes),
29
+ gaps: [...(input.gaps ?? []), ...nativePlan.gaps],
30
+ });
31
+ }
@@ -0,0 +1,2 @@
1
+ import type { NativeNodePlan, PlanNativeNodesInput } from '../types/native-node-planning.js';
2
+ export declare function planNativeNodes(input: PlanNativeNodesInput): Promise<NativeNodePlan>;
@@ -0,0 +1,99 @@
1
+ import { HumanMessage, SystemMessage } from '@langchain/core/messages';
2
+ import { isDeepStrictEqual } from 'node:util';
3
+ import { z } from 'zod';
4
+ import { createNativeOutputContracts, createWorkflowPlanningCapabilities, validateNativeApiResponseReferences, } from '@openapi-flow/core';
5
+ import { createNativeNodePlanSchema } from '../schemas/native-node-plan-schema.js';
6
+ import { nativeNodePlanningPrompt } from '../prompts/native-node-planning-prompt.js';
7
+ import { assertSelectionInput } from '../legacy/planning/select-operation.js';
8
+ import { parseStructuredOutput } from '../legacy/planning/parse-structured-output.js';
9
+ import { createPreparedNativeNodeMaterials } from './create-prepared-native-node-materials.js';
10
+ import { assembleNativeNodeMaterials } from './assemble-native-node-materials.js';
11
+ import { NativeNodePlanningError } from './native-node-planning-error.js';
12
+ export async function planNativeNodes(input) {
13
+ assertSelectionInput(input.scenario, input.model);
14
+ if (!input.planId?.trim())
15
+ throw new Error('planNativeNodes.planId is required');
16
+ const capabilities = input.capabilities ?? [];
17
+ const apiMaterials = input.apiMaterials ?? [];
18
+ const prepared = input.preparedNativeNodes ?? [];
19
+ createNativeOutputContracts({ nativeNodes: prepared, capabilities });
20
+ const apiIds = apiMaterials.map((material) => material.callId);
21
+ const existingIds = [...apiIds, ...prepared.map((node) => node.id)];
22
+ if (existingIds.some((id) => !id.trim()) ||
23
+ new Set(existingIds).size !== existingIds.length)
24
+ throw new Error('native planning materials require unique non-empty IDs');
25
+ validateNativeApiResponseReferences({
26
+ nativeNodes: prepared,
27
+ capabilities,
28
+ apiCallIds: apiIds,
29
+ });
30
+ // No registered choice means no native-selection model call, not an inferred registry.
31
+ if (!capabilities.length)
32
+ return { nativeNodes: [], gaps: [] };
33
+ const planningCapabilities = createWorkflowPlanningCapabilities({
34
+ capabilities,
35
+ apiCallIds: apiIds,
36
+ });
37
+ const schema = createNativeNodePlanSchema(planningCapabilities);
38
+ const output = await input.model
39
+ .withStructuredOutput(z.toJSONSchema(schema), {
40
+ name: 'plan_native_nodes',
41
+ method: 'functionCalling',
42
+ strict: true,
43
+ })
44
+ .invoke([
45
+ new SystemMessage(nativeNodePlanningPrompt),
46
+ new HumanMessage(JSON.stringify({
47
+ scenario: input.scenario,
48
+ apiMaterials: apiMaterials.map(({ callId, operation }) => ({
49
+ callId,
50
+ key: operation.key,
51
+ method: operation.method,
52
+ path: operation.path,
53
+ operation: operation.operation,
54
+ effective: operation.effective,
55
+ })),
56
+ preparedNativeNodes: createPreparedNativeNodeMaterials(prepared, capabilities),
57
+ capabilities: planningCapabilities.map((capability) => ({
58
+ name: capability.name,
59
+ description: capability.description,
60
+ parametersSchema: z.toJSONSchema(capability.parametersSchema),
61
+ })),
62
+ })),
63
+ ]);
64
+ let proposal;
65
+ try {
66
+ proposal = parseStructuredOutput(schema, output, 'model native node plan');
67
+ if (!isDeepStrictEqual(proposal, output))
68
+ throw new Error('native model schema must validate without defaults, coercion or transformation');
69
+ }
70
+ catch (error) {
71
+ if (!(error instanceof Error))
72
+ throw error;
73
+ throw new NativeNodePlanningError({ stage: 'proposal-schema', output }, error);
74
+ }
75
+ try {
76
+ const nodes = assembleNativeNodeMaterials(prepared, proposal.nativeNodes);
77
+ if (proposal.nativeNodes.some((node) => apiIds.includes(node.id)))
78
+ throw new Error('native node plan contains an API callId');
79
+ createNativeOutputContracts({ nativeNodes: nodes, capabilities });
80
+ validateNativeApiResponseReferences({
81
+ nativeNodes: nodes,
82
+ capabilities,
83
+ apiCallIds: apiIds,
84
+ });
85
+ const gaps = proposal.gaps.map((gap, index) => ({
86
+ id: `${input.planId}-gap-${index + 1}`,
87
+ stage: 'workflow-graph',
88
+ description: gap.description,
89
+ }));
90
+ if (gaps.some((gap) => [...existingIds, ...nodes.map((node) => node.id)].includes(gap.id)))
91
+ throw new Error('native planning gap ID collides with a declared node');
92
+ return { nativeNodes: proposal.nativeNodes, gaps };
93
+ }
94
+ catch (error) {
95
+ if (!(error instanceof Error))
96
+ throw error;
97
+ throw new NativeNodePlanningError({ stage: 'node-validation', output: proposal }, error);
98
+ }
99
+ }
@@ -0,0 +1,3 @@
1
+ import type { ReviewableWorkflowGraphPlan } from '@openapi-flow/core';
2
+ import type { PlanReviewableWorkflowGraphInput } from '../types/reviewable-workflow-planning.js';
3
+ export declare function planReviewableWorkflowGraph(input: PlanReviewableWorkflowGraphInput): Promise<ReviewableWorkflowGraphPlan>;
@@ -0,0 +1,101 @@
1
+ import { HumanMessage, SystemMessage } from '@langchain/core/messages';
2
+ import { isDeepStrictEqual } from 'node:util';
3
+ import { z } from 'zod';
4
+ import { createReviewableWorkflowGraphPlan, createNativeOutputContracts, createWorkflowPlanningCapabilities, validateNativeApiResponseReferences, } from '@openapi-flow/core';
5
+ import { completeReviewableWorkflowGraphProposal } from './complete-reviewable-workflow-graph-proposal.js';
6
+ import { createReviewableWorkflowGraphSchema } from '../schemas/reviewable-workflow-graph-schema.js';
7
+ import { reviewableWorkflowGraphPrompt } from '../prompts/reviewable-workflow-graph-prompt.js';
8
+ import { assertSelectionInput } from '../legacy/planning/select-operation.js';
9
+ import { parseStructuredOutput } from '../legacy/planning/parse-structured-output.js';
10
+ import { ReviewableWorkflowGraphPlanningError } from './reviewable-workflow-graph-planning-error.js';
11
+ import { createPreparedNativeNodeMaterials } from './create-prepared-native-node-materials.js';
12
+ import { assembleNativeNodeMaterials } from './assemble-native-node-materials.js';
13
+ export async function planReviewableWorkflowGraph(input) {
14
+ assertSelectionInput(input.scenario, input.model);
15
+ const preparedNativeNodes = input.preparedNativeNodes ?? [];
16
+ const apiCallIds = input.materials.map((material) => material.status === 'ready' ? material.arguments.callId : material.callId);
17
+ const planningCapabilities = createWorkflowPlanningCapabilities({
18
+ capabilities: input.capabilities,
19
+ apiCallIds,
20
+ });
21
+ validateNativeApiResponseReferences({
22
+ nativeNodes: preparedNativeNodes,
23
+ capabilities: input.capabilities,
24
+ apiCallIds,
25
+ });
26
+ const nativeOutputs = createNativeOutputContracts({
27
+ nativeNodes: preparedNativeNodes,
28
+ capabilities: input.capabilities,
29
+ });
30
+ const readyIds = input.materials
31
+ .filter((item) => item.status === 'ready')
32
+ .map((item) => item.arguments.callId);
33
+ const schema = createReviewableWorkflowGraphSchema(planningCapabilities, readyIds);
34
+ const output = await input.model
35
+ .withStructuredOutput(schema, {
36
+ name: 'plan_reviewable_workflow_graph',
37
+ method: 'functionCalling',
38
+ strict: true,
39
+ })
40
+ .invoke([
41
+ new SystemMessage(reviewableWorkflowGraphPrompt),
42
+ new HumanMessage(JSON.stringify({
43
+ scenario: input.scenario,
44
+ preparedNativeNodes: createPreparedNativeNodeMaterials(preparedNativeNodes, input.capabilities),
45
+ nativeOutputs,
46
+ materials: input.materials.map(({ operation, ...material }) => ({
47
+ ...material,
48
+ operation: {
49
+ key: operation.key,
50
+ method: operation.method,
51
+ path: operation.path,
52
+ operation: {
53
+ summary: operation.operation.summary,
54
+ description: operation.operation.description,
55
+ responses: operation.operation.responses,
56
+ },
57
+ },
58
+ inputPorts: ['main'],
59
+ outputPorts: ['main'],
60
+ })),
61
+ gaps: input.gaps.map((gap) => ({
62
+ ...gap,
63
+ inputPorts: ['main'],
64
+ outputPorts: ['main'],
65
+ })),
66
+ capabilities: planningCapabilities.map((capability) => ({
67
+ name: capability.name,
68
+ description: capability.description,
69
+ parametersSchema: z.toJSONSchema(capability.parametersSchema),
70
+ waitsForAllInputs: capability.waitsForAllInputs,
71
+ exclusiveOutputPorts: capability.exclusiveOutputPorts,
72
+ })),
73
+ })),
74
+ ]);
75
+ let proposal;
76
+ try {
77
+ const parsed = parseStructuredOutput(schema, output, 'model reviewable workflow graph');
78
+ if (!isDeepStrictEqual(parsed, output))
79
+ throw new Error('native model schema must validate without defaults, coercion or transformation');
80
+ proposal = completeReviewableWorkflowGraphProposal(parsed, input.capabilities.length, readyIds.length);
81
+ }
82
+ catch (error) {
83
+ if (!(error instanceof Error))
84
+ throw error;
85
+ throw new ReviewableWorkflowGraphPlanningError({ stage: 'proposal-schema', output }, error);
86
+ }
87
+ try {
88
+ return createReviewableWorkflowGraphPlan({
89
+ ...input,
90
+ proposal: {
91
+ ...proposal,
92
+ nativeNodes: assembleNativeNodeMaterials(preparedNativeNodes, proposal.nativeNodes),
93
+ },
94
+ });
95
+ }
96
+ catch (error) {
97
+ if (!(error instanceof Error))
98
+ throw error;
99
+ throw new ReviewableWorkflowGraphPlanningError({ stage: 'graph-validation', output }, error);
100
+ }
101
+ }
@@ -0,0 +1,3 @@
1
+ import type { ReviewableWorkflowGraphPlan } from '@openapi-flow/core';
2
+ import type { PlanWorkflowConnectionsInput } from '../types/workflow-orchestration.js';
3
+ export declare function planWorkflowConnections(input: PlanWorkflowConnectionsInput): Promise<ReviewableWorkflowGraphPlan>;
@@ -0,0 +1,62 @@
1
+ import { HumanMessage, SystemMessage } from '@langchain/core/messages';
2
+ import { createReviewableWorkflowGraphPlan } from '@openapi-flow/core';
3
+ import { createReviewableWorkflowGraphSchema } from '../schemas/reviewable-workflow-graph-schema.js';
4
+ import { completeReviewableWorkflowGraphProposal } from './complete-reviewable-workflow-graph-proposal.js';
5
+ import { workflowConnectionsPrompt } from '../prompts/workflow-connections-prompt.js';
6
+ import { assertSelectionInput } from '../legacy/planning/select-operation.js';
7
+ import { parseStructuredOutput } from '../legacy/planning/parse-structured-output.js';
8
+ import { ReviewableWorkflowGraphPlanningError } from './reviewable-workflow-graph-planning-error.js';
9
+ import { prepareWorkflowConnectionMaterials } from './prepare-workflow-connection-materials.js';
10
+ import { createPreparedNativeNodeMaterials } from './create-prepared-native-node-materials.js';
11
+ export async function planWorkflowConnections(input) {
12
+ assertSelectionInput(input.scenario, input.model);
13
+ const { materials, capabilities, nativeNodes, gaps, edges, contracts } = prepareWorkflowConnectionMaterials(input);
14
+ const context = { materials, capabilities, gaps };
15
+ const readyIds = materials.flatMap((material) => material.status === 'ready' ? [material.arguments.callId] : []);
16
+ const schema = createReviewableWorkflowGraphSchema([], readyIds);
17
+ const output = await input.model
18
+ .withStructuredOutput(schema, {
19
+ name: 'plan_workflow_connections',
20
+ method: 'functionCalling',
21
+ strict: true,
22
+ })
23
+ .invoke([
24
+ new SystemMessage(workflowConnectionsPrompt),
25
+ new HumanMessage(JSON.stringify({
26
+ scenario: input.scenario,
27
+ nodes: contracts,
28
+ ...(nativeNodes.length
29
+ ? {
30
+ nativeNodes: createPreparedNativeNodeMaterials(nativeNodes, capabilities),
31
+ }
32
+ : {}),
33
+ edges,
34
+ gaps,
35
+ readyCallIds: readyIds,
36
+ })),
37
+ ]);
38
+ let proposal;
39
+ try {
40
+ proposal = completeReviewableWorkflowGraphProposal(parseStructuredOutput(schema, output, 'model workflow connections'), 0, readyIds.length);
41
+ }
42
+ catch (error) {
43
+ if (!(error instanceof Error))
44
+ throw error;
45
+ throw new ReviewableWorkflowGraphPlanningError({ stage: 'proposal-schema', output }, error);
46
+ }
47
+ try {
48
+ return createReviewableWorkflowGraphPlan({
49
+ ...context,
50
+ proposal: {
51
+ ...proposal,
52
+ nativeNodes,
53
+ edges: [...edges, ...proposal.edges],
54
+ },
55
+ });
56
+ }
57
+ catch (error) {
58
+ if (!(error instanceof Error))
59
+ throw error;
60
+ throw new ReviewableWorkflowGraphPlanningError({ stage: 'graph-validation', output }, error);
61
+ }
62
+ }
@@ -0,0 +1,3 @@
1
+ import type { WorkflowGraphPlan } from '@openapi-flow/core';
2
+ import type { PlanWorkflowGraphInput } from '../types/workflow-planning.js';
3
+ export declare function planWorkflowGraph(input: PlanWorkflowGraphInput): Promise<WorkflowGraphPlan>;
@@ -0,0 +1,99 @@
1
+ import { SystemMessage, HumanMessage } from '@langchain/core/messages';
2
+ import { isDeepStrictEqual } from 'node:util';
3
+ import { createWorkflowGraphPlan, createNativeOutputContracts, createWorkflowPlanningCapabilities, validateNativeApiResponseReferences, } from '@openapi-flow/core';
4
+ import { z } from 'zod';
5
+ import { createWorkflowGraphProposalSchema } from '../schemas/workflow-graph-proposal-schema.js';
6
+ import { WorkflowGraphPlanningError } from './workflow-graph-planning-error.js';
7
+ import { workflowGraphPrompt } from '../prompts/workflow-graph-prompt.js';
8
+ import { assertSelectionInput } from '../legacy/planning/select-operation.js';
9
+ import { parseStructuredOutput } from '../legacy/planning/parse-structured-output.js';
10
+ import { createPreparedNativeNodeMaterials } from './create-prepared-native-node-materials.js';
11
+ import { assembleNativeNodeMaterials } from './assemble-native-node-materials.js';
12
+ export async function planWorkflowGraph(input) {
13
+ assertSelectionInput(input.scenario, input.model);
14
+ const preparedNativeNodes = input.preparedNativeNodes ?? [];
15
+ const apiCallIds = input.materials.map((material) => material.arguments.callId);
16
+ const planningCapabilities = createWorkflowPlanningCapabilities({
17
+ capabilities: input.capabilities,
18
+ apiCallIds,
19
+ });
20
+ const schema = createWorkflowGraphProposalSchema(planningCapabilities);
21
+ validateNativeApiResponseReferences({
22
+ nativeNodes: preparedNativeNodes,
23
+ capabilities: input.capabilities,
24
+ apiCallIds,
25
+ });
26
+ const nativeOutputs = createNativeOutputContracts({
27
+ nativeNodes: preparedNativeNodes,
28
+ capabilities: input.capabilities,
29
+ });
30
+ const output = await input.model
31
+ .withStructuredOutput(schema, {
32
+ name: 'plan_workflow_graph',
33
+ method: 'functionCalling',
34
+ strict: true,
35
+ })
36
+ .invoke([
37
+ new SystemMessage(workflowGraphPrompt),
38
+ new HumanMessage(JSON.stringify({
39
+ scenario: input.scenario,
40
+ preparedNativeNodes: createPreparedNativeNodeMaterials(preparedNativeNodes, input.capabilities),
41
+ nativeOutputs,
42
+ // Request values are already generated. Avoid duplicating the resolved
43
+ // response schemas through both operation and pathItem in this stage.
44
+ materials: input.materials.map(({ operation, arguments: args }) => ({
45
+ operation: {
46
+ key: operation.key,
47
+ method: operation.method,
48
+ path: operation.path,
49
+ operation: {
50
+ summary: operation.operation.summary,
51
+ description: operation.operation.description,
52
+ tags: operation.operation.tags,
53
+ responses: operation.operation.responses,
54
+ },
55
+ },
56
+ arguments: {
57
+ callId: args.callId,
58
+ values: args.values,
59
+ bindings: args.bindings,
60
+ },
61
+ inputPorts: ['main'],
62
+ outputPorts: ['main'],
63
+ })),
64
+ capabilities: planningCapabilities.map((capability) => ({
65
+ name: capability.name,
66
+ description: capability.description,
67
+ parametersSchema: z.toJSONSchema(capability.parametersSchema),
68
+ waitsForAllInputs: capability.waitsForAllInputs,
69
+ exclusiveOutputPorts: capability.exclusiveOutputPorts,
70
+ })),
71
+ })),
72
+ ]);
73
+ let proposal;
74
+ try {
75
+ proposal = parseStructuredOutput(schema, output, 'model workflow graph');
76
+ if (!isDeepStrictEqual(proposal, output))
77
+ throw new Error('native model schema must validate without defaults, coercion or transformation');
78
+ }
79
+ catch (error) {
80
+ if (!(error instanceof Error))
81
+ throw error;
82
+ throw new WorkflowGraphPlanningError({ stage: 'proposal-schema', output }, error);
83
+ }
84
+ try {
85
+ return createWorkflowGraphPlan({
86
+ ...input,
87
+ proposal: {
88
+ edges: proposal.edges,
89
+ gaps: proposal.gaps,
90
+ nativeNodes: assembleNativeNodeMaterials(preparedNativeNodes, proposal.additionalNativeNodes),
91
+ },
92
+ });
93
+ }
94
+ catch (error) {
95
+ if (!(error instanceof Error))
96
+ throw error;
97
+ throw new WorkflowGraphPlanningError({ stage: 'graph-validation', output: proposal }, error);
98
+ }
99
+ }
@@ -0,0 +1,3 @@
1
+ import type { PlanWorkflowConnectionsInput, WorkflowConnectionMaterials } from '../types/workflow-orchestration.js';
2
+ /** Validate immutable supplied data before paying for any orchestration model call. */
3
+ export declare function prepareWorkflowConnectionMaterials(input: PlanWorkflowConnectionsInput): WorkflowConnectionMaterials;
@@ -0,0 +1,66 @@
1
+ import { createReviewableNodeContracts, createNativeOutputContracts, validateWorkflowEdges, validateApiArguments, validateApiBindingAssignments, validateNativeApiResponseReferences, } from '@openapi-flow/core';
2
+ /** Validate immutable supplied data before paying for any orchestration model call. */
3
+ export function prepareWorkflowConnectionMaterials(input) {
4
+ const materials = input.materials ?? [];
5
+ const capabilities = input.capabilities ?? [];
6
+ const nativeNodes = input.nativeNodes ?? [];
7
+ const gaps = input.gaps ?? [];
8
+ const edges = input.edges ?? [];
9
+ validateNativeApiResponseReferences({
10
+ nativeNodes,
11
+ capabilities,
12
+ apiCallIds: materials.map((material) => material.status === 'ready' ? material.arguments.callId : material.callId),
13
+ });
14
+ const nativeOutputs = createNativeOutputContracts({
15
+ nativeNodes,
16
+ capabilities,
17
+ });
18
+ for (const material of materials) {
19
+ if (material.status !== 'ready')
20
+ continue;
21
+ const args = material.arguments;
22
+ const validation = validateApiArguments({
23
+ operation: material.operation,
24
+ ...args,
25
+ });
26
+ if (args.unresolvedInputs.length || !validation.valid)
27
+ throw new Error(`materials[${args.callId}] has unresolved OAS request inputs`);
28
+ }
29
+ if (materials.length)
30
+ validateApiBindingAssignments({
31
+ nativeOutputs,
32
+ materials: materials.map((material) => ({
33
+ operation: material.operation,
34
+ callId: material.status === 'ready'
35
+ ? material.arguments.callId
36
+ : material.callId,
37
+ requestMediaType: material.status === 'ready'
38
+ ? material.arguments.requestMediaType
39
+ : material.requestMediaType,
40
+ })),
41
+ calls: materials.map((material) => ({
42
+ callId: material.status === 'ready'
43
+ ? material.arguments.callId
44
+ : material.callId,
45
+ bindings: material.status === 'ready'
46
+ ? material.arguments.bindings
47
+ : material.bindings,
48
+ })),
49
+ });
50
+ const plan = {
51
+ nativeNodes,
52
+ gaps,
53
+ edges,
54
+ starts: [],
55
+ blockedCalls: materials.flatMap((material) => material.status === 'blocked'
56
+ ? [{ callId: material.callId, gapIds: material.gapIds }]
57
+ : []),
58
+ };
59
+ const contracts = createReviewableNodeContracts({
60
+ materials,
61
+ capabilities,
62
+ plan,
63
+ });
64
+ validateWorkflowEdges({ contracts, edges });
65
+ return { materials, capabilities, nativeNodes, gaps, edges, contracts };
66
+ }