@openapi-flow/langchain 0.3.14 → 0.3.16

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 (46) hide show
  1. package/README.md +14 -0
  2. package/dist/arguments/analyze-api-input-answers.js +118 -84
  3. package/dist/arguments/generate-api-arguments.js +105 -81
  4. package/dist/bindings/plan-api-bindings-by-call.d.ts +4 -0
  5. package/dist/bindings/plan-api-bindings-by-call.js +77 -0
  6. package/dist/bindings/plan-api-bindings.js +1 -0
  7. package/dist/bindings/plan-api-call-bindings.d.ts +3 -0
  8. package/dist/bindings/plan-api-call-bindings.js +82 -0
  9. package/dist/bindings/select-api-binding-sources.d.ts +3 -0
  10. package/dist/bindings/select-api-binding-sources.js +55 -0
  11. package/dist/model/invoke-structured-model.js +2 -2
  12. package/dist/prompts/api-call-bindings-prompt.d.ts +2 -0
  13. package/dist/prompts/api-call-bindings-prompt.js +8 -0
  14. package/dist/prompts/incremental-workflow-connections-prompt.d.ts +2 -0
  15. package/dist/prompts/incremental-workflow-connections-prompt.js +10 -0
  16. package/dist/public-api.d.ts +8 -0
  17. package/dist/public-api.js +6 -0
  18. package/dist/schemas/api-call-binding-plan-schema.d.ts +7 -0
  19. package/dist/schemas/api-call-binding-plan-schema.js +46 -0
  20. package/dist/schemas/connection-planning-field-schemas.d.ts +8 -0
  21. package/dist/schemas/connection-planning-field-schemas.js +27 -0
  22. package/dist/schemas/workflow-connection-goals-schema.d.ts +4 -0
  23. package/dist/schemas/workflow-connection-goals-schema.js +53 -0
  24. package/dist/schemas/workflow-connection-step-schema.d.ts +4 -0
  25. package/dist/schemas/workflow-connection-step-schema.js +69 -0
  26. package/dist/selection/select-api-operations.js +1 -0
  27. package/dist/types/api-call-binding-planning.d.ts +17 -0
  28. package/dist/types/api-call-binding-planning.js +1 -0
  29. package/dist/types/incremental-connection-planning.d.ts +60 -0
  30. package/dist/types/incremental-connection-planning.js +1 -0
  31. package/dist/types/native-node-planning.d.ts +3 -0
  32. package/dist/types/structured-model.d.ts +4 -1
  33. package/dist/workflow/connections/invoke-connection-planning-model.d.ts +3 -0
  34. package/dist/workflow/connections/invoke-connection-planning-model.js +35 -0
  35. package/dist/workflow/connections/plan-workflow-connection-goals.d.ts +4 -0
  36. package/dist/workflow/connections/plan-workflow-connection-goals.js +55 -0
  37. package/dist/workflow/connections/plan-workflow-connection-step.d.ts +2 -0
  38. package/dist/workflow/connections/plan-workflow-connection-step.js +98 -0
  39. package/dist/workflow/connections/resolve-connection-port-selection.d.ts +4 -0
  40. package/dist/workflow/connections/resolve-connection-port-selection.js +15 -0
  41. package/dist/workflow/connections/workflow-connection-planning-error.d.ts +8 -0
  42. package/dist/workflow/connections/workflow-connection-planning-error.js +26 -0
  43. package/dist/workflow/generate-native-node-parameters.js +3 -1
  44. package/dist/workflow/plan-native-instance-dependencies.js +3 -1
  45. package/dist/workflow/select-native-node-instances.js +3 -1
  46. package/package.json +2 -2
