@nylorun/harness 0.11.1-beta → 0.13.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 (131) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +124 -5
  3. package/dist/definition/agent-definition.d.ts +11 -0
  4. package/dist/definition/agent-definition.js +12 -0
  5. package/dist/definition/assemble.d.ts +22 -0
  6. package/dist/{build → definition}/assemble.js +6 -7
  7. package/dist/definition/bind-agent.d.ts +9 -0
  8. package/dist/definition/bind-agent.js +21 -0
  9. package/dist/{build → definition}/bind-tool.d.ts +2 -1
  10. package/dist/{build → definition}/bind-tool.js +1 -0
  11. package/dist/definition/bound.d.ts +16 -0
  12. package/dist/definition/builder.d.ts +30 -0
  13. package/dist/definition/builder.js +94 -0
  14. package/dist/definition/declaration.d.ts +3 -0
  15. package/dist/definition/declaration.js +53 -0
  16. package/dist/{build → definition}/helpers.d.ts +1 -1
  17. package/dist/{build → definition}/manifest.d.ts +3 -1
  18. package/dist/definition/manifest.js +45 -0
  19. package/dist/{session → definition}/output-contract.d.ts +2 -2
  20. package/dist/{session → definition}/output-contract.js +1 -1
  21. package/dist/definition/registry.d.ts +10 -0
  22. package/dist/definition/registry.js +48 -0
  23. package/dist/{build → definition}/schema.d.ts +4 -4
  24. package/dist/errors.d.ts +1 -1
  25. package/dist/execution/dispatch.d.ts +2 -0
  26. package/dist/execution/dispatch.js +164 -0
  27. package/dist/execution/initial-state.d.ts +3 -0
  28. package/dist/execution/initial-state.js +14 -0
  29. package/dist/execution/invocation.d.ts +21 -0
  30. package/dist/execution/invocation.js +32 -0
  31. package/dist/{model → execution/model}/adapters.d.ts +2 -2
  32. package/dist/{model → execution/model}/adapters.js +2 -2
  33. package/dist/{model → execution/model}/normalize.d.ts +2 -2
  34. package/dist/{model → execution/model}/normalize.js +2 -2
  35. package/dist/{model → execution/model}/prepared.d.ts +3 -3
  36. package/dist/{step → execution/model}/project.d.ts +1 -1
  37. package/dist/{step → execution/model}/project.js +2 -10
  38. package/dist/execution/observe.d.ts +17 -0
  39. package/dist/execution/observe.js +53 -0
  40. package/dist/execution/options.d.ts +10 -0
  41. package/dist/execution/options.js +49 -0
  42. package/dist/execution/resume.d.ts +4 -0
  43. package/dist/execution/resume.js +52 -0
  44. package/dist/execution/run.d.ts +5 -0
  45. package/dist/execution/run.js +256 -0
  46. package/dist/execution/state.d.ts +8 -0
  47. package/dist/execution/state.js +208 -0
  48. package/dist/{step → execution/step}/canonicalize.d.ts +2 -2
  49. package/dist/{step → execution/step}/canonicalize.js +2 -2
  50. package/dist/{step → execution/step}/compose.d.ts +3 -2
  51. package/dist/{step → execution/step}/compose.js +5 -5
  52. package/dist/{step → execution/step}/context-draft.d.ts +3 -5
  53. package/dist/{step → execution/step}/context-draft.js +5 -22
  54. package/dist/execution/step/describe.d.ts +9 -0
  55. package/dist/execution/step/describe.js +22 -0
  56. package/dist/{step → execution/step}/model-configuration.d.ts +4 -3
  57. package/dist/{step → execution/step}/model-configuration.js +3 -3
  58. package/dist/execution/step/resolve.d.ts +11 -0
  59. package/dist/{step → execution/step}/resolve.js +5 -3
  60. package/dist/execution/step/run.d.ts +29 -0
  61. package/dist/{step → execution/step}/run.js +19 -53
  62. package/dist/execution/step/runtime.d.ts +32 -0
  63. package/dist/execution/step/runtime.js +1 -0
  64. package/dist/{step → execution/step}/seal.d.ts +13 -8
  65. package/dist/{step → execution/step}/seal.js +8 -6
  66. package/dist/{step → execution/step}/slot-assembly.d.ts +4 -4
  67. package/dist/{step → execution/step}/slot-assembly.js +4 -4
  68. package/dist/{step → execution/step}/step-context.d.ts +11 -12
  69. package/dist/{step → execution/step}/step-context.js +5 -27
  70. package/dist/execution/tool-result.d.ts +4 -0
  71. package/dist/execution/tool-result.js +30 -0
  72. package/dist/execution/transcript.d.ts +2 -0
  73. package/dist/{session/seed.js → execution/transcript.js} +9 -39
  74. package/dist/index.d.ts +15 -12
  75. package/dist/index.js +5 -5
  76. package/dist/types/agent.d.ts +9 -0
  77. package/dist/types/agent.js +1 -0
  78. package/dist/types/execution.d.ts +97 -0
  79. package/dist/types/execution.js +1 -0
  80. package/dist/types/manifest.d.ts +16 -13
  81. package/dist/types/middleware.d.ts +11 -40
  82. package/dist/types/model.d.ts +10 -10
  83. package/dist/types/observe.d.ts +165 -0
  84. package/dist/types/observe.js +1 -0
  85. package/dist/types/shared.d.ts +1 -225
  86. package/dist/types/tool.d.ts +21 -19
  87. package/dist/types/transcript.d.ts +65 -0
  88. package/dist/types/transcript.js +1 -0
  89. package/dist/utils/canonical.d.ts +1 -0
  90. package/dist/utils/canonical.js +10 -0
  91. package/dist/utils/immutable.d.ts +1 -0
  92. package/dist/utils/immutable.js +8 -0
  93. package/package.json +5 -5
  94. package/dist/build/agent.d.ts +0 -18
  95. package/dist/build/agent.js +0 -37
  96. package/dist/build/assemble.d.ts +0 -8
  97. package/dist/build/builder.d.ts +0 -46
  98. package/dist/build/builder.js +0 -151
  99. package/dist/build/manifest.js +0 -20
  100. package/dist/session/capability-state.d.ts +0 -14
  101. package/dist/session/capability-state.js +0 -67
  102. package/dist/session/event-log.d.ts +0 -12
  103. package/dist/session/event-log.js +0 -63
  104. package/dist/session/input-queue.d.ts +0 -41
  105. package/dist/session/input-queue.js +0 -94
  106. package/dist/session/record.d.ts +0 -11
  107. package/dist/session/record.js +0 -26
  108. package/dist/session/scheduler.d.ts +0 -62
  109. package/dist/session/scheduler.js +0 -485
  110. package/dist/session/seed.d.ts +0 -10
  111. package/dist/session/session.d.ts +0 -18
  112. package/dist/session/session.js +0 -103
  113. package/dist/session/state.d.ts +0 -15
  114. package/dist/session/state.js +0 -48
  115. package/dist/session/submission-stream.d.ts +0 -16
  116. package/dist/session/submission-stream.js +0 -46
  117. package/dist/step/resolve.d.ts +0 -10
  118. package/dist/step/run.d.ts +0 -33
  119. package/dist/turn/plan-runner.d.ts +0 -70
  120. package/dist/turn/plan-runner.js +0 -388
  121. package/dist/turn/runner.d.ts +0 -69
  122. package/dist/turn/runner.js +0 -158
  123. package/dist/types/session.d.ts +0 -227
  124. package/dist/utils/maps.d.ts +0 -1
  125. package/dist/utils/maps.js +0 -37
  126. package/dist/utils/observe.d.ts +0 -8
  127. package/dist/utils/observe.js +0 -29
  128. /package/dist/{types/session.js → definition/bound.js} +0 -0
  129. /package/dist/{build → definition}/helpers.js +0 -0
  130. /package/dist/{build → definition}/schema.js +0 -0
  131. /package/dist/{model → execution/model}/prepared.js +0 -0
