@nylorun/harness 0.12.0-beta → 0.15.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.
- package/CHANGELOG.md +71 -0
- package/HOST_CONTRACT.md +27 -0
- package/README.md +86 -5
- package/dist/compatibility.d.ts +3 -0
- package/dist/compatibility.js +3 -0
- package/dist/definition/agent-definition.d.ts +19 -0
- package/dist/definition/agent-definition.js +20 -0
- package/dist/definition/compatibility.d.ts +11 -0
- package/dist/definition/compatibility.js +30 -0
- package/dist/definition/registry.d.ts +10 -0
- package/dist/definition/registry.js +49 -0
- package/dist/index.d.ts +4 -15
- package/dist/index.js +1 -6
- package/dist/loop/dispatch.d.ts +2 -0
- package/dist/loop/dispatch.js +327 -0
- package/dist/loop/host-suspension.d.ts +6 -0
- package/dist/loop/host-suspension.js +10 -0
- package/dist/loop/initial-state.d.ts +13 -0
- package/dist/loop/initial-state.js +30 -0
- package/dist/loop/invocation.d.ts +24 -0
- package/dist/loop/invocation.js +37 -0
- package/dist/{model → loop/model}/adapters.d.ts +4 -2
- package/dist/{model → loop/model}/adapters.js +3 -2
- package/dist/{model → loop/model}/normalize.d.ts +2 -2
- package/dist/{model → loop/model}/normalize.js +2 -2
- package/dist/{model → loop/model}/prepared.d.ts +3 -3
- package/dist/{step → loop/model}/project.d.ts +1 -1
- package/dist/{step → loop/model}/project.js +2 -10
- package/dist/loop/observe.d.ts +17 -0
- package/dist/loop/observe.js +53 -0
- package/dist/loop/options.d.ts +11 -0
- package/dist/loop/options.js +69 -0
- package/dist/loop/resume.d.ts +4 -0
- package/dist/loop/resume.js +52 -0
- package/dist/loop/run.d.ts +5 -0
- package/dist/loop/run.js +264 -0
- package/dist/loop/state.d.ts +8 -0
- package/dist/loop/state.js +218 -0
- package/dist/{step → loop/step}/canonicalize.d.ts +2 -2
- package/dist/{step → loop/step}/canonicalize.js +2 -2
- package/dist/{step → loop/step}/compose.d.ts +3 -2
- package/dist/{step → loop/step}/compose.js +8 -5
- package/dist/loop/step/context-draft.d.ts +8 -0
- package/dist/{step → loop/step}/context-draft.js +5 -22
- package/dist/loop/step/describe.d.ts +9 -0
- package/dist/loop/step/describe.js +22 -0
- package/dist/loop/step/dynamics.d.ts +29 -0
- package/dist/loop/step/dynamics.js +147 -0
- package/dist/{step → loop/step}/model-configuration.d.ts +4 -3
- package/dist/{step → loop/step}/model-configuration.js +3 -3
- package/dist/loop/step/resolve.d.ts +11 -0
- package/dist/{step → loop/step}/resolve.js +5 -3
- package/dist/loop/step/run.d.ts +30 -0
- package/dist/{step → loop/step}/run.js +104 -53
- package/dist/loop/step/runtime.d.ts +40 -0
- package/dist/{step → loop/step}/seal.d.ts +13 -8
- package/dist/{step → loop/step}/seal.js +8 -6
- package/dist/{step → loop/step}/slot-assembly.d.ts +4 -4
- package/dist/{step → loop/step}/slot-assembly.js +4 -4
- package/dist/{step → loop/step}/step-context.d.ts +11 -12
- package/dist/{step → loop/step}/step-context.js +5 -27
- package/dist/loop/tool-result.d.ts +4 -0
- package/dist/loop/tool-result.js +30 -0
- package/dist/loop/transcript.d.ts +2 -0
- package/dist/{session/seed.js → loop/transcript.js} +11 -41
- package/dist/loop/waits.d.ts +50 -0
- package/dist/loop/waits.js +11 -0
- package/dist/run/durable.d.ts +71 -0
- package/dist/run/durable.js +164 -0
- package/dist/run/index.d.ts +33 -0
- package/dist/run/index.js +38 -0
- package/dist/types/client.d.ts +88 -0
- package/dist/types/execution.d.ts +114 -0
- package/dist/utils/ids.d.ts +1 -0
- package/dist/utils/ids.js +11 -1
- package/package.json +18 -6
- package/dist/build/agent.d.ts +0 -17
- package/dist/build/agent.js +0 -32
- package/dist/build/assemble.d.ts +0 -7
- package/dist/build/assemble.js +0 -41
- package/dist/build/bind-tool.d.ts +0 -3
- package/dist/build/bind-tool.js +0 -18
- package/dist/build/builder.d.ts +0 -38
- package/dist/build/builder.js +0 -136
- package/dist/build/helpers.d.ts +0 -6
- package/dist/build/helpers.js +0 -4
- package/dist/build/manifest.d.ts +0 -7
- package/dist/build/manifest.js +0 -20
- package/dist/build/schema.d.ts +0 -14
- package/dist/build/schema.js +0 -205
- package/dist/errors.d.ts +0 -17
- package/dist/errors.js +0 -17
- package/dist/session/capability-state.d.ts +0 -14
- package/dist/session/capability-state.js +0 -67
- package/dist/session/event-log.d.ts +0 -12
- package/dist/session/event-log.js +0 -63
- package/dist/session/input-queue.d.ts +0 -41
- package/dist/session/input-queue.js +0 -94
- package/dist/session/output-contract.d.ts +0 -6
- package/dist/session/output-contract.js +0 -12
- package/dist/session/record.d.ts +0 -11
- package/dist/session/record.js +0 -26
- package/dist/session/scheduler.d.ts +0 -62
- package/dist/session/scheduler.js +0 -475
- package/dist/session/seed.d.ts +0 -10
- package/dist/session/session.d.ts +0 -17
- package/dist/session/session.js +0 -101
- package/dist/session/state.d.ts +0 -15
- package/dist/session/state.js +0 -48
- package/dist/session/submission-stream.d.ts +0 -16
- package/dist/session/submission-stream.js +0 -46
- package/dist/step/context-draft.d.ts +0 -10
- package/dist/step/resolve.d.ts +0 -10
- package/dist/step/run.d.ts +0 -33
- package/dist/turn/plan-runner.d.ts +0 -72
- package/dist/turn/plan-runner.js +0 -389
- package/dist/turn/runner.d.ts +0 -69
- package/dist/turn/runner.js +0 -159
- package/dist/types/manifest.d.ts +0 -19
- package/dist/types/middleware.d.ts +0 -95
- package/dist/types/model.d.ts +0 -184
- package/dist/types/session.d.ts +0 -230
- package/dist/types/session.js +0 -1
- package/dist/types/shared.d.ts +0 -249
- package/dist/types/shared.js +0 -1
- package/dist/types/tool.d.ts +0 -139
- package/dist/types/tool.js +0 -1
- package/dist/utils/immutable.d.ts +0 -5
- package/dist/utils/immutable.js +0 -68
- package/dist/utils/maps.d.ts +0 -1
- package/dist/utils/maps.js +0 -37
- package/dist/utils/observe.d.ts +0 -3
- package/dist/utils/observe.js +0 -13
- /package/dist/{model → loop/model}/prepared.js +0 -0
- /package/dist/{types/manifest.js → loop/step/runtime.js} +0 -0
- /package/dist/types/{middleware.js → client.js} +0 -0
- /package/dist/types/{model.js → execution.js} +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ToolRegistry } from "../../definition/registry.js";
|
|
2
|
+
import type { AgentDefinition } from "../../definition/agent-definition.js";
|
|
3
|
+
import type { ModelAdapter } from "@nylorun/core/define";
|
|
4
|
+
import type { InputEvent, TranscriptEntry } from "@nylorun/core/define";
|
|
5
|
+
import type { ToolResult } from "@nylorun/core/define";
|
|
6
|
+
import type { BoundMiddleware } from "@nylorun/core/define";
|
|
7
|
+
import type { JsonValue } from "@nylorun/core/define";
|
|
8
|
+
/** Compiled definition pieces plus the per-run model adapter for one step. */
|
|
9
|
+
export interface StepRuntime {
|
|
10
|
+
readonly middleware: readonly BoundMiddleware[];
|
|
11
|
+
readonly invoke: ModelAdapter;
|
|
12
|
+
readonly registry: ToolRegistry;
|
|
13
|
+
/** Full definition for before/after dynamics (optional for middleware-only agents). */
|
|
14
|
+
readonly definition?: AgentDefinition;
|
|
15
|
+
/** Mutable session memory bag shared with tools. */
|
|
16
|
+
sessionState?: Record<string, JsonValue>;
|
|
17
|
+
/** Called after Patch/Decision applied so the host can record. */
|
|
18
|
+
recordAfterDynamics?: () => Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
export interface StepInput {
|
|
21
|
+
readonly executionId: string;
|
|
22
|
+
readonly turnId: string;
|
|
23
|
+
readonly stepId: string;
|
|
24
|
+
/** One-based position of this turn within the execution. */
|
|
25
|
+
readonly turnNumber: number;
|
|
26
|
+
/** One-based position of this Model Step within the Turn. */
|
|
27
|
+
readonly stepNumber: number;
|
|
28
|
+
readonly info?: unknown;
|
|
29
|
+
readonly arrivals: readonly InputEvent[];
|
|
30
|
+
readonly toolResults: readonly ToolResult[];
|
|
31
|
+
readonly transcript: readonly TranscriptEntry[];
|
|
32
|
+
}
|
|
33
|
+
/** Internal view consumed by a single model step. */
|
|
34
|
+
export interface ExecutionSnapshot {
|
|
35
|
+
readonly id: string;
|
|
36
|
+
readonly status: "running";
|
|
37
|
+
readonly turnCount: number;
|
|
38
|
+
readonly revision: number;
|
|
39
|
+
readonly transcript: readonly TranscriptEntry[];
|
|
40
|
+
}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
1
|
+
import type { BoundToolDefinition } from "@nylorun/core/define";
|
|
2
|
+
import type { ModelCandidate } from "@nylorun/core/define";
|
|
3
|
+
import type { JsonValue, Tripwire } from "@nylorun/core/define";
|
|
4
|
+
import type { RequiredInteraction, ToolOwner, ToolResult } from "@nylorun/core/define";
|
|
4
5
|
import type { StepContext } from "./step-context.js";
|
|
5
|
-
import type { TurnOutputContract } from "
|
|
6
|
+
import type { TurnOutputContract } from "@nylorun/core/define";
|
|
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:
|
|
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 "
|
|
3
|
-
import { HarnessError, isHarnessError } from "
|
|
4
|
-
import { assertJson, copyJson } from "
|
|
2
|
+
import { createId } from "../../utils/ids.js";
|
|
3
|
+
import { HarnessError, isHarnessError } from "@nylorun/core/define";
|
|
4
|
+
import { assertJson, copyJson } from "@nylorun/core/define";
|
|
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
|
|
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 "
|
|
1
|
+
import { type HarnessErrorCode } from "@nylorun/core/define";
|
|
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.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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 "
|
|
1
|
+
import { HarnessError } from "@nylorun/core/define";
|
|
2
2
|
/**
|
|
3
|
-
* Shared per-step slot store.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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 {
|
|
2
|
-
import type { StepInput
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
import type {
|
|
6
|
-
import type {
|
|
1
|
+
import type { BoundToolDefinition } from "@nylorun/core/define";
|
|
2
|
+
import type { StepInput } from "./runtime.js";
|
|
3
|
+
import type { InternalModelConfigurationSnapshot } from "./describe.js";
|
|
4
|
+
import type { ContextSnapshot, ModelCandidate, ModelDirective } from "@nylorun/core/define";
|
|
5
|
+
import type { StepRequest, StepResponse } from "@nylorun/core/define";
|
|
6
|
+
import type { Tripwire } from "@nylorun/core/define";
|
|
7
|
+
import type { ObserveEmit } from "../observe.js";
|
|
8
|
+
import type { Interaction } from "@nylorun/core/define";
|
|
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
|
|
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():
|
|
26
|
-
sealConfiguration(snapshot:
|
|
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 "
|
|
1
|
+
import { HarnessError, isHarnessError } from "@nylorun/core/define";
|
|
2
|
+
import { freezeGraph } from "@nylorun/core/define";
|
|
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
|
|
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
|
-
|
|
132
|
+
executionId: this.input.executionId,
|
|
142
133
|
turnId: this.input.turnId,
|
|
143
134
|
stepId: this.input.stepId,
|
|
144
|
-
|
|
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 "@nylorun/core/define";
|
|
2
|
+
import type { SavedToolCall } from "../types/execution.js";
|
|
3
|
+
import type { ToolOutcome, ToolResult } from "@nylorun/core/define";
|
|
4
|
+
export declare function toolResult(call: SavedToolCall, definition: BoundToolDefinition, outcome: ToolOutcome): ToolResult;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { HarnessError } from "@nylorun/core/define";
|
|
2
|
+
import { copyJson } from "@nylorun/core/define";
|
|
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
|
+
}
|
|
@@ -1,39 +1,20 @@
|
|
|
1
|
-
import { HarnessError } from "
|
|
2
|
-
import { normalizeCandidate } from "
|
|
3
|
-
import { assertJson, copyJson, copyJsonObject } from "
|
|
4
|
-
export function
|
|
1
|
+
import { HarnessError } from "@nylorun/core/define";
|
|
2
|
+
import { normalizeCandidate } from "./model/normalize.js";
|
|
3
|
+
import { assertJson, copyJson, copyJsonObject } from "@nylorun/core/define";
|
|
4
|
+
export function validateTranscript(value) {
|
|
5
5
|
try {
|
|
6
|
-
|
|
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 === "
|
|
11
|
+
if (cause instanceof HarnessError && cause.code === "execution.invalid-state")
|
|
10
12
|
throw cause;
|
|
11
|
-
throw new HarnessError("
|
|
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("
|
|
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("
|
|
262
|
+
throw new HarnessError("execution.invalid-state", message);
|
|
293
263
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { JsonObject, JsonValue } from "@nylorun/core/define";
|
|
2
|
+
/** Internal signal thrown by durable wait helpers; caught by the tool dispatcher. */
|
|
3
|
+
export declare class WaitSignal {
|
|
4
|
+
readonly outcome: {
|
|
5
|
+
readonly kind: "interaction-required";
|
|
6
|
+
readonly interaction: {
|
|
7
|
+
readonly kind: "approval" | "response";
|
|
8
|
+
readonly prompt: string;
|
|
9
|
+
readonly metadata?: JsonObject;
|
|
10
|
+
};
|
|
11
|
+
readonly token?: JsonValue;
|
|
12
|
+
readonly wait: {
|
|
13
|
+
readonly kind: "ask" | "approve" | "sleep" | "waitFor";
|
|
14
|
+
readonly waitId: string;
|
|
15
|
+
readonly name?: string;
|
|
16
|
+
};
|
|
17
|
+
} | {
|
|
18
|
+
readonly kind: "deferred";
|
|
19
|
+
readonly token?: JsonValue;
|
|
20
|
+
readonly wait: {
|
|
21
|
+
readonly kind: "ask" | "approve" | "sleep" | "waitFor";
|
|
22
|
+
readonly waitId: string;
|
|
23
|
+
readonly name?: string;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
readonly name = "WaitSignal";
|
|
27
|
+
constructor(outcome: {
|
|
28
|
+
readonly kind: "interaction-required";
|
|
29
|
+
readonly interaction: {
|
|
30
|
+
readonly kind: "approval" | "response";
|
|
31
|
+
readonly prompt: string;
|
|
32
|
+
readonly metadata?: JsonObject;
|
|
33
|
+
};
|
|
34
|
+
readonly token?: JsonValue;
|
|
35
|
+
readonly wait: {
|
|
36
|
+
readonly kind: "ask" | "approve" | "sleep" | "waitFor";
|
|
37
|
+
readonly waitId: string;
|
|
38
|
+
readonly name?: string;
|
|
39
|
+
};
|
|
40
|
+
} | {
|
|
41
|
+
readonly kind: "deferred";
|
|
42
|
+
readonly token?: JsonValue;
|
|
43
|
+
readonly wait: {
|
|
44
|
+
readonly kind: "ask" | "approve" | "sleep" | "waitFor";
|
|
45
|
+
readonly waitId: string;
|
|
46
|
+
readonly name?: string;
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export declare function isWaitSignal(value: unknown): value is WaitSignal;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Internal signal thrown by durable wait helpers; caught by the tool dispatcher. */
|
|
2
|
+
export class WaitSignal {
|
|
3
|
+
outcome;
|
|
4
|
+
name = "WaitSignal";
|
|
5
|
+
constructor(outcome) {
|
|
6
|
+
this.outcome = outcome;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function isWaitSignal(value) {
|
|
10
|
+
return value instanceof WaitSignal;
|
|
11
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { AgentManifest } from "@nylorun/core/define";
|
|
2
|
+
import type { ExecutionInput, ExecutionState, RunResult } from "../types/execution.js";
|
|
3
|
+
import type { JsonObject } from "@nylorun/core/define";
|
|
4
|
+
import type { ActionOutcome } from "@nylorun/core/contracts";
|
|
5
|
+
import { ENGINE_VERSION } from "../compatibility.js";
|
|
6
|
+
/** Private persistence contract for hosts; this is not a session wire type. */
|
|
7
|
+
export interface DurableCheckpoint {
|
|
8
|
+
readonly version: 1;
|
|
9
|
+
readonly engineVersion: typeof ENGINE_VERSION;
|
|
10
|
+
readonly manifestHash: string;
|
|
11
|
+
readonly sessionId: string;
|
|
12
|
+
readonly turnId: string;
|
|
13
|
+
/** Increment for each human/event continuation, not for an action result. */
|
|
14
|
+
readonly segment: number;
|
|
15
|
+
readonly input: ExecutionInput;
|
|
16
|
+
readonly state?: ExecutionState;
|
|
17
|
+
readonly info?: JsonObject;
|
|
18
|
+
}
|
|
19
|
+
export interface HostEffect {
|
|
20
|
+
readonly effectId: string;
|
|
21
|
+
readonly sessionId: string;
|
|
22
|
+
readonly turnId: string;
|
|
23
|
+
readonly agentId: string;
|
|
24
|
+
readonly manifestHash: string;
|
|
25
|
+
readonly kind: "model" | "tool" | "beforeModelCall" | "afterModelCall";
|
|
26
|
+
readonly capabilityId?: string;
|
|
27
|
+
readonly toolName?: string;
|
|
28
|
+
readonly input: unknown;
|
|
29
|
+
readonly context: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
export type EffectResolution = {
|
|
32
|
+
readonly status: "completed";
|
|
33
|
+
readonly outcome: ActionOutcome;
|
|
34
|
+
} | {
|
|
35
|
+
readonly status: "pending" | "uncertain";
|
|
36
|
+
};
|
|
37
|
+
export interface DurableHost {
|
|
38
|
+
/** Atomically load-or-create by effectId; validate identical request on replay.
|
|
39
|
+
* Return recorded outcomes. Record intent BEFORE invoking a provider or exposing
|
|
40
|
+
* customer work. Uncertain effects must never be automatically executed again.
|
|
41
|
+
*/
|
|
42
|
+
resolveEffect(effect: HostEffect): Promise<EffectResolution>;
|
|
43
|
+
}
|
|
44
|
+
export type DurableResult = {
|
|
45
|
+
readonly status: "waiting" | "uncertain";
|
|
46
|
+
readonly checkpoint: DurableCheckpoint;
|
|
47
|
+
readonly effectIds: readonly string[];
|
|
48
|
+
} | {
|
|
49
|
+
readonly status: "completed" | "paused" | "cancelled" | "failed";
|
|
50
|
+
readonly checkpoint: DurableCheckpoint;
|
|
51
|
+
readonly result: RunResult<unknown>;
|
|
52
|
+
};
|
|
53
|
+
export declare function createDurableCheckpoint(input: {
|
|
54
|
+
manifest: AgentManifest;
|
|
55
|
+
sessionId: string;
|
|
56
|
+
turnId: string;
|
|
57
|
+
input: ExecutionInput;
|
|
58
|
+
state?: ExecutionState;
|
|
59
|
+
info?: JsonObject;
|
|
60
|
+
segment?: number;
|
|
61
|
+
}): DurableCheckpoint;
|
|
62
|
+
/** Deterministic reconstruction uses individually journaled effects, never a replayable whole loop.
|
|
63
|
+
* A suspended checkpoint is the immutable segment start plus the host's durable effect journal.
|
|
64
|
+
* Returning waiting releases all execution stacks; no process-local continuation survives.
|
|
65
|
+
*/
|
|
66
|
+
export declare function runDurable(options: {
|
|
67
|
+
manifest: AgentManifest;
|
|
68
|
+
checkpoint: DurableCheckpoint;
|
|
69
|
+
host: DurableHost;
|
|
70
|
+
signal?: AbortSignal;
|
|
71
|
+
}): Promise<DurableResult>;
|