@openapi-flow/core 0.3.0 → 0.3.2

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 CHANGED
@@ -2,7 +2,11 @@
2
2
 
3
3
  Zod `^4.6.5` is a required peer, shared with the host rather than installed as a separately pinned runtime copy. Development tests use 4.6.5; the strict installed-consumer check also uses the host's 4.6.7. This preserves the public schema type boundary without casts or dependency overrides.
4
4
 
5
- Version **0.3.0**. Canonical draft, clarification and runtime-input APIs described below are included in this release. Ajv 8.20.0 does not correctly validate a declared `properties.__proto__`; generated validation may reject valid data or omit that property's constraints. This known limitation was explicitly accepted for release, without renaming data or skipping its failing regression. See the [release record](https://github.com/carefreelife98/openapi-flow/blob/main/docs/releases/0.3.0.md).
5
+ Version **0.3.2**. Canonical draft, clarification and runtime-input APIs described below are included in this release. Ajv 8.20.0 does not correctly validate a declared `properties.__proto__`; generated validation may reject valid data or omit that property's constraints. This previously accepted limitation remains unchanged, without renaming data or skipping its failing regression. See the [release record](https://github.com/carefreelife98/openapi-flow/blob/main/docs/releases/0.3.2.md).
6
+
7
+ Native and fixed-material connection planning accept the optional, existing `WorkflowEntryPointContract` as `entrypoint`. Core validates and snapshots this owner-provided start alongside the other inputs; it does not infer one when absent, add a selectable trigger or let model output modify it.
8
+
9
+ Connection planning accepts explicit current `deferredApiInputIds` derived with `collectDeferredApiInputSlots`. Missing inputs remain absent and require canonical template preflight before execution; supplied values and the full DAG are still validated. See [input deferral](https://github.com/carefreelife98/openapi-flow/blob/main/docs/deferred-connection-planning.md).
6
10
 
7
11
  canonical `gapNodes` and the separate `createWorkflowDraftCapabilityGap`,
8
12
  `inspectWorkflowDraftCapabilityGap`, `describeWorkflowDraftCapabilityGap` functions
@@ -184,6 +184,7 @@ export type * from './types/api-bindings.js';
184
184
  export type * from './types/api-binding-planning.js';
185
185
  export type * from './types/native-node-planning.js';
186
186
  export type * from './types/workflow-connection-planning.js';
187
+ export type * from './types/workflow-api-input-readiness.js';
187
188
  export type * from './types/workflow-planning-materials.js';
188
189
  export type * from './types/workflow-graph-planning.js';
189
190
  export { describeWorkflowGraphPlanning } from './workflow/graphs/describe-workflow-graph-planning.js';
@@ -4,6 +4,10 @@ export declare const nativeNodePlanningOptionsSchema: z.ZodObject<{
4
4
  planId: z.ZodString;
5
5
  scenario: z.ZodString;
6
6
  allowRuntimeParameters: z.ZodOptional<z.ZodBoolean>;
7
+ entrypoint: z.ZodOptional<z.ZodObject<{
8
+ kind: z.ZodString;
9
+ description: z.ZodString;
10
+ }, z.core.$strict>>;
7
11
  }, z.core.$strict>;
8
12
  export declare const nativePlanningProposalSchema: z.ZodObject<{
9
13
  nativeNodes: z.ZodArray<z.ZodObject<{
@@ -1,10 +1,11 @@
1
1
  import { z } from 'zod';
2
- import { planningEvidenceTextSchema } from './planning-evidence-schema.js';
2
+ import { planningEvidenceTextSchema, workflowEntryPointContractSchema, } from './planning-evidence-schema.js';
3
3
  import { workflowDraftNativeNodeSchema } from './workflow-draft-schema.js';
4
4
  export const nativeNodePlanningOptionsSchema = z.strictObject({
5
5
  planId: planningEvidenceTextSchema,
6
6
  scenario: planningEvidenceTextSchema,
7
7
  allowRuntimeParameters: z.boolean().optional(),
8
+ entrypoint: workflowEntryPointContractSchema.optional(),
8
9
  });
9
10
  export const nativePlanningProposalSchema = z.strictObject({
10
11
  nativeNodes: z.array(workflowDraftNativeNodeSchema),
@@ -0,0 +1,2 @@
1
+ import { z } from 'zod';
2
+ export declare const workflowDeferredApiInputIdsSchema: z.ZodArray<z.ZodString>;
@@ -0,0 +1,6 @@
1
+ import { z } from 'zod';
2
+ export const workflowDeferredApiInputIdsSchema = z
3
+ .array(z.string().refine((value) => value.trim().length > 0))
4
+ .refine((ids) => new Set(ids).size === ids.length, {
5
+ message: 'deferredApiInputIds must contain distinct current input slot IDs',
6
+ });
@@ -4,6 +4,10 @@ import type { WorkflowPlanningSourceEvidence } from '../types/workflow-planning-
4
4
  import type { WorkflowPlanNodeContract } from '../types/workflow-plan.js';
5
5
  export declare const workflowConnectionIdentitySchema: z.ZodObject<{
6
6
  scenario: z.ZodString;
7
+ entrypoint: z.ZodOptional<z.ZodObject<{
8
+ kind: z.ZodString;
9
+ description: z.ZodString;
10
+ }, z.core.$strict>>;
7
11
  }, z.core.$strict>;
8
12
  export declare const workflowConnectionProposalSchema: z.ZodObject<{
9
13
  edges: z.ZodArray<z.ZodObject<{
@@ -1,9 +1,10 @@
1
1
  import { z } from 'zod';
2
- import { planningEvidenceTextSchema } from './planning-evidence-schema.js';
2
+ import { planningEvidenceTextSchema, workflowEntryPointContractSchema, } from './planning-evidence-schema.js';
3
3
  import { workflowDraftNativeNodeSchema, workflowDraftEdgeSchema, } from './workflow-draft-schema.js';
4
4
  import { workflowReviewGapSchema, workflowBlockedCallSchema, } from './workflow-planning-material-schema.js';
5
5
  export const workflowConnectionIdentitySchema = z.strictObject({
6
6
  scenario: planningEvidenceTextSchema,
7
+ entrypoint: workflowEntryPointContractSchema.optional(),
7
8
  });
8
9
  export const workflowConnectionProposalSchema = z.strictObject({
9
10
  edges: z.array(workflowDraftEdgeSchema),
@@ -21,13 +21,13 @@ export declare const workflowDraftEditPlanSchema: z.ZodObject<{
21
21
  decision: z.ZodRecord<z.ZodString, z.ZodJSONSchema>;
22
22
  newNodeId: z.ZodOptional<z.ZodString>;
23
23
  stages: z.ZodArray<z.ZodEnum<{
24
+ clarification: "clarification";
24
25
  "api-bindings": "api-bindings";
25
26
  "api-arguments": "api-arguments";
26
27
  "native-parameters": "native-parameters";
27
28
  requirements: "requirements";
28
29
  connections: "connections";
29
30
  "resolve-contracts": "resolve-contracts";
30
- clarification: "clarification";
31
31
  }>>;
32
32
  }, z.core.$strict>>;
33
33
  }, z.core.$strict>;
@@ -1,4 +1,5 @@
1
1
  import type { ApiBindingMaterial } from './api-bindings.js';
2
+ import type { WorkflowPlanningContext } from './planning-evidence.js';
2
3
  import type { z } from 'zod';
3
4
  import type { JsonValueObject } from './api-arguments.js';
4
5
  import type { JsonObject } from './openapi.js';
@@ -8,7 +9,7 @@ import type { NativeInstanceDependencyPlan, NativeNodeConfigurationDependencies
8
9
  import type { WorkflowNativeMaterialSources, MissingWorkflowNativeMaterialRequirement, ResolveNativeMaterialSnapshotInput } from './native-material-snapshot.js';
9
10
  import type { WorkflowReviewGap } from './reviewable-workflow.js';
10
11
  import type { PlannedNativeNode, WorkflowCapability, WorkflowPlanGap, WorkflowPlanNodeContract, NativeRuntimeParameterSelection } from './workflow-plan.js';
11
- export interface NativeNodePlanningInput {
12
+ export interface NativeNodePlanningInput extends Pick<WorkflowPlanningContext, 'entrypoint'> {
12
13
  planId: string;
13
14
  scenario: string;
14
15
  capabilities?: WorkflowCapability[];
@@ -38,7 +39,7 @@ export interface NativePlanningApiMaterial {
38
39
  operation: ApiBindingMaterial['operation']['operation'];
39
40
  effective: ApiBindingMaterial['operation']['effective'];
40
41
  }
41
- export interface NativeNodePlanningContext {
42
+ export interface NativeNodePlanningContext extends Pick<WorkflowPlanningContext, 'entrypoint'> {
42
43
  scenario: string;
43
44
  apiMaterials: NativePlanningApiMaterial[];
44
45
  preparedNativeNodes: PreparedNativeNodeMaterial[];
@@ -2,6 +2,7 @@ import type { ApiOperationContract } from './api-operation.js';
2
2
  import type { ApiOperationKey } from './api-catalog.js';
3
3
  import type { OutputBinding } from './api-arguments.js';
4
4
  import type { WorkflowConnectionPlanningRecord } from './workflow-connection-planning.js';
5
+ import type { WorkflowApiInputDeferral } from './workflow-api-input-readiness.js';
5
6
  import type { WorkflowApiMaterial, WorkflowCapability, WorkflowGraphPlan, PlannedNativeNode, WorkflowPlanEdge } from './workflow-plan.js';
6
7
  export interface WorkflowReviewGap {
7
8
  id: string;
@@ -44,7 +45,7 @@ export interface ReviewableWorkflowGraphPlan extends WorkflowGraphPlan {
44
45
  /** Optional original connection-only decision and supplied-material evidence. */
45
46
  connectionPlanning?: WorkflowConnectionPlanningRecord;
46
47
  }
47
- export interface ReviewableWorkflowPlanningContext {
48
+ export interface ReviewableWorkflowPlanningContext extends WorkflowApiInputDeferral {
48
49
  materials: ReviewableWorkflowApiMaterial[];
49
50
  capabilities: WorkflowCapability[];
50
51
  }
@@ -0,0 +1,8 @@
1
+ import type { ReviewableWorkflowApiMaterial } from './reviewable-workflow.js';
2
+ export interface WorkflowApiInputDeferral {
3
+ /** Exact current OAS-derived input slot IDs explicitly deferred by the caller. */
4
+ deferredApiInputIds?: string[];
5
+ }
6
+ export interface WorkflowApiInputReadinessInput extends WorkflowApiInputDeferral {
7
+ materials: ReviewableWorkflowApiMaterial[];
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -2,23 +2,27 @@ import type { ReviewableWorkflowApiMaterial, ReviewableWorkflowGraphPlan, Review
2
2
  import type { PlannedNativeNode, WorkflowCapability, WorkflowPlanEdge, WorkflowPlanNodeContract } from './workflow-plan.js';
3
3
  import type { PreparedNativeNodeMaterial } from './native-node-planning.js';
4
4
  import type { WorkflowPlanningSourceEvidence } from './workflow-planning-materials.js';
5
- export interface WorkflowConnectionMaterialInput {
5
+ import type { WorkflowApiInputDeferral } from './workflow-api-input-readiness.js';
6
+ import type { DeferredApiInputSlot } from './deferred-api-inputs.js';
7
+ import type { WorkflowPlanningContext } from './planning-evidence.js';
8
+ export interface WorkflowConnectionMaterialInput extends WorkflowApiInputDeferral {
6
9
  materials?: ReviewableWorkflowApiMaterial[];
7
10
  capabilities?: WorkflowCapability[];
8
11
  nativeNodes?: PlannedNativeNode[];
9
12
  gaps?: WorkflowReviewGap[];
10
13
  edges?: WorkflowPlanEdge[];
11
14
  }
12
- export interface WorkflowConnectionPlanningInput extends WorkflowConnectionMaterialInput {
15
+ export interface WorkflowConnectionPlanningInput extends WorkflowConnectionMaterialInput, Pick<WorkflowPlanningContext, 'entrypoint'> {
13
16
  scenario: string;
14
17
  }
15
- export interface WorkflowConnectionMaterials {
18
+ export interface WorkflowConnectionMaterials extends WorkflowApiInputDeferral {
16
19
  materials: ReviewableWorkflowApiMaterial[];
17
20
  capabilities: WorkflowCapability[];
18
21
  nativeNodes: PlannedNativeNode[];
19
22
  gaps: WorkflowReviewGap[];
20
23
  edges: WorkflowPlanEdge[];
21
24
  contracts: WorkflowPlanNodeContract[];
25
+ deferredApiInputs?: DeferredApiInputSlot[];
22
26
  }
23
27
  export interface WorkflowConnectionApiRole {
24
28
  callId: string;
@@ -30,7 +34,7 @@ export interface WorkflowNativeParameterReadiness {
30
34
  /** Explicit runtime ownership, not missing plan-time values or unresolved graph gaps. */
31
35
  executionInputPointers: string[];
32
36
  }
33
- export interface WorkflowConnectionPlanningContext {
37
+ export interface WorkflowConnectionPlanningContext extends Pick<WorkflowPlanningContext, 'entrypoint'> {
34
38
  scenario: string;
35
39
  nodes: WorkflowPlanNodeContract[];
36
40
  nativeNodes?: PreparedNativeNodeMaterial[];
@@ -39,8 +43,10 @@ export interface WorkflowConnectionPlanningContext {
39
43
  gaps: WorkflowReviewGap[];
40
44
  readyCallIds: string[];
41
45
  apiRoles: WorkflowConnectionApiRole[];
46
+ /** Code-derived missing values, never missing API capabilities or generated literals. */
47
+ deferredApiInputs?: DeferredApiInputSlot[];
42
48
  }
43
- export interface WorkflowConnectionPlanningSnapshot extends WorkflowConnectionMaterials {
49
+ export interface WorkflowConnectionPlanningSnapshot extends WorkflowConnectionMaterials, Pick<WorkflowPlanningContext, 'entrypoint'> {
44
50
  scenario: string;
45
51
  }
46
52
  export interface WorkflowConnectionPlanningDescription {
@@ -8,9 +8,11 @@ import { createNativePlanningCapabilityMaterial } from '../planning/create-nativ
8
8
  import { prepareWorkflowConnectionMaterials } from './prepare-workflow-connection-materials.js';
9
9
  /** Capture declared data before awaiting the model; never clone opaque callbacks or forward audit metadata. */
10
10
  export function describeWorkflowConnectionPlanning(input) {
11
- const { scenario } = workflowConnectionIdentitySchema.parse({
11
+ const identity = workflowConnectionIdentitySchema.parse({
12
12
  scenario: input.scenario,
13
+ ...(input.entrypoint === undefined ? {} : { entrypoint: input.entrypoint }),
13
14
  });
15
+ const { scenario } = identity;
14
16
  for (const field of [
15
17
  'materials',
16
18
  'capabilities',
@@ -30,13 +32,14 @@ export function describeWorkflowConnectionPlanning(input) {
30
32
  const materials = captured.materials;
31
33
  const prepared = prepareWorkflowConnectionMaterials({
32
34
  materials,
35
+ deferredApiInputIds: input.deferredApiInputIds,
33
36
  capabilities: captured.capabilities,
34
37
  nativeNodes: captured.preparedNativeNodes,
35
38
  gaps: structuredClone((input.gaps === undefined ? [] : input.gaps).map((gap) => workflowReviewGapSchema.parse(gap))),
36
39
  edges: structuredClone((input.edges === undefined ? [] : input.edges).map((edge) => workflowDraftEdgeSchema.parse(edge))),
37
40
  });
38
41
  const context = {
39
- scenario,
42
+ ...structuredClone(identity),
40
43
  nodes: structuredClone(prepared.contracts),
41
44
  ...(prepared.nativeNodes.length
42
45
  ? {
@@ -65,9 +68,12 @@ export function describeWorkflowConnectionPlanning(input) {
65
68
  purpose: material.purpose,
66
69
  },
67
70
  ]),
71
+ ...(prepared.deferredApiInputs === undefined
72
+ ? {}
73
+ : { deferredApiInputs: structuredClone(prepared.deferredApiInputs) }),
68
74
  };
69
75
  return {
70
- input: { ...prepared, scenario },
76
+ input: { ...prepared, ...identity },
71
77
  context,
72
78
  sources: structuredClone({
73
79
  materials,
@@ -1,7 +1,7 @@
1
1
  import { createReviewableNodeContracts } from '../create-reviewable-node-contracts.js';
2
2
  import { createNativeOutputContracts } from '../create-native-output-contracts.js';
3
3
  import { validateWorkflowEdges } from '../validate-workflow-edges.js';
4
- import { inspectApiArgumentRequirements } from '../../arguments/clarification/inspect-api-argument-requirements.js';
4
+ import { validateWorkflowApiInputReadiness } from '../validate-workflow-api-input-readiness.js';
5
5
  import { validateApiBindingAssignments } from '../../bindings/validate-api-binding-assignments.js';
6
6
  import { validateNativeApiResponseReferences } from '../validate-native-api-response-references.js';
7
7
  import { createNativeParameterGenerationContract } from '../../schemas/create-native-parameter-generation-contract.js';
@@ -57,17 +57,10 @@ export function prepareWorkflowConnectionMaterials(input) {
57
57
  nativeNodes,
58
58
  capabilities,
59
59
  });
60
- for (const material of materials) {
61
- if (material.status !== 'ready')
62
- continue;
63
- const args = material.arguments;
64
- const validation = inspectApiArgumentRequirements({
65
- operation: material.operation,
66
- ...args,
67
- });
68
- if (args.unresolvedInputs.length || validation.status !== 'ready')
69
- throw new Error(`materials[${args.callId}] has unresolved OAS request inputs or scenario-requested inputs`);
70
- }
60
+ const deferredApiInputs = validateWorkflowApiInputReadiness({
61
+ materials,
62
+ deferredApiInputIds: input.deferredApiInputIds,
63
+ });
71
64
  if (materials.length)
72
65
  validateApiBindingAssignments({
73
66
  nativeOutputs,
@@ -104,5 +97,16 @@ export function prepareWorkflowConnectionMaterials(input) {
104
97
  plan,
105
98
  });
106
99
  validateWorkflowEdges({ contracts, edges });
107
- return { materials, capabilities, nativeNodes, gaps, edges, contracts };
100
+ return {
101
+ materials,
102
+ capabilities,
103
+ nativeNodes,
104
+ gaps,
105
+ edges,
106
+ contracts,
107
+ ...(input.deferredApiInputIds === undefined
108
+ ? {}
109
+ : { deferredApiInputIds: [...input.deferredApiInputIds] }),
110
+ ...(deferredApiInputs.length ? { deferredApiInputs } : {}),
111
+ };
108
112
  }
@@ -10,6 +10,7 @@ export function describeNativeNodePlanning(input) {
10
10
  planId: input.planId,
11
11
  scenario: input.scenario,
12
12
  allowRuntimeParameters: input.allowRuntimeParameters,
13
+ ...(input.entrypoint === undefined ? {} : { entrypoint: input.entrypoint }),
13
14
  });
14
15
  const { capabilities, apiMaterials, preparedNativeNodes: prepared, } = captureWorkflowPlanningMaterials(input);
15
16
  const apiIds = apiMaterials.map((material) => material.callId);
@@ -28,6 +29,9 @@ export function describeNativeNodePlanning(input) {
28
29
  planningCapabilities,
29
30
  context: {
30
31
  scenario: options.scenario,
32
+ ...(options.entrypoint === undefined
33
+ ? {}
34
+ : { entrypoint: structuredClone(options.entrypoint) }),
31
35
  apiMaterials: apiMaterials.map(({ callId, operation, purpose }) => ({
32
36
  callId,
33
37
  ...(purpose === undefined ? {} : { purpose }),
@@ -1,4 +1,4 @@
1
- import { inspectApiArgumentRequirements } from '../arguments/clarification/inspect-api-argument-requirements.js';
1
+ import { validateWorkflowApiInputReadiness } from './validate-workflow-api-input-readiness.js';
2
2
  import { validateApiBindingAssignments } from '../bindings/validate-api-binding-assignments.js';
3
3
  import { validateApiBindingGaps } from '../bindings/validate-api-binding-gaps.js';
4
4
  import { createReviewableNodeContracts } from './create-reviewable-node-contracts.js';
@@ -31,20 +31,8 @@ export function validateReviewableWorkflowGraphPlan(input) {
31
31
  item.gapIds.some((id) => !blocked.get(item.callId)?.includes(id)))
32
32
  throw new Error(`review plan omitted blocked requirement for ${item.callId}`);
33
33
  }
34
- else {
35
- const args = item.arguments;
36
- const result = inspectApiArgumentRequirements({
37
- operation: item.operation,
38
- callId: args.callId,
39
- requestedInputs: args.requestedInputs,
40
- values: args.values,
41
- bindings: args.bindings,
42
- requestMediaType: args.requestMediaType,
43
- });
44
- if (args.unresolvedInputs.length || result.status !== 'ready')
45
- throw new Error(`review ready material ${args.callId} has unresolved request inputs`);
46
- }
47
34
  }
35
+ validateWorkflowApiInputReadiness(input);
48
36
  if (materials.length)
49
37
  validateApiBindingAssignments({
50
38
  nativeOutputs: createNativeOutputContracts({
@@ -0,0 +1,4 @@
1
+ import type { DeferredApiInputSlot } from '../types/deferred-api-inputs.js';
2
+ import type { WorkflowApiInputReadinessInput } from '../types/workflow-api-input-readiness.js';
3
+ /** Missing literals may be planned, but only with explicit, current slot ownership. */
4
+ export declare function validateWorkflowApiInputReadiness(input: WorkflowApiInputReadinessInput): DeferredApiInputSlot[];
@@ -0,0 +1,33 @@
1
+ import { collectDeferredApiInputSlots } from '../inputs/collect-deferred-api-input-slots.js';
2
+ import { workflowDeferredApiInputIdsSchema } from '../schemas/workflow-api-input-deferral-schema.js';
3
+ /** Missing literals may be planned, but only with explicit, current slot ownership. */
4
+ export function validateWorkflowApiInputReadiness(input) {
5
+ const ids = input.deferredApiInputIds === undefined
6
+ ? []
7
+ : workflowDeferredApiInputIdsSchema.parse(input.deferredApiInputIds);
8
+ const ready = input.materials.filter((material) => material.status === 'ready');
9
+ // This validates supplied values against their original OAS before deriving missing slots.
10
+ const slots = collectDeferredApiInputSlots({
11
+ materials: ready.map((material) => ({
12
+ operation: material.operation,
13
+ callId: material.arguments.callId,
14
+ values: material.arguments.values,
15
+ bindings: material.arguments.bindings,
16
+ requestMediaType: material.arguments.requestMediaType,
17
+ requestedInputs: material.arguments.requestedInputs,
18
+ })),
19
+ });
20
+ for (const id of ids)
21
+ if (!slots.some((slot) => slot.id === id))
22
+ throw new Error(`deferredApiInputIds contains unknown or stale slot ${id}`);
23
+ for (const slot of slots)
24
+ if (!ids.includes(slot.id))
25
+ throw new Error(`materials[${slot.callId}] has unresolved OAS request inputs or scenario-requested inputs: ${slot.targetPointer}; explicitly defer current slot ${slot.id} or supply its value`);
26
+ for (const material of ready) {
27
+ const args = material.arguments;
28
+ if (new Set(args.unresolvedInputs).size !== args.unresolvedInputs.length ||
29
+ args.unresolvedInputs.some((pointer) => !slots.some((slot) => slot.callId === args.callId && slot.targetPointer === pointer)))
30
+ throw new Error(`materials[${args.callId}].unresolvedInputs must name current OAS request input slots without duplicates`);
31
+ }
32
+ return slots;
33
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openapi-flow/core",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "license": "MIT",
5
5
  "description": "Engine-independent OpenAPI catalogs, operation contracts and typed request schemas",
6
6
  "keywords": [