@@ -0,0 +1,98 @@
1
+ import { isDeepStrictEqual } from 'node:util';
2
+ import { HumanMessage, SystemMessage } from '@langchain/core/messages';
3
+ import { describeWorkflowConnectionStep, workflowConnectionPlanningDecisionSchema, workflowConnectionRejectedProposalSchema, runOpenApiFlowOperation, } from '@openapi-flow/core';
4
+ import { createWorkflowConnectionStepSchema } from '../../schemas/workflow-connection-step-schema.js';
5
+ import { workflowConnectionStepPrompt } from '../../prompts/incremental-workflow-connections-prompt.js';
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';
9
+ export async function planWorkflowConnectionStep(input) {
10
+ const operation = 'planWorkflowConnectionStep';
11
+ const { description, capabilities, capabilityIndex, schema } = runOpenApiFlowOperation({
12
+ owner: 'langchain',
13
+ operation,
14
+ stage: 'input-validation',
15
+ code: 'PLANNING_INPUT_INVALID',
16
+ }, () => {
17
+ const description = describeWorkflowConnectionStep(input);
18
+ if (input.rejectedProposals !== undefined) {
19
+ if (!Array.isArray(input.rejectedProposals))
20
+ throw new Error('rejectedProposals must be an array when supplied');
21
+ for (const proposal of input.rejectedProposals) {
22
+ workflowConnectionRejectedProposalSchema.parse(proposal);
23
+ if (proposal.expected.sessionId !== description.expected.sessionId ||
24
+ proposal.expected.sourceFingerprint !==
25
+ description.expected.sourceFingerprint ||
26
+ proposal.expected.revision > description.expected.revision)
27
+ throw new Error('Rejected proposal must belong to this session/source and not a future revision');
28
+ }
29
+ }
30
+ // An omitted optional registry has no augmentation choices; never infer an engine registry.
31
+ const capabilities = input.capabilities === undefined ? [] : input.capabilities;
32
+ return {
33
+ description,
34
+ capabilities,
35
+ capabilityIndex: capabilities.map(({ name, description }) => ({
36
+ name,
37
+ description,
38
+ })),
39
+ schema: createWorkflowConnectionStepSchema(description, capabilities),
40
+ };
41
+ });
42
+ const output = await invokeConnectionPlanningModel({
43
+ model: input.model,
44
+ operation,
45
+ name: 'plan_workflow_connection_step',
46
+ schema,
47
+ messages: [
48
+ new SystemMessage(workflowConnectionStepPrompt),
49
+ new HumanMessage(JSON.stringify({
50
+ ...description,
51
+ availableNativeCapabilities: capabilityIndex,
52
+ ...(input.rejectedProposals === undefined
53
+ ? {}
54
+ : { rejectedProposals: input.rejectedProposals }),
55
+ })),
56
+ ],
57
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
58
+ });
59
+ return validateConnectionProposal({
60
+ operation,
61
+ stage: 'contract-validation',
62
+ code: 'WORKFLOW_GRAPH_PLANNING_FAILED',
63
+ output,
64
+ }, () => {
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
+ const raw = output.decision;
70
+ const decision = raw.kind !== 'patch'
71
+ ? raw
72
+ : {
73
+ ...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
+ })),
92
+ };
93
+ return {
94
+ expected: structuredClone(description.expected),
95
+ decision: workflowConnectionPlanningDecisionSchema.parse(decision),
96
+ };
97
+ });
98
+ }
@@ -0,0 +1,4 @@
1
+ import type { WorkflowPlanNodeContract } from '@openapi-flow/core';
2
+ import type { WorkflowConnectionEndpointSelection } from '../../types/incremental-connection-planning.js';
3
+ /** The schema deliberately excludes a unique port from the model's decision. This is not a fallback. */
4
+ export declare function resolveConnectionPortSelection(selection: WorkflowConnectionEndpointSelection, contracts: WorkflowPlanNodeContract[], direction: 'inputs' | 'outputs'): string;
@@ -0,0 +1,15 @@
1
+ /** The schema deliberately excludes a unique port from the model's decision. This is not a fallback. */
2
+ export function resolveConnectionPortSelection(selection, contracts, direction) {
3
+ const node = contracts.find((contract) => contract.id === selection.nodeId);
4
+ if (!node)
5
+ throw new Error(`Connection selection has no node ${selection.nodeId}`);
6
+ const ports = node[direction];
7
+ if (ports.length === 1) {
8
+ if (selection.port !== undefined)
9
+ throw new Error(`Connection selection ${node.id} must not regenerate its unique port`);
10
+ return ports[0];
11
+ }
12
+ if (selection.port === undefined || !ports.includes(selection.port))
13
+ throw new Error(`Connection selection ${node.id} requires an actual ${direction} port`);
14
+ return selection.port;
15
+ }
@@ -0,0 +1,8 @@
1
+ import { OpenApiFlowError } from '@openapi-flow/core';
2
+ import type { WorkflowConnectionPlanningFailure } from '../../types/incremental-connection-planning.js';
3
+ /** Raw output is retained for a private host diagnostic, not in the public error projection. */
4
+ export declare class WorkflowConnectionPlanningError extends OpenApiFlowError {
5
+ readonly output: unknown;
6
+ constructor(failure: WorkflowConnectionPlanningFailure, cause: unknown);
7
+ }
8
+ export declare function validateConnectionProposal<Result>(failure: WorkflowConnectionPlanningFailure, execute: () => Result): Result;
@@ -0,0 +1,26 @@
1
+ import { OpenApiFlowError } from '@openapi-flow/core';
2
+ /** Raw output is retained for a private host diagnostic, not in the public error projection. */
3
+ export class WorkflowConnectionPlanningError extends OpenApiFlowError {
4
+ output;
5
+ constructor(failure, cause) {
6
+ super({
7
+ message: cause instanceof Error ? cause.message : failure.operation,
8
+ diagnostic: {
9
+ owner: 'langchain',
10
+ operation: failure.operation,
11
+ stage: failure.stage,
12
+ code: failure.code,
13
+ },
14
+ cause,
15
+ });
16
+ this.output = failure.output;
17
+ }
18
+ }
19
+ export function validateConnectionProposal(failure, execute) {
20
+ try {
21
+ return execute();
22
+ }
23
+ catch (cause) {
24
+ throw new WorkflowConnectionPlanningError(failure, cause);
25
+ }
26
+ }
@@ -5,6 +5,7 @@ import { nativeNodeParametersPrompt } from '../prompts/native-node-planning-prom
5
5
  import { NativeNodePlanningError } from './native-node-planning-error.js';
