@openapi-flow/core 0.3.9 → 0.3.11

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 (55) hide show
  1. package/dist/arguments/clarification/api-input-requirement-dialect.d.ts +4 -0
  2. package/dist/arguments/clarification/api-input-requirement-dialect.js +8 -0
  3. package/dist/arguments/clarification/extraction/capture-api-input-answer-context.js +2 -3
  4. package/dist/arguments/clarification/extraction/create-api-input-answer-extraction-record.js +8 -2
  5. package/dist/arguments/clarification/extraction/resolve-api-input-answer-interpretations.d.ts +3 -0
  6. package/dist/arguments/clarification/extraction/resolve-api-input-answer-interpretations.js +51 -0
  7. package/dist/arguments/clarification/extraction/resolve-api-input-answer-sources.js +2 -3
  8. package/dist/arguments/clarification/extraction/validate-api-input-answer-analysis.d.ts +3 -0
  9. package/dist/arguments/clarification/extraction/validate-api-input-answer-analysis.js +55 -0
  10. package/dist/arguments/clarification/extraction/validate-api-input-answer-extraction-record.js +3 -0
  11. package/dist/arguments/enum/describe-api-input-enum-answer-choices.d.ts +4 -0
  12. package/dist/arguments/enum/describe-api-input-enum-answer-choices.js +23 -0
  13. package/dist/arguments/enum/list-api-input-enum-candidates.d.ts +3 -0
  14. package/dist/arguments/enum/list-api-input-enum-candidates.js +73 -0
  15. package/dist/draft/edits/api/describe-workflow-draft-api-enum-choices.d.ts +3 -0
  16. package/dist/draft/edits/api/describe-workflow-draft-api-enum-choices.js +70 -0
  17. package/dist/draft/edits/api/resolve-workflow-draft-api-call-arguments.js +9 -5
  18. package/dist/draft/edits/api/resolve-workflow-draft-api-enum-selections.d.ts +4 -0
  19. package/dist/draft/edits/api/resolve-workflow-draft-api-enum-selections.js +38 -0
  20. package/dist/draft/edits/enum/verify-workflow-draft-api-enum-selection.d.ts +3 -0
  21. package/dist/draft/edits/enum/verify-workflow-draft-api-enum-selection.js +23 -0
  22. package/dist/draft/edits/inputs/describe-workflow-draft-api-input-edit-answer-requirements.d.ts +4 -0
  23. package/dist/draft/edits/inputs/describe-workflow-draft-api-input-edit-answer-requirements.js +30 -0
  24. package/dist/draft/edits/inputs/describe-workflow-draft-api-input-edit-enum-choices.d.ts +4 -0
  25. package/dist/draft/edits/inputs/describe-workflow-draft-api-input-edit-enum-choices.js +42 -0
  26. package/dist/draft/edits/inputs/resolve-workflow-draft-api-input-edit-reply.d.ts +3 -0
  27. package/dist/draft/edits/inputs/resolve-workflow-draft-api-input-edit-reply.js +24 -0
  28. package/dist/draft/edits/inputs/resolve-workflow-draft-api-input-edits.js +20 -0
  29. package/dist/openapi/common/create-oas-value-validation-cache.d.ts +3 -0
  30. package/dist/openapi/common/create-oas-value-validation-cache.js +46 -0
  31. package/dist/openapi/common/create-oas-value-validator.js +12 -3
  32. package/dist/public-api.d.ts +11 -0
  33. package/dist/public-api.js +8 -0
  34. package/dist/schemas/api-input-answer-extraction-schema.d.ts +15 -0
  35. package/dist/schemas/api-input-answer-extraction-schema.js +4 -0
  36. package/dist/schemas/api-input-enum-answer-selection-schema.d.ts +25 -0
  37. package/dist/schemas/api-input-enum-answer-selection-schema.js +11 -0
  38. package/dist/schemas/create-workflow-draft-api-input-edit-values-schema.js +11 -2
  39. package/dist/schemas/workflow-draft-api-enum-choice-schema.d.ts +5 -0
  40. package/dist/schemas/workflow-draft-api-enum-choice-schema.js +25 -0
  41. package/dist/schemas/workflow-draft-api-enum-selection-schema.d.ts +4 -0
  42. package/dist/schemas/workflow-draft-api-enum-selection-schema.js +14 -0
  43. package/dist/schemas/workflow-draft-api-input-edit-proposal-schema.js +3 -1
  44. package/dist/types/api-clarification.d.ts +2 -0
  45. package/dist/types/api-input-answer-extraction.d.ts +9 -2
  46. package/dist/types/api-input-enum-answers.d.ts +25 -0
  47. package/dist/types/api-input-enum-answers.js +1 -0
  48. package/dist/types/api-input-enum.d.ts +26 -0
  49. package/dist/types/api-input-enum.js +1 -0
  50. package/dist/types/oas-value-validation.d.ts +13 -0
  51. package/dist/types/workflow-draft-api-call-planning.d.ts +4 -0
  52. package/dist/types/workflow-draft-api-enum-selection.d.ts +39 -0
  53. package/dist/types/workflow-draft-api-enum-selection.js +1 -0
  54. package/dist/types/workflow-draft-api-input-edit.d.ts +15 -2
  55. package/package.json +1 -1