@@ -0,0 +1,11 @@
1
+ import type { TurnOutputContract } from "../../definition/output-contract.js";
2
+ import type { InputEvent } from "../../types/transcript.js";
3
+ import type { ModelRequest } from "../../types/model.js";
4
+ import type { ToolResult } from "../../types/tool.js";
5
+ import type { StepContext } from "./step-context.js";
6
+ export declare function resolveModelRequest(input: {
7
+ context: StepContext;
8
+ arrivals: readonly InputEvent[];
9
+ toolResults: readonly ToolResult[];
10
+ output?: TurnOutputContract;
11
+ }): ModelRequest;
@@ -1,17 +1,19 @@
1
+ import { describeConfiguration } from "./describe.js";
1
2
  export function resolveModelRequest(input) {
2
3
  const ctx = input.context;
4
+ const configuration = describeConfiguration(ctx.configurationSnapshot());
3
5
  return Object.freeze({
4
- sessionId: ctx.input.sessionId,
6
+ executionId: ctx.input.executionId,
5
7
  turnId: ctx.input.turnId,
6
8
  stepId: ctx.input.stepId,
7
9
  ...(ctx.selectedDirective === undefined ? {} : { model: ctx.selectedDirective }),
8
- configuration: ctx.configurationSnapshot(),
10
+ configuration,
9
11
  instructions: Object.freeze([...ctx.instructions]),
10
12
  context: ctx.contextSnapshot(),
11
13
  transcript: Object.freeze([...ctx.input.transcript]),
12
14
  arrivals: Object.freeze([...input.arrivals]),
13
15
  toolResults: Object.freeze([...input.toolResults]),
14
- tools: Object.freeze([...ctx.offeredTools]),
16
+ tools: configuration.tools,
15
17
  ...(input.output === undefined ? {} : { outputSchema: input.output.schema.jsonSchema }),
16
18
  });
17
19
  }
@@ -0,0 +1,29 @@
1
+ import type { ExecutionSnapshot, StepRuntime } from "./runtime.js";
2
+ import type { TurnOutputContract } from "../../definition/output-contract.js";
3
+ import type { ModelCandidate } from "../../types/model.js";
4
+ import type { InputEvent } from "../../types/transcript.js";
5
+ import type { ToolResult } from "../../types/tool.js";
6
+ import type { ObserveEmit } from "../observe.js";
7
+ import { type SealedStepOutput } from "./seal.js";
8
+ export interface StepRunResult {
9
+ readonly stepId: string;
10
+ readonly candidate?: ModelCandidate;
11
+ readonly output: SealedStepOutput;
12
+ readonly requestedModelId?: string;
13
+ readonly modelInvocationId?: string;
14
+ }
15
+ export declare function runStep(input: {
16
+ agent: StepRuntime;
17
+ observe: ObserveEmit;
18
+ state: ExecutionSnapshot;
19
+ executionId: string;
20
+ turnId: string;
21
+ stepId: string;
22
+ turnNumber: number;
23
+ stepNumber: number;
24
+ arrivals: readonly InputEvent[];
25
+ toolResults: readonly ToolResult[];
26
+ signal: AbortSignal;
27
+ info?: unknown;
28
+ output?: TurnOutputContract;
29
+ }): Promise<StepRunResult>;
@@ -1,31 +1,31 @@
1
1
  import { normalizeCandidate } from "../model/normalize.js";