6
6
  /** Zero or one value call for one selected instance; no hidden ownership or connection planning. */
7
7
  export async function generateNativeNodeParameters(input) {
8
+ input.signal?.throwIfAborted();
8
9
  if (input.model !== undefined &&
9
10
  (!input.model || typeof input.model.withStructuredOutput !== 'function'))
10
11
  throw new Error('generateNativeNodeParameters.model must support structured output when supplied');
@@ -62,7 +63,8 @@ export async function generateNativeNodeParameters(input) {
62
63
  ? {}
63
64
  : { replies: description.replies }),
64
65
  })),
65
- ]);
66
+ ], input.signal === undefined ? undefined : { signal: input.signal });
67
+ input.signal?.throwIfAborted();
66
68
  try {
67
69
  // Validate output separately so callers can distinguish a malformed reply from stale source material.
68
70
  schema.parse(output);
@@ -6,6 +6,7 @@ import { serializeStructuredOutputSchema } from '../schemas/serialize-structured
6
6
  import { NativeNodePlanningError } from './native-node-planning-error.js';
7
7
  /** Zero or one producer-choice call; no parameters, output contracts or runtime DAG edges. */
8
8
  export async function planNativeInstanceDependencies(input) {
9
+ input.signal?.throwIfAborted();
9
10
  if (input.model !== undefined &&
10
11
  (!input.model || typeof input.model.withStructuredOutput !== 'function'))
11
12
  throw new Error('planNativeInstanceDependencies.model must support structured output when supplied');
@@ -30,7 +31,8 @@ export async function planNativeInstanceDependencies(input) {
30
31
  .invoke([
31
32
  new SystemMessage(nativeInstanceDependenciesPrompt),
32
33
  new HumanMessage(JSON.stringify(context)),
33
- ]);
34
+ ], input.signal === undefined ? undefined : { signal: input.signal });
35
+ input.signal?.throwIfAborted();
34
36
  try {
35
37
  if (!isDeepStrictEqual(describeNativeInstanceDependencies(input), context) ||
36
38
  explanations !== input.includeExplanations)
@@ -6,6 +6,7 @@ import { nativeInstanceSelectionPrompt } from '../prompts/native-node-planning-p
6
6
  import { NativeNodePlanningError } from './native-node-planning-error.js';
7
7
  /** One checkpointable role/ownership selection; parameter values are a separate public stage. */
8
8
  export async function selectNativeNodeInstances(input) {
9
+ input.signal?.throwIfAborted();
9
10
  if (input.model !== undefined &&
10
11
  (!input.model || typeof input.model.withStructuredOutput !== 'function'))
11
12
  throw new Error('selectNativeNodeInstances.model must support structured output when supplied');
@@ -38,7 +39,8 @@ export async function selectNativeNodeInstances(input) {
38
39
  .invoke([
39
40
  new SystemMessage(nativeInstanceSelectionPrompt),
40
41
  new HumanMessage(JSON.stringify(context)),
41
- ]);
42
+ ], input.signal === undefined ? undefined : { signal: input.signal });
43
+ input.signal?.throwIfAborted();
42
44
  try {
43
45
  if (!isDeepStrictEqual(describeNativeInstanceSelection(input).context, context) ||
44
46
  JSON.stringify([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openapi-flow/langchain",
3
- "version": "0.3.14",
3
+ "version": "0.3.16",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Composable LangChain planning for OpenAPI workflows",
@@ -28,7 +28,7 @@
28
28
  "typecheck": "tsc -p tsconfig.json --noEmit"
29
29
  },
30
30
  "dependencies": {
31
- "@openapi-flow/core": "0.3.14"
31
+ "@openapi-flow/core": "0.3.16"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "@langchain/core": "^1.0.0",