@@ -0,0 +1,4 @@
1
+ import type { ApiInputRequirement } from '../../types/api-clarification.js';
2
+ import type { SchemaDialect } from '../../types/schema-dialect.js';
3
+ /** A compiled projection declares its actual dialect; the source OAS version remains unchanged. */
4
+ export declare function apiInputRequirementDialect(requirement: ApiInputRequirement): SchemaDialect;
@@ -0,0 +1,8 @@
1
+ /** A compiled projection declares its actual dialect; the source OAS version remains unchanged. */
2
+ export function apiInputRequirementDialect(requirement) {
3
+ if (requirement.schemaDialect === 'draft-2020-12')
4
+ return 'draft-2020-12';
5
+ return requirement.openapiVersion.startsWith('3.0.')
6
+ ? 'openapi-3.0'
7
+ : 'draft-2020-12';
8
+ }
@@ -1,5 +1,6 @@
1
1
  import { apiInputAnswerContextSchema } from '../../../schemas/api-input-answer-extraction-schema.js';
2
2
  import { createOasValueValidator } from '../../../openapi/common/create-oas-value-validator.js';
3
+ import { apiInputRequirementDialect } from '../api-input-requirement-dialect.js';
3
4
  /** Capture supplied pending contracts before any asynchronous model work. */
4
5
  export function captureApiInputAnswerContext(input) {
5
6
  apiInputAnswerContextSchema.parse(input);
@@ -9,9 +10,7 @@ export function captureApiInputAnswerContext(input) {
9
10
  if (ids.has(requirement.id))
10
11
  throw new Error(`Duplicate API input requirementId: ${requirement.id}`);
11
12
  ids.add(requirement.id);
12
- createOasValueValidator(requirement.schema, requirement.openapiVersion.startsWith('3.0.')
13
- ? 'openapi-3.0'
14
- : 'draft-2020-12', `API input requirement ${requirement.id} ${requirement.targetPointer}`);
13
+ createOasValueValidator(requirement.schema, apiInputRequirementDialect(requirement), `API input requirement ${requirement.id} ${requirement.targetPointer}`);
15
14
  }
16
15
  return snapshot;
17
16
  }
@@ -1,19 +1,25 @@
1
1
  import { apiInputAnswerExtractionDecisionSchema } from '../../../schemas/api-input-answer-extraction-schema.js';
2
2
  import { captureApiInputAnswerContext } from './capture-api-input-answer-context.js';
3
- import { resolveApiInputAnswerSources } from './resolve-api-input-answer-sources.js';
3
+ import { resolveApiInputAnswerInterpretations } from './resolve-api-input-answer-interpretations.js';
4
4
  export function createApiInputAnswerExtractionRecord(input) {
5
5
  const evidence = captureApiInputAnswerContext({
6
6
  reply: input.reply,
7
7
  requirements: input.requirements,
8
+ ...(input.selectOasEnums === undefined
9
+ ? {}
10
+ : { selectOasEnums: input.selectOasEnums }),
8
11
  });
9
12
  const decision = structuredClone(apiInputAnswerExtractionDecisionSchema.parse(input.decision));
10
- const verification = resolveApiInputAnswerSources({
13
+ const verification = resolveApiInputAnswerInterpretations({
11
14
  ...evidence,
12
15
  selections: decision.answers.map((source) => ({
13
16
  requirementId: source.requirementId,
14
17
  sourceFormat: source.sourceFormat,
15
18
  sourceText: source.sourceText,
16
19
  })),
20
+ ...(decision.enumSelections === undefined
21
+ ? {}
22
+ : { enumSelections: decision.enumSelections }),
17
23
  });
18
24
  return {
19
25
  kind: 'model-extracted-api-input-answers',
@@ -0,0 +1,3 @@
1
+ import type { ResolveApiInputAnswerInterpretationsInput, ResolvedApiInputAnswerInterpretations } from '../../../types/api-input-enum-answers.js';
2
+ /** Literal values and semantic intent have different sources and must never be conflated. */
3
+ export declare function resolveApiInputAnswerInterpretations(input: ResolveApiInputAnswerInterpretationsInput): ResolvedApiInputAnswerInterpretations;
@@ -0,0 +1,51 @@
1
+ import { apiInputEnumAnswerSelectionsSchema } from '../../../schemas/api-input-enum-answer-selection-schema.js';
2
+ import { captureApiInputAnswerContext } from './capture-api-input-answer-context.js';
3
+ import { resolveApiInputAnswerSources } from './resolve-api-input-answer-sources.js';
4
+ import { describeApiInputEnumAnswerChoices } from '../../enum/describe-api-input-enum-answer-choices.js';
5
+ import { readApiInputLiteralSource } from '../../sources/read-api-input-literal-source.js';
6
+ /** Literal values and semantic intent have different sources and must never be conflated. */
7
+ export function resolveApiInputAnswerInterpretations(input) {
8
+ const context = captureApiInputAnswerContext({
9
+ reply: input.reply,
10
+ requirements: input.requirements,
11
+ ...(input.selectOasEnums === undefined
12
+ ? {}
13
+ : { selectOasEnums: input.selectOasEnums }),
14
+ });
15
+ const result = resolveApiInputAnswerSources({
16
+ reply: context.reply,
17
+ requirements: context.requirements,
18
+ selections: input.selections,
19
+ });
20
+ if (input.enumSelections === undefined)
21
+ return result;
22
+ const selections = apiInputEnumAnswerSelectionsSchema.parse(input.enumSelections);
23
+ if (context.selectOasEnums !== true)
24
+ throw new Error('API enum answer selection requires selectOasEnums: true in the original context');
25
+ const choices = describeApiInputEnumAnswerChoices(context);
26
+ const answered = new Set(result.answers.map((answer) => answer.requirementId));
27
+ result.enumSelections = selections.map((selection) => {
28
+ if (answered.has(selection.requirementId))
29
+ throw new Error(`Duplicate requirementId: ${selection.requirementId}`);
30
+ const candidate = choices
31
+ .find((choice) => choice.requirementId === selection.requirementId)
32
+ ?.candidates.find((item) => item.id === selection.candidateId);
33
+ if (!candidate)
34
+ throw new Error(`API enum answer ${selection.requirementId} has an unknown or stale OAS candidate: ${selection.candidateId}`);
35
+ const { occurrences } = readApiInputLiteralSource({
36
+ ...selection.intent,
37
+ text: context.reply,
38
+ label: `Enum answer intent ${selection.requirementId}`,
39
+ });
40
+ answered.add(selection.requirementId);
41
+ result.answers.push({
42
+ requirementId: selection.requirementId,
43
+ value: structuredClone(candidate.value),
44
+ });
45
+ return { ...selection, candidate: structuredClone(candidate), occurrences };
46
+ });
47
+ result.unansweredRequirementIds = context.requirements
48
+ .filter((item) => !answered.has(item.id))
49
+ .map((item) => item.id);
50
+ return result;
51
+ }
@@ -2,6 +2,7 @@ import { apiInputAnswerSourcesSchema } from '../../../schemas/api-input-answer-e
2
2
  import { captureApiInputAnswerContext } from './capture-api-input-answer-context.js';
3
3
  import { readApiInputLiteralSource } from '../../sources/read-api-input-literal-source.js';
4
4
  import { createOasValueValidator } from '../../../openapi/common/create-oas-value-validator.js';
5
+ import { apiInputRequirementDialect } from '../api-input-requirement-dialect.js';
5
6
  /** Model-selected source text is the only value source, never a model-generated value. */
6
7
  export function resolveApiInputAnswerSources(input) {
7
8
  const context = captureApiInputAnswerContext({
@@ -24,9 +25,7 @@ export function resolveApiInputAnswerSources(input) {
24
25
  text: context.reply,
25
26
  label: `Answer ${requirement.id}`,
26
27
  });
27
- const checked = createOasValueValidator(requirement.schema, requirement.openapiVersion.startsWith('3.0.')
28
- ? 'openapi-3.0'
29
- : 'draft-2020-12', `answer ${requirement.targetPointer}`).validate(value);
28
+ const checked = createOasValueValidator(requirement.schema, apiInputRequirementDialect(requirement), `answer ${requirement.targetPointer}`).validate(value);
30
29
  if (!checked.valid)
31
30
  throw new Error(`Answer ${requirement.id} violates its supplied OAS schema: ${checked.errors.map((error) => error.message).join('; ')}`);
32
31
  answered.add(requirement.id);
@@ -0,0 +1,3 @@
1
+ import type { ValidateApiInputAnswerAnalysisInput } from '../../../types/api-input-answer-extraction.js';
2
+ /** Replay model choices against independently supplied original questions and reply. */
3
+ export declare function validateApiInputAnswerAnalysis(input: ValidateApiInputAnswerAnalysisInput): void;
@@ -0,0 +1,55 @@
1
+ import { isDeepStrictEqual } from 'node:util';
2
+ import { resolveApiInputAnswerInterpretations } from './resolve-api-input-answer-interpretations.js';
3
+ import { validateApiInputAnswerExtractionRecord } from './validate-api-input-answer-extraction-record.js';
4
+ /** Replay model choices against independently supplied original questions and reply. */
5
+ export function validateApiInputAnswerAnalysis(input) {
6
+ const context = {
7
+ reply: input.reply,
8
+ requirements: input.requirements,
9
+ ...(input.selectOasEnums === undefined
10
+ ? {}
11
+ : { selectOasEnums: input.selectOasEnums }),
12
+ };
13
+ const { analysis } = input;
14
+ if (!Array.isArray(analysis.sources))
15
+ throw new Error('API input answer analysis.sources must be an array');
16
+ const resolved = resolveApiInputAnswerInterpretations({
17
+ ...context,
18
+ selections: analysis.sources.map((source) => ({
19
+ requirementId: source.requirementId,
20
+ sourceFormat: source.sourceFormat,
21
+ sourceText: source.sourceText,
22
+ })),
23
+ ...(analysis.enumSelections === undefined
24
+ ? {}
25
+ : {
26
+ enumSelections: analysis.enumSelections.map((selection) => ({
27
+ requirementId: selection.requirementId,
28
+ candidateId: selection.candidateId,
29
+ intent: selection.intent,
30
+ reason: selection.reason,
31
+ })),
32
+ }),
33
+ });
34
+ if (analysis.extraction !== undefined) {
35
+ validateApiInputAnswerExtractionRecord({
36
+ ...context,
37
+ record: analysis.extraction,
38
+ });
39
+ if (!isDeepStrictEqual(analysis.extraction.verification, resolved))
40
+ throw new Error('API input explanation differs from its code-resolved answer selection');
41
+ }
42
+ const status = !input.requirements.length
43
+ ? 'no-pending-inputs'
44
+ : input.reply === ''
45
+ ? 'empty-reply'
46
+ : 'extracted';
47
+ if (!isDeepStrictEqual(analysis, {
48
+ status,
49
+ ...resolved,
50
+ ...(analysis.extraction === undefined
51
+ ? {}
52
+ : { extraction: analysis.extraction }),
53
+ }))
54
+ throw new Error('API input analysis differs from its original reply, contracts or code-resolved values');
55
+ }
@@ -5,6 +5,9 @@ export function validateApiInputAnswerExtractionRecord(input) {
5
5
  const expected = createApiInputAnswerExtractionRecord({
6
6
  reply: input.reply,
7
7
  requirements: input.requirements,
8
+ ...(input.selectOasEnums === undefined
9
+ ? {}
10
+ : { selectOasEnums: input.selectOasEnums }),
8
11
  decision: input.record.decision,
9
12
  });
10
13
  if (!isDeepStrictEqual(expected, input.record))
@@ -0,0 +1,4 @@
1
+ import type { ApiInputAnswerContext } from '../../types/api-input-answer-extraction.js';
2
+ import type { ApiInputEnumAnswerChoice } from '../../types/api-input-enum-answers.js';
3
+ /** Pending question contracts are the only value authority; defaults/examples are not candidates. */
4
+ export declare function describeApiInputEnumAnswerChoices(input: ApiInputAnswerContext): ApiInputEnumAnswerChoice[];
@@ -0,0 +1,23 @@
1
+ import { captureApiInputAnswerContext } from '../clarification/extraction/capture-api-input-answer-context.js';
2
+ import { createOasValueValidator } from '../../openapi/common/create-oas-value-validator.js';
3
+ import { createSchemaResourceContext } from '../../bindings/resources/create-schema-resource-context.js';
4
+ import { listApiInputEnumCandidates } from './list-api-input-enum-candidates.js';
5
+ import { apiInputRequirementDialect } from '../clarification/api-input-requirement-dialect.js';
6
+ /** Pending question contracts are the only value authority; defaults/examples are not candidates. */
7
+ export function describeApiInputEnumAnswerChoices(input) {
8
+ const context = captureApiInputAnswerContext(input);
9
+ if (context.selectOasEnums !== true)
10
+ return [];
11
+ return context.requirements.flatMap((requirement) => {
12
+ const normalized = createOasValueValidator(requirement.schema, apiInputRequirementDialect(requirement), `API enum answer ${requirement.id}`).schema;
13
+ const resources = createSchemaResourceContext(normalized);
14
+ const candidates = listApiInputEnumCandidates({
15
+ source: { kind: 'requirement', requirement },
16
+ schemas: [resources.reference(resources.root)],
17
+ resources,
18
+ });
19
+ return candidates.length
20
+ ? [{ requirementId: requirement.id, candidates }]
21
+ : [];
22
+ });
23
+ }
@@ -0,0 +1,3 @@
1
+ import type { ApiInputEnumCandidatesInput, ApiInputEnumCandidate } from '../../types/api-input-enum.js';
2
+ /** Enumerate declared values only. A source resource retains references and all sibling assertions. */
3
+ export declare function listApiInputEnumCandidates(input: ApiInputEnumCandidatesInput): ApiInputEnumCandidate[];
@@ -0,0 +1,73 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { createOasValueValidator } from '../../openapi/common/create-oas-value-validator.js';
3
+ /** Enumerate declared values only. A source resource retains references and all sibling assertions. */
4
+ export function listApiInputEnumCandidates(input) {
5
+ const material = input.source.kind === 'operation' ? input.source : input.source.requirement;
6
+ const operation = input.source.kind === 'operation'
7
+ ? input.source.operation.key
8
+ : input.source.requirement.operation;
9
+ if (!input.schemas.length)
10
+ throw new Error(`API enum ${material.callId}${material.targetPointer} has no original OAS target schema`);
11
+ const schema = input.schemas.length === 1 ? input.schemas[0] : { anyOf: input.schemas };
12
+ const validator = createOasValueValidator(input.resources.bundle(schema), 'draft-2020-12', `API enum ${material.callId}${material.targetPointer}`);
13
+ const identity = input.source.kind === 'operation'
14
+ ? JSON.stringify([
15
+ input.source.callId,
16
+ input.source.operation,
17
+ input.source.requestMediaType,
18
+ input.source.targetPointer,
19
+ ])
20
+ : JSON.stringify(['requirement', input.source.requirement]);
21
+ const candidates = [];
22
+ const active = new Set();
23
+ function visit(current, pointer) {
24
+ if (typeof current === 'boolean' || active.has(current))
25
+ return;
26
+ active.add(current);
27
+ try {
28
+ if (Array.isArray(current.enum))
29
+ current.enum.forEach((value, index) => {
30
+ if (!validator.validate(value).valid)
31
+ return;
32
+ const schemaPointer = `${pointer}/enum/${index}`;
33
+ candidates.push({
34
+ id: createHash('sha256')
35
+ .update(identity)
36
+ .update(JSON.stringify([schemaPointer, value]))
37
+ .digest('hex'),
38
+ callId: material.callId,
39
+ operation: structuredClone(operation),
40
+ targetPointer: material.targetPointer,
41
+ schemaPointer,
42
+ value: structuredClone(value),
43
+ });
44
+ });
45
+ if (typeof current.$ref === 'string') {
46
+ const resolved = input.resources.resolve(current);
47
+ if (typeof resolved !== 'boolean') {
48
+ const reference = input.resources.reference(resolved);
49
+ if (typeof reference === 'boolean' ||
50
+ typeof reference.$ref !== 'string')
51
+ throw new Error(`API enum ${material.callId}${material.targetPointer} has no original schema reference`);
52
+ visit(resolved, decodeURIComponent(new URL(reference.$ref).hash.slice(1)));
53
+ }
54
+ }
55
+ for (const key of ['allOf', 'anyOf', 'oneOf']) {
56
+ const children = current[key];
57
+ if (Array.isArray(children))
58
+ children.forEach((child, index) => {
59
+ if (typeof child === 'boolean' ||
60
+ (child !== null &&
61
+ typeof child === 'object' &&
62
+ !Array.isArray(child)))
63
+ visit(child, `${pointer}/${key}/${index}`);
64
+ });
65
+ }
66
+ }
67
+ finally {
68
+ active.delete(current);
69
+ }
70
+ }
71
+ input.schemas.forEach((item, index) => visit(item, `/${index}`));
72
+ return candidates.filter((candidate, index) => candidates.findIndex((item) => item.id === candidate.id) === index);
73
+ }
@@ -0,0 +1,3 @@
1
+ import type { WorkflowDraftApiEnumChoicesInput, WorkflowDraftApiEnumChoicesDescription } from '../../../types/workflow-draft-api-enum-selection.js';
2
+ /** Only unresolved original-OAS inputs. Defaults/examples never become choices. */
3
+ export declare function describeWorkflowDraftApiEnumChoices(input: WorkflowDraftApiEnumChoicesInput): WorkflowDraftApiEnumChoicesDescription;
@@ -0,0 +1,70 @@
1
+ import { resolveApiCallArgumentsContext } from './resolve-api-call-arguments-context.js';
2
+ import { applyConfirmedApiInputs } from '../../../arguments/clarification/apply-confirmed-api-inputs.js';
3
+ import { inspectApiArgumentRequirements } from '../../../arguments/clarification/inspect-api-argument-requirements.js';
4
+ import { schemasAtPointer } from '../../../bindings/schema-at-pointer.js';
5
+ import { hasPointer } from '../../../bindings/json-pointer.js';
6
+ import { createSchemaResourceContext } from '../../../bindings/resources/create-schema-resource-context.js';
7
+ import { listApiInputEnumCandidates } from '../../../arguments/enum/list-api-input-enum-candidates.js';
8
+ /** Only unresolved original-OAS inputs. Defaults/examples never become choices. */
9
+ export function describeWorkflowDraftApiEnumChoices(input) {
10
+ const { description, contract } = resolveApiCallArgumentsContext(input);
11
+ const values = applyConfirmedApiInputs({
12
+ callId: description.nodeId,
13
+ operation: description.operation,
14
+ requestMediaType: description.requestMediaType,
15
+ bindings: input.bindingPlan.bindings,
16
+ confirmedInputs: input.confirmedInputs,
17
+ values: contract.valuesSchema.parse(input.proposal.values),
18
+ });
19
+ const inspected = inspectApiArgumentRequirements({
20
+ callId: description.nodeId,
21
+ operation: description.operation,
22
+ requestMediaType: description.requestMediaType,
23
+ bindings: input.bindingPlan.bindings,
24
+ values,
25
+ requestedInputs: input.proposal.requestedInputs,
26
+ });
27
+ const targets = new Set(inspected.requirements.flatMap((requirement) => [
28
+ requirement.targetPointer,
29
+ ...(requirement.requestedInputs ?? []),
30
+ ]));
31
+ const candidates = [];
32
+ const choiceTargets = [];
33
+ const resources = createSchemaResourceContext(description.requestSchema);
34
+ for (const targetPointer of targets) {
35
+ if (hasPointer(values, targetPointer) ||
36
+ input.bindingPlan.bindings.some((binding) => overlaps(binding.targetPointer, targetPointer)) ||
37
+ (input.confirmedInputs ?? []).some((item) => overlaps(item.targetPointer, targetPointer)))
38
+ continue;
39
+ const schemas = schemasAtPointer(resources.root, targetPointer, resources);
40
+ const selected = listApiInputEnumCandidates({
41
+ source: {
42
+ kind: 'operation',
43
+ callId: description.nodeId,
44
+ operation: description.operation,
45
+ requestMediaType: description.requestMediaType,
46
+ targetPointer,
47
+ },
48
+ schemas,
49
+ resources,
50
+ });
51
+ if (selected.length) {
52
+ candidates.push(...selected);
53
+ const requirement = inspected.requirements.find((item) => item.targetPointer === targetPointer ||
54
+ item.requestedInputs?.includes(targetPointer));
55
+ choiceTargets.push({
56
+ targetPointer,
57
+ schema: resources.bundle(schemas.length === 1 ? schemas[0] : { anyOf: schemas }),
58
+ ...(requirement?.parameterDescription === undefined
59
+ ? {}
60
+ : { description: requirement.parameterDescription }),
61
+ });
62
+ }
63
+ }
64
+ return { candidates, targets: choiceTargets };
65
+ }
66
+ function overlaps(left, right) {
67
+ return (left === right ||
68
+ left.startsWith(right + '/') ||
69
+ right.startsWith(left + '/'));
70
+ }
@@ -5,6 +5,7 @@ import { inspectApiArgumentRequirements } from '../../../arguments/clarification
5
5
  import { resolveWorkflowDraftSourceEvidence } from '../references/resolve-workflow-draft-source-evidence.js';
6
6
  import { jsonValuesEqual } from '../../../utils/json-values-equal.js';
7
7
  import { resolveWorkflowDraftApiLiteralSources } from './resolve-workflow-draft-api-literal-sources.js';
8
+ import { resolveWorkflowDraftApiEnumSelections } from './resolve-workflow-draft-api-enum-selections.js';
8
9
  /** Resolve one actual request; partial values become typed questions/slots, never dummy data. */
9
10
  export function resolveWorkflowDraftApiCallArguments(input) {
10
11
  const { description, fingerprint } = resolveApiCallArgumentsContext(input);
@@ -13,13 +14,18 @@ export function resolveWorkflowDraftApiCallArguments(input) {
13
14
  const proposal = createWorkflowDraftApiCallArgumentsSchema(input).parse(input.proposal);
14
15
  if (!jsonValuesEqual(proposal, input.proposal))
15
16
  throw new Error('API call arguments must validate without defaults, coercion or transformation');
17
+ const literalSources = resolveWorkflowDraftApiLiteralSources({
18
+ description,
19
+ proposal,
20
+ });
21
+ const enums = resolveWorkflowDraftApiEnumSelections({ ...input, proposal });
16
22
  const values = applyConfirmedApiInputs({
17
23
  callId: description.nodeId,
18
24
  operation: description.operation,
19
25
  requestMediaType: description.requestMediaType,
20
26
  bindings: input.bindingPlan.bindings,
21
27
  confirmedInputs: input.confirmedInputs,
22
- values: proposal.values,
28
+ values: enums.values,
23
29
  });
24
30
  const inspected = inspectApiArgumentRequirements({
25
31
  callId: description.nodeId,
@@ -32,10 +38,8 @@ export function resolveWorkflowDraftApiCallArguments(input) {
32
38
  const fields = {
33
39
  fingerprint,
34
40
  proposal,
35
- literalSources: resolveWorkflowDraftApiLiteralSources({
36
- description,
37
- proposal,
38
- }),
41
+ literalSources,
42
+ ...(enums.selections.length ? { enumSelections: enums.selections } : {}),
39
43
  ...resolveWorkflowDraftSourceEvidence({
40
44
  description,
41
45
  decision: proposal,
@@ -0,0 +1,4 @@
1
+ import type { ResolveWorkflowDraftApiCallArgumentsInput } from '../../../types/workflow-draft-api-call-planning.js';
2
+ import type { WorkflowDraftApiEnumResolution } from '../../../types/workflow-draft-api-enum-selection.js';
3
+ /** Copy from the current OAS, never from model-supplied values or same-name fields. */
4
+ export declare function resolveWorkflowDraftApiEnumSelections(input: ResolveWorkflowDraftApiCallArgumentsInput): WorkflowDraftApiEnumResolution;
@@ -0,0 +1,38 @@
1
+ import { describeWorkflowDraftApiEnumChoices } from './describe-workflow-draft-api-enum-choices.js';
2
+ import { createWorkflowDraftApiEnumSelectionSchema } from '../../../schemas/workflow-draft-api-enum-selection-schema.js';
3
+ import { assignApiInputValue } from '../../../arguments/clarification/assign-api-input-value.js';
4
+ import { resolveApiCallArgumentsContext } from './resolve-api-call-arguments-context.js';
5
+ import { verifyWorkflowDraftApiEnumSelection } from '../enum/verify-workflow-draft-api-enum-selection.js';
6
+ /** Copy from the current OAS, never from model-supplied values or same-name fields. */
7
+ export function resolveWorkflowDraftApiEnumSelections(input) {
8
+ const values = structuredClone(input.proposal.values);
9
+ const verified = [];
10
+ if (input.enumSelections === undefined)
11
+ return { values, selections: verified };
12
+ const { candidates } = describeWorkflowDraftApiEnumChoices(input);
13
+ const proposal = createWorkflowDraftApiEnumSelectionSchema(input).parse({
14
+ selections: input.enumSelections,
15
+ });
16
+ const { description } = resolveApiCallArgumentsContext(input);
17
+ for (const selection of proposal.selections) {
18
+ const candidate = candidates.find((item) => item.id === selection.candidateId);
19
+ if (!candidate)
20
+ throw new Error(`API enum selection ${selection.candidateId} is absent from the current OAS choices`);
21
+ if (verified.some((item) => item.targetPointer === candidate.targetPointer ||
22
+ item.targetPointer.startsWith(candidate.targetPointer + '/') ||
23
+ candidate.targetPointer.startsWith(item.targetPointer + '/')))
24
+ throw new Error(`API enum selections overlap at ${candidate.targetPointer}`);
25
+ const receipt = verifyWorkflowDraftApiEnumSelection({
26
+ selection,
27
+ candidates,
28
+ messages: [...description.messages, ...description.backgroundMessages],
29
+ });
30
+ assignApiInputValue(values, candidate.targetPointer, structuredClone(candidate.value), {
31
+ operation: description.operation,
32
+ requestMediaType: description.requestMediaType,
33
+ callId: description.nodeId,
34
+ });
35
+ verified.push(receipt);
36
+ }
37
+ return { values, selections: verified };
38
+ }
@@ -0,0 +1,3 @@
1
+ import type { VerifyWorkflowDraftApiEnumSelectionInput, VerifiedWorkflowDraftApiEnumSelection } from '../../../types/workflow-draft-api-enum-selection.js';
2
+ /** Human intent is a separate receipt; the selected request value comes only from the OAS. */
3
+ export declare function verifyWorkflowDraftApiEnumSelection(input: VerifyWorkflowDraftApiEnumSelectionInput): VerifiedWorkflowDraftApiEnumSelection;
@@ -0,0 +1,23 @@
1
+ import { createWorkflowDraftApiEnumChoiceSchema } from '../../../schemas/workflow-draft-api-enum-choice-schema.js';
2
+ import { readApiInputLiteralSource } from '../../../arguments/sources/read-api-input-literal-source.js';
3
+ /** Human intent is a separate receipt; the selected request value comes only from the OAS. */
4
+ export function verifyWorkflowDraftApiEnumSelection(input) {
5
+ const selection = createWorkflowDraftApiEnumChoiceSchema(input.candidates, input.messages.map((message) => message.id)).parse(input.selection);
6
+ const candidate = input.candidates.find((item) => item.id === selection.candidateId);
7
+ if (!candidate)
8
+ throw new Error(`API enum selection ${selection.candidateId} is absent from the current OAS choices`);
9
+ const message = input.messages.find((item) => item.id === selection.messageId);
10
+ if (!message)
11
+ throw new Error(`API enum selection cites unavailable message ${selection.messageId}`);
12
+ const source = readApiInputLiteralSource({
13
+ sourceFormat: 'text',
14
+ sourceText: selection.sourceText,
15
+ text: message.text,
16
+ label: `API enum ${candidate.targetPointer}`,
17
+ });
18
+ return {
19
+ ...structuredClone(candidate),
20
+ ...selection,
21
+ occurrences: source.occurrences,
22
+ };
23
+ }
@@ -0,0 +1,4 @@
1
+ import type { ResolveWorkflowDraftApiInputEditsInput } from '../../../types/workflow-draft-api-input-edit.js';
2
+ import type { ApiInputRequirement } from '../../../types/api-clarification.js';
3
+ /** Questions for actual pending set-targets, retaining references and declaring the compiled dialect. */
4
+ export declare function describeWorkflowDraftApiInputEditAnswerRequirements(input: ResolveWorkflowDraftApiInputEditsInput): ApiInputRequirement[];
@@ -0,0 +1,30 @@
1
+ import { describeWorkflowDraftApiInputEdit } from './describe-workflow-draft-api-input-edit.js';
2
+ import { resolveWorkflowDraftApiInputEdits } from './resolve-workflow-draft-api-input-edits.js';
3
+ import { createSchemaResourceContext } from '../../../bindings/resources/create-schema-resource-context.js';
4
+ /** Questions for actual pending set-targets, retaining references and declaring the compiled dialect. */
5
+ export function describeWorkflowDraftApiInputEditAnswerRequirements(input) {
6
+ const result = resolveWorkflowDraftApiInputEdits(input);
7
+ if (result.status === 'ready')
8
+ return [];
9
+ const described = describeWorkflowDraftApiInputEdit(input);
10
+ const resources = createSchemaResourceContext(input.contract.schemaResource);
11
+ return result.pendingTargets.map((target) => {
12
+ if (target.kind !== 'set')
13
+ throw new Error(`Pending API edit ${input.contract.id}:${target.id} is not a set-target`);
14
+ return {
15
+ kind: 'requested-input',
16
+ id: `${input.contract.id}:${target.id}`,
17
+ callId: described.call.id,
18
+ operation: structuredClone(described.operation.key),
19
+ targetPointer: target.pointer,
20
+ schema: resources.bundle(target.schema),
21
+ openapiVersion: described.operation.openapiVersion,
22
+ schemaDialect: 'draft-2020-12',
23
+ requestedInputs: [target.pointer],
24
+ ...(typeof described.operation.operation.summary === 'string'
25
+ ? { operationSummary: described.operation.operation.summary }
26
+ : {}),
27
+ message: `Provide the new explicitly requested value at ${target.pointer}. The existing value is not an answer to this edit.`,
28
+ };
29
+ });
30
+ }
@@ -0,0 +1,4 @@
1
+ import type { WorkflowDraftApiInputEditContractInput } from '../../../types/workflow-draft-api-input-edit.js';
2
+ import type { WorkflowDraftApiEnumChoicesDescription } from '../../../types/workflow-draft-api-enum-selection.js';
3
+ /** Only previously validated set-targets; never advertise remove targets, bindings or unrelated fields. */
4
+ export declare function describeWorkflowDraftApiInputEditEnumChoices(input: WorkflowDraftApiInputEditContractInput): WorkflowDraftApiEnumChoicesDescription;
@@ -0,0 +1,42 @@
1
+ import { validateWorkflowDraftApiInputEditContract } from './validate-workflow-draft-api-input-edit-contract.js';
2
+ import { describeWorkflowDraftApiInputEdit } from './describe-workflow-draft-api-input-edit.js';
3
+ import { createSchemaResourceContext } from '../../../bindings/resources/create-schema-resource-context.js';
4
+ import { listApiInputEnumCandidates } from '../../../arguments/enum/list-api-input-enum-candidates.js';
5
+ /** Only previously validated set-targets; never advertise remove targets, bindings or unrelated fields. */
6
+ export function describeWorkflowDraftApiInputEditEnumChoices(input) {
7
+ validateWorkflowDraftApiInputEditContract(input);
8
+ if (input.selectOasEnums !== undefined &&
9
+ typeof input.selectOasEnums !== 'boolean')
10
+ throw new Error('API input edit selectOasEnums must be a boolean');
11
+ const result = {
12
+ candidates: [],
13
+ targets: [],
14
+ };
15
+ if (input.selectOasEnums !== true)
16
+ return result;
17
+ const description = describeWorkflowDraftApiInputEdit(input);
18
+ const resources = createSchemaResourceContext(input.contract.schemaResource);
19
+ for (const target of input.contract.targets) {
20
+ if (target.kind !== 'set')
21
+ continue;
22
+ const candidates = listApiInputEnumCandidates({
23
+ source: {
24
+ kind: 'operation',
25
+ callId: description.call.id,
26
+ operation: description.operation,
27
+ requestMediaType: description.call.requestMediaType,
28
+ targetPointer: target.pointer,
29
+ },
30
+ schemas: [target.schema],
31
+ resources,
32
+ });
33
+ if (candidates.length) {
34
+ result.candidates.push(...candidates);
35
+ result.targets.push({
36
+ targetPointer: target.pointer,
37
+ schema: resources.bundle(target.schema),
38
+ });
39
+ }
40
+ }
41
+ return result;
42
+ }
@@ -0,0 +1,3 @@
1
+ import type { ResolveWorkflowDraftApiInputEditReplyInput, WorkflowDraftApiInputEditAnswers } from '../../../types/workflow-draft-api-input-edit.js';
2
+ /** Interpretations become validated answer values, never a replacement model proposal. */
3
+ export declare function resolveWorkflowDraftApiInputEditReply(input: ResolveWorkflowDraftApiInputEditReplyInput): WorkflowDraftApiInputEditAnswers;
@@ -0,0 +1,24 @@
1
+ import { describeWorkflowDraftApiInputEditAnswerRequirements } from './describe-workflow-draft-api-input-edit-answer-requirements.js';
2
+ import { validateApiInputAnswerAnalysis } from '../../../arguments/clarification/extraction/validate-api-input-answer-analysis.js';
3
+ import { createWorkflowDraftApiInputEditAnswersSchema } from '../../../schemas/create-workflow-draft-api-input-edit-answers-schema.js';
4
+ /** Interpretations become validated answer values, never a replacement model proposal. */
5
+ export function resolveWorkflowDraftApiInputEditReply(input) {
6
+ const requirements = describeWorkflowDraftApiInputEditAnswerRequirements(input);
7
+ validateApiInputAnswerAnalysis({
8
+ reply: input.reply,
9
+ requirements,
10
+ ...(input.selectOasEnums === undefined
11
+ ? {}
12
+ : { selectOasEnums: input.selectOasEnums }),
13
+ analysis: input.analysis,
14
+ });
15
+ return createWorkflowDraftApiInputEditAnswersSchema(input).parse({
16
+ contractId: input.contract.id,
17
+ answers: input.analysis.answers.map((answer) => {
18
+ const target = input.contract.targets.find((target) => `${input.contract.id}:${target.id}` === answer.requirementId);
19
+ if (!target)
20
+ throw new Error(`API edit reply references an unavailable target ${answer.requirementId}`);
21
+ return { targetId: target.id, value: structuredClone(answer.value) };
22
+ }),
23
+ });
24
+ }