@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.
- package/README.md +21 -0
- package/dist/arguments/analyze-api-input-answers.js +34 -6
- package/dist/arguments/api-argument-planning-error.d.ts +11 -0
- package/dist/arguments/api-argument-planning-error.js +32 -0
- package/dist/arguments/assert-api-argument-generation-source.d.ts +4 -0
- package/dist/arguments/assert-api-argument-generation-source.js +16 -0
- package/dist/arguments/attribute-api-literal-generation-sources.d.ts +4 -0
- package/dist/arguments/attribute-api-literal-generation-sources.js +16 -0
- package/dist/arguments/create-api-argument-rejection.d.ts +3 -0
- package/dist/arguments/create-api-argument-rejection.js +38 -0
- package/dist/arguments/fingerprint-api-argument-source.d.ts +4 -0
- package/dist/arguments/fingerprint-api-argument-source.js +13 -0
- package/dist/arguments/generate-api-arguments.js +108 -40
- 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/bindings/plan-api-call-bindings.js +30 -9
- package/dist/bindings/select-api-binding-sources.js +32 -8
- 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 +11 -1
- package/dist/prompts/api-input-answers-prompt.d.ts +1 -1
- package/dist/prompts/api-input-answers-prompt.js +8 -7
- package/dist/prompts/api-material-repair-prompt.d.ts +1 -0
- package/dist/prompts/api-material-repair-prompt.js +1 -0
- 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 +9 -0
- package/dist/prompts/native-node-planning-prompt.d.ts +1 -1
- package/dist/prompts/native-node-planning-prompt.js +2 -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-native-repair-prompt.d.ts +1 -0
- package/dist/prompts/workflow-connection-native-repair-prompt.js +1 -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 +28 -0
- package/dist/public-api.js +21 -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-input-answer-source-schema.d.ts +5 -5
- package/dist/schemas/api-input-answer-source-schema.js +14 -6
- package/dist/schemas/api-literal-generation-output-schema.d.ts +35 -4
- package/dist/schemas/api-literal-generation-output-schema.js +49 -14
- package/dist/schemas/create-connection-material-repair-choice-schema.d.ts +4 -0
- package/dist/schemas/create-connection-material-repair-choice-schema.js +23 -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/native-planning-rejection-schema.d.ts +11 -0
- package/dist/schemas/native-planning-rejection-schema.js +8 -0
- 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-call-binding-planning.d.ts +2 -1
- package/dist/types/api-input-answers.d.ts +3 -6
- package/dist/types/argument-generation.d.ts +37 -12
- package/dist/types/incremental-connection-planning.d.ts +10 -3
- package/dist/types/native-instance-selection-review.d.ts +12 -0
- package/dist/types/native-instance-selection-review.js +1 -0
- package/dist/types/native-node-planning.d.ts +10 -2
- package/dist/types/native-planning-rejection.d.ts +21 -0
- package/dist/types/native-planning-rejection.js +1 -0
- 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-native-repair.d.ts +16 -0
- package/dist/types/workflow-connection-native-repair.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/generate-workflow-connection-native-parameters.d.ts +4 -0
- package/dist/workflow/connections/generate-workflow-connection-native-parameters.js +80 -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-native-dependencies.d.ts +4 -0
- package/dist/workflow/connections/plan-workflow-connection-native-dependencies.js +73 -0
- 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-native-repair-error.d.ts +6 -0
- package/dist/workflow/connections/workflow-connection-native-repair-error.js +18 -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/create-native-planning-rejection.d.ts +4 -0
- package/dist/workflow/native-selection/create-native-planning-rejection.js +45 -0
- package/dist/workflow/native-selection/describe-native-planning-request.d.ts +5 -0
- package/dist/workflow/native-selection/describe-native-planning-request.js +26 -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 +97 -0
- package/dist/workflow/native-selection/validate-native-planning-rejections.d.ts +2 -0
- package/dist/workflow/native-selection/validate-native-planning-rejections.js +14 -0
- package/dist/workflow/resolve-native-node-planning-output.js +3 -1
- package/dist/workflow/select-native-node-instances.js +44 -17
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @openapi-flow/langchain
|
|
2
2
|
|
|
3
|
+
0.4.0 adds independent selection/goal review, scoped connection
|
|
4
|
+
outlines and originating-stage recovery planners. Each call is independently
|
|
5
|
+
composable; loops, budget, checkpoints and user review stay in the host. Connection
|
|
6
|
+
steps select explicit start/finish intent, while code resolves a unique actual
|
|
7
|
+
port and validates the whole patch. No missing edge is treated as completion.
|
|
8
|
+
Custom model doubles must follow the supplied structured schema. Publication and
|
|
9
|
+
accepted limitations are tracked in the
|
|
10
|
+
[release record](https://github.com/carefreelife98/openapi-flow/blob/main/docs/releases/0.4.0.md).
|
|
11
|
+
|
|
12
|
+
0.4.0 source adds `reviewNativeInstanceSelection` and explicit
|
|
13
|
+
`selectNativeNodeInstances({ feedback: { selection, review }, ...source })`.
|
|
14
|
+
Review makes at most one model call (zero with no reported gaps), uses exact supplied
|
|
15
|
+
gap IDs and producer/capability choices, and retains the original selection unchanged.
|
|
16
|
+
Only `needs-reselection` feedback permits a new explicitly requested selection;
|
|
17
|
+
unsupported behavior and business decisions cannot be bypassed this way. Ordinary
|
|
18
|
+
selection and configuration validation still applies to the new candidate. The host
|
|
19
|
+
owns budgets, checkpointing, user questions and whether to invoke either function;
|
|
20
|
+
there is no hidden loop, output repair or execution approval. Classification is model
|
|
21
|
+
evidence, not a proof of scenario correctness. See [native planning](../../docs/native-feature-planning.md).
|
|
22
|
+
This is not part of published 0.3.18.
|
|
23
|
+
|
|
3
24
|
Version **0.3.18** distinguishes independent inputs, selected response sources,
|
|
4
25
|
missing requested sources and partially missing sources in the model output.
|
|
5
26
|
Code constructs only the fixed fields implied by the validated decision. Invalid
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
|
|
2
|
-
import {
|
|
2
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
3
|
+
import { captureApiInputAnswerContext, createApiInputAnswerExtractionRecord, resolveApiInputAnswerInterpretations, describeApiInputEnumAnswerChoices, describeApiInputSources, describeApiInputMessageSources, hasApiInputAnswerSourceText, resolveApiInputSourceSelections, runOpenApiFlowOperation, } from '@openapi-flow/core';
|
|
3
4
|
import { createApiInputAnswerSourceSchema, apiInputAnswerExplanationOptionsSchema, } from '../schemas/api-input-answer-source-schema.js';
|
|
4
5
|
import { apiInputAnswersPrompt } from '../prompts/api-input-answers-prompt.js';
|
|
5
6
|
import { serializeStructuredOutputSchema } from '../schemas/serialize-structured-output-schema.js';
|
|
6
7
|
import { parseStructuredOutput } from '../legacy/planning/parse-structured-output.js';
|
|
7
8
|
import { invokeStructuredModel } from '../model/invoke-structured-model.js';
|
|
9
|
+
import { modelSignalSchema } from '../schemas/model-signal-schema.js';
|
|
8
10
|
export async function analyzeApiInputAnswers(input) {
|
|
9
11
|
const { options, snapshot } = runOpenApiFlowOperation({
|
|
10
12
|
owner: 'langchain',
|
|
@@ -12,12 +14,16 @@ export async function analyzeApiInputAnswers(input) {
|
|
|
12
14
|
stage: 'input-validation',
|
|
13
15
|
code: 'PLANNING_INPUT_INVALID',
|
|
14
16
|
}, () => {
|
|
17
|
+
modelSignalSchema.parse(input.signal);
|
|
15
18
|
const options = apiInputAnswerExplanationOptionsSchema.parse({
|
|
16
19
|
includeExplanations: input.includeExplanations,
|
|
17
20
|
selectOasEnums: input.selectOasEnums,
|
|
18
21
|
});
|
|
19
22
|
const snapshot = captureApiInputAnswerContext({
|
|
20
23
|
reply: input.reply,
|
|
24
|
+
...(input.sourceMessages === undefined
|
|
25
|
+
? {}
|
|
26
|
+
: { sourceMessages: input.sourceMessages }),
|
|
21
27
|
requirements: input.requirements,
|
|
22
28
|
...(input.purpose === undefined ? {} : { purpose: input.purpose }),
|
|
23
29
|
...(options.selectOasEnums === undefined
|
|
@@ -29,7 +35,7 @@ export async function analyzeApiInputAnswers(input) {
|
|
|
29
35
|
throw new Error('analyzeApiInputAnswers.model must support structured output when supplied');
|
|
30
36
|
return { options, snapshot };
|
|
31
37
|
});
|
|
32
|
-
if (!snapshot.requirements.length || snapshot
|
|
38
|
+
if (!snapshot.requirements.length || !hasApiInputAnswerSourceText(snapshot))
|
|
33
39
|
return {
|
|
34
40
|
status: snapshot.requirements.length
|
|
35
41
|
? 'empty-reply'
|
|
@@ -38,8 +44,21 @@ export async function analyzeApiInputAnswers(input) {
|
|
|
38
44
|
sources: [],
|
|
39
45
|
unansweredRequirementIds: snapshot.requirements.map((item) => item.id),
|
|
40
46
|
};
|
|
41
|
-
const catalog =
|
|
42
|
-
|
|
47
|
+
const catalog = snapshot.sourceMessages === undefined
|
|
48
|
+
? describeApiInputSources(snapshot.reply)
|
|
49
|
+
: undefined;
|
|
50
|
+
const messageSources = snapshot.sourceMessages === undefined
|
|
51
|
+
? undefined
|
|
52
|
+
: describeApiInputMessageSources(snapshot.sourceMessages);
|
|
53
|
+
let hasSources;
|
|
54
|
+
if (messageSources !== undefined)
|
|
55
|
+
hasSources = messageSources.some(({ sources }) => sources.json.length > 0 || sources.text.length > 0);
|
|
56
|
+
else {
|
|
57
|
+
if (catalog === undefined)
|
|
58
|
+
throw new Error('API input answer sources are missing');
|
|
59
|
+
hasSources = catalog.json.length > 0 || catalog.text.length > 0;
|
|
60
|
+
}
|
|
61
|
+
if (!hasSources)
|
|
43
62
|
return {
|
|
44
63
|
status: 'extracted',
|
|
45
64
|
answers: [],
|
|
@@ -55,7 +74,7 @@ export async function analyzeApiInputAnswers(input) {
|
|
|
55
74
|
if (!input.model)
|
|
56
75
|
throw new Error('analyzeApiInputAnswers.model is required for a nonempty reply with pending inputs');
|
|
57
76
|
const enumChoices = describeApiInputEnumAnswerChoices(snapshot);
|
|
58
|
-
const schema = createApiInputAnswerSourceSchema(snapshot.requirements, catalog, options.includeExplanations === true, enumChoices);
|
|
77
|
+
const schema = createApiInputAnswerSourceSchema(snapshot.requirements, catalog, options.includeExplanations === true, enumChoices, messageSources);
|
|
59
78
|
return {
|
|
60
79
|
model: input.model,
|
|
61
80
|
schema,
|
|
@@ -70,6 +89,7 @@ export async function analyzeApiInputAnswers(input) {
|
|
|
70
89
|
name: 'extract_api_input_answers',
|
|
71
90
|
method: 'functionCalling',
|
|
72
91
|
strict: true,
|
|
92
|
+
signal: input.signal,
|
|
73
93
|
messages: [
|
|
74
94
|
new SystemMessage(apiInputAnswersPrompt),
|
|
75
95
|
new HumanMessage(JSON.stringify({
|
|
@@ -78,7 +98,9 @@ export async function analyzeApiInputAnswers(input) {
|
|
|
78
98
|
...(snapshot.purpose === undefined
|
|
79
99
|
? {}
|
|
80
100
|
: { purpose: snapshot.purpose }),
|
|
81
|
-
|
|
101
|
+
...(catalog === undefined
|
|
102
|
+
? { messageSources }
|
|
103
|
+
: { sources: catalog }),
|
|
82
104
|
...(enumChoices.length ? { enumChoices } : {}),
|
|
83
105
|
})),
|
|
84
106
|
],
|
|
@@ -89,6 +111,9 @@ export async function analyzeApiInputAnswers(input) {
|
|
|
89
111
|
stage: 'contract-validation',
|
|
90
112
|
code: 'API_ARGUMENT_VALIDATION_FAILED',
|
|
91
113
|
}, () => {
|
|
114
|
+
if (snapshot.sourceMessages !== undefined &&
|
|
115
|
+
!isDeepStrictEqual(snapshot.sourceMessages, input.sourceMessages))
|
|
116
|
+
throw new Error('sourceMessages changed during API input answer analysis');
|
|
92
117
|
const parsed = parseStructuredOutput(schema, output, 'model clarification answer sources');
|
|
93
118
|
const selections = resolveApiInputSourceSelections({
|
|
94
119
|
...snapshot,
|
|
@@ -115,6 +140,9 @@ export async function analyzeApiInputAnswers(input) {
|
|
|
115
140
|
intent: {
|
|
116
141
|
sourceFormat: intent.sourceFormat,
|
|
117
142
|
sourceText: intent.sourceText,
|
|
143
|
+
...(intent.messageId === undefined
|
|
144
|
+
? {}
|
|
145
|
+
: { messageId: intent.messageId }),
|
|
118
146
|
},
|
|
119
147
|
reason: answer.reason,
|
|
120
148
|
},
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { OpenApiFlowError } from '@openapi-flow/core';
|
|
2
|
+
import type { ApiArgumentPlanningFailure } from '../types/argument-generation.js';
|
|
3
|
+
/** Preserve the original typed error and cause; inherited toJSON exposes only its safe diagnostic. */
|
|
4
|
+
export declare class ApiArgumentPlanningError extends OpenApiFlowError {
|
|
5
|
+
readonly originalError: OpenApiFlowError;
|
|
6
|
+
readonly sourceFingerprint: string;
|
|
7
|
+
readonly output: unknown;
|
|
8
|
+
constructor(failure: ApiArgumentPlanningFailure);
|
|
9
|
+
}
|
|
10
|
+
/** Only this literal stage's output/contract rejection is eligible; transport/configuration/enum errors are not. */
|
|
11
|
+
export declare function rethrowApiArgumentPlanningError(error: unknown, sourceFingerprint: string, output: unknown): never;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { OpenApiFlowError, isOpenApiFlowError } from '@openapi-flow/core';
|
|
2
|
+
/** Preserve the original typed error and cause; inherited toJSON exposes only its safe diagnostic. */
|
|
3
|
+
export class ApiArgumentPlanningError extends OpenApiFlowError {
|
|
4
|
+
originalError;
|
|
5
|
+
sourceFingerprint;
|
|
6
|
+
output;
|
|
7
|
+
constructor(failure) {
|
|
8
|
+
super({
|
|
9
|
+
message: failure.error.message,
|
|
10
|
+
diagnostic: failure.error.diagnostic,
|
|
11
|
+
cause: failure.error.cause,
|
|
12
|
+
});
|
|
13
|
+
this.originalError = failure.error;
|
|
14
|
+
this.sourceFingerprint = failure.sourceFingerprint;
|
|
15
|
+
this.output = failure.output;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Only this literal stage's output/contract rejection is eligible; transport/configuration/enum errors are not. */
|
|
19
|
+
export function rethrowApiArgumentPlanningError(error, sourceFingerprint, output) {
|
|
20
|
+
if (error instanceof ApiArgumentPlanningError)
|
|
21
|
+
throw error;
|
|
22
|
+
if (isOpenApiFlowError(error) &&
|
|
23
|
+
error.diagnostic.owner === 'langchain' &&
|
|
24
|
+
((error.diagnostic.stage === 'model-output' &&
|
|
25
|
+
error.diagnostic.code === 'MODEL_OUTPUT_INVALID' &&
|
|
26
|
+
['generateApiArguments', 'parseStructuredOutput'].includes(error.diagnostic.operation)) ||
|
|
27
|
+
(error.diagnostic.stage === 'contract-validation' &&
|
|
28
|
+
error.diagnostic.code === 'API_ARGUMENT_VALIDATION_FAILED' &&
|
|
29
|
+
error.diagnostic.operation === 'generateApiArguments')))
|
|
30
|
+
throw new ApiArgumentPlanningError({ error, sourceFingerprint, output });
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ApiLiteralGenerationInput, WorkflowConnectionApiRepairDescription } from '@openapi-flow/core';
|
|
2
|
+
import type { GenerateApiArgumentsInput } from '../types/argument-generation.js';
|
|
3
|
+
/** Both asynchronous decisions must finish against the same explicit original source and repair request. */
|
|
4
|
+
export declare function assertApiArgumentGenerationSource(input: GenerateApiArgumentsInput, snapshot: ApiLiteralGenerationInput, materialRepair?: WorkflowConnectionApiRepairDescription): void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
2
|
+
import { describeWorkflowConnectionApiRepair } from '@openapi-flow/core';
|
|
3
|
+
/** Both asynchronous decisions must finish against the same explicit original source and repair request. */
|
|
4
|
+
export function assertApiArgumentGenerationSource(input, snapshot, materialRepair) {
|
|
5
|
+
if (snapshot.literalSourceMessages !== undefined &&
|
|
6
|
+
!isDeepStrictEqual(snapshot.literalSourceMessages, input.literalSourceMessages))
|
|
7
|
+
throw new Error('literalSourceMessages changed during argument generation');
|
|
8
|
+
if (materialRepair !== undefined &&
|
|
9
|
+
(input.materialRepair === undefined ||
|
|
10
|
+
!isDeepStrictEqual(materialRepair, describeWorkflowConnectionApiRepair({
|
|
11
|
+
stage: 'api-arguments',
|
|
12
|
+
repair: input.materialRepair,
|
|
13
|
+
planning: input,
|
|
14
|
+
}))))
|
|
15
|
+
throw new Error('API material repair feedback changed during argument generation');
|
|
16
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ApiLiteralGenerationInput, ApiLiteralProposalSource } from '@openapi-flow/core';
|
|
2
|
+
import type { ApiLiteralGenerationSource } from '../types/argument-generation.js';
|
|
3
|
+
/** Single-source identity is code-owned; multi-source identity must be explicitly selected. */
|
|
4
|
+
export declare function attributeApiLiteralGenerationSources(input: ApiLiteralGenerationInput, sources: ApiLiteralGenerationSource[]): ApiLiteralProposalSource[];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Single-source identity is code-owned; multi-source identity must be explicitly selected. */
|
|
2
|
+
export function attributeApiLiteralGenerationSources(input, sources) {
|
|
3
|
+
const messages = input.literalSourceMessages;
|
|
4
|
+
if (messages === undefined)
|
|
5
|
+
return sources.map((source) => ({ ...source, messageId: 'scenario' }));
|
|
6
|
+
const first = messages[0];
|
|
7
|
+
if (!first)
|
|
8
|
+
throw new Error('literalSourceMessages must not be empty');
|
|
9
|
+
if (messages.length === 1)
|
|
10
|
+
return sources.map((source) => ({ ...source, messageId: first.id }));
|
|
11
|
+
return sources.map((source) => {
|
|
12
|
+
if (source.messageId === undefined)
|
|
13
|
+
throw new Error('Multiple literalSourceMessages require a source messageId');
|
|
14
|
+
return { ...source, messageId: source.messageId };
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CreateApiArgumentRejectionInput, ApiArgumentRejection } from '../types/argument-generation.js';
|
|
2
|
+
/** Return feedback only for the original unchanged literal source and lossless JSON output. */
|
|
3
|
+
export declare function createApiArgumentRejection(input: CreateApiArgumentRejectionInput): ApiArgumentRejection | undefined;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
2
|
+
import { describeApiLiteralGeneration, describeWorkflowConnectionApiRepair, } from '@openapi-flow/core';
|
|
3
|
+
import { apiLiteralGenerationOptionsSchema } from '../schemas/api-literal-generation-output-schema.js';
|
|
4
|
+
import { apiArgumentRejectionSchema } from '../schemas/api-argument-rejection-schema.js';
|
|
5
|
+
import { fingerprintApiArgumentSource } from './fingerprint-api-argument-source.js';
|
|
6
|
+
import { ApiArgumentPlanningError } from './api-argument-planning-error.js';
|
|
7
|
+
/** Return feedback only for the original unchanged literal source and lossless JSON output. */
|
|
8
|
+
export function createApiArgumentRejection(input) {
|
|
9
|
+
const error = input.error;
|
|
10
|
+
if (!(error instanceof ApiArgumentPlanningError))
|
|
11
|
+
return undefined;
|
|
12
|
+
const options = apiLiteralGenerationOptionsSchema.parse({
|
|
13
|
+
includeExplanations: input.includeExplanations,
|
|
14
|
+
selectOasEnums: input.selectOasEnums,
|
|
15
|
+
trackRequestedInputs: input.trackRequestedInputs,
|
|
16
|
+
});
|
|
17
|
+
const current = describeApiLiteralGeneration(input);
|
|
18
|
+
const materialRepair = input.materialRepair === undefined
|
|
19
|
+
? undefined
|
|
20
|
+
: describeWorkflowConnectionApiRepair({
|
|
21
|
+
stage: 'api-arguments',
|
|
22
|
+
repair: input.materialRepair,
|
|
23
|
+
planning: input,
|
|
24
|
+
});
|
|
25
|
+
if (error.sourceFingerprint !==
|
|
26
|
+
fingerprintApiArgumentSource(current.input, options, materialRepair))
|
|
27
|
+
return undefined;
|
|
28
|
+
const result = apiArgumentRejectionSchema.safeParse({
|
|
29
|
+
sourceFingerprint: error.sourceFingerprint,
|
|
30
|
+
code: error.diagnostic.code,
|
|
31
|
+
stage: error.diagnostic.stage,
|
|
32
|
+
reason: error.message,
|
|
33
|
+
...(error.output === undefined ? {} : { output: error.output }),
|
|
34
|
+
});
|
|
35
|
+
if (!result.success || !isDeepStrictEqual(result.data.output, error.output))
|
|
36
|
+
return undefined;
|
|
37
|
+
return structuredClone(result.data);
|
|
38
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ApiLiteralGenerationInput, WorkflowConnectionApiRepairDescription } from '@openapi-flow/core';
|
|
2
|
+
import type { ApiLiteralGenerationOptions } from '../types/argument-generation.js';
|
|
3
|
+
/** Only the validated Core snapshot and effective options participate, never a model/client or prior outputs. */
|
|
4
|
+
export declare function fingerprintApiArgumentSource(snapshot: ApiLiteralGenerationInput, options: ApiLiteralGenerationOptions, materialRepair?: WorkflowConnectionApiRepairDescription): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
/** Only the validated Core snapshot and effective options participate, never a model/client or prior outputs. */
|
|
3
|
+
export function fingerprintApiArgumentSource(snapshot, options, materialRepair) {
|
|
4
|
+
return createHash('sha256')
|
|
5
|
+
.update(JSON.stringify({
|
|
6
|
+
snapshot,
|
|
7
|
+
includeExplanations: options.includeExplanations === true,
|
|
8
|
+
selectOasEnums: options.selectOasEnums === true,
|
|
9
|
+
trackRequestedInputs: options.trackRequestedInputs === true,
|
|
10
|
+
...(materialRepair === undefined ? {} : { materialRepair }),
|
|
11
|
+
}))
|
|
12
|
+
.digest('hex');
|
|
13
|
+
}
|
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
import { SystemMessage, HumanMessage } from '@langchain/core/messages';
|
|
2
|
-
import { describeApiLiteralGeneration, createApiLiteralGenerationRecord, applyConfirmedApiInputs, createApiRequestSchema, inspectApiArgumentRequirements, resolveApiLiteralProposalSources, runOpenApiFlowOperation, runOpenApiFlowAsyncOperation, } from '@openapi-flow/core';
|
|
2
|
+
import { describeApiLiteralGeneration, createApiLiteralGenerationRecord, applyConfirmedApiInputs, createApiRequestSchema, inspectApiArgumentRequirements, resolveApiLiteralProposalSources, runOpenApiFlowOperation, runOpenApiFlowAsyncOperation, isOpenApiFlowError, describeWorkflowConnectionApiRepair, } from '@openapi-flow/core';
|
|
3
3
|
import { apiLiteralGenerationOptionsSchema, createApiLiteralGenerationOutputSchema, } from '../schemas/api-literal-generation-output-schema.js';
|
|
4
|
-
import { apiArgumentsPrompt } from '../prompts/api-arguments-prompt.js';
|
|
4
|
+
import { apiArgumentsPrompt, apiArgumentReplanningPrompt, } from '../prompts/api-arguments-prompt.js';
|
|
5
5
|
import { parseStructuredOutput } from '../legacy/planning/parse-structured-output.js';
|
|
6
6
|
import { interpretApiArgumentEnums } from './interpret-api-argument-enums.js';
|
|
7
7
|
import { invokeStructuredModel } from '../model/invoke-structured-model.js';
|
|
8
|
+
import { resolveApiLiteralGenerationOutput } from './resolve-api-literal-generation-output.js';
|
|
9
|
+
import { apiArgumentRejectionsSchema } from '../schemas/api-argument-rejection-schema.js';
|
|
10
|
+
import { fingerprintApiArgumentSource } from './fingerprint-api-argument-source.js';
|
|
11
|
+
import { rethrowApiArgumentPlanningError } from './api-argument-planning-error.js';
|
|
12
|
+
import { modelSignalSchema } from '../schemas/model-signal-schema.js';
|
|
13
|
+
import { apiMaterialRepairPrompt } from '../prompts/api-material-repair-prompt.js';
|
|
14
|
+
import { attributeApiLiteralGenerationSources } from './attribute-api-literal-generation-sources.js';
|
|
15
|
+
import { assertApiArgumentGenerationSource } from './assert-api-argument-generation-source.js';
|
|
8
16
|
export async function generateApiArguments(input) {
|
|
9
|
-
const { options, snapshot, contract, context, trackInputs, schema } = runOpenApiFlowOperation({
|
|
17
|
+
const { options, snapshot, contract, context, trackInputs, schema, sourceFingerprint, rejectedProposals, materialRepair, } = runOpenApiFlowOperation({
|
|
10
18
|
owner: 'langchain',
|
|
11
19
|
operation: 'generateApiArguments',
|
|
12
20
|
stage: 'input-validation',
|
|
13
21
|
code: 'PLANNING_INPUT_INVALID',
|
|
14
22
|
}, () => {
|
|
23
|
+
modelSignalSchema.parse(input.signal);
|
|
15
24
|
if (input.model !== undefined &&
|
|
16
|
-
(!input.model ||
|
|
17
|
-
typeof input.model.withStructuredOutput !== 'function'))
|
|
25
|
+
(!input.model || typeof input.model.withStructuredOutput !== 'function'))
|
|
18
26
|
throw new Error('generateApiArguments.model must support structured output when supplied');
|
|
19
27
|
if (typeof input.callId !== 'string' || !input.callId.trim())
|
|
20
28
|
throw new Error('callId must be non-empty');
|
|
@@ -24,61 +32,113 @@ export async function generateApiArguments(input) {
|
|
|
24
32
|
trackRequestedInputs: input.trackRequestedInputs,
|
|
25
33
|
});
|
|
26
34
|
const { input: snapshot, contract, context, } = describeApiLiteralGeneration(input);
|
|
35
|
+
const materialRepair = input.materialRepair === undefined
|
|
36
|
+
? undefined
|
|
37
|
+
: describeWorkflowConnectionApiRepair({
|
|
38
|
+
stage: 'api-arguments',
|
|
39
|
+
repair: input.materialRepair,
|
|
40
|
+
planning: input,
|
|
41
|
+
});
|
|
27
42
|
const trackInputs = options.trackRequestedInputs === true ||
|
|
28
|
-
options.selectOasEnums === true
|
|
29
|
-
|
|
43
|
+
options.selectOasEnums === true ||
|
|
44
|
+
snapshot.literalSourceMessages !== undefined ||
|
|
45
|
+
materialRepair !== undefined;
|
|
46
|
+
const schema = createApiLiteralGenerationOutputSchema(contract, options.includeExplanations === true, trackInputs ? createApiRequestSchema(snapshot) : undefined, snapshot.literalSourceMessages);
|
|
47
|
+
const sourceFingerprint = fingerprintApiArgumentSource(snapshot, options, materialRepair);
|
|
48
|
+
const rejectedProposals = input.rejectedProposals === undefined
|
|
49
|
+
? undefined
|
|
50
|
+
: apiArgumentRejectionsSchema.parse(input.rejectedProposals);
|
|
51
|
+
if (rejectedProposals?.some((item) => item.sourceFingerprint !== sourceFingerprint))
|
|
52
|
+
throw new Error('API argument rejection feedback belongs to a different source');
|
|
53
|
+
if (!contract.hasLiteralInputs && rejectedProposals?.length)
|
|
54
|
+
throw new Error('API argument rejection feedback requires a literal model decision');
|
|
30
55
|
if (contract.hasLiteralInputs && !input.model)
|
|
31
56
|
throw new Error('generateApiArguments.model must support structured output when literal inputs remain');
|
|
32
|
-
return {
|
|
57
|
+
return {
|
|
58
|
+
options,
|
|
59
|
+
snapshot,
|
|
60
|
+
contract,
|
|
61
|
+
context,
|
|
62
|
+
trackInputs,
|
|
63
|
+
schema,
|
|
64
|
+
sourceFingerprint,
|
|
65
|
+
rejectedProposals,
|
|
66
|
+
materialRepair,
|
|
67
|
+
};
|
|
33
68
|
});
|
|
34
|
-
let proposed =
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
};
|
|
69
|
+
let proposed = trackInputs
|
|
70
|
+
? { literalInputs: { state: 'not-provided' }, requestedInputs: [] }
|
|
71
|
+
: { values: {} };
|
|
38
72
|
if (contract.hasLiteralInputs) {
|
|
39
73
|
const model = input.model;
|
|
40
74
|
if (!model || typeof model.withStructuredOutput !== 'function')
|
|
41
75
|
throw new Error('generateApiArguments.model must support structured output when literal inputs remain');
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
76
|
+
try {
|
|
77
|
+
proposed = await invokeStructuredModel({
|
|
78
|
+
model,
|
|
79
|
+
schema,
|
|
80
|
+
operation: 'generateApiArguments',
|
|
81
|
+
name: 'generate_api_arguments',
|
|
82
|
+
method: 'functionCalling',
|
|
83
|
+
// Preserve the existing provider-default strictness of literal generation.
|
|
84
|
+
strict: undefined,
|
|
85
|
+
signal: input.signal,
|
|
86
|
+
messages: [
|
|
87
|
+
new SystemMessage([
|
|
88
|
+
apiArgumentsPrompt,
|
|
89
|
+
...(rejectedProposals === undefined
|
|
90
|
+
? []
|
|
91
|
+
: [apiArgumentReplanningPrompt]),
|
|
92
|
+
...(materialRepair === undefined
|
|
93
|
+
? []
|
|
94
|
+
: [apiMaterialRepairPrompt]),
|
|
95
|
+
].join('\n')),
|
|
96
|
+
new HumanMessage(JSON.stringify({
|
|
97
|
+
...context,
|
|
98
|
+
...(rejectedProposals === undefined ? {} : { rejectedProposals }),
|
|
99
|
+
...(materialRepair === undefined ? {} : { materialRepair }),
|
|
100
|
+
...(options.selectOasEnums === true
|
|
101
|
+
? { selectOasEnums: true }
|
|
102
|
+
: {}),
|
|
103
|
+
})),
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
const cause = isOpenApiFlowError(error) ? error.cause : undefined;
|
|
109
|
+
// The parser's documented raw output is retained as-is, never parsed/repaired from its message.
|
|
110
|
+
const output = typeof cause === 'object' &&
|
|
111
|
+
cause !== null &&
|
|
112
|
+
Object.getOwnPropertyDescriptor(cause, 'lc_error_code')?.value ===
|
|
113
|
+
'OUTPUT_PARSING_FAILURE'
|
|
114
|
+
? Object.getOwnPropertyDescriptor(cause, 'llmOutput')?.value
|
|
115
|
+
: undefined;
|
|
116
|
+
rethrowApiArgumentPlanningError(error, sourceFingerprint, output);
|
|
117
|
+
}
|
|
60
118
|
}
|
|
119
|
+
let interpretingEnums = false;
|
|
61
120
|
return runOpenApiFlowAsyncOperation({
|
|
62
121
|
owner: 'langchain',
|
|
63
122
|
operation: 'generateApiArguments',
|
|
64
123
|
stage: 'contract-validation',
|
|
65
124
|
code: 'API_ARGUMENT_VALIDATION_FAILED',
|
|
66
125
|
}, async () => {
|
|
67
|
-
|
|
126
|
+
assertApiArgumentGenerationSource(input, snapshot, materialRepair);
|
|
127
|
+
const output = parseStructuredOutput(schema, proposed, `model arguments for ${snapshot.callId}`);
|
|
128
|
+
const parsed = resolveApiLiteralGenerationOutput(output);
|
|
68
129
|
const values = applyConfirmedApiInputs({
|
|
69
130
|
...snapshot,
|
|
70
131
|
values: parsed.values,
|
|
71
132
|
});
|
|
72
|
-
const requestedInputs =
|
|
73
|
-
const literalSources =
|
|
133
|
+
const requestedInputs = parsed.requestedInputs;
|
|
134
|
+
const literalSources = parsed.literalSources !== undefined
|
|
74
135
|
? resolveApiLiteralProposalSources({
|
|
75
136
|
callId: snapshot.callId,
|
|
76
137
|
values: parsed.values,
|
|
77
|
-
sources: parsed.literalSources
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
messages: [{ id: 'scenario', text: snapshot.scenario }],
|
|
138
|
+
sources: attributeApiLiteralGenerationSources(snapshot, parsed.literalSources),
|
|
139
|
+
messages: snapshot.literalSourceMessages === undefined
|
|
140
|
+
? [{ id: 'scenario', text: snapshot.scenario }]
|
|
141
|
+
: snapshot.literalSourceMessages,
|
|
82
142
|
})
|
|
83
143
|
: undefined;
|
|
84
144
|
const inspection = inspectApiArgumentRequirements({
|
|
@@ -100,7 +160,7 @@ export async function generateApiArguments(input) {
|
|
|
100
160
|
? {
|
|
101
161
|
literalGeneration: createApiLiteralGenerationRecord({
|
|
102
162
|
...snapshot,
|
|
103
|
-
...(
|
|
163
|
+
...(parsed.explanation !== undefined
|
|
104
164
|
? {
|
|
105
165
|
proposal: { values: parsed.values },
|
|
106
166
|
reason: parsed.explanation.reason,
|
|
@@ -113,15 +173,23 @@ export async function generateApiArguments(input) {
|
|
|
113
173
|
if (options.selectOasEnums === true) {
|
|
114
174
|
if (literalSources === undefined)
|
|
115
175
|
throw new Error('generateApiArguments enum interpretation requires source-verified literalSources');
|
|
116
|
-
|
|
176
|
+
interpretingEnums = true;
|
|
177
|
+
const interpreted = await interpretApiArgumentEnums({
|
|
117
178
|
...snapshot,
|
|
118
179
|
...options,
|
|
119
180
|
arguments: result,
|
|
120
181
|
proposal: { values: parsed.values },
|
|
121
182
|
literalSources,
|
|
122
183
|
model: input.model,
|
|
184
|
+
signal: input.signal,
|
|
123
185
|
});
|
|
186
|
+
assertApiArgumentGenerationSource(input, snapshot, materialRepair);
|
|
187
|
+
return interpreted;
|
|
124
188
|
}
|
|
125
189
|
return result;
|
|
190
|
+
}).catch((error) => {
|
|
191
|
+
if (interpretingEnums || !contract.hasLiteralInputs)
|
|
192
|
+
throw error;
|
|
193
|
+
rethrowApiArgumentPlanningError(error, sourceFingerprint, proposed);
|
|
126
194
|
});
|
|
127
195
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ApiLiteralGenerationOutput, ResolvedApiLiteralGenerationOutput } from '../types/argument-generation.js';
|
|
2
|
+
/** Only an explicit absence decision produces empty values; supplied empty literals are never removed. */
|
|
3
|
+
export declare function resolveApiLiteralGenerationOutput(output: ApiLiteralGenerationOutput): ResolvedApiLiteralGenerationOutput;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Only an explicit absence decision produces empty values; supplied empty literals are never removed. */
|
|
2
|
+
export function resolveApiLiteralGenerationOutput(output) {
|
|
3
|
+
if ('literalInputs' in output) {
|
|
4
|
+
const literals = output.literalInputs;
|
|
5
|
+
return {
|
|
6
|
+
...(literals.state === 'not-provided'
|
|
7
|
+
? { values: {}, literalSources: [] }
|
|
8
|
+
: { values: literals.values, literalSources: literals.literalSources }),
|
|
9
|
+
requestedInputs: output.requestedInputs,
|
|
10
|
+
...('explanation' in output ? { explanation: output.explanation } : {}),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
return output;
|
|
14
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describeApiBindingPlanning, validateApiCallBindingPlan, assembleApiBindingPlan, runOpenApiFlowOperation, } from '@openapi-flow/core';
|
|
1
|
+
import { describeApiBindingPlanning, validateApiCallBindingPlan, assembleApiBindingPlan, runOpenApiFlowOperation, isOpenApiFlowError, } from '@openapi-flow/core';
|
|
2
2
|
import { apiBindingCallExecutionSchema } from '../schemas/api-call-binding-plan-schema.js';
|
|
3
3
|
import { selectApiBindingSources } from './select-api-binding-sources.js';
|
|
4
4
|
import { planApiCallBindings } from './plan-api-call-bindings.js';
|
|
@@ -59,8 +59,17 @@ export async function planApiBindingsByCall(input) {
|
|
|
59
59
|
results.set(result.callId, result);
|
|
60
60
|
}
|
|
61
61
|
catch (error) {
|
|
62
|
-
if (!failed)
|
|
63
|
-
|
|
62
|
+
if (!failed) {
|
|
63
|
+
// This aggregate API historically returns the caller's exact cancellation reason.
|
|
64
|
+
// A late structured result must not change that public cancellation contract.
|
|
65
|
+
failure =
|
|
66
|
+
input.signal?.aborted &&
|
|
67
|
+
isOpenApiFlowError(error) &&
|
|
68
|
+
error.diagnostic.code === 'MODEL_ABORTED' &&
|
|
69
|
+
error.cause === input.signal.reason
|
|
70
|
+
? input.signal.reason
|
|
71
|
+
: error;
|
|
72
|
+
}
|
|
64
73
|
failed = true;
|
|
65
74
|
}
|
|
66
75
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { isDeepStrictEqual } from 'node:util';
|
|
2
2
|
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
|
|
3
|
-
import { describeApiCallBindingPlanning, resolveApiBindingSourceSelection, resolveApiCallBindingPlan, listApiResponsePointers, runOpenApiFlowOperation, } from '@openapi-flow/core';
|
|
3
|
+
import { describeApiCallBindingPlanning, resolveApiBindingSourceSelection, resolveApiCallBindingPlan, listApiResponsePointers, runOpenApiFlowOperation, describeWorkflowConnectionApiRepair, } from '@openapi-flow/core';
|
|
4
4
|
import { createApiCallBindingPlanSchema } from '../schemas/api-call-binding-plan-schema.js';
|
|
5
5
|
import { apiCallBindingsPrompt } from '../prompts/api-call-bindings-prompt.js';
|
|
6
6
|
import { invokeStructuredModel } from '../model/invoke-structured-model.js';
|
|
7
7
|
import { parseStructuredOutput } from '../legacy/planning/parse-structured-output.js';
|
|
8
|
+
import { apiMaterialRepairPrompt } from '../prompts/api-material-repair-prompt.js';
|
|
8
9
|
export async function planApiCallBindings(input) {
|
|
9
|
-
const { description, sources } = runOpenApiFlowOperation({
|
|
10
|
+
const { description, sources, materialRepair } = runOpenApiFlowOperation({
|
|
10
11
|
owner: 'langchain',
|
|
11
12
|
operation: 'planApiCallBindings',
|
|
12
13
|
stage: 'input-validation',
|
|
@@ -24,7 +25,14 @@ export async function planApiCallBindings(input) {
|
|
|
24
25
|
});
|
|
25
26
|
if (!isDeepStrictEqual(sources, expected))
|
|
26
27
|
throw new Error('binding source selection changed or belongs to another call or source snapshot');
|
|
27
|
-
|
|
28
|
+
const materialRepair = input.materialRepair === undefined
|
|
29
|
+
? undefined
|
|
30
|
+
: describeWorkflowConnectionApiRepair({
|
|
31
|
+
stage: 'api-bindings',
|
|
32
|
+
repair: input.materialRepair,
|
|
33
|
+
planning: input,
|
|
34
|
+
});
|
|
35
|
+
return { description, sources, materialRepair };
|
|
28
36
|
});
|
|
29
37
|
input.signal?.throwIfAborted();
|
|
30
38
|
if (!sources.sourceNodeIds.length)
|
|
@@ -48,7 +56,9 @@ export async function planApiCallBindings(input) {
|
|
|
48
56
|
strict: true,
|
|
49
57
|
signal: input.signal,
|
|
50
58
|
messages: [
|
|
51
|
-
new SystemMessage(
|
|
59
|
+
new SystemMessage(materialRepair === undefined
|
|
60
|
+
? apiCallBindingsPrompt
|
|
61
|
+
: [apiCallBindingsPrompt, apiMaterialRepairPrompt].join('\n')),
|
|
52
62
|
new HumanMessage(JSON.stringify({
|
|
53
63
|
scenario: description.input.scenario,
|
|
54
64
|
target: description.target,
|
|
@@ -65,6 +75,7 @@ export async function planApiCallBindings(input) {
|
|
|
65
75
|
responsePointerCatalog: listApiResponsePointers(material.operation),
|
|
66
76
|
})),
|
|
67
77
|
nativeSources: description.input.nativeOutputs?.filter((source) => selected.has(source.nodeId)),
|
|
78
|
+
...(materialRepair === undefined ? {} : { materialRepair }),
|
|
68
79
|
})),
|
|
69
80
|
],
|
|
70
81
|
});
|
|
@@ -74,9 +85,19 @@ export async function planApiCallBindings(input) {
|
|
|
74
85
|
operation: 'planApiCallBindings',
|
|
75
86
|
stage: 'contract-validation',
|
|
76
87
|
code: 'API_BINDING_VALIDATION_FAILED',
|
|
77
|
-
}, () =>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
88
|
+
}, () => {
|
|
89
|
+
if (materialRepair !== undefined &&
|
|
90
|
+
(input.materialRepair === undefined ||
|
|
91
|
+
!isDeepStrictEqual(materialRepair, describeWorkflowConnectionApiRepair({
|
|
92
|
+
stage: 'api-bindings',
|
|
93
|
+
repair: input.materialRepair,
|
|
94
|
+
planning: input,
|
|
95
|
+
}))))
|
|
96
|
+
throw new Error('API material repair feedback changed during binding planning');
|
|
97
|
+
return resolveApiCallBindingPlan({
|
|
98
|
+
...description.input,
|
|
99
|
+
sources,
|
|
100
|
+
proposal: parseStructuredOutput(schema, output, 'API call bindings'),
|
|
101
|
+
});
|
|
102
|
+
});
|
|
82
103
|
}
|