@nylorun/harness 0.13.0-beta → 0.16.0-beta

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 (123) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/HOST_CONTRACT.md +27 -0
  3. package/README.md +62 -100
  4. package/dist/compatibility.d.ts +3 -0
  5. package/dist/compatibility.js +3 -0
  6. package/dist/definition/agent-definition.d.ts +11 -3
  7. package/dist/definition/agent-definition.js +18 -10
  8. package/dist/definition/compatibility.d.ts +11 -0
  9. package/dist/definition/compatibility.js +30 -0
  10. package/dist/definition/registry.d.ts +2 -2
  11. package/dist/definition/registry.js +8 -7
  12. package/dist/index.d.ts +4 -18
  13. package/dist/index.js +1 -6
  14. package/dist/loop/dispatch.js +327 -0
  15. package/dist/loop/host-suspension.d.ts +6 -0
  16. package/dist/loop/host-suspension.js +10 -0
  17. package/dist/loop/initial-state.d.ts +13 -0
  18. package/dist/loop/initial-state.js +30 -0
  19. package/dist/{execution → loop}/invocation.d.ts +5 -2
  20. package/dist/{execution → loop}/invocation.js +8 -3
  21. package/dist/{execution → loop}/model/adapters.d.ts +4 -2
  22. package/dist/{execution → loop}/model/adapters.js +3 -2
  23. package/dist/{execution → loop}/model/normalize.d.ts +2 -2
  24. package/dist/{execution → loop}/model/normalize.js +2 -2
  25. package/dist/{execution → loop}/model/prepared.d.ts +2 -2
  26. package/dist/{execution → loop}/model/project.d.ts +1 -1
  27. package/dist/{execution → loop}/model/project.js +1 -1
  28. package/dist/{execution → loop}/observe.d.ts +2 -2
  29. package/dist/{execution → loop}/observe.js +1 -1
  30. package/dist/{execution → loop}/options.d.ts +2 -1
  31. package/dist/{execution → loop}/options.js +28 -8
  32. package/dist/{execution → loop}/resume.d.ts +1 -1
  33. package/dist/{execution → loop}/resume.js +2 -2
  34. package/dist/{execution → loop}/run.d.ts +1 -1
  35. package/dist/{execution → loop}/run.js +9 -1
  36. package/dist/{execution → loop}/state.d.ts +2 -2
  37. package/dist/{execution → loop}/state.js +13 -3
  38. package/dist/{execution → loop}/step/canonicalize.d.ts +2 -2
  39. package/dist/{execution → loop}/step/canonicalize.js +1 -1
  40. package/dist/{execution → loop}/step/compose.d.ts +2 -2
  41. package/dist/{execution → loop}/step/compose.js +4 -1
  42. package/dist/{execution → loop}/step/context-draft.d.ts +2 -2
  43. package/dist/{execution → loop}/step/context-draft.js +2 -2
  44. package/dist/{execution → loop}/step/describe.d.ts +3 -3
  45. package/dist/{execution → loop}/step/describe.js +1 -1
  46. package/dist/loop/step/dynamics.d.ts +29 -0
  47. package/dist/loop/step/dynamics.js +149 -0
  48. package/dist/{execution → loop}/step/model-configuration.d.ts +2 -2
  49. package/dist/{execution → loop}/step/model-configuration.js +3 -3
  50. package/dist/{execution → loop}/step/resolve.d.ts +4 -4
  51. package/dist/{execution → loop}/step/run.d.ts +5 -4
  52. package/dist/{execution → loop}/step/run.js +87 -2
  53. package/dist/{execution → loop}/step/runtime.d.ts +12 -4
  54. package/dist/{execution → loop}/step/seal.d.ts +5 -5
  55. package/dist/{execution → loop}/step/seal.js +2 -2
  56. package/dist/{execution → loop}/step/slot-assembly.d.ts +1 -1
  57. package/dist/{execution → loop}/step/slot-assembly.js +1 -1
  58. package/dist/{execution → loop}/step/step-context.d.ts +5 -5
  59. package/dist/{execution → loop}/step/step-context.js +2 -2
  60. package/dist/{execution → loop}/tool-result.d.ts +2 -2
  61. package/dist/{execution → loop}/tool-result.js +2 -2
  62. package/dist/{execution → loop}/transcript.d.ts +1 -1
  63. package/dist/{execution → loop}/transcript.js +2 -2
  64. package/dist/loop/waits.d.ts +50 -0
  65. package/dist/loop/waits.js +11 -0
  66. package/dist/run/durable.d.ts +80 -0
  67. package/dist/run/durable.js +176 -0
  68. package/dist/run/index.d.ts +33 -0
  69. package/dist/run/index.js +38 -0
  70. package/dist/types/client.d.ts +88 -0
  71. package/dist/types/execution.d.ts +22 -5
  72. package/dist/utils/ids.d.ts +1 -0
  73. package/dist/utils/ids.js +11 -1
  74. package/package.json +21 -9
  75. package/dist/definition/assemble.d.ts +0 -22
  76. package/dist/definition/assemble.js +0 -43
  77. package/dist/definition/bind-agent.d.ts +0 -9
  78. package/dist/definition/bind-agent.js +0 -21
  79. package/dist/definition/bind-tool.d.ts +0 -4
  80. package/dist/definition/bind-tool.js +0 -19
  81. package/dist/definition/bound.d.ts +0 -16
  82. package/dist/definition/builder.d.ts +0 -30
  83. package/dist/definition/builder.js +0 -94
  84. package/dist/definition/declaration.d.ts +0 -3
  85. package/dist/definition/declaration.js +0 -53
  86. package/dist/definition/helpers.d.ts +0 -6
  87. package/dist/definition/helpers.js +0 -4
  88. package/dist/definition/manifest.d.ts +0 -9
  89. package/dist/definition/manifest.js +0 -45
  90. package/dist/definition/output-contract.d.ts +0 -6
  91. package/dist/definition/output-contract.js +0 -12
  92. package/dist/definition/schema.d.ts +0 -14
  93. package/dist/definition/schema.js +0 -205
  94. package/dist/errors.d.ts +0 -17
  95. package/dist/errors.js +0 -17
  96. package/dist/execution/dispatch.js +0 -164
  97. package/dist/execution/initial-state.d.ts +0 -3
  98. package/dist/execution/initial-state.js +0 -14
  99. package/dist/types/agent.d.ts +0 -9
  100. package/dist/types/agent.js +0 -1
  101. package/dist/types/manifest.d.ts +0 -22
  102. package/dist/types/manifest.js +0 -1
  103. package/dist/types/middleware.d.ts +0 -66
  104. package/dist/types/middleware.js +0 -1
  105. package/dist/types/model.d.ts +0 -184
  106. package/dist/types/model.js +0 -1
  107. package/dist/types/observe.d.ts +0 -165
  108. package/dist/types/observe.js +0 -1
  109. package/dist/types/shared.d.ts +0 -25
  110. package/dist/types/shared.js +0 -1
  111. package/dist/types/tool.d.ts +0 -138
  112. package/dist/types/tool.js +0 -1
  113. package/dist/types/transcript.d.ts +0 -65
  114. package/dist/types/transcript.js +0 -1
  115. package/dist/utils/canonical.d.ts +0 -1
  116. package/dist/utils/canonical.js +0 -10
  117. package/dist/utils/immutable.d.ts +0 -6
  118. package/dist/utils/immutable.js +0 -76
  119. /package/dist/{execution → loop}/dispatch.d.ts +0 -0
  120. /package/dist/{execution → loop}/model/prepared.js +0 -0
  121. /package/dist/{execution → loop}/step/resolve.js +0 -0
  122. /package/dist/{execution → loop}/step/runtime.js +0 -0
  123. /package/dist/{definition/bound.js → types/client.js} +0 -0