2
- import { HarnessError, isHarnessError } from "../errors.js";
3
- import { copyJson } from "../utils/immutable.js";
2
+ import { HarnessError, isHarnessError } from "../../errors.js";
3
+ import { copyJson } from "../../utils/immutable.js";
4
4
  import { runMiddleware } from "./compose.js";
5
5
  import { ContextDraft } from "./context-draft.js";
6
6
  import { StepContext } from "./step-context.js";
7
- import { projectModelCall } from "./project.js";
7
+ import { projectModelCall } from "../model/project.js";
8
8
  import { resolveModelRequest } from "./resolve.js";
9
9
  import { sealStep } from "./seal.js";
10
10
  import { ModelConfigurationDraft } from "./model-configuration.js";
11
- import { createId } from "../utils/ids.js";
11
+ import { createId } from "../../utils/ids.js";
12
12
  export async function runStep(input) {
13
- let state = input.state;
14
13
  let requestedModelId;
14
+ let modelInvocationId;
15
15
  const stepInput = Object.freeze({
16
- sessionId: input.sessionId,
16
+ executionId: input.executionId,
17
17
  turnId: input.turnId,
18
18
  stepId: input.stepId,
19
19
  turnNumber: input.turnNumber,
20
20
  stepNumber: input.stepNumber,
21
- session: input.session,
21
+ info: input.info,
22
22
  arrivals: Object.freeze([...input.arrivals]),
23
23
  toolResults: Object.freeze([...input.toolResults]),
24
24
  transcript: Object.freeze([...input.state.transcript]),
25
25
  });
26
26
  const configuration = new ModelConfigurationDraft();
27
- const runtimeContext = new ContextDraft(input.session.context);
28
- const context = new StepContext(stepInput, input.observe, configuration, runtimeContext, input.states);
27
+ const runtimeContext = new ContextDraft();
28
+ const context = new StepContext(stepInput, input.observe, configuration, runtimeContext);
29
29
  input.observe(() => ({
30
30
  type: "step.started",
31
31
  turnId: input.turnId,
@@ -35,10 +35,14 @@ export async function runStep(input) {
35
35
  attributes: snapshotStepStart(stepInput),
36
36
  }));
37
37
  await runMiddleware(input.agent.middleware, context, async () => {
38
+ input.signal.throwIfAborted();
38
39
  if (context.currentTripwire)
39
40
  return context.tripwire(context.currentTripwire);
40
41
  try {
41
- context.sealConfiguration(configuration.snapshot());
42
+ const selected = configuration.snapshot();
43
+ for (const tool of selected.tools)
44
+ input.agent.registry.reference(tool);
45
+ context.sealConfiguration(selected);
42
46
  context.sealContext(runtimeContext.snapshot());
43
47
  }
44
48
  catch (error) {
@@ -57,16 +61,10 @@ export async function runStep(input) {
57
61
  requestedModelId = request.model?.id;
58
62
  const call = projectModelCall(request);
59
63
  const invocationId = createId("invocation");
60
- const active = Object.freeze({
61
- kind: "model",
62
- turnId: input.turnId,
63
- stepId: input.stepId,
64
- invocationId,
65
- call,
66
- });
67
- state = await input.recordModelRequested(state, active);
64
+ modelInvocationId = invocationId;
68
65
  input.observe(() => ({
69
66
  type: "model.requested",
67
+ invocationId,
70
68
  turnId: input.turnId,
71
69
  stepId: input.stepId,
72
70
  ...(request.model?.id === undefined ? {} : { requestedModelId: request.model.id }),
@@ -91,6 +89,7 @@ export async function runStep(input) {
91
89
  const reported = Object.freeze({ adapter: value.adapter, call: copyJson(value.call) });
92
90
  input.observe(() => ({
93
91
  type: "model.prepared",
92
+ invocationId,
94
93
  turnId: input.turnId,
95
94
  stepId: input.stepId,
96
95
  ...(request.model?.id === undefined ? {} : { requestedModelId: request.model.id }),
@@ -100,11 +99,6 @@ export async function runStep(input) {
100
99
  });
101
100
  if (input.signal.aborted)
102
101
  throw input.signal.reason;
103
- if (isDeferred(outcome))
104
- return context.deferModel(Object.freeze({
105
- ...active,
106
- ...(outcome.token === undefined ? {} : { token: copyJson(outcome.token) }),
107
- }));
108
102
  const minted = context.mintFromModel(normalizeCandidate(outcome));
109
103
  const candidate = context.currentCandidate;
110
104
  if (!candidate)
@@ -124,47 +118,19 @@ export async function runStep(input) {
124
118
  const candidate = output.kind === "tools" ? output.plan.candidate : context.currentCandidate;
125
119
  return Object.freeze({
126
120
  stepId: input.stepId,
127
- state,
128
121
  ...(candidate ? { candidate } : {}),
129
122
  ...(requestedModelId === undefined ? {} : { requestedModelId }),
130
123
  output,
124
+ ...(modelInvocationId ? { modelInvocationId } : {}),
131
125
  });
132
126
  }
133
- function isDeferred(value) {
134
- return (typeof value === "object" && value !== null && "kind" in value && value.kind === "deferred");
135
- }
136
127
  function snapshotStepStart(input) {
137
- const session = Object.freeze({
138
- ...(input.session.userId === undefined ? {} : { userId: input.session.userId }),
139
- ...(input.session.context === undefined ? {} : { context: copyJson(input.session.context) }),
140
- });
141
128
  return Object.freeze({
142
- ...(Object.keys(session).length === 0 ? {} : { session }),
143
129
  arrivals: copyJson(input.arrivals),
144
130
  toolResults: copyJson(input.toolResults),
145
131
  transcript: input.transcript,
146
132
  });
147
133
  }
148
134
  function snapshotConfiguration(configuration) {
149
- return Object.freeze({
150
- version: configuration.version,
151
- ...(configuration.model === undefined ? {} : { model: copyJson(configuration.model) }),
152
- instructions: copyJson(configuration.instructions),
153
- tools: snapshotTools(configuration.tools),
154
- toolContracts: copyJson(configuration.toolContracts),
155
- contributors: copyJson(configuration.contributors),
156
- });
157
- }
158
- function snapshotTools(tools) {
159
- return Object.freeze(tools.map((tool) => Object.freeze({
160
- name: tool.name,
161
- ...(tool.description === undefined ? {} : { description: tool.description }),
162
- owner: tool.owner,
163
- inputSchema: Object.freeze({ jsonSchema: copyJson(tool.inputSchema.jsonSchema) }),
164
- ...(tool.outputSchema === undefined
165
- ? {}
166
- : {
167
- outputSchema: Object.freeze({ jsonSchema: copyJson(tool.outputSchema.jsonSchema) }),
168
- }),
169
- })));
135
+ return copyJson(configuration);
170
136
  }
@@ -0,0 +1,32 @@
1
+ import type { ToolRegistry } from "../../definition/registry.js";
2
+ import type { ModelAdapter } from "../../types/model.js";
3
+ import type { InputEvent, TranscriptEntry } from "../../types/transcript.js";
4
+ import type { ToolResult } from "../../types/tool.js";
5
+ import type { BoundMiddleware } from "../../definition/bound.js";
6
+ /** Compiled definition pieces plus the per-run model adapter for one step. */
7
+ export interface StepRuntime {
8
+ readonly middleware: readonly BoundMiddleware[];
9
+ readonly invoke: ModelAdapter;
10
+ readonly registry: ToolRegistry;
11
+ }
12
+ export interface StepInput {
13
+ readonly executionId: string;
14
+ readonly turnId: string;
15
+ readonly stepId: string;
16
+ /** One-based position of this turn within the execution. */
17
+ readonly turnNumber: number;
18
+ /** One-based position of this Model Step within the Turn. */
19
+ readonly stepNumber: number;
20
+ readonly info?: unknown;
21
+ readonly arrivals: readonly InputEvent[];
22
+ readonly toolResults: readonly ToolResult[];
23
+ readonly transcript: readonly TranscriptEntry[];
24
+ }
25
+ /** Internal view consumed by a single model step. */
26
+ export interface ExecutionSnapshot {
27
+ readonly id: string;
28
+ readonly status: "running";
29
+ readonly turnCount: number;
30
+ readonly revision: number;
31
+ readonly transcript: readonly TranscriptEntry[];
32
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,9 +1,17 @@
1
- import type { ModelCandidate } from "../types/model.js";
2
- import type { Tripwire } from "../types/shared.js";
3
- import type { BoundToolDefinition, RequiredInteraction, SealedToolCall, ToolOwner, ToolResult } from "../types/tool.js";
1
+ import type { BoundToolDefinition } from "../../definition/bound.js";
2
+ import type { ModelCandidate } from "../../types/model.js";
3
+ import type { JsonValue, Tripwire } from "../../types/shared.js";
4
+ import type { RequiredInteraction, ToolOwner, ToolResult } from "../../types/tool.js";
4
5
  import type { StepContext } from "./step-context.js";
5
- import type { TurnOutputContract } from "../session/output-contract.js";
6
+ import type { TurnOutputContract } from "../../definition/output-contract.js";
7
+ export interface SealedToolCall {
8
+ readonly callId: string;
9
+ readonly toolName: string;
10
+ readonly args: JsonValue;
11
+ }
6
12
  export interface ExecutablePlanEntry {
13
+ readonly definition: BoundToolDefinition;
14
+ readonly rawArgs: JsonValue;
7
15
  readonly call: SealedToolCall;
8
16
  readonly invocationId: string;
9
17
  readonly owner: ToolOwner;
@@ -25,10 +33,7 @@ export type SealedStepOutput = {
25
33
  readonly tripwire: Tripwire;
26
34
  } | {
27
35
  readonly kind: "final";
28
- readonly output: import("../types/shared.js").JsonValue;
29
- } | {
30
- readonly kind: "deferred-model";
31
- readonly active: import("../types/session.js").ActiveModelExecutionRecord;
36
+ readonly output: JsonValue;
32
37
  } | {
33
38
  readonly kind: "tools";
34
39
  readonly plan: InternalToolPlan;
@@ -1,7 +1,7 @@
1
1
  import { textFromOutput } from "../model/normalize.js";
2
- import { createId } from "../utils/ids.js";
3
- import { HarnessError, isHarnessError } from "../errors.js";
4
- import { assertJson, copyJson } from "../utils/immutable.js";
2
+ import { createId } from "../../utils/ids.js";
3
+ import { HarnessError, isHarnessError } from "../../errors.js";
4
+ import { assertJson, copyJson } from "../../utils/immutable.js";
5
5
  const failed = (callId, toolName, code, message, details) => Object.freeze({
6
6
  kind: "failed",
7
7
  callId,
@@ -14,8 +14,6 @@ const failed = (callId, toolName, code, message, details) => Object.freeze({
14
14
  export function sealStep(context, outputContract) {
15
15
  if (context.currentTripwire)
16
16
  return Object.freeze({ kind: "tripwire", tripwire: context.currentTripwire });
17
- if (context.currentModelDeferred)
18
- return Object.freeze({ kind: "deferred-model", active: context.currentModelDeferred });
19
17
  const calls = context.canonicalCalls();
20
18
  if (!calls.length) {
21
19
  if (outputContract)
@@ -45,7 +43,9 @@ function sealStructuredOutput(context, contract) {
45
43
  return invalidOutput("Structured terminal output must contain exactly one JSON block and no text blocks");
46
44
  const validation = contract.schema.validate(json[0].value);
47
45
  if (!validation.ok)
48
- return invalidOutput(`Structured terminal output failed validation: ${validation.issues.map(renderIssue).join("; ")}`);
46
+ return invalidOutput(`Structured terminal output failed validation: ${validation.issues
47
+ .map(renderIssue)
48
+ .join("; ")}`);
49
49
  try {
50
50
  assertJson(validation.value, "structured terminal output");
51
51
  return Object.freeze({ kind: "final", output: copyJson(validation.value) });
@@ -113,6 +113,8 @@ function sealCall(context, catalog, candidate) {
113
113
  order,
114
114
  canonical,
115
115
  executable: Object.freeze({
116
+ definition: tool,
117
+ rawArgs: copyJson(candidate.args),
116
118
  call: Object.freeze({
117
119
  callId: candidate.id,
118
120
  toolName: candidate.name,
@@ -1,4 +1,4 @@
1
- import { type HarnessErrorCode } from "../errors.js";
1
+ import { type HarnessErrorCode } from "../../errors.js";
2
2
  export interface SlotOwner {
3
3
  readonly middlewareId: string;
4
4
  readonly middlewareOrder: number;
@@ -11,9 +11,9 @@ export interface SlotDeclaration<Value> {
11
11
  readonly reason?: string;
12
12
  }
13
13
  /**
14
- * Shared per-step slot store. It has no session lifetime: declarations are discarded with the
15
- * draft that owns this instance. Configuration and context supply their typed values and snapshot
16
- * them after this assembler has applied ownership, replacement, and canonical ordering.
14
+ * Shared per-step slot store. Declarations are discarded with the draft that owns this instance.
15
+ * Configuration and context supply their typed values and snapshot them after this assembler has
16
+ * applied ownership, replacement, and canonical ordering.
17
17
  */
18
18
  export declare class SlotDraft<Value> {
19
19
  #private;
@@ -1,8 +1,8 @@
1
- import { HarnessError } from "../errors.js";
1
+ import { HarnessError } from "../../errors.js";
2
2
  /**
3
- * Shared per-step slot store. It has no session lifetime: declarations are discarded with the
4
- * draft that owns this instance. Configuration and context supply their typed values and snapshot
5
- * them after this assembler has applied ownership, replacement, and canonical ordering.
3
+ * Shared per-step slot store. Declarations are discarded with the draft that owns this instance.
4
+ * Configuration and context supply their typed values and snapshot them after this assembler has
5
+ * applied ownership, replacement, and canonical ordering.
6
6
  */
7
7
  export class SlotDraft {
8
8
  #slots = new Map();
@@ -1,35 +1,34 @@
1
- import type { ContextSnapshot, ModelCandidate, ModelDirective, ModelConfigurationSnapshot } from "../types/model.js";
2
- import type { StepInput, StepRequest, StepResponse } from "../types/middleware.js";
3
- import type { Tripwire } from "../types/shared.js";
4
- import type { ActiveModelExecutionRecord } from "../types/session.js";
5
- import type { ObserveEmit } from "../utils/observe.js";
6
- import type { BoundToolDefinition, Interaction } from "../types/tool.js";
1
+ import type { BoundToolDefinition } from "../../definition/bound.js";
2
+ import type { StepInput } from "./runtime.js";
3
+ import type { InternalModelConfigurationSnapshot } from "./describe.js";
4
+ import type { ContextSnapshot, ModelCandidate, ModelDirective } from "../../types/model.js";
5
+ import type { StepRequest, StepResponse } from "../../types/middleware.js";
6
+ import type { Tripwire } from "../../types/shared.js";
7
+ import type { ObserveEmit } from "../observe.js";
8
+ import type { Interaction } from "../../types/tool.js";
7
9
  import { type CanonicalCall } from "./canonicalize.js";
8
10
  import { ContextDraft } from "./context-draft.js";
9
11
  import { ModelConfigurationDraft } from "./model-configuration.js";
10
- import type { CapabilityStateRegistry } from "../session/capability-state.js";
11
12
  export declare function isBrandedResponse(value: unknown): value is StepResponse;
12
13
  /** Mutable Step state. Middleware receives leased request views and one branded response. */
13
14
  export declare class StepContext {
14
15
  #private;
15
16
  readonly input: Readonly<StepInput>;
16
- constructor(input: Readonly<StepInput>, observe: ObserveEmit, configuration: ModelConfigurationDraft, context: ContextDraft, states?: CapabilityStateRegistry);
17
+ constructor(input: Readonly<StepInput>, observe: ObserveEmit, configuration: ModelConfigurationDraft, context: ContextDraft);
17
18
  get currentTripwire(): Tripwire | undefined;
18
19
  get currentCandidate(): Readonly<ModelCandidate> | undefined;
19
- get currentModelDeferred(): ActiveModelExecutionRecord | undefined;
20
20
  get selectedDirective(): ModelDirective | undefined;
21
21
  get instructions(): readonly string[];
22
22
  contextSnapshot(): ContextSnapshot;
23
23
  get offeredTools(): readonly BoundToolDefinition[];
24
24
  get catalogByName(): ReadonlyMap<string, BoundToolDefinition>;
25
- configurationSnapshot(): ModelConfigurationSnapshot;
26
- sealConfiguration(snapshot: ModelConfigurationSnapshot): void;
25
+ configurationSnapshot(): InternalModelConfigurationSnapshot;
26
+ sealConfiguration(snapshot: InternalModelConfigurationSnapshot): void;
27
27
  sealContext(snapshot: ContextSnapshot): void;
28
28
  denialFor(callId: string): string | undefined;
29
29
  interactionFor(callId: string): Interaction | undefined;
30
30
  canonicalCalls(): readonly CanonicalCall[];
31
31
  mintFromModel(candidate: Readonly<ModelCandidate>): StepResponse;
32
- deferModel(active: ActiveModelExecutionRecord): StepResponse;
33
32
  tripwire(error: Tripwire): StepResponse;
34
33
  seal(): void;
35
34
  requestFacade(middlewareId: string, middlewareOrder: number): {
@@ -1,4 +1,5 @@
1
- import { HarnessError, isHarnessError } from "../errors.js";
1
+ import { HarnessError, isHarnessError } from "../../errors.js";
2
+ import { freezeGraph } from "../../utils/immutable.js";
2
3
  import { callsFromCanonical, candidateFromCanonical, canonicalizeOutput, identityKey, } from "./canonicalize.js";
3
4
  import { normalizeCandidate } from "../model/normalize.js";
4
5
  import { ContextDraft } from "./context-draft.js";
@@ -13,24 +14,21 @@ export class StepContext {
13
14
  #observe;
14
15
  #context;
15
16
  #configuration;
16
- #states;
17
17
  #denials = new Map();
18
18
  #interactions = new Map();
19
19
  #identities = new Map();
20
20
  #canonical = Object.freeze([]);
21
21
  #candidate;
22
22
  #tripwire;
23
- #modelDeferred;
24
23
  #response;
25
24
  #sealed = false;
26
25
  #configurationSnapshot;
27
26
  #contextSnapshot;
28
- constructor(input, observe, configuration, context, states) {
27
+ constructor(input, observe, configuration, context) {
29
28
  this.input = input;
30
29
  this.#observe = observe;
31
30
  this.#configuration = configuration;
32
31
  this.#context = context;
33
- this.#states = states;
34
32
  }
35
33
  get currentTripwire() {
36
34
  return this.#tripwire;
@@ -38,9 +36,6 @@ export class StepContext {
38
36
  get currentCandidate() {
39
37
  return this.#candidate;
40
38
  }
41
- get currentModelDeferred() {
42
- return this.#modelDeferred;
43
- }
44
39
  get selectedDirective() {
45
40
  return this.configurationSnapshot().model;
46
41
  }
@@ -83,10 +78,6 @@ export class StepContext {
83
78
  this.#identities.set(call.id, identityKey(call.name, call.args));
84
79
  return this.#ensureResponse();
85
80
  }
86
- deferModel(active) {
87
- this.#modelDeferred = active;
88
- return this.#ensureResponse();
89
- }
90
81
  tripwire(error) {
91
82
  this.#tripwire ??= Object.freeze({ ...error });
92
83
  return this.#ensureResponse();
@@ -138,10 +129,10 @@ export class StepContext {
138
129
  }
139
130
  });
140
131
  const request = {
141
- sessionId: this.input.sessionId,
132
+ executionId: this.input.executionId,
142
133
  turnId: this.input.turnId,
143
134
  stepId: this.input.stepId,
144
- session: this.input.session,
135
+ info: this.input.info,
145
136
  turnNumber: this.input.turnNumber,
146
137
  stepNumber: this.input.stepNumber,
147
138
  arrivals: this.input.arrivals,
@@ -171,11 +162,6 @@ export class StepContext {
171
162
  return minted;
172
163
  },
173
164
  };
174
- if (this.#states?.has(middlewareId))
175
- Object.defineProperty(request, "state", {
176
- enumerable: true,
177
- get: () => this.#states.get(middlewareId),
178
- });
179
165
  const value = Object.freeze(request);
180
166
  return Object.freeze({
181
167
  value,
@@ -253,11 +239,3 @@ function pickSidecar(key, replacement, normalized, current) {
253
239
  const value = source?.[key];
254
240
  return value === undefined ? {} : { [key]: value };
255
241
  }
256
- function freezeGraph(value, seen = new WeakSet()) {
257
- if (!value || typeof value !== "object" || seen.has(value))
258
- return value;
259
- seen.add(value);
260
- for (const item of Object.values(value))
261
- freezeGraph(item, seen);
262
- return Object.freeze(value);
263
- }
@@ -0,0 +1,4 @@
1
+ import type { BoundToolDefinition } from "../definition/bound.js";
2
+ import type { SavedToolCall } from "../types/execution.js";
3
+ import type { ToolOutcome, ToolResult } from "../types/tool.js";
4
+ export declare function toolResult(call: SavedToolCall, definition: BoundToolDefinition, outcome: ToolOutcome): ToolResult;
@@ -0,0 +1,30 @@
1
+ import { HarnessError } from "../errors.js";
2
+ import { copyJson } from "../utils/immutable.js";
3
+ export function toolResult(call, definition, outcome) {
4
+ const identity = { callId: call.callId, toolName: call.toolName };
5
+ if (outcome.kind === "completed") {
6
+ const checked = definition.outputSchema?.validate(outcome.output);
7
+ if (checked && !checked.ok)
8
+ return {
9
+ ...identity,
10
+ kind: "failed",
11
+ code: "tool.invalid-output",
12
+ message: checked.issues.map((issue) => issue.message).join("; "),
13
+ details: { phase: "output", issues: checked.issues },
14
+ };
15
+ return copyJson({
16
+ ...identity,
17
+ kind: "completed",
18
+ output: checked?.ok ? checked.value : outcome.output,
19
+ });
20
+ }
21
+ if (outcome.kind === "failed" &&
22
+ typeof outcome.code === "string" &&
23
+ typeof outcome.message === "string")
24
+ return copyJson({ ...identity, kind: "failed", code: outcome.code, message: outcome.message });
25
+ if (outcome.kind === "denied" && typeof outcome.reason !== "string")
26
+ throw new HarnessError("tool.invalid-tool-result", "Tool denial reason must be a string");
27
+ if (outcome.kind === "denied" && typeof outcome.reason === "string")
28
+ return copyJson({ ...identity, kind: "denied", reason: outcome.reason });
29
+ throw new HarnessError("tool.invalid-tool-result", "Expected a completed, failed, or denied tool result");
30
+ }
@@ -0,0 +1,2 @@
1
+ import type { TranscriptEntry } from "../types/transcript.js";
2
+ export declare function validateTranscript(value: readonly TranscriptEntry[]): readonly TranscriptEntry[];
@@ -1,39 +1,20 @@
1
1
  import { HarnessError } from "../errors.js";
2
- import { normalizeCandidate } from "../model/normalize.js";
2
+ import { normalizeCandidate } from "./model/normalize.js";
3
3
  import { assertJson, copyJson, copyJsonObject } from "../utils/immutable.js";
4
- export function normalizeSessionSeed(seed) {
4
+ export function validateTranscript(value) {
5
5
  try {
6
- return normalizeSeed(seed);
6
+ if (!Array.isArray(value))
7
+ fail("Transcript must be an array");
8
+ return Object.freeze(value.map((entry, index) => entryAt(entry, index)));
7
9
  }
8
10
  catch (cause) {
9
- if (cause instanceof HarnessError && cause.code === "session.invalid-seed")
11
+ if (cause instanceof HarnessError && cause.code === "execution.invalid-state")
10
12
  throw cause;
11
- throw new HarnessError("session.invalid-seed", "Session seed contains invalid typed JSON", {
13
+ throw new HarnessError("execution.invalid-state", "Transcript contains invalid typed JSON", {
12
14
  cause,
13
15
  });
14
16
  }
15
17
  }
16
- function normalizeSeed(seed) {
17
- if (!seed || typeof seed !== "object")
18
- fail("Session seed must be an object");
19
- if (!Array.isArray(seed.transcript))
20
- fail("Session seed transcript must be an array");
21
- optionalString(seed.id, "Session seed id");
22
- optionalString(seed.userId, "Session seed userId");
23
- const turnCount = count(seed.turnCount, "turnCount");
24
- const revision = count(seed.revision, "revision");
25
- const transcript = Object.freeze(seed.transcript.map((entry, index) => entryAt(entry, index)));
26
- return Object.freeze({
27
- ...(seed.id === undefined ? {} : { id: seed.id }),
28
- ...(seed.userId === undefined ? {} : { userId: seed.userId }),
29
- ...(seed.context === undefined
30
- ? {}
31
- : { context: copyJsonObject(seed.context, "session seed context") }),
32
- turnCount,
33
- revision,
34
- transcript,
35
- });
36
- }
37
18
  function entryAt(value, index) {
38
19
  if (!value || typeof value !== "object")
39
20
  fail(`Transcript entry ${index} must be an object`);
@@ -61,7 +42,7 @@ function entryAt(value, index) {
61
42
  });
62
43
  }
63
44
  catch (cause) {
64
- throw new HarnessError("session.invalid-seed", `Invalid candidate at transcript ${index}`, {
45
+ throw new HarnessError("execution.invalid-state", `Invalid candidate at transcript ${index}`, {
65
46
  cause,
66
47
  });
67
48
  }
@@ -273,21 +254,10 @@ function exactKeys(value, allowed, label) {
273
254
  if (!allowed.includes(key))
274
255
  fail(`${label} has unknown field '${key}'`);
275
256
  }
276
- function count(value, label) {
277
- if (value === undefined)
278
- return 0;
279
- if (!Number.isSafeInteger(value) || value < 0)
280
- fail(`Session seed ${label} must be a non-negative safe integer`);
281
- return value;
282
- }
283
- function optionalString(value, label) {
284
- if (value !== undefined)
285
- requiredString(value, label);
286
- }
287
257
  function requiredString(value, label) {
288
258
  if (typeof value !== "string" || value.length === 0)
289
259
  fail(`${label} must be a non-empty string`);
290
260
  }
291
261
  function fail(message) {
292
- throw new HarnessError("session.invalid-seed", message);
262
+ throw new HarnessError("execution.invalid-state", message);
293
263
  }
package/dist/index.d.ts CHANGED
@@ -1,15 +1,18 @@
1
- export { Agent, AgentBuilder, AgentBuildError, AgentLifecycleError, BoundAgentBuilder, } from "./build/builder.js";
2
- export type { AgentOptions } from "./build/builder.js";
1
+ export { Agent, AgentBuilder, AgentBuildError, AgentLifecycleError } from "./definition/builder.js";
2
+ export type { AgentOptions } from "./definition/builder.js";
3
3
  export { HarnessError, isHarnessError } from "./errors.js";
4
4
  export type { HarnessErrorCode, HarnessErrorDetails, HarnessErrorOptions } from "./errors.js";
5
- export { BuiltAgent } from "./build/agent.js";
6
- export { middleware, model, tool } from "./build/helpers.js";
7
- export { defineSchema } from "./build/schema.js";
8
- export { preparedModel } from "./model/prepared.js";
9
- export type { PreparedModelOptions } from "./model/prepared.js";
10
- export type { AgentManifest, MiddlewareManifest } from "./types/manifest.js";
11
- export type { BoundMiddleware, CapabilityDeclaration, CapabilityItems, CapabilityState, MiddlewareContributions, StepInput, StepMiddleware, StepRequest, StepResponse, } from "./types/middleware.js";
5
+ export type { BuiltAgent } from "./types/agent.js";
6
+ export { middleware, model, tool } from "./definition/helpers.js";
7
+ export { defineSchema } from "./definition/schema.js";
8
+ export { preparedModel } from "./execution/model/prepared.js";
9
+ export type { PreparedModelOptions } from "./execution/model/prepared.js";
10
+ export type { AgentManifest, CapabilityManifest, ManifestTool } from "./types/manifest.js";
11
+ export type { CapabilityDeclaration, CapabilityItems, MiddlewareContributions, StepMiddleware, StepRequest, StepResponse, } from "./types/middleware.js";
12
12
  export type { ModelCandidate, ModelControls, ModelDirective, ModelEvidence, ModelFinishReason, ModelAdapter, ModelAdapterContext, ModelPreparedCall, ContextContributor, ContextMutationOptions, ContextSnapshot, ModelCall, ModelCallTool, ModelOutputBlock, PromptContentPart, PromptItem, ModelConfigurationContributor, ModelConfigurationInstruction, ModelConfigurationMutationOptions, ModelConfigurationSnapshot, ModelConfigurationTool, ModelRequest, ModelToolCall, ModelUsage, } from "./types/model.js";
13
- export type { BuildDiagnostic, ContextItem, DeferredOutcome, JsonObject, JsonPrimitive, JsonValue, ObserveEvent, ObserveModelConfigurationSnapshot, ObserveModelRequested, ObserveSealedCall, ObserveToolSnapshot, Observer, Tripwire, } from "./types/shared.js";
14
- export type { ActiveExecutionRecord, ActiveInteractionExecutionRecord, ActiveModelExecutionRecord, ActiveToolCallRecord, ActiveToolsExecutionRecord, InteractionReply, InputCompletion, InputEvent, InputHandle, InputOptions, OutputInputOptions, MessageInput, Session, SessionInput, SessionIdentity, SessionEvent, SessionOptions, SessionRecord, SessionRecorder, SessionRunOptions, SessionSeed, SeededSessionOptions, SessionSnapshot, TranscriptEntry, UserContentPart, } from "./types/session.js";
15
- export type { BoundToolSchema, BoundToolDefinition, Interaction, RequiredInteraction, SealedToolCall, ToolContent, ToolDefinition, ToolExecutionContext, ToolExecutionResume, ToolInputSchema, ToolOutputSchema, ToolSchema, ToolSchemaSource, StandardToolSchema, StandardSchemaIssue, SchemaIssue, SchemaValidation, SchemaOutput, ToolOwner, ToolOutcome, ToolResult, ToolValidationFailureDetails, } from "./types/tool.js";
13
+ export type { BuildDiagnostic, ContextItem, DeferredOutcome, JsonObject, JsonPrimitive, JsonValue, Tripwire, } from "./types/shared.js";
14
+ export type { ObserveEvent, ObserveModelConfigurationSnapshot, ObserveModelRequested, ObserveSealedCall, ObserveToolSnapshot, Observer, } from "./types/observe.js";
15
+ export type { InputEvent, MessageInput, InteractionReply, TranscriptEntry, UserContentPart, } from "./types/transcript.js";
16
+ export type { ExecutionInput, ExecutionState, ExecutionEvent, RunOptions, RunResult, SavedToolCall, ExecutionPlan, ToolReference, } from "./types/execution.js";
17
+ export { createExecutionState, validateExecutionState } from "./execution/state.js";
18
+ export type { Interaction, RequiredInteraction, ToolContent, ToolDefinition, ToolDescriptor, ToolExecutionContext, ToolExecutionResume, ToolInputSchema, ToolOutputSchema, ToolSchema, ToolSchemaSource, StandardToolSchema, StandardSchemaIssue, SchemaIssue, SchemaValidation, SchemaOutput, ToolOwner, ToolOutcome, ToolResult, ToolValidationFailureDetails, } from "./types/tool.js";