@warlock.js/ai 4.3.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,9 +8,15 @@ import { PlannerPlan, PlannerStep } from "./planner-plan.type.mjs";
8
8
  /**
9
9
  * Discriminator literal the planner stamps onto its report's `type`
10
10
  * field. A member of the shared
11
- * {@link import("../result/base-report.type").ReportType} closed union,
12
- * so {@link PlannerReport} narrows `type` against the shared union
13
- * directly rather than overriding it.
11
+ * {@link import("../result/base-report.type").ReportType} closed union.
12
+ *
13
+ * {@link PlannerReport} re-declares `type` as this literal by *overriding*
14
+ * it (`Omit<BaseReport, "type"> & { type: PlannerReportType }`) rather than
15
+ * intersecting (`BaseReport & { type: "planner" }`). Intersecting a single
16
+ * literal against `BaseReport.type` (the whole `ReportType` union) lets a
17
+ * strict TypeScript collapse the entire report to `never` ("property `type`
18
+ * has conflicting types in some constituents"); the `Omit` override sidesteps
19
+ * that while still producing the same `type: "planner"` for consumers.
14
20
  */
15
21
  type PlannerReportType = "planner";
16
22
  /**
@@ -45,7 +51,7 @@ type PlannerStepSnapshot = {
45
51
  * per-step record (one entry per step the planner attempted), and
46
52
  * `plan` is the verbatim LLM output before any step ran.
47
53
  */
48
- type PlannerReport = BaseReport & {
54
+ type PlannerReport = Omit<BaseReport, "type"> & {
49
55
  type: PlannerReportType; /** Structural fingerprint — same value exposed on the planner instance. */
50
56
  signature: string; /** The full plan the planner's LLM generated before execution began. */
51
57
  plan?: PlannerPlan; /** Per-step forensic records, in execution order. */
@@ -73,7 +79,7 @@ type PlannerReport = BaseReport & {
73
79
  *
74
80
  * console.log(report.plan?.summary, usage.total);
75
81
  */
76
- type PlannerResult<TOutput = unknown> = ExecuteResult<TOutput> & {
82
+ type PlannerResult<TOutput = unknown> = Omit<ExecuteResult<TOutput>, "report"> & {
77
83
  /** Discriminant for narrowing a heterogeneous result union. */type: "planner";
78
84
  report: PlannerReport;
79
85
  };
@@ -1 +1 @@
1
- {"version":3,"file":"planner-result.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/contracts/planner/planner-result.type.ts"],"mappings":";;;;;;;;;AAaA;;;;AAA6B;KAAjB,iBAAA;;;;;;;;;;KAWA,mBAAA;EAIJ,0DAFN,KAAA,UAMA;EAJA,IAAA,EAAM,WAAA,EAME;EAJR,MAAA,sCAMA;EAJA,MAAA,YAMA;EAJA,KAAA,GAAQ,OAAA;EACR,SAAA;EACA,OAAA;EACA,QAAA;EACA,KAAA,EAAO,KAAA,EAgBG;EAdV,WAAA,GAAc,UAAA;AAAA;;;;;;;;;;;;KAcJ,aAAA,GAAgB,UAAA;EAC1B,IAAA,EAAM,iBAAA,EAMS;EAJf,SAAA,UAMW;EAJX,IAAA,GAAO,WAAA,EA4BG;EA1BV,aAAA,EAAe,mBAAA,IA0BQ;EAxBvB,WAAA;AAAA;;;;;;;;;;;AA2BqB;;;;;;;;;;;KAHX,aAAA,sBAAmC,aAAA,CAAc,OAAA;iEAE3D,IAAA;EACA,MAAA,EAAQ,aAAA;AAAA"}
1
+ {"version":3,"file":"planner-result.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/contracts/planner/planner-result.type.ts"],"mappings":";;;;;;;;;AAmBA;;;;AAA6B;AAW7B;;;;;;KAXY,iBAAA;;;;;;;;;;KAWA,mBAAA;EAYV,0DAVA,KAAA,UAYA;EAVA,IAAA,EAAM,WAAA,EAYN;EAVA,MAAA,sCAUwB;EARxB,MAAA,YAsBU;EApBV,KAAA,GAAQ,OAAA;EACR,SAAA;EACA,OAAA;EACA,QAAA;EACA,KAAA,EAAO,KAAA,EAqBA;EAnBP,WAAA,GAAc,UAAA;AAAA;;;;;;;;;;;;KAcJ,aAAA,GAAgB,IAAA,CAAK,UAAA;EAC/B,IAAA,EAAM,iBAAA,EAgCI;EA9BV,SAAA,UA8BuB;EA5BvB,IAAA,GAAO,WAAA,EA4B2C;EA1BlD,aAAA,EAAe,mBAAA,IA6BP;EA3BR,WAAA;AAAA;;;;;;;;;AA2BqB;;;;;;;;;;;;;KAHX,aAAA,sBAAmC,IAAA,CAAK,aAAA,CAAc,OAAA;iEAEhE,IAAA;EACA,MAAA,EAAQ,aAAA;AAAA"}
@@ -9,10 +9,14 @@ import { AgentBranchSnapshot } from "../supervisor/iteration-snapshot.type.mjs";
9
9
  //#region ../@warlock.js/ai/src/contracts/result/orchestrator-result.type.d.ts
10
10
  /**
11
11
  * Discriminator literal the orchestrator stamps onto its report's
12
- * `type` field (design §15.5). Now a member of the shared
13
- * {@link ReportType} closed union in `base-report.type.ts`, so
14
- * {@link OrchestratorReport} narrows `type` against the shared union
15
- * directly rather than overriding it.
12
+ * `type` field (design §15.5). A member of the shared
13
+ * {@link ReportType} closed union in `base-report.type.ts`.
14
+ *
15
+ * {@link OrchestratorReport} re-declares `type` as this literal by
16
+ * *overriding* it (`Omit<BaseReport, "type"> & { type: ... }`) rather than
17
+ * intersecting `BaseReport` with it: intersecting a single literal against
18
+ * `BaseReport.type` (the whole `ReportType` union) lets a strict TypeScript
19
+ * collapse the report to `never` ("conflicting types in some constituents").
16
20
  */
17
21
  type OrchestratorReportType = "orchestrator";
18
22
  /**
@@ -88,13 +92,13 @@ type TurnSnapshot = Readonly<{
88
92
  * recurse via `children[]` will NOT reach prior turns — intentional.
89
93
  *
90
94
  * @remarks
91
- * `type` and `status` narrow the shared {@link BaseReport} fields to
92
- * the orchestrator-specific literals. Both `"orchestrator"` and
93
- * `"awaiting-input"` are now members of the shared {@link ReportType} /
94
- * {@link ReportStatus} unions, so this inherits {@link BaseReport}
95
- * directly and re-declares the two fields as compatible narrowings.
95
+ * `type` and `status` are the orchestrator-specific literals both
96
+ * `"orchestrator"` and `"awaiting-input"` are members of the shared
97
+ * {@link ReportType} / {@link ReportStatus} unions. `type` is OVERRIDDEN
98
+ * via `Omit<BaseReport, "type">` (not intersected) so a strict TypeScript
99
+ * can't collapse the report to `never`; `status` is re-declared compatibly.
96
100
  */
97
- type OrchestratorReport = BaseReport & {
101
+ type OrchestratorReport = Omit<BaseReport, "type"> & {
98
102
  type: OrchestratorReportType;
99
103
  status: OrchestratorReportStatus;
100
104
  sessionId: string;
@@ -128,7 +132,7 @@ type OrchestratorReport = BaseReport & {
128
132
  * await myMessageStore.applyCompaction(result.sessionId, result.compaction);
129
133
  * }
130
134
  */
131
- type OrchestratorResult<TOutput = unknown> = ExecuteResult<TOutput> & {
135
+ type OrchestratorResult<TOutput = unknown> = Omit<ExecuteResult<TOutput>, "report"> & {
132
136
  sessionId: string;
133
137
  turnIndex: number;
134
138
  compaction?: CompactionResult;
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator-result.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/contracts/result/orchestrator-result.type.ts"],"mappings":";;;;;;;;;;;AAeA;;;;AAAkC;KAAtB,sBAAA;;;;AAS0B;AAStC;;;KATY,0BAAA;AASoE;AAWhF;;;;;;AAXgF,KAApE,wBAAA,GAA2B,YAAA,GAAe,0BAA0B;;;AAiB/D;AAajB;;;;;;KAnBY,gBAAA;EAuCH,6DArCP,OAAA,EAAS,OAAO,EAiBS;EAfzB,iBAAA,UAeiC;EAbjC,eAAA;AAAA;;;;;;;;;;;KAaU,YAAA,GAAe,QAAA;EAgBd,gCAdX,IAAA,UAgBA;EAdA,KAAA,EAAO,eAAA,EAgBP;EAdA,QAAA;IACE,MAAA;IACA,GAAA;IACA,SAAA;EAAA,GAqCQ;EAlCV,MAAA,EAAQ,MAAA,SAAe,mBAAA;EAEvB,KAAA,WAiCM;EA/BN,QAAA,GAAW,cAAA;EACX,SAAA;EACA,OAAA;EACA,QAAA;EACA,KAAA,EAAO,KAAA;EA2BP;;;;;EArBA,WAAA,GAAc,UAAA;AAAA;;;;;AA6BK;AA4BrB;;;;;;;;;;;;KArCY,kBAAA,GAAqB,UAAA;EAC/B,IAAA,EAAM,sBAAA;EACN,MAAA,EAAQ,wBAAA;EACR,SAAA;EACA,SAAA,UAqCQ;EAnCR,SAAA;EACA,OAAA;EAEA,KAAA,EAAO,YAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;KA4BG,kBAAA,sBAAwC,aAAA,CAAc,OAAA;EAChE,SAAA;EACA,SAAA;EACA,UAAA,GAAa,gBAAA;EACb,MAAA,EAAQ,kBAAA;AAAA"}
1
+ {"version":3,"file":"orchestrator-result.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/contracts/result/orchestrator-result.type.ts"],"mappings":";;;;;;;;;;;AAmBA;;;;AAAkC;AASlC;;;;KATY,sBAAA;AAkBZ;;;;AAAgF;AAWhF;;AAXA,KATY,0BAAA;;;;;;;AA0BK;KAjBL,wBAAA,GAA2B,YAAA,GAAe,0BAA0B;;;;;;;;;;KAWpE,gBAAA;EAmBuB,6DAjBjC,OAAA,EAAS,OAAO,EAmBhB;EAjBA,iBAAA,UAmBO;EAjBP,eAAA;AAAA;;;;;;;;;;;KAaU,YAAA,GAAe,QAAA;EAoBzB,gCAlBA,IAAA,UAwBA;EAtBA,KAAA,EAAO,eAAA,EAsBiB;EApBxB,QAAA;IACE,MAAA;IACA,GAAA;IACA,SAAA;EAAA,GAqC6B;EAlC/B,MAAA,EAAQ,MAAA,SAAe,mBAAA,GAoCf;EAlCR,KAAA,WAyCmB;EAvCnB,QAAA,GAAW,cAAA;EACX,SAAA;EACA,OAAA;EACA,QAAA;EACA,KAAA,EAAO,KAAA;EA4BP;;;;;EAtBA,WAAA,GAAc,UAAA;AAAA;;;AA6BK;AA4BrB;;;;;;;;;;;;;;KArCY,kBAAA,GAAqB,IAAA,CAAK,UAAA;EACpC,IAAA,EAAM,sBAAA;EACN,MAAA,EAAQ,wBAAA;EACR,SAAA;EACA,SAAA,UAqCQ;EAnCR,SAAA;EACA,OAAA;EAEA,KAAA,EAAO,YAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;KA4BG,kBAAA,sBAAwC,IAAA,CAAK,aAAA,CAAc,OAAA;EACrE,SAAA;EACA,SAAA;EACA,UAAA,GAAa,gBAAA;EACb,MAAA,EAAQ,kBAAA;AAAA"}
@@ -24,7 +24,7 @@ type SupervisorTerminatedBy = "router" | "route" | "classifier" | "evaluate" | "
24
24
  * on {@link BaseReport.children}, which duplicates nothing: it's the
25
25
  * reports of the child agents/workflows dispatched across iterations.
26
26
  */
27
- type SupervisorReport = BaseReport & {
27
+ type SupervisorReport = Omit<BaseReport, "type"> & {
28
28
  supervisorName: string; /** Structural fingerprint — same value exposed on the instance. */
29
29
  signature: string;
30
30
  terminatedBy: SupervisorTerminatedBy; /** How many iterations ran (including the terminal one). */
@@ -1 +1 @@
1
- {"version":3,"file":"supervisor-result.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/contracts/result/supervisor-result.type.ts"],"mappings":";;;;;;;;AAWA;;;;KAAY,sBAAA;AAsBZ;;;;;;;;;;;;;AAAA,KAAY,gBAAA,GAAmB,UAAA;EAC7B,cAAA,UAKA;EAHA,SAAA;EACA,YAAA,EAAc,sBAAA,EAKH;EAHX,UAAA,UAUM;EARN,WAAA;EACA,SAAA,EAAW,iBAAA;EAgBoB;AAAA;AA+BjC;;;;EAxCE,GAAA,GAAM,WAAA;EA4CE;;;;;;;;EAnCR,UAAA,GAAa,kBAAA;AAAA;;AAmCW;;;;;;;;;;;;;;;;;;;;;;;;;;;KAJd,gBAAA,sBAAsC,UAAA;wEAEhD,IAAA;EACA,IAAA,GAAO,OAAA;EACP,MAAA,EAAQ,gBAAA;AAAA"}
1
+ {"version":3,"file":"supervisor-result.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/contracts/result/supervisor-result.type.ts"],"mappings":";;;;;;;;AAWA;;;;KAAY,sBAAA;AAsBZ;;;;;;;;;;;;;AAAA,KAAY,gBAAA,GAAmB,IAAA,CAAK,UAAA;EAClC,cAAA,UAGA;EADA,SAAA;EACA,YAAA,EAAc,sBAAA,EAId;EAFA,UAAA,UAGW;EADX,WAAA;EACA,SAAA,EAAW,iBAAA;EAgBX;;;AAA+B;AA+BjC;;EAxCE,GAAA,GAAM,WAAA;EAwC0C;;;;;;;;EA/BhD,UAAA,GAAa,kBAAA;AAAA;;;;AAmCW;;;;;;;;;;;;;;;;;;;;;;;;;KAJd,gBAAA,sBAAsC,UAAA;wEAEhD,IAAA;EACA,IAAA,GAAO,OAAA;EACP,MAAA,EAAQ,gBAAA;AAAA"}
@@ -23,8 +23,8 @@ import { BaseReport } from "./base-report.type.mjs";
23
23
  * console.log(call.name, call.tripIndex, call.input, call.output);
24
24
  * }
25
25
  */
26
- type ToolCall = BaseReport & {
27
- /** Discriminator already fixed on BaseReport, narrowed to "tool" here. */type: "tool"; /** Which LLM trip triggered this tool call (0-indexed). */
26
+ type ToolCall = Omit<BaseReport, "type"> & {
27
+ /** Discriminator overridden to "tool" via `Omit<BaseReport, "type">`. */type: "tool"; /** Which LLM trip triggered this tool call (0-indexed). */
28
28
  tripIndex: number; /** Input passed to the tool (validated args from the model's request). */
29
29
  input: unknown; /** Output returned by the tool (undefined if an error occurred). */
30
30
  output?: unknown; /** Typed AI error thrown during dispatch (validation or execute), if any. */
@@ -1 +1 @@
1
- {"version":3,"file":"tool-call.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/contracts/result/tool-call.type.ts"],"mappings":";;;;;;AAwBA;;;;;;;;;;;;;AAmBe;;;;;;KAnBH,QAAA,GAAW,UAAA;4EAErB,IAAA;EAEA,SAAA;EAEA,KAAA;EAEA,MAAA;EAEA,KAAA,GAAQ,OAAO;;;;;;;;;EASf,aAAA;AAAA"}
1
+ {"version":3,"file":"tool-call.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/contracts/result/tool-call.type.ts"],"mappings":";;;;;;AAwBA;;;;;;;;;;;;;;;;;;AAmBe;KAnBH,QAAA,GAAW,IAAA,CAAK,UAAA;2EAE1B,IAAA;EAEA,SAAA;EAEA,KAAA;EAEA,MAAA;EAEA,KAAA,GAAQ,OAAA;;;;;;;;;EASR,aAAA;AAAA"}
@@ -14,7 +14,7 @@ import { StepSnapshot } from "./step-result.type.mjs";
14
14
  * structure — one entry per defined step — while `children` gives
15
15
  * the cross-cutting tree view shared with other primitives.
16
16
  */
17
- type WorkflowReport = BaseReport & {
17
+ type WorkflowReport = Omit<BaseReport, "type"> & {
18
18
  workflowName: string; /** Structural fingerprint — same value exposed on the workflow instance. */
19
19
  signature: string; /** ISO-8601 timestamp when cancellation was observed, if any. */
20
20
  cancelledAt?: string; /** Per-step snapshots keyed by step name. */
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-result.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/contracts/result/workflow-result.type.ts"],"mappings":";;;;;;;;AAeA;;;;;;;;KAAY,cAAA,GAAiB,UAAA;EAC3B,YAAA,UAD2B;EAG3B,SAAA;EAEA,WAAA,WAEA;EAAA,KAAA,EAAO,MAAA,SAAe,YAAA,GAAA;EAEtB,KAAA,EAAO,QAAA,CAAS,MAAA;AAAA;;;AAAM;AAgBxB;;;;;;;;;;KAAY,cAAA,sBAAoC,UAAA;EAC9C,IAAA;EACA,IAAA,GAAO,OAAA;EACP,MAAA,EAAQ,cAAA;EACR,KAAA,GAAQ,OAAA;AAAA"}
1
+ {"version":3,"file":"workflow-result.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/contracts/result/workflow-result.type.ts"],"mappings":";;;;;;;;AAeA;;;;;;;;KAAY,cAAA,GAAiB,IAAA,CAAK,UAAA;EAChC,YAAA,UAQe;EANf,SAAA,UAHgC;EAKhC,WAAA,WAFA;EAIA,KAAA,EAAO,MAAA,SAAe,YAAA,GAAtB;EAEA,KAAA,EAAO,QAAA,CAAS,MAAA;AAAA;;;;;AAAM;AAgBxB;;;;;;;;KAAY,cAAA,sBAAoC,UAAA;EAC9C,IAAA;EACA,IAAA,GAAO,OAAA;EACP,MAAA,EAAQ,cAAA;EACR,KAAA,GAAQ,OAAA;AAAA"}
@@ -19,23 +19,20 @@
19
19
  * (the planner still truncates the tail to `skipped` defensively).
20
20
  */
21
21
  function planSchema(capabilityNames, maxSteps) {
22
- const stepsSchema = {
23
- type: "array",
24
- minItems: 1,
25
- description: "Ordered steps to execute, one capability dispatch each.",
26
- items: stepItemsSchema(capabilityNames)
27
- };
28
- if (maxSteps !== void 0) stepsSchema.maxItems = maxSteps;
29
22
  const jsonSchema = {
30
23
  type: "object",
31
24
  properties: {
32
25
  summary: {
33
- type: "string",
26
+ type: ["string", "null"],
34
27
  description: "One-line summary of the overall strategy."
35
28
  },
36
- steps: stepsSchema
29
+ steps: {
30
+ type: "array",
31
+ description: "Ordered steps to execute, one capability dispatch each.",
32
+ items: stepItemsSchema(capabilityNames)
33
+ }
37
34
  },
38
- required: ["steps"],
35
+ required: ["summary", "steps"],
39
36
  additionalProperties: false
40
37
  };
41
38
  return { "~standard": {
@@ -66,7 +63,7 @@ function stepItemsSchema(capabilityNames) {
66
63
  type: "object",
67
64
  properties: {
68
65
  id: {
69
- type: "string",
66
+ type: ["string", "null"],
70
67
  description: "Stable step id, referenced by dependsOn."
71
68
  },
72
69
  capability: {
@@ -79,16 +76,22 @@ function stepItemsSchema(capabilityNames) {
79
76
  description: "Concrete input passed to the capability's execute()."
80
77
  },
81
78
  reason: {
82
- type: "string",
79
+ type: ["string", "null"],
83
80
  description: "Why this step exists."
84
81
  },
85
82
  dependsOn: {
86
- type: "array",
83
+ type: ["array", "null"],
87
84
  items: { type: "string" },
88
85
  description: "Ids of steps this one conceptually follows."
89
86
  }
90
87
  },
91
- required: ["capability", "input"],
88
+ required: [
89
+ "id",
90
+ "capability",
91
+ "input",
92
+ "reason",
93
+ "dependsOn"
94
+ ],
92
95
  additionalProperties: false
93
96
  };
94
97
  }
@@ -1 +1 @@
1
- {"version":3,"file":"plan-schema.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai/src/planner/plan-schema.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { PlannerPlan, PlannerStep } from \"../contracts/planner/planner-plan.type\";\n\n/**\n * Build the Standard Schema the planning agent emits — an ordered\n * `{ steps: [...], summary? }` plan whose every step references one of\n * `capabilityNames` via the `capability` field.\n *\n * Mirrors the router's hand-built schema approach\n * (`supervisor/router-factory.ts`): the JSON Schema extension carries\n * the capability names as an `enum` so capable providers enforce the\n * choice natively, while `validate()` still accepts the shape softly so\n * providers without native structured output can pass a parsed object\n * through. Validation is intentionally lenient on `capability` — an\n * unknown name is surfaced later by the planner as a typed\n * `PlannerPlanInvalidError`, with the full forensic context, rather\n * than as an opaque schema issue here.\n *\n * `maxSteps`, when provided, is emitted as the `steps` array's\n * `maxItems` so capable providers refuse to over-produce up front\n * (the planner still truncates the tail to `skipped` defensively).\n */\nexport function planSchema(\n capabilityNames: string[],\n maxSteps?: number,\n): StandardSchemaV1<PlannerPlan> {\n const stepsSchema: Record<string, unknown> = {\n type: \"array\",\n minItems: 1,\n description: \"Ordered steps to execute, one capability dispatch each.\",\n items: stepItemsSchema(capabilityNames),\n };\n\n if (maxSteps !== undefined) {\n stepsSchema.maxItems = maxSteps;\n }\n\n const jsonSchema = {\n type: \"object\",\n properties: {\n summary: {\n type: \"string\",\n description: \"One-line summary of the overall strategy.\",\n },\n steps: stepsSchema,\n },\n required: [\"steps\"],\n additionalProperties: false,\n };\n\n return {\n \"~standard\": {\n version: 1,\n vendor: \"warlock-planner\",\n jsonSchema: {\n input: () => jsonSchema,\n },\n validate(value: unknown): StandardSchemaV1.Result<PlannerPlan> {\n if (!value || typeof value !== \"object\") {\n return { issues: [{ message: \"plan must be an object\" }] };\n }\n\n const record = value as { steps?: unknown; summary?: unknown };\n\n if (!Array.isArray(record.steps) || record.steps.length === 0) {\n return { issues: [{ message: \"plan `steps` must be a non-empty array\" }] };\n }\n\n const steps: PlannerStep[] = [];\n\n for (const raw of record.steps) {\n const normalized = normalizeStep(raw);\n\n if (!normalized) {\n return {\n issues: [{ message: \"each plan step must carry a string `capability` and `input`\" }],\n };\n }\n\n steps.push(normalized);\n }\n\n const summary = typeof record.summary === \"string\" ? record.summary : undefined;\n\n return { value: summary !== undefined ? { steps, summary } : { steps } };\n },\n } as StandardSchemaV1<PlannerPlan>[\"~standard\"] & {\n jsonSchema: { input: () => Record<string, unknown> };\n },\n };\n}\n\n/** Per-step JSON Schema object — one capability dispatch. */\nfunction stepItemsSchema(capabilityNames: string[]): Record<string, unknown> {\n return {\n type: \"object\",\n properties: {\n id: { type: \"string\", description: \"Stable step id, referenced by dependsOn.\" },\n capability: {\n type: \"string\",\n enum: capabilityNames,\n description: \"Name of the capability to dispatch for this step.\",\n },\n input: {\n type: \"string\",\n description: \"Concrete input passed to the capability's execute().\",\n },\n reason: { type: \"string\", description: \"Why this step exists.\" },\n dependsOn: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Ids of steps this one conceptually follows.\",\n },\n },\n required: [\"capability\", \"input\"],\n additionalProperties: false,\n };\n}\n\n/**\n * Coerce one raw step object into a {@link PlannerStep}, returning\n * `undefined` when the mandatory `capability` / `input` strings are\n * missing. Optional fields are copied only when well-typed.\n */\nfunction normalizeStep(raw: unknown): PlannerStep | undefined {\n if (!raw || typeof raw !== \"object\") {\n return undefined;\n }\n\n const record = raw as {\n id?: unknown;\n capability?: unknown;\n input?: unknown;\n reason?: unknown;\n dependsOn?: unknown;\n };\n\n if (typeof record.capability !== \"string\" || record.capability.length === 0) {\n return undefined;\n }\n\n if (typeof record.input !== \"string\") {\n return undefined;\n }\n\n const step: PlannerStep = {\n capability: record.capability,\n input: record.input,\n };\n\n if (typeof record.id === \"string\") {\n step.id = record.id;\n }\n\n if (typeof record.reason === \"string\") {\n step.reason = record.reason;\n }\n\n if (Array.isArray(record.dependsOn) && record.dependsOn.every((entry) => typeof entry === \"string\")) {\n step.dependsOn = record.dependsOn as string[];\n }\n\n return step;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,WACd,iBACA,UAC+B;CAC/B,MAAM,cAAuC;EAC3C,MAAM;EACN,UAAU;EACV,aAAa;EACb,OAAO,gBAAgB,eAAe;CACxC;CAEA,IAAI,aAAa,QACf,YAAY,WAAW;CAGzB,MAAM,aAAa;EACjB,MAAM;EACN,YAAY;GACV,SAAS;IACP,MAAM;IACN,aAAa;GACf;GACA,OAAO;EACT;EACA,UAAU,CAAC,OAAO;EAClB,sBAAsB;CACxB;CAEA,OAAO,EACL,aAAa;EACX,SAAS;EACT,QAAQ;EACR,YAAY,EACV,aAAa,WACf;EACA,SAAS,OAAsD;GAC7D,IAAI,CAAC,SAAS,OAAO,UAAU,UAC7B,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,yBAAyB,CAAC,EAAE;GAG3D,MAAM,SAAS;GAEf,IAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,KAAK,OAAO,MAAM,WAAW,GAC1D,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,yCAAyC,CAAC,EAAE;GAG3E,MAAM,QAAuB,CAAC;GAE9B,KAAK,MAAM,OAAO,OAAO,OAAO;IAC9B,MAAM,aAAa,cAAc,GAAG;IAEpC,IAAI,CAAC,YACH,OAAO,EACL,QAAQ,CAAC,EAAE,SAAS,8DAA8D,CAAC,EACrF;IAGF,MAAM,KAAK,UAAU;GACvB;GAEA,MAAM,UAAU,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU;GAEtE,OAAO,EAAE,OAAO,YAAY,SAAY;IAAE;IAAO;GAAQ,IAAI,EAAE,MAAM,EAAE;EACzE;CACF,EAGF;AACF;;AAGA,SAAS,gBAAgB,iBAAoD;CAC3E,OAAO;EACL,MAAM;EACN,YAAY;GACV,IAAI;IAAE,MAAM;IAAU,aAAa;GAA2C;GAC9E,YAAY;IACV,MAAM;IACN,MAAM;IACN,aAAa;GACf;GACA,OAAO;IACL,MAAM;IACN,aAAa;GACf;GACA,QAAQ;IAAE,MAAM;IAAU,aAAa;GAAwB;GAC/D,WAAW;IACT,MAAM;IACN,OAAO,EAAE,MAAM,SAAS;IACxB,aAAa;GACf;EACF;EACA,UAAU,CAAC,cAAc,OAAO;EAChC,sBAAsB;CACxB;AACF;;;;;;AAOA,SAAS,cAAc,KAAuC;CAC5D,IAAI,CAAC,OAAO,OAAO,QAAQ,UACzB;CAGF,MAAM,SAAS;CAQf,IAAI,OAAO,OAAO,eAAe,YAAY,OAAO,WAAW,WAAW,GACxE;CAGF,IAAI,OAAO,OAAO,UAAU,UAC1B;CAGF,MAAM,OAAoB;EACxB,YAAY,OAAO;EACnB,OAAO,OAAO;CAChB;CAEA,IAAI,OAAO,OAAO,OAAO,UACvB,KAAK,KAAK,OAAO;CAGnB,IAAI,OAAO,OAAO,WAAW,UAC3B,KAAK,SAAS,OAAO;CAGvB,IAAI,MAAM,QAAQ,OAAO,SAAS,KAAK,OAAO,UAAU,OAAO,UAAU,OAAO,UAAU,QAAQ,GAChG,KAAK,YAAY,OAAO;CAG1B,OAAO;AACT"}
1
+ {"version":3,"file":"plan-schema.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai/src/planner/plan-schema.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { PlannerPlan, PlannerStep } from \"../contracts/planner/planner-plan.type\";\n\n/**\n * Build the Standard Schema the planning agent emits — an ordered\n * `{ steps: [...], summary? }` plan whose every step references one of\n * `capabilityNames` via the `capability` field.\n *\n * Mirrors the router's hand-built schema approach\n * (`supervisor/router-factory.ts`): the JSON Schema extension carries\n * the capability names as an `enum` so capable providers enforce the\n * choice natively, while `validate()` still accepts the shape softly so\n * providers without native structured output can pass a parsed object\n * through. Validation is intentionally lenient on `capability` — an\n * unknown name is surfaced later by the planner as a typed\n * `PlannerPlanInvalidError`, with the full forensic context, rather\n * than as an opaque schema issue here.\n *\n * `maxSteps`, when provided, is emitted as the `steps` array's\n * `maxItems` so capable providers refuse to over-produce up front\n * (the planner still truncates the tail to `skipped` defensively).\n */\nexport function planSchema(\n capabilityNames: string[],\n maxSteps?: number,\n): StandardSchemaV1<PlannerPlan> {\n // OpenAI strict `json_schema` mode (and other native structured-output\n // providers) require EVERY property to appear in `required` — with truly\n // optional fields expressed as nullable — and reject array `minItems` /\n // `maxItems`. So the schema is strict-shaped: all keys required, the\n // optional ones nullable, no item-count bounds. A non-empty plan is\n // enforced in `validate()`, and `maxSteps` by the runtime's tail\n // truncation, so neither bound is needed on the wire.\n void maxSteps;\n\n const jsonSchema = {\n type: \"object\",\n properties: {\n summary: {\n type: [\"string\", \"null\"],\n description: \"One-line summary of the overall strategy.\",\n },\n steps: {\n type: \"array\",\n description: \"Ordered steps to execute, one capability dispatch each.\",\n items: stepItemsSchema(capabilityNames),\n },\n },\n required: [\"summary\", \"steps\"],\n additionalProperties: false,\n };\n\n return {\n \"~standard\": {\n version: 1,\n vendor: \"warlock-planner\",\n jsonSchema: {\n input: () => jsonSchema,\n },\n validate(value: unknown): StandardSchemaV1.Result<PlannerPlan> {\n if (!value || typeof value !== \"object\") {\n return { issues: [{ message: \"plan must be an object\" }] };\n }\n\n const record = value as { steps?: unknown; summary?: unknown };\n\n if (!Array.isArray(record.steps) || record.steps.length === 0) {\n return { issues: [{ message: \"plan `steps` must be a non-empty array\" }] };\n }\n\n const steps: PlannerStep[] = [];\n\n for (const raw of record.steps) {\n const normalized = normalizeStep(raw);\n\n if (!normalized) {\n return {\n issues: [{ message: \"each plan step must carry a string `capability` and `input`\" }],\n };\n }\n\n steps.push(normalized);\n }\n\n const summary = typeof record.summary === \"string\" ? record.summary : undefined;\n\n return { value: summary !== undefined ? { steps, summary } : { steps } };\n },\n } as StandardSchemaV1<PlannerPlan>[\"~standard\"] & {\n jsonSchema: { input: () => Record<string, unknown> };\n },\n };\n}\n\n/** Per-step JSON Schema object — one capability dispatch. */\nfunction stepItemsSchema(capabilityNames: string[]): Record<string, unknown> {\n return {\n type: \"object\",\n properties: {\n id: {\n type: [\"string\", \"null\"],\n description: \"Stable step id, referenced by dependsOn.\",\n },\n capability: {\n type: \"string\",\n enum: capabilityNames,\n description: \"Name of the capability to dispatch for this step.\",\n },\n input: {\n type: \"string\",\n description: \"Concrete input passed to the capability's execute().\",\n },\n reason: { type: [\"string\", \"null\"], description: \"Why this step exists.\" },\n dependsOn: {\n type: [\"array\", \"null\"],\n items: { type: \"string\" },\n description: \"Ids of steps this one conceptually follows.\",\n },\n },\n // Strict mode: every property required; the genuinely-optional ones\n // (id / reason / dependsOn) are nullable. `validate()` treats null and\n // missing identically, so a model emitting `null` round-trips fine.\n required: [\"id\", \"capability\", \"input\", \"reason\", \"dependsOn\"],\n additionalProperties: false,\n };\n}\n\n/**\n * Coerce one raw step object into a {@link PlannerStep}, returning\n * `undefined` when the mandatory `capability` / `input` strings are\n * missing. Optional fields are copied only when well-typed.\n */\nfunction normalizeStep(raw: unknown): PlannerStep | undefined {\n if (!raw || typeof raw !== \"object\") {\n return undefined;\n }\n\n const record = raw as {\n id?: unknown;\n capability?: unknown;\n input?: unknown;\n reason?: unknown;\n dependsOn?: unknown;\n };\n\n if (typeof record.capability !== \"string\" || record.capability.length === 0) {\n return undefined;\n }\n\n if (typeof record.input !== \"string\") {\n return undefined;\n }\n\n const step: PlannerStep = {\n capability: record.capability,\n input: record.input,\n };\n\n if (typeof record.id === \"string\") {\n step.id = record.id;\n }\n\n if (typeof record.reason === \"string\") {\n step.reason = record.reason;\n }\n\n if (Array.isArray(record.dependsOn) && record.dependsOn.every((entry) => typeof entry === \"string\")) {\n step.dependsOn = record.dependsOn as string[];\n }\n\n return step;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,WACd,iBACA,UAC+B;CAU/B,MAAM,aAAa;EACjB,MAAM;EACN,YAAY;GACV,SAAS;IACP,MAAM,CAAC,UAAU,MAAM;IACvB,aAAa;GACf;GACA,OAAO;IACL,MAAM;IACN,aAAa;IACb,OAAO,gBAAgB,eAAe;GACxC;EACF;EACA,UAAU,CAAC,WAAW,OAAO;EAC7B,sBAAsB;CACxB;CAEA,OAAO,EACL,aAAa;EACX,SAAS;EACT,QAAQ;EACR,YAAY,EACV,aAAa,WACf;EACA,SAAS,OAAsD;GAC7D,IAAI,CAAC,SAAS,OAAO,UAAU,UAC7B,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,yBAAyB,CAAC,EAAE;GAG3D,MAAM,SAAS;GAEf,IAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,KAAK,OAAO,MAAM,WAAW,GAC1D,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,yCAAyC,CAAC,EAAE;GAG3E,MAAM,QAAuB,CAAC;GAE9B,KAAK,MAAM,OAAO,OAAO,OAAO;IAC9B,MAAM,aAAa,cAAc,GAAG;IAEpC,IAAI,CAAC,YACH,OAAO,EACL,QAAQ,CAAC,EAAE,SAAS,8DAA8D,CAAC,EACrF;IAGF,MAAM,KAAK,UAAU;GACvB;GAEA,MAAM,UAAU,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU;GAEtE,OAAO,EAAE,OAAO,YAAY,SAAY;IAAE;IAAO;GAAQ,IAAI,EAAE,MAAM,EAAE;EACzE;CACF,EAGF;AACF;;AAGA,SAAS,gBAAgB,iBAAoD;CAC3E,OAAO;EACL,MAAM;EACN,YAAY;GACV,IAAI;IACF,MAAM,CAAC,UAAU,MAAM;IACvB,aAAa;GACf;GACA,YAAY;IACV,MAAM;IACN,MAAM;IACN,aAAa;GACf;GACA,OAAO;IACL,MAAM;IACN,aAAa;GACf;GACA,QAAQ;IAAE,MAAM,CAAC,UAAU,MAAM;IAAG,aAAa;GAAwB;GACzE,WAAW;IACT,MAAM,CAAC,SAAS,MAAM;IACtB,OAAO,EAAE,MAAM,SAAS;IACxB,aAAa;GACf;EACF;EAIA,UAAU;GAAC;GAAM;GAAc;GAAS;GAAU;EAAW;EAC7D,sBAAsB;CACxB;AACF;;;;;;AAOA,SAAS,cAAc,KAAuC;CAC5D,IAAI,CAAC,OAAO,OAAO,QAAQ,UACzB;CAGF,MAAM,SAAS;CAQf,IAAI,OAAO,OAAO,eAAe,YAAY,OAAO,WAAW,WAAW,GACxE;CAGF,IAAI,OAAO,OAAO,UAAU,UAC1B;CAGF,MAAM,OAAoB;EACxB,YAAY,OAAO;EACnB,OAAO,OAAO;CAChB;CAEA,IAAI,OAAO,OAAO,OAAO,UACvB,KAAK,KAAK,OAAO;CAGnB,IAAI,OAAO,OAAO,WAAW,UAC3B,KAAK,SAAS,OAAO;CAGvB,IAAI,MAAM,QAAQ,OAAO,SAAS,KAAK,OAAO,UAAU,OAAO,UAAU,OAAO,UAAU,QAAQ,GAChG,KAAK,YAAY,OAAO;CAG1B,OAAO;AACT"}
package/package.json CHANGED
@@ -15,10 +15,10 @@
15
15
  "@standard-schema/spec": "^1.0.0"
16
16
  },
17
17
  "peerDependencies": {
18
- "@warlock.js/cache": "4.3.0",
19
- "@warlock.js/logger": "4.3.0"
18
+ "@warlock.js/cache": "4.4.0",
19
+ "@warlock.js/logger": "4.4.0"
20
20
  },
21
- "version": "4.3.0",
21
+ "version": "4.4.0",
22
22
  "main": "./cjs/index.cjs",
23
23
  "module": "./esm/index.mjs",
24
24
  "types": "./esm/index.d.mts",