@@ -1,43 +0,0 @@
1
- import { bindAgent } from "./bind-agent.js";
2
- import { createManifest } from "./manifest.js";
3
- const diagnostic = (code, message, extra = {}) => Object.freeze({ code, message, ...extra });
4
- export function assembleAgent(middleware, identity, run) {
5
- const diagnostics = [];
6
- if (typeof identity.id !== "string" || identity.id.length === 0) {
7
- diagnostics.push(diagnostic("agent.invalid-id", "Agent id must be a non-empty string"));
8
- }
9
- if (typeof identity.name !== "string" || identity.name.length === 0) {
10
- diagnostics.push(diagnostic("agent.invalid-name", "Agent name must be a non-empty string"));
11
- }
12
- const middlewareIds = new Set();
13
- const frozen = [];
14
- for (const item of middleware) {
15
- if (!item.id)
16
- diagnostics.push(diagnostic("middleware.invalid-id", "Middleware id must not be empty"));
17
- else if (middlewareIds.has(item.id))
18
- diagnostics.push(diagnostic("middleware.duplicate-id", `Duplicate middleware id '${item.id}'`));
19
- else if (typeof item.handle !== "function")
20
- diagnostics.push(diagnostic("middleware.invalid", `Middleware '${item.id}' must provide a function`));
21
- else {
22
- middlewareIds.add(item.id);
23
- frozen.push(Object.freeze({
24
- id: item.id,
25
- handle: item.handle,
26
- hasMiddleware: item.hasMiddleware,
27
- ...(item.tools === undefined ? {} : { tools: item.tools }),
28
- ...(item.contributions === undefined ? {} : { contributions: item.contributions }),
29
- }));
30
- }
31
- }
32
- if (diagnostics.length)
33
- return Object.freeze({ ok: false, diagnostics: Object.freeze(diagnostics) });
34
- const frozenMiddleware = Object.freeze(frozen);
35
- const manifest = createManifest({
36
- id: identity.id,
37
- name: identity.name,
38
- outputSchema: identity.outputSchema,
39
- middleware: frozenMiddleware,
40
- });
41
- const agent = bindAgent(frozenMiddleware, manifest, identity, run);
42
- return Object.freeze({ ok: true, agent, manifest });
43
- }
@@ -1,9 +0,0 @@
1
- import type { AgentManifest } from "../types/manifest.js";
2
- import type { BoundMiddleware } from "./bound.js";
3
- import type { BuiltAgent } from "../types/agent.js";
4
- import type { RunOptions, RunResult } from "../types/execution.js";
5
- import type { ToolSchemaSource } from "../types/tool.js";
6
- import { type AgentDefinition } from "./agent-definition.js";
7
- export declare function bindAgent(middleware: readonly BoundMiddleware[], manifest: AgentManifest, options: {
8
- outputSchema?: ToolSchemaSource;
9
- } | undefined, run: (definition: AgentDefinition, options: RunOptions<any>) => Promise<RunResult<any>>): BuiltAgent;
@@ -1,21 +0,0 @@
1
- import { bindOutputContract } from "./output-contract.js";
2
- import { registerDefinition } from "./agent-definition.js";
3
- import { ToolRegistry } from "./registry.js";
4
- export function bindAgent(middleware, manifest, options = {}, run) {
5
- const definition = Object.freeze({
6
- id: manifest.id,
7
- middleware,
8
- registry: new ToolRegistry(middleware),
9
- ...(options.outputSchema === undefined
10
- ? {}
11
- : { output: bindOutputContract(options.outputSchema) }),
12
- });
13
- const agent = {
14
- id: definition.id,
15
- name: manifest.name,
16
- manifest,
17
- run: (options) => run(definition, options),
18
- };
19
- registerDefinition(agent, definition);
20
- return agent;
21
- }
@@ -1,4 +0,0 @@
1
- import type { BoundToolDefinition } from "./bound.js";
2
- import type { ToolDefinition } from "../types/tool.js";
3
- /** Prepares an executable Tool and records its middleware slot provenance. */
4
- export declare function bindTool(item: ToolDefinition, owner: BoundToolDefinition["owner"]): BoundToolDefinition;
@@ -1,19 +0,0 @@
1
- import { HarnessError } from "../errors.js";
2
- import { normalizedSchemasFor } from "./schema.js";
3
- /** Prepares an executable Tool and records its middleware slot provenance. */
4
- export function bindTool(item, owner) {
5
- if (!item.name)
6
- throw new HarnessError("tool.invalid-name", "Tool name must not be empty");
7
- if (typeof item.execute !== "function")
8
- throw new HarnessError("tool.invalid", `Tool '${item.name}' must provide execute()`);
9
- const schemas = normalizedSchemasFor(item);
10
- return Object.freeze({
11
- source: item,
12
- name: item.name,
13
- ...(item.description ? { description: item.description } : {}),
14
- inputSchema: schemas.inputSchema,
15
- ...(schemas.outputSchema === undefined ? {} : { outputSchema: schemas.outputSchema }),
16
- execute: item.execute.bind(item),
17
- owner: Object.freeze({ ...owner }),
18
- });
19
- }
@@ -1,16 +0,0 @@
1
- import type { MiddlewareContributions, StepMiddleware } from "../types/middleware.js";
2
- import type { ToolDefinition, ToolExecutionContext, ToolInputSchema, ToolOutcome, ToolOutputSchema, ToolOwner, ToolSchema } from "../types/tool.js";
3
- export interface BoundToolDefinition<Info = unknown> extends Omit<ToolDefinition<ToolInputSchema, Info, ToolOutputSchema | undefined>, "inputSchema" | "outputSchema" | "execute"> {
4
- readonly inputSchema: ToolSchema<unknown>;
5
- readonly outputSchema?: ToolSchema<unknown>;
6
- readonly execute: (args: unknown, context: ToolExecutionContext<Info>) => Promise<ToolOutcome>;
7
- readonly owner: ToolOwner;
8
- readonly source: ToolDefinition<any, any, any>;
9
- }
10
- export interface BoundMiddleware {
11
- readonly id: string;
12
- readonly handle: StepMiddleware;
13
- readonly hasMiddleware: boolean;
14
- readonly tools?: readonly ToolDefinition<any, any, any>[];
15
- readonly contributions?: MiddlewareContributions;
16
- }
@@ -1,30 +0,0 @@
1
- import type { CapabilityDeclaration, StepMiddleware } from "../types/middleware.js";
2
- import type { BuildDiagnostic } from "../types/shared.js";
3
- import { HarnessError } from "../errors.js";
4
- import type { ToolSchemaSource, SchemaOutput } from "../types/tool.js";
5
- import type { BuiltAgent } from "../types/agent.js";
6
- export interface AgentOptions<Schema extends ToolSchemaSource | undefined = undefined> {
7
- readonly outputSchema?: Schema;
8
- readonly id: string;
9
- readonly name: string;
10
- readonly instructions?: string | readonly string[];
11
- }
12
- export declare class AgentBuildError extends HarnessError {
13
- readonly diagnostics: readonly BuildDiagnostic[];
14
- constructor(diagnostics: readonly BuildDiagnostic[]);
15
- }
16
- export declare class AgentLifecycleError extends HarnessError {
17
- constructor(message: string);
18
- }
19
- export declare function Agent<Info = unknown, Schema extends ToolSchemaSource | undefined = undefined>(options: AgentOptions<Schema>): AgentBuilder<Info, Schema>;
20
- export declare class AgentBuilder<Info = unknown, Schema extends ToolSchemaSource | undefined = undefined> {
21
- #private;
22
- constructor(options: AgentOptions<Schema>);
23
- use(middleware: StepMiddleware<Info>): this;
24
- use(id: string, middleware: StepMiddleware<Info>): this;
25
- use(declaration: CapabilityDeclaration<Info>): this;
26
- build(): BuiltAgent<Info, Schema extends ToolSchemaSource ? SchemaOutput<Schema> : string>;
27
- private nextMiddlewareId;
28
- private push;
29
- private assertOpen;
30
- }
@@ -1,94 +0,0 @@
1
- import { HarnessError } from "../errors.js";
2
- import { execute } from "../execution/run.js";
3
- import { assembleAgent } from "./assemble.js";
4
- import { compileDeclaration } from "./declaration.js";
5
- export class AgentBuildError extends HarnessError {
6
- diagnostics;
7
- constructor(diagnostics) {
8
- super("agent.build-failed", diagnostics.map((item) => item.message).join("; ") || "Agent build failed");
9
- this.diagnostics = diagnostics;
10
- this.name = "AgentBuildError";
11
- }
12
- }
13
- export class AgentLifecycleError extends HarnessError {
14
- constructor(message) {
15
- super("agent.lifecycle-sealed", message);
16
- this.name = "AgentLifecycleError";
17
- }
18
- }
19
- export function Agent(options) {
20
- return new AgentBuilder(options);
21
- }
22
- export class AgentBuilder {
23
- #state;
24
- constructor(options) {
25
- this.#state = createState(options);
26
- }
27
- use(idOrMiddleware, middleware) {
28
- if (typeof idOrMiddleware === "function") {
29
- return this.push({
30
- id: this.nextMiddlewareId(),
31
- handle: idOrMiddleware,
32
- hasMiddleware: true,
33
- });
34
- }
35
- if (typeof idOrMiddleware === "object")
36
- return this.push(compileDeclaration(idOrMiddleware));
37
- return this.push({
38
- id: idOrMiddleware,
39
- handle: middleware,
40
- hasMiddleware: true,
41
- });
42
- }
43
- build() {
44
- if (this.#state.agent)
45
- return this.#state.agent;
46
- if (this.#state.error)
47
- throw this.#state.error;
48
- this.#state.sealed = true;
49
- const result = assembleAgent(this.#state.middleware, {
50
- id: this.#state.id,
51
- name: this.#state.name,
52
- outputSchema: this.#state.outputSchema,
53
- }, execute);
54
- if (!result.ok) {
55
- this.#state.error = new AgentBuildError(result.diagnostics);
56
- throw this.#state.error;
57
- }
58
- this.#state.agent = result.agent;
59
- return this.#state.agent;
60
- }
61
- nextMiddlewareId() {
62
- const taken = new Set(this.#state.middleware.map((item) => item.id));
63
- let id;
64
- do {
65
- this.#state.middlewareSeq += 1;
66
- id = `middleware-${this.#state.middlewareSeq}`;
67
- } while (taken.has(id));
68
- return id;
69
- }
70
- push(entry) {
71
- this.assertOpen();
72
- this.#state.middleware.push(entry);
73
- return this;
74
- }
75
- assertOpen() {
76
- if (this.#state.sealed)
77
- throw new AgentLifecycleError("AgentBuilder cannot be changed after build()");
78
- }
79
- }
80
- function createState(options) {
81
- const middleware = [];
82
- if (options.instructions !== undefined) {
83
- const instructions = typeof options.instructions === "string" ? [options.instructions] : options.instructions;
84
- middleware.push(compileDeclaration({ id: "agent", instructions }));
85
- }
86
- return {
87
- id: options.id,
88
- outputSchema: options.outputSchema,
89
- name: options.name,
90
- middleware,
91
- sealed: false,
92
- middlewareSeq: 0,
93
- };
94
- }
@@ -1,3 +0,0 @@
1
- import type { BoundMiddleware } from "./bound.js";
2
- import type { CapabilityDeclaration } from "../types/middleware.js";
3
- export declare function compileDeclaration<State>(declaration: CapabilityDeclaration<State>): BoundMiddleware;
@@ -1,53 +0,0 @@
1
- export function compileDeclaration(declaration) {
2
- const tools = copyItems(declaration.tools, declaration.id);
3
- const instructions = copyItems(declaration.instructions, declaration.id);
4
- const model = declaration.model;
5
- const contributions = snapshotContributions(instructions?.items, tools?.items, model);
6
- const handle = async (request, next) => {
7
- if (tools)
8
- request.configuration.tools.set(tools.slot, tools.items);
9
- if (instructions)
10
- request.configuration.instructions.set(instructions.slot, instructions.items);
11
- if (model)
12
- request.configuration.model.select(model);
13
- return declaration.middleware ? declaration.middleware(request, next) : next();
14
- };
15
- return {
16
- id: declaration.id,
17
- handle,
18
- hasMiddleware: declaration.middleware !== undefined,
19
- tools: tools?.items,
20
- ...(contributions === undefined ? {} : { contributions }),
21
- };
22
- }
23
- function snapshotContributions(instructions, tools, model) {
24
- const snapInstructions = instructions === undefined ? undefined : Object.freeze([...instructions]);
25
- const snapTools = tools === undefined
26
- ? undefined
27
- : Object.freeze(tools.map((tool) => Object.freeze({
28
- name: tool.name,
29
- ...(tool.description === undefined ? {} : { description: tool.description }),
30
- })));
31
- const snapModel = model === undefined ? undefined : snapshotModel(model);
32
- if (snapInstructions === undefined && snapTools === undefined && snapModel === undefined) {
33
- return undefined;
34
- }
35
- return Object.freeze({
36
- ...(snapInstructions === undefined ? {} : { instructions: snapInstructions }),
37
- ...(snapTools === undefined ? {} : { tools: snapTools }),
38
- ...(snapModel === undefined ? {} : { model: snapModel }),
39
- });
40
- }
41
- function snapshotModel(model) {
42
- return Object.freeze({
43
- ...(model.id === undefined ? {} : { id: model.id }),
44
- ...(model.controls === undefined ? {} : { controls: Object.freeze({ ...model.controls }) }),
45
- });
46
- }
47
- function copyItems(value, defaultSlot) {
48
- if (value === undefined)
49
- return undefined;
50
- if (!("items" in value))
51
- return Object.freeze({ slot: defaultSlot, items: Object.freeze([...value]) });
52
- return Object.freeze({ slot: value.slot, items: Object.freeze([...value.items]) });
53
- }
@@ -1,6 +0,0 @@
1
- import type { ModelAdapter } from "../types/model.js";
2
- import type { StepMiddleware } from "../types/middleware.js";
3
- import type { ToolDefinition, ToolInputSchema, ToolOutputSchema } from "../types/tool.js";
4
- export declare const tool: <InputSchema extends ToolInputSchema, Info = unknown, OutputSchema extends ToolOutputSchema | undefined = undefined>(value: ToolDefinition<InputSchema, Info, OutputSchema>) => ToolDefinition<InputSchema, Info, OutputSchema>;
5
- export declare const model: <T extends ModelAdapter>(value: T) => T;
6
- export declare const middleware: <T extends StepMiddleware>(value: T) => T;
@@ -1,4 +0,0 @@
1
- import { prepareTool } from "./schema.js";
2
- export const tool = (value) => prepareTool(value);
3
- export const model = (value) => value;
4
- export const middleware = (value) => value;
@@ -1,9 +0,0 @@
1
- import type { BoundMiddleware } from "./bound.js";
2
- import type { AgentManifest } from "../types/manifest.js";
3
- import type { ToolSchemaSource } from "../types/tool.js";
4
- export declare function createManifest(input: {
5
- id: string;
6
- name: string;
7
- outputSchema?: ToolSchemaSource;
8
- middleware: readonly BoundMiddleware[];
9
- }): AgentManifest;
@@ -1,45 +0,0 @@
1
- import { bindOutputContract } from "./output-contract.js";
2
- import { normalizedSchemasFor } from "./schema.js";
3
- import { deepFreeze } from "../utils/immutable.js";
4
- export function createManifest(input) {
5
- const capabilities = input.middleware.map((item) => projectCapability(item));
6
- return deepFreeze({
7
- id: input.id,
8
- name: input.name,
9
- ...(input.outputSchema === undefined
10
- ? {}
11
- : { outputSchema: bindOutputContract(input.outputSchema).schema.jsonSchema }),
12
- capabilities,
13
- });
14
- }
15
- function projectCapability(item) {
16
- const contributions = item.contributions;
17
- return {
18
- id: item.id,
19
- kind: capabilityKind(item),
20
- hasMiddleware: item.hasMiddleware,
21
- ...(contributions?.instructions === undefined
22
- ? {}
23
- : { instructions: contributions.instructions }),
24
- ...(item.tools === undefined ? {} : { tools: item.tools.map((tool) => projectTool(tool)) }),
25
- ...(contributions?.model === undefined ? {} : { model: contributions.model }),
26
- };
27
- }
28
- function capabilityKind(item) {
29
- if (item.id === "agent")
30
- return "agent";
31
- if (item.contributions !== undefined)
32
- return "capability";
33
- return "middleware";
34
- }
35
- function projectTool(tool) {
36
- const schemas = normalizedSchemasFor(tool);
37
- return {
38
- name: tool.name,
39
- ...(tool.description === undefined ? {} : { description: tool.description }),
40
- inputSchema: schemas.inputSchema.jsonSchema,
41
- ...(schemas.outputSchema === undefined
42
- ? {}
43
- : { outputSchema: schemas.outputSchema.jsonSchema }),
44
- };
45
- }
@@ -1,6 +0,0 @@
1
- import type { ToolSchema, ToolSchemaSource } from "../types/tool.js";
2
- /** Runtime-only validator paired with the portable JSON Schema projected to models. */
3
- export interface TurnOutputContract {
4
- readonly schema: ToolSchema<unknown>;
5
- }
6
- export declare function bindOutputContract(source: ToolSchemaSource): TurnOutputContract;
@@ -1,12 +0,0 @@
1
- import { HarnessError, isHarnessError } from "../errors.js";
2
- import { normalizeSchema } from "./schema.js";
3
- export function bindOutputContract(source) {
4
- try {
5
- return Object.freeze({ schema: normalizeSchema(source, "output") });
6
- }
7
- catch (cause) {
8
- if (isHarnessError(cause))
9
- throw new HarnessError("output.invalid-schema", cause.message, { cause });
10
- throw new HarnessError("output.invalid-schema", String(cause), { cause });
11
- }
12
- }
@@ -1,14 +0,0 @@
1
- import type { ToolDefinition, ToolSchema, ToolSchemaSource } from "../types/tool.js";
2
- export type { SchemaValidation } from "../types/tool.js";
3
- interface NormalizedToolSchemas {
4
- readonly inputSchema: ToolSchema<unknown>;
5
- readonly outputSchema?: ToolSchema<unknown>;
6
- }
7
- /** Creates a portable, explicitly validated schema source from raw JSON Schema. */
8
- export declare function defineSchema<T>(value: ToolSchema<T>): ToolSchema<T>;
9
- /** Eagerly prepares a definition authored through Harness's tool() helper. */
10
- export declare function prepareTool<T extends ToolDefinition>(definition: T): T;
11
- /** Returns cached normalized contracts, preparing raw definitions on first bind. */
12
- export declare function normalizedSchemasFor(definition: ToolDefinition): NormalizedToolSchemas;
13
- /** Converts an accepted tool schema source into Harness's immutable runtime representation. */
14
- export declare function normalizeSchema<T>(source: ToolSchemaSource<T>, role: "input" | "output"): ToolSchema<T>;
@@ -1,205 +0,0 @@
1
- import { z } from "zod";
2
- import { HarnessError } from "../errors.js";
3
- import { copyJsonObject } from "../utils/immutable.js";
4
- const preparedSchemas = new WeakMap();
5
- /** Creates a portable, explicitly validated schema source from raw JSON Schema. */
6
- export function defineSchema(value) {
7
- if (!value || typeof value !== "object" || typeof value.validate !== "function")
8
- throw new HarnessError("tool.invalid-schema", "Tool schema must provide validate()");
9
- return Object.freeze({
10
- jsonSchema: copyJsonObject(value.jsonSchema, "tool schema jsonSchema"),
11
- validate: value.validate.bind(value),
12
- });
13
- }
14
- /** Eagerly prepares a definition authored through Harness's tool() helper. */
15
- export function prepareTool(definition) {
16
- normalizedSchemasFor(definition);
17
- return definition;
18
- }
19
- /** Returns cached normalized contracts, preparing raw definitions on first bind. */
20
- export function normalizedSchemasFor(definition) {
21
- const cached = preparedSchemas.get(definition);
22
- if (cached)
23
- return cached;
24
- const normalized = Object.freeze({
25
- inputSchema: normalizeSchema(definition.inputSchema, "input"),
26
- ...(definition.outputSchema === undefined
27
- ? {}
28
- : { outputSchema: normalizeSchema(definition.outputSchema, "output") }),
29
- });
30
- preparedSchemas.set(definition, normalized);
31
- return normalized;
32
- }
33
- /** Converts an accepted tool schema source into Harness's immutable runtime representation. */
34
- export function normalizeSchema(source, role) {
35
- const normalized = isZodSchema(source)
36
- ? normalizeZodSchema(source, role)
37
- : isStandardSchema(source)
38
- ? normalizeStandardSchema(source, role)
39
- : isToolSchema(source)
40
- ? normalizeExplicitSchema(source)
41
- : undefined;
42
- if (!normalized)
43
- throw new HarnessError("tool.invalid-schema", "Tool schema must be a Zod schema, synchronous Standard Schema with JSON Schema conversion, or defineSchema() contract");
44
- if (role === "input" && normalized.jsonSchema.type !== "object")
45
- throw new HarnessError("tool.invalid-schema", "Tool inputSchema JSON Schema root type must be object");
46
- return normalized;
47
- }
48
- function normalizeZodSchema(source, role) {
49
- if (hasDeclaredAsyncWork(source))
50
- throw new HarnessError("tool.invalid-schema", "Tool schema must validate synchronously");
51
- let jsonSchema;
52
- try {
53
- jsonSchema = copyJsonObject(z.toJSONSchema(source, { target: "draft-07" }), `tool.${role}Schema.jsonSchema`);
54
- }
55
- catch (error) {
56
- throw new HarnessError("tool.invalid-schema", `Tool ${role}Schema must convert to JSON Schema: ${message(error)}`, { cause: error });
57
- }
58
- return Object.freeze({
59
- jsonSchema,
60
- validate(value) {
61
- try {
62
- const result = source.safeParse(value);
63
- if (result.success)
64
- return { ok: true, value: result.data };
65
- return {
66
- ok: false,
67
- issues: Object.freeze(result.error.issues.map((entry) => issue(entry.path.filter(isPathSegment), entry.code, entry.message))),
68
- };
69
- }
70
- catch (error) {
71
- return { ok: false, issues: [issue([], "schema_error", synchronousIssue(error))] };
72
- }
73
- },
74
- });
75
- }
76
- function normalizeStandardSchema(source, role) {
77
- let jsonSchema;
78
- try {
79
- jsonSchema = copyJsonObject(role === "input"
80
- ? source["~standard"].jsonSchema.input()
81
- : source["~standard"].jsonSchema.output(), `tool.${role}Schema.jsonSchema`);
82
- }
83
- catch (error) {
84
- throw new HarnessError("tool.invalid-schema", `Tool ${role}Schema must convert to JSON Schema: ${message(error)}`, { cause: error });
85
- }
86
- return Object.freeze({
87
- jsonSchema,
88
- validate(value) {
89
- try {
90
- const result = source["~standard"].validate(value);
91
- if (isPromiseLike(result))
92
- return {
93
- ok: false,
94
- issues: [issue([], "async_validation", "Schema validation must be synchronous")],
95
- };
96
- if (result && typeof result === "object" && "issues" in result && result.issues)
97
- return { ok: false, issues: Object.freeze(result.issues.map(standardIssue)) };
98
- if (result && typeof result === "object" && "value" in result)
99
- return { ok: true, value: result.value };
100
- return {
101
- ok: false,
102
- issues: [issue([], "schema_error", "Standard Schema returned an invalid result")],
103
- };
104
- }
105
- catch (error) {
106
- return { ok: false, issues: [issue([], "schema_error", synchronousIssue(error))] };
107
- }
108
- },
109
- });
110
- }
111
- function normalizeExplicitSchema(source) {
112
- return Object.freeze({
113
- jsonSchema: copyJsonObject(source.jsonSchema, "tool schema jsonSchema"),
114
- validate(value) {
115
- try {
116
- const result = source.validate(value);
117
- if (isPromiseLike(result))
118
- return {
119
- ok: false,
120
- issues: [issue([], "async_validation", "Schema validation must be synchronous")],
121
- };
122
- if (!result || typeof result !== "object" || typeof result.ok !== "boolean")
123
- return {
124
- ok: false,
125
- issues: [issue([], "schema_error", "Tool schema returned an invalid result")],
126
- };
127
- if (result.ok)
128
- return { ok: true, value: result.value };
129
- return { ok: false, issues: Object.freeze(result.issues.map(normalizeIssue)) };
130
- }
131
- catch (error) {
132
- return { ok: false, issues: [issue([], "schema_error", synchronousIssue(error))] };
133
- }
134
- },
135
- });
136
- }
137
- function isZodSchema(value) {
138
- return value instanceof z.ZodType;
139
- }
140
- function isStandardSchema(value) {
141
- if (!value || typeof value !== "object" || !("~standard" in value))
142
- return false;
143
- const standard = value["~standard"];
144
- if (!standard || typeof standard !== "object")
145
- return false;
146
- const record = standard;
147
- if (typeof record.validate !== "function" ||
148
- !record.jsonSchema ||
149
- typeof record.jsonSchema !== "object")
150
- return false;
151
- const jsonSchema = record.jsonSchema;
152
- return typeof jsonSchema.input === "function" && typeof jsonSchema.output === "function";
153
- }
154
- function isToolSchema(value) {
155
- return (!!value &&
156
- typeof value === "object" &&
157
- "jsonSchema" in value &&
158
- "validate" in value &&
159
- typeof value.validate === "function");
160
- }
161
- /** Zod exposes declared checks in its stable v4 definition graph; reject async checks before a run. */
162
- function hasDeclaredAsyncWork(schema) {
163
- return visitDefinition(schema._zod?.def, new Set());
164
- }
165
- function visitDefinition(value, seen) {
166
- if (typeof value === "function")
167
- return value.constructor.name === "AsyncFunction";
168
- if (!value || typeof value !== "object")
169
- return false;
170
- if (seen.has(value))
171
- return false;
172
- seen.add(value);
173
- const nestedDefinition = value._zod?.def;
174
- if (nestedDefinition !== undefined && nestedDefinition !== value)
175
- return visitDefinition(nestedDefinition, seen);
176
- for (const item of Object.values(value)) {
177
- if (visitDefinition(item, seen))
178
- return true;
179
- }
180
- return false;
181
- }
182
- function standardIssue(value) {
183
- return issue(value.path?.filter(isPathSegment) ?? [], value.code ?? "invalid", value.message ?? "Invalid value");
184
- }
185
- function normalizeIssue(value) {
186
- return issue(value.path?.filter(isPathSegment) ?? [], value.code ?? "invalid", value.message ?? "Invalid value");
187
- }
188
- function issue(path, code, text) {
189
- return Object.freeze({ path: Object.freeze([...path]), code, message: text });
190
- }
191
- function isPathSegment(value) {
192
- return typeof value === "string" || typeof value === "number";
193
- }
194
- function isPromiseLike(value) {
195
- return (!!value && typeof value === "object" && typeof value.then === "function");
196
- }
197
- function synchronousIssue(error) {
198
- const reason = message(error);
199
- return reason.includes("Promise during synchronous parse")
200
- ? "Schema validation must be synchronous"
201
- : reason;
202
- }
203
- function message(error) {
204
- return error instanceof Error ? error.message : String(error);
205
- }
package/dist/errors.d.ts DELETED
@@ -1,17 +0,0 @@
1
- /** Machine-readable error raised by Harness-owned code. */
2
- export type HarnessErrorCode = "execution.invalid-state" | "execution.invalid-input" | "execution.incompatible" | "execution.record-failed" | "tool.unregistered" | "tool.invalid-binding" | "agent.build-failed" | "agent.lifecycle-sealed" | "context.invalid-item" | "context.invalid-item-type" | "context.invalid-order" | "context.invalid-reason" | "context.invalid-slot" | "interaction.invalid" | "interaction.missing-resume" | "interaction.uncorrelated-resume" | "input.invalid-content" | "output.invalid" | "output.invalid-schema" | "json.invalid-data" | "json.invalid-object" | "middleware.next-after-return" | "middleware.next-called-twice" | "middleware.request-mutators-revoked" | "model.candidate-missing" | "model.adapter-invalid-options" | "model.adapter-invalid-response" | "model.invalid-candidate" | "model.invalid-directive" | "model.unsupported-content" | "model.unsupported-output-schema" | "configuration.duplicate-tool-name" | "configuration.invalid" | "configuration.invalid-instructions" | "configuration.invalid-order" | "configuration.invalid-reason" | "configuration.invalid-slot" | "configuration.invalid-tools" | "configuration.model-selection-conflict" | "response.invalid-replacement" | "tool.invalid" | "tool.invalid-arguments" | "tool.invalid-output" | "tool.invalid-name" | "tool.invalid-schema" | "tool.invalid-tool-result";
3
- export type HarnessErrorDetails = Readonly<Record<string, string | number | boolean>>;
4
- export interface HarnessErrorOptions {
5
- readonly cause?: unknown;
6
- readonly details?: HarnessErrorDetails;
7
- }
8
- /**
9
- * The sole error shape produced by Harness itself. Message text is explanatory;
10
- * callers must branch on `code`.
11
- */
12
- export declare class HarnessError extends Error {
13
- readonly code: HarnessErrorCode;
14
- readonly details: HarnessErrorDetails;
15
- constructor(code: HarnessErrorCode, message: string, options?: HarnessErrorOptions);
16
- }
17
- export declare function isHarnessError(error: unknown): error is HarnessError;
package/dist/errors.js DELETED
@@ -1,17 +0,0 @@
1
- /**
2
- * The sole error shape produced by Harness itself. Message text is explanatory;
3
- * callers must branch on `code`.
4
- */
5
- export class HarnessError extends Error {
6
- code;
7
- details;
8
- constructor(code, message, options = {}) {
9
- super(message, options.cause === undefined ? undefined : { cause: options.cause });
10
- this.name = "HarnessError";
11
- this.code = code;
12
- this.details = Object.freeze({ ...(options.details ?? {}) });
13
- }
14
- }
15
- export function isHarnessError(error) {
16
- return error instanceof HarnessError;
17
- }