@openapi-flow/langchain 0.3.18 → 0.4.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.
- package/README.md +21 -0
- package/dist/arguments/analyze-api-input-answers.js +3 -0
- package/dist/arguments/api-argument-planning-error.d.ts +11 -0
- package/dist/arguments/api-argument-planning-error.js +32 -0
- package/dist/arguments/create-api-argument-rejection.d.ts +3 -0
- package/dist/arguments/create-api-argument-rejection.js +31 -0
- package/dist/arguments/fingerprint-api-argument-source.d.ts +4 -0
- package/dist/arguments/fingerprint-api-argument-source.js +12 -0
- package/dist/arguments/generate-api-arguments.js +78 -32
- package/dist/arguments/interpret-api-argument-enums.js +1 -0
- package/dist/arguments/resolve-api-literal-generation-output.d.ts +3 -0
- package/dist/arguments/resolve-api-literal-generation-output.js +14 -0
- package/dist/bindings/plan-api-bindings-by-call.js +12 -3
- package/dist/model/invoke-structured-model.js +32 -6
- package/dist/prompts/api-arguments-prompt.d.ts +2 -1
- package/dist/prompts/api-arguments-prompt.js +2 -1
- package/dist/prompts/incremental-workflow-connections-prompt.d.ts +2 -2
- package/dist/prompts/incremental-workflow-connections-prompt.js +5 -4
- package/dist/prompts/native-instance-selection-review-prompt.d.ts +1 -0
- package/dist/prompts/native-instance-selection-review-prompt.js +8 -0
- package/dist/prompts/native-node-planning-prompt.d.ts +1 -1
- package/dist/prompts/native-node-planning-prompt.js +1 -0
- package/dist/prompts/workflow-connection-goal-recovery-prompt.d.ts +1 -0
- package/dist/prompts/workflow-connection-goal-recovery-prompt.js +8 -0
- package/dist/prompts/workflow-connection-goal-review-prompt.d.ts +1 -0
- package/dist/prompts/workflow-connection-goal-review-prompt.js +7 -0
- package/dist/prompts/workflow-connection-outline-prompt.d.ts +1 -0
- package/dist/prompts/workflow-connection-outline-prompt.js +6 -0
- package/dist/prompts/workflow-connection-revision-prompt.d.ts +1 -0
- package/dist/prompts/workflow-connection-revision-prompt.js +10 -0
- package/dist/public-api.d.ts +20 -0
- package/dist/public-api.js +15 -0
- package/dist/schemas/api-argument-rejection-schema.d.ts +28 -0
- package/dist/schemas/api-argument-rejection-schema.js +20 -0
- package/dist/schemas/api-literal-generation-output-schema.d.ts +53 -1
- package/dist/schemas/api-literal-generation-output-schema.js +37 -12
- package/dist/schemas/create-connection-material-repair-choice-schema.d.ts +4 -0
- package/dist/schemas/create-connection-material-repair-choice-schema.js +21 -0
- package/dist/schemas/model-signal-schema.d.ts +3 -0
- package/dist/schemas/model-signal-schema.js +3 -0
- package/dist/schemas/native-node-parameter-contract.js +2 -0
- package/dist/schemas/native-node-planning-contract.js +30 -23
- package/dist/schemas/workflow-connection-goal-recovery-schema.d.ts +4 -0
- package/dist/schemas/workflow-connection-goal-recovery-schema.js +16 -0
- package/dist/schemas/workflow-connection-goal-rejection-schema.d.ts +76 -0
- package/dist/schemas/workflow-connection-goal-rejection-schema.js +2 -1
- package/dist/schemas/workflow-connection-goal-review-schema.d.ts +4 -0
- package/dist/schemas/workflow-connection-goal-review-schema.js +26 -0
- package/dist/schemas/workflow-connection-goals-schema.d.ts +4 -2
- package/dist/schemas/workflow-connection-outline-rejection-schema.d.ts +25 -0
- package/dist/schemas/workflow-connection-outline-rejection-schema.js +21 -0
- package/dist/schemas/workflow-connection-outline-schema.d.ts +3 -0
- package/dist/schemas/workflow-connection-outline-schema.js +25 -0
- package/dist/schemas/workflow-connection-revision-rejection-schema.d.ts +113 -0
- package/dist/schemas/workflow-connection-revision-rejection-schema.js +23 -0
- package/dist/schemas/workflow-connection-revision-schema.d.ts +4 -0
- package/dist/schemas/workflow-connection-revision-schema.js +23 -0
- package/dist/schemas/workflow-connection-step-schema.d.ts +5 -3
- package/dist/schemas/workflow-connection-step-schema.js +62 -31
- package/dist/types/api-input-answers.d.ts +1 -0
- package/dist/types/argument-generation.d.ts +31 -11
- package/dist/types/incremental-connection-planning.d.ts +10 -3
- package/dist/types/native-instance-selection-review.d.ts +9 -0
- package/dist/types/native-instance-selection-review.js +1 -0
- package/dist/types/native-node-planning.d.ts +6 -2
- package/dist/types/workflow-connection-goal-recovery.d.ts +22 -0
- package/dist/types/workflow-connection-goal-recovery.js +1 -0
- package/dist/types/workflow-connection-goal-review.d.ts +13 -0
- package/dist/types/workflow-connection-goal-review.js +1 -0
- package/dist/types/workflow-connection-outline.d.ts +22 -0
- package/dist/types/workflow-connection-outline.js +1 -0
- package/dist/types/workflow-connection-revision.d.ts +34 -0
- package/dist/types/workflow-connection-revision.js +1 -0
- package/dist/workflow/connections/create-workflow-connection-goal-rejection.js +8 -2
- package/dist/workflow/connections/create-workflow-connection-outline-rejection.d.ts +3 -0
- package/dist/workflow/connections/create-workflow-connection-outline-rejection.js +28 -0
- package/dist/workflow/connections/create-workflow-connection-revision-rejection.d.ts +3 -0
- package/dist/workflow/connections/create-workflow-connection-revision-rejection.js +32 -0
- package/dist/workflow/connections/describe-workflow-connection-outline-request.d.ts +3 -0
- package/dist/workflow/connections/describe-workflow-connection-outline-request.js +30 -0
- package/dist/workflow/connections/invoke-connection-planning-model.js +3 -0
- package/dist/workflow/connections/plan-workflow-connection-goal-recovery.d.ts +3 -0
- package/dist/workflow/connections/plan-workflow-connection-goal-recovery.js +111 -0
- package/dist/workflow/connections/plan-workflow-connection-goals.js +35 -16
- package/dist/workflow/connections/plan-workflow-connection-outline.d.ts +4 -0
- package/dist/workflow/connections/plan-workflow-connection-outline.js +93 -0
- package/dist/workflow/connections/plan-workflow-connection-revision.d.ts +3 -0
- package/dist/workflow/connections/plan-workflow-connection-revision.js +163 -0
- package/dist/workflow/connections/plan-workflow-connection-step.js +75 -29
- package/dist/workflow/connections/resolve-connection-selections.d.ts +6 -0
- package/dist/workflow/connections/resolve-connection-selections.js +28 -0
- package/dist/workflow/connections/review-workflow-connection-goals.d.ts +4 -0
- package/dist/workflow/connections/review-workflow-connection-goals.js +64 -0
- package/dist/workflow/connections/validate-workflow-goal-review-feedback.d.ts +4 -0
- package/dist/workflow/connections/validate-workflow-goal-review-feedback.js +22 -0
- package/dist/workflow/connections/workflow-connection-planning-error.d.ts +1 -0
- package/dist/workflow/connections/workflow-connection-planning-error.js +2 -0
- package/dist/workflow/native-selection/native-instance-selection-review-error.d.ts +6 -0
- package/dist/workflow/native-selection/native-instance-selection-review-error.js +18 -0
- package/dist/workflow/native-selection/review-native-instance-selection.d.ts +4 -0
- package/dist/workflow/native-selection/review-native-instance-selection.js +81 -0
- package/dist/workflow/resolve-native-node-planning-output.js +3 -1
- package/dist/workflow/select-native-node-instances.js +11 -2
- package/package.json +2 -2
|
@@ -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 {
|
|
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
|
-
...(
|
|
108
|
+
...(rejectedSnapshot === undefined
|
|
53
109
|
? {}
|
|
54
|
-
: { 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
|
|
75
|
-
|
|
76
|
-
|
|
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
|
+
}
|
|
@@ -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,6 @@
|
|
|
1
|
+
import { OpenApiFlowError } from '@openapi-flow/core';
|
|
2
|
+
import type { NativeInstanceSelectionReviewFailure } from '../../types/native-instance-selection-review.js';
|
|
3
|
+
export declare class NativeInstanceSelectionReviewError extends OpenApiFlowError {
|
|
4
|
+
readonly failure: NativeInstanceSelectionReviewFailure;
|
|
5
|
+
constructor(failure: NativeInstanceSelectionReviewFailure, cause: Error);
|
|
6
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { OpenApiFlowError } from '@openapi-flow/core';
|
|
2
|
+
export class NativeInstanceSelectionReviewError extends OpenApiFlowError {
|
|
3
|
+
failure;
|
|
4
|
+
constructor(failure, cause) {
|
|
5
|
+
super({
|
|
6
|
+
message: `Native selection review failed: ${cause.message}`,
|
|
7
|
+
diagnostic: {
|
|
8
|
+
owner: 'langchain',
|
|
9
|
+
operation: 'reviewNativeInstanceSelection',
|
|
10
|
+
stage: 'model-output',
|
|
11
|
+
code: 'MODEL_OUTPUT_INVALID',
|
|
12
|
+
},
|
|
13
|
+
cause,
|
|
14
|
+
});
|
|
15
|
+
this.name = 'NativeInstanceSelectionReviewError';
|
|
16
|
+
this.failure = failure;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { NativeInstanceSelectionReview } from '@openapi-flow/core';
|
|
2
|
+
import type { ReviewNativeInstanceSelectionInput } from '../../types/native-instance-selection-review.js';
|
|
3
|
+
/** One review call only. The host owns replanning, user questions, budgets and persistence. */
|
|
4
|
+
export declare function reviewNativeInstanceSelection(input: ReviewNativeInstanceSelectionInput): Promise<NativeInstanceSelectionReview>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
2
|
+
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
|
|
3
|
+
import { describeNativeInstanceSelectionReview, createNativeInstanceSelectionReview, createNativeInstanceSelectionReviewSchema, runOpenApiFlowOperation, } from '@openapi-flow/core';
|
|
4
|
+
import { invokeStructuredModel } from '../../model/invoke-structured-model.js';
|
|
5
|
+
import { serializeStructuredOutputSchema } from '../../schemas/serialize-structured-output-schema.js';
|
|
6
|
+
import { modelSignalSchema } from '../../schemas/model-signal-schema.js';
|
|
7
|
+
import { nativeInstanceSelectionReviewPrompt } from '../../prompts/native-instance-selection-review-prompt.js';
|
|
8
|
+
import { NativeInstanceSelectionReviewError } from './native-instance-selection-review-error.js';
|
|
9
|
+
/** One review call only. The host owns replanning, user questions, budgets and persistence. */
|
|
10
|
+
export async function reviewNativeInstanceSelection(input) {
|
|
11
|
+
const operation = 'reviewNativeInstanceSelection';
|
|
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 describeNativeInstanceSelectionReview(input);
|
|
20
|
+
});
|
|
21
|
+
input.signal?.throwIfAborted();
|
|
22
|
+
if (!description.gaps.length)
|
|
23
|
+
return createNativeInstanceSelectionReview({
|
|
24
|
+
...input,
|
|
25
|
+
proposal: { assessments: {} },
|
|
26
|
+
});
|
|
27
|
+
const model = runOpenApiFlowOperation({
|
|
28
|
+
owner: 'langchain',
|
|
29
|
+
operation,
|
|
30
|
+
stage: 'model-configuration',
|
|
31
|
+
code: 'MODEL_CONFIGURATION_FAILED',
|
|
32
|
+
}, () => {
|
|
33
|
+
if (!input.model ||
|
|
34
|
+
typeof input.model.withStructuredOutput !== 'function')
|
|
35
|
+
throw new Error('reviewNativeInstanceSelection.model must support structured output for reported gaps');
|
|
36
|
+
return input.model;
|
|
37
|
+
});
|
|
38
|
+
const checkCurrent = (originalFailure) => {
|
|
39
|
+
runOpenApiFlowOperation({
|
|
40
|
+
owner: 'langchain',
|
|
41
|
+
operation,
|
|
42
|
+
stage: 'input-validation',
|
|
43
|
+
code: 'PLANNING_INPUT_INVALID',
|
|
44
|
+
}, () => {
|
|
45
|
+
try {
|
|
46
|
+
if (!isDeepStrictEqual(description, describeNativeInstanceSelectionReview(input)))
|
|
47
|
+
throw new Error('Native selection review source changed during model invocation');
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (originalFailure !== undefined)
|
|
51
|
+
throw new AggregateError([originalFailure, error], 'Native review input changed while a failed model call was received', { cause: error });
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
const output = await invokeStructuredModel({
|
|
57
|
+
operation,
|
|
58
|
+
model,
|
|
59
|
+
schema: serializeStructuredOutputSchema(createNativeInstanceSelectionReviewSchema(description), 'draft-2020-12'),
|
|
60
|
+
name: 'review_native_instance_selection',
|
|
61
|
+
method: 'jsonSchema',
|
|
62
|
+
strict: true,
|
|
63
|
+
messages: [
|
|
64
|
+
new SystemMessage(nativeInstanceSelectionReviewPrompt),
|
|
65
|
+
new HumanMessage(JSON.stringify(description)),
|
|
66
|
+
],
|
|
67
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
68
|
+
}).catch((error) => {
|
|
69
|
+
checkCurrent(error);
|
|
70
|
+
throw error;
|
|
71
|
+
});
|
|
72
|
+
checkCurrent();
|
|
73
|
+
try {
|
|
74
|
+
return createNativeInstanceSelectionReview({ ...input, proposal: output });
|
|
75
|
+
}
|
|
76
|
+
catch (cause) {
|
|
77
|
+
if (!(cause instanceof Error))
|
|
78
|
+
throw cause;
|
|
79
|
+
throw new NativeInstanceSelectionReviewError({ output }, cause);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { resolveNativeNodeParameterSource } from './resolve-native-node-parameter-source.js';
|
|
2
2
|
/** Structural projection only: no values, identities or unmet requirements are repaired. */
|
|
3
3
|
export function resolveNativeNodePlanningOutput(output) {
|
|
4
|
-
if (
|
|
4
|
+
if ('nativeNodes' in output)
|
|
5
5
|
return {
|
|
6
6
|
proposal: {
|
|
7
7
|
nativeNodes: output.nativeNodes.map(resolveNativeNodeParameterSource),
|
|
8
8
|
gaps: output.gaps,
|
|
9
9
|
},
|
|
10
10
|
};
|
|
11
|
+
if ('gaps' in output)
|
|
12
|
+
return { proposal: { nativeNodes: [], gaps: output.gaps } };
|
|
11
13
|
const { decision } = output;
|
|
12
14
|
if ('additions' in decision)
|
|
13
15
|
return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
|
|
2
2
|
import { isDeepStrictEqual } from 'node:util';
|
|
3
|
-
import { createNativeInstanceSelectionSchema, describeNativeInstanceSelection, resolveNativeInstanceSelection, } from '@openapi-flow/core';
|
|
3
|
+
import { createNativeInstanceSelectionSchema, describeNativeInstanceSelection, resolveNativeInstanceSelection, describeNativeInstanceSelectionFeedback, } from '@openapi-flow/core';
|
|
4
4
|
import { serializeStructuredOutputSchema } from '../schemas/serialize-structured-output-schema.js';
|
|
5
5
|
import { nativeInstanceSelectionPrompt } from '../prompts/native-node-planning-prompt.js';
|
|
6
6
|
import { NativeNodePlanningError } from './native-node-planning-error.js';
|
|
@@ -11,6 +11,9 @@ export async function selectNativeNodeInstances(input) {
|
|
|
11
11
|
(!input.model || typeof input.model.withStructuredOutput !== 'function'))
|
|
12
12
|
throw new Error('selectNativeNodeInstances.model must support structured output when supplied');
|
|
13
13
|
const { context } = describeNativeInstanceSelection(input);
|
|
14
|
+
const feedback = input.feedback === undefined
|
|
15
|
+
? undefined
|
|
16
|
+
: describeNativeInstanceSelectionFeedback(input, input.feedback);
|
|
14
17
|
const originalOptions = JSON.stringify([
|
|
15
18
|
input.planId,
|
|
16
19
|
input.allowRuntimeParameters,
|
|
@@ -38,11 +41,17 @@ export async function selectNativeNodeInstances(input) {
|
|
|
38
41
|
})
|
|
39
42
|
.invoke([
|
|
40
43
|
new SystemMessage(nativeInstanceSelectionPrompt),
|
|
41
|
-
new HumanMessage(JSON.stringify(
|
|
44
|
+
new HumanMessage(JSON.stringify({
|
|
45
|
+
...context,
|
|
46
|
+
...(feedback === undefined ? {} : { selectionFeedback: feedback }),
|
|
47
|
+
})),
|
|
42
48
|
], input.signal === undefined ? undefined : { signal: input.signal });
|
|
43
49
|
input.signal?.throwIfAborted();
|
|
44
50
|
try {
|
|
45
51
|
if (!isDeepStrictEqual(describeNativeInstanceSelection(input).context, context) ||
|
|
52
|
+
!isDeepStrictEqual(feedback, input.feedback === undefined
|
|
53
|
+
? undefined
|
|
54
|
+
: describeNativeInstanceSelectionFeedback(input, input.feedback)) ||
|
|
46
55
|
JSON.stringify([
|
|
47
56
|
input.planId,
|
|
48
57
|
input.allowRuntimeParameters,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openapi-flow/langchain",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
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.
|
|
31
|
+
"@openapi-flow/core": "0.4.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@langchain/core": "^1.0.0",
|