@nylorun/harness 0.8.0-beta.1 → 0.11.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 +64 -0
- package/README.md +5 -38
- package/dist/build/assemble.js +1 -0
- package/dist/build/bind-tool.js +4 -3
- package/dist/build/builder.js +26 -0
- package/dist/build/helpers.d.ts +2 -2
- package/dist/build/manifest.js +12 -1
- package/dist/build/schema.d.ts +11 -16
- package/dist/build/schema.js +141 -22
- package/dist/errors.d.ts +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.js +2 -0
- package/dist/model/adapters.d.ts +160 -0
- package/dist/model/adapters.js +545 -0
- package/dist/{model-normalize.d.ts → model/normalize.d.ts} +2 -2
- package/dist/{model-normalize.js → model/normalize.js} +35 -4
- package/dist/model/prepared.d.ts +16 -0
- package/dist/model/prepared.js +11 -0
- package/dist/session/event-log.d.ts +4 -3
- package/dist/session/input-queue.d.ts +7 -4
- package/dist/session/input-queue.js +12 -0
- package/dist/session/output-contract.d.ts +6 -0
- package/dist/session/output-contract.js +12 -0
- package/dist/session/scheduler.js +1 -1
- package/dist/session/seed.js +79 -5
- package/dist/session/session.d.ts +8 -5
- package/dist/session/session.js +38 -2
- package/dist/session/state.d.ts +1 -1
- package/dist/session/submission-stream.d.ts +5 -4
- package/dist/step/context-draft.js +1 -7
- package/dist/step/model-configuration.js +6 -20
- package/dist/step/project.js +25 -3
- package/dist/step/resolve.d.ts +1 -0
- package/dist/step/resolve.js +1 -0
- package/dist/step/run.d.ts +1 -0
- package/dist/step/run.js +25 -4
- package/dist/step/seal.d.ts +4 -2
- package/dist/step/seal.js +64 -13
- package/dist/step/step-context.js +1 -1
- package/dist/turn/plan-runner.js +38 -3
- package/dist/turn/runner.d.ts +6 -4
- package/dist/turn/runner.js +6 -4
- package/dist/types/manifest.d.ts +5 -4
- package/dist/types/middleware.d.ts +10 -1
- package/dist/types/model.d.ts +21 -13
- package/dist/types/session.d.ts +34 -13
- package/dist/types/shared.d.ts +16 -3
- package/dist/types/tool.d.ts +54 -17
- package/package.json +15 -12
- package/dist/utils/digest.d.ts +0 -1
- package/dist/utils/digest.js +0 -14
package/dist/step/seal.js
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
|
-
import { textFromOutput } from "../model
|
|
1
|
+
import { textFromOutput } from "../model/normalize.js";
|
|
2
2
|
import { createId } from "../utils/ids.js";
|
|
3
3
|
import { HarnessError, isHarnessError } from "../errors.js";
|
|
4
4
|
import { assertJson, copyJson } from "../utils/immutable.js";
|
|
5
|
-
const failed = (callId, toolName, code, message) => Object.freeze({
|
|
5
|
+
const failed = (callId, toolName, code, message, details) => Object.freeze({
|
|
6
|
+
kind: "failed",
|
|
7
|
+
callId,
|
|
8
|
+
toolName,
|
|
9
|
+
code,
|
|
10
|
+
message,
|
|
11
|
+
...(details ? { details } : {}),
|
|
12
|
+
});
|
|
6
13
|
/** Converts the reviewed canonical candidate into either a final response or an executable tool plan. */
|
|
7
|
-
export function sealStep(context) {
|
|
14
|
+
export function sealStep(context, outputContract) {
|
|
8
15
|
if (context.currentTripwire)
|
|
9
16
|
return Object.freeze({ kind: "tripwire", tripwire: context.currentTripwire });
|
|
10
17
|
if (context.currentModelDeferred)
|
|
11
18
|
return Object.freeze({ kind: "deferred-model", active: context.currentModelDeferred });
|
|
12
19
|
const calls = context.canonicalCalls();
|
|
13
|
-
if (!calls.length)
|
|
20
|
+
if (!calls.length) {
|
|
21
|
+
if (outputContract)
|
|
22
|
+
return sealStructuredOutput(context, outputContract);
|
|
14
23
|
return Object.freeze({
|
|
15
24
|
kind: "final",
|
|
16
25
|
output: textFromOutput(context.currentCandidate?.output ?? []),
|
|
17
26
|
});
|
|
27
|
+
}
|
|
18
28
|
const catalog = context.catalogByName;
|
|
19
29
|
const sealed = calls.map((call) => sealCall(context, catalog, call));
|
|
20
30
|
const canonicalCandidate = context.currentCandidate ?? Object.freeze({ output: Object.freeze([]) });
|
|
@@ -28,6 +38,28 @@ export function sealStep(context) {
|
|
|
28
38
|
}),
|
|
29
39
|
});
|
|
30
40
|
}
|
|
41
|
+
function sealStructuredOutput(context, contract) {
|
|
42
|
+
const output = context.currentCandidate?.output ?? [];
|
|
43
|
+
const json = output.filter((block) => block.type === "json");
|
|
44
|
+
if (json.length !== 1 || output.some((block) => block.type === "text"))
|
|
45
|
+
return invalidOutput("Structured terminal output must contain exactly one JSON block and no text blocks");
|
|
46
|
+
const validation = contract.schema.validate(json[0].value);
|
|
47
|
+
if (!validation.ok)
|
|
48
|
+
return invalidOutput(`Structured terminal output failed validation: ${validation.issues.map(renderIssue).join("; ")}`);
|
|
49
|
+
try {
|
|
50
|
+
assertJson(validation.value, "structured terminal output");
|
|
51
|
+
return Object.freeze({ kind: "final", output: copyJson(validation.value) });
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
return invalidOutput(error instanceof Error ? error.message : String(error));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function invalidOutput(message) {
|
|
58
|
+
return Object.freeze({
|
|
59
|
+
kind: "tripwire",
|
|
60
|
+
tripwire: Object.freeze({ code: "output.invalid", message }),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
31
63
|
function sealCall(context, catalog, candidate) {
|
|
32
64
|
const order = Object.freeze({ callId: candidate.id, toolName: candidate.name });
|
|
33
65
|
const canonical = Object.freeze({
|
|
@@ -55,11 +87,11 @@ function sealCall(context, catalog, candidate) {
|
|
|
55
87
|
immediate: failed(candidate.id, candidate.name, "tool.unknown", `Unknown Tool '${candidate.name}'`),
|
|
56
88
|
};
|
|
57
89
|
const args = validatedArguments(tool, candidate);
|
|
58
|
-
if (
|
|
90
|
+
if (!args.ok)
|
|
59
91
|
return {
|
|
60
92
|
order,
|
|
61
93
|
canonical,
|
|
62
|
-
immediate: failed(candidate.id, candidate.name, args.
|
|
94
|
+
immediate: failed(candidate.id, candidate.name, "tool.invalid-arguments", args.message, args.details),
|
|
63
95
|
};
|
|
64
96
|
const denial = context.denialFor(candidate.id);
|
|
65
97
|
if (denial)
|
|
@@ -84,26 +116,45 @@ function sealCall(context, catalog, candidate) {
|
|
|
84
116
|
call: Object.freeze({
|
|
85
117
|
callId: candidate.id,
|
|
86
118
|
toolName: candidate.name,
|
|
87
|
-
args,
|
|
119
|
+
args: args.value,
|
|
88
120
|
}),
|
|
89
121
|
invocationId: createId("invocation"),
|
|
90
122
|
owner: tool.owner,
|
|
91
123
|
execute: tool.execute,
|
|
124
|
+
...(tool.outputSchema === undefined ? {} : { outputSchema: tool.outputSchema }),
|
|
92
125
|
...(interaction ? { interaction } : {}),
|
|
93
126
|
}),
|
|
94
127
|
};
|
|
95
128
|
}
|
|
96
129
|
function validatedArguments(tool, candidate) {
|
|
97
|
-
const validation = tool.
|
|
130
|
+
const validation = tool.inputSchema.validate(candidate.args);
|
|
98
131
|
if (!validation.ok)
|
|
99
|
-
return
|
|
132
|
+
return {
|
|
133
|
+
ok: false,
|
|
134
|
+
message: validation.issues.map(renderIssue).join("; "),
|
|
135
|
+
details: Object.freeze({ phase: "input", issues: validation.issues }),
|
|
136
|
+
};
|
|
100
137
|
try {
|
|
101
138
|
assertJson(validation.value, `arguments for '${candidate.name}'`);
|
|
102
|
-
return copyJson(validation.value);
|
|
139
|
+
return { ok: true, value: copyJson(validation.value) };
|
|
103
140
|
}
|
|
104
141
|
catch (error) {
|
|
105
|
-
return
|
|
106
|
-
|
|
107
|
-
:
|
|
142
|
+
return {
|
|
143
|
+
ok: false,
|
|
144
|
+
message: isHarnessError(error) ? error.message : String(error),
|
|
145
|
+
details: Object.freeze({
|
|
146
|
+
phase: "input",
|
|
147
|
+
issues: Object.freeze([
|
|
148
|
+
Object.freeze({
|
|
149
|
+
path: Object.freeze([]),
|
|
150
|
+
code: "invalid_json",
|
|
151
|
+
message: isHarnessError(error) ? error.message : String(error),
|
|
152
|
+
}),
|
|
153
|
+
]),
|
|
154
|
+
}),
|
|
155
|
+
};
|
|
108
156
|
}
|
|
109
157
|
}
|
|
158
|
+
function renderIssue(issue) {
|
|
159
|
+
return `${issue.path.join(".") || "(root)"}: ${issue.message}`;
|
|
160
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HarnessError, isHarnessError } from "../errors.js";
|
|
2
2
|
import { callsFromCanonical, candidateFromCanonical, canonicalizeOutput, identityKey, } from "./canonicalize.js";
|
|
3
|
-
import { normalizeCandidate } from "../model
|
|
3
|
+
import { normalizeCandidate } from "../model/normalize.js";
|
|
4
4
|
import { ContextDraft } from "./context-draft.js";
|
|
5
5
|
import { ModelConfigurationDraft } from "./model-configuration.js";
|
|
6
6
|
const branded = new WeakSet();
|
package/dist/turn/plan-runner.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HarnessError, isHarnessError } from "../errors.js";
|
|
2
2
|
import { createId } from "../utils/ids.js";
|
|
3
|
-
import { copyJson, copyJsonObject } from "../utils/immutable.js";
|
|
3
|
+
import { assertJson, copyJson, copyJsonObject } from "../utils/immutable.js";
|
|
4
4
|
/** Owns one sealed plan's deterministic interaction and concurrent execution progress. */
|
|
5
5
|
export class ToolPlanRunner {
|
|
6
6
|
plan;
|
|
@@ -309,8 +309,18 @@ function resumeValue(event, pending) {
|
|
|
309
309
|
function resultFrom(entry, outcome) {
|
|
310
310
|
const base = { callId: entry.call.callId, toolName: entry.call.toolName };
|
|
311
311
|
switch (outcome.kind) {
|
|
312
|
-
case "completed":
|
|
313
|
-
|
|
312
|
+
case "completed": {
|
|
313
|
+
const output = validatedOutput(entry, outcome.output);
|
|
314
|
+
if (!output.ok)
|
|
315
|
+
return Object.freeze({
|
|
316
|
+
...base,
|
|
317
|
+
kind: "failed",
|
|
318
|
+
code: "tool.invalid-output",
|
|
319
|
+
message: output.message,
|
|
320
|
+
details: output.details,
|
|
321
|
+
});
|
|
322
|
+
return Object.freeze({ ...base, kind: "completed", output: output.value });
|
|
323
|
+
}
|
|
314
324
|
case "denied":
|
|
315
325
|
if (typeof outcome.reason !== "string")
|
|
316
326
|
throw new HarnessError("tool.invalid-tool-result", "Tool denial reason must be a string");
|
|
@@ -326,6 +336,31 @@ function resultFrom(entry, outcome) {
|
|
|
326
336
|
});
|
|
327
337
|
}
|
|
328
338
|
}
|
|
339
|
+
function validatedOutput(entry, value) {
|
|
340
|
+
const validation = entry.outputSchema?.validate(value) ?? { ok: true, value };
|
|
341
|
+
if (!validation.ok)
|
|
342
|
+
return validationFailure("output", validation.issues);
|
|
343
|
+
try {
|
|
344
|
+
assertJson(validation.value, `output for '${entry.call.toolName}'`);
|
|
345
|
+
return { ok: true, value: copyJson(validation.value) };
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
return validationFailure("output", [
|
|
349
|
+
Object.freeze({
|
|
350
|
+
path: Object.freeze([]),
|
|
351
|
+
code: "invalid_json",
|
|
352
|
+
message: error instanceof Error ? error.message : String(error),
|
|
353
|
+
}),
|
|
354
|
+
]);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function validationFailure(phase, issues) {
|
|
358
|
+
return {
|
|
359
|
+
ok: false,
|
|
360
|
+
message: issues.map((item) => `${item.path.join(".") || "(root)"}: ${item.message}`).join("; "),
|
|
361
|
+
details: Object.freeze({ phase, issues: Object.freeze([...issues]) }),
|
|
362
|
+
};
|
|
363
|
+
}
|
|
329
364
|
function completedEvent(entry, context, result) {
|
|
330
365
|
return {
|
|
331
366
|
type: "tool.completed",
|
package/dist/turn/runner.d.ts
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import type { ActiveExecutionRecord, InputEvent, SessionEvent, SessionRecord, SessionSnapshot } from "../types/session.js";
|
|
2
|
-
import type { JsonObject, Tripwire } from "../types/shared.js";
|
|
2
|
+
import type { JsonObject, JsonValue, Tripwire } from "../types/shared.js";
|
|
3
3
|
import type { RequiredInteraction } from "../types/tool.js";
|
|
4
4
|
import type { LoopAgent } from "../build/agent.js";
|
|
5
5
|
import type { ObserveEmit } from "../utils/observe.js";
|
|
6
6
|
import { ToolPlanRunner } from "./plan-runner.js";
|
|
7
7
|
import type { CapabilityStateRegistry } from "../session/capability-state.js";
|
|
8
|
+
import type { TurnOutputContract } from "../session/output-contract.js";
|
|
8
9
|
export interface PendingTurn {
|
|
9
10
|
readonly plan: ToolPlanRunner;
|
|
10
11
|
readonly turnId: string;
|
|
11
12
|
readonly stepId: string;
|
|
12
13
|
readonly stepNumber: number;
|
|
14
|
+
readonly output?: TurnOutputContract;
|
|
13
15
|
}
|
|
14
16
|
export type TurnProgress = {
|
|
15
17
|
readonly kind: "final";
|
|
16
18
|
readonly state: SessionSnapshot;
|
|
17
19
|
readonly turnId: string;
|
|
18
20
|
readonly stepId: string;
|
|
19
|
-
readonly output:
|
|
21
|
+
readonly output: JsonValue;
|
|
20
22
|
} | {
|
|
21
23
|
readonly kind: "interaction-required";
|
|
22
24
|
readonly state: SessionSnapshot;
|
|
@@ -42,7 +44,7 @@ export interface TurnRunContext {
|
|
|
42
44
|
readonly assertCurrent: () => void;
|
|
43
45
|
readonly onPlanActive: (pending: PendingTurn | undefined) => void;
|
|
44
46
|
readonly commit: (state: SessionSnapshot, transition: SessionRecord["transition"], active?: ActiveExecutionRecord) => Promise<SessionSnapshot>;
|
|
45
|
-
readonly onConversation: (event: SessionEvent) => void;
|
|
47
|
+
readonly onConversation: (event: SessionEvent<JsonValue>) => void;
|
|
46
48
|
readonly claimInterrupts: (state: SessionSnapshot, turnId: string) => Promise<{
|
|
47
49
|
readonly state: SessionSnapshot;
|
|
48
50
|
readonly arrivals: readonly InputEvent[];
|
|
@@ -57,7 +59,7 @@ export declare class TurnRunner {
|
|
|
57
59
|
readonly userId?: string;
|
|
58
60
|
readonly context?: JsonObject;
|
|
59
61
|
}>);
|
|
60
|
-
start(state: SessionSnapshot, event: InputEvent, context: TurnRunContext): Promise<TurnProgress>;
|
|
62
|
+
start(state: SessionSnapshot, event: InputEvent, context: TurnRunContext, output?: TurnOutputContract): Promise<TurnProgress>;
|
|
61
63
|
continue(state: SessionSnapshot, context: TurnRunContext): Promise<TurnProgress>;
|
|
62
64
|
resume(state: SessionSnapshot, pending: PendingTurn, event: InputEvent, context: TurnRunContext): Promise<TurnProgress>;
|
|
63
65
|
private advance;
|
package/dist/turn/runner.js
CHANGED
|
@@ -13,11 +13,11 @@ export class TurnRunner {
|
|
|
13
13
|
this.sessionId = sessionId;
|
|
14
14
|
this.session = session;
|
|
15
15
|
}
|
|
16
|
-
async start(state, event, context) {
|
|
16
|
+
async start(state, event, context, output) {
|
|
17
17
|
const turnId = createId("turn");
|
|
18
18
|
state = await context.commit(beginTurn(state, turnId, event), "input");
|
|
19
19
|
context.onConversation({ type: "input", event, turnId });
|
|
20
|
-
return this.advance(state, turnId, 1, [event], [], context);
|
|
20
|
+
return this.advance(state, turnId, 1, [event], [], context, output);
|
|
21
21
|
}
|
|
22
22
|
async continue(state, context) {
|
|
23
23
|
const turnId = createId("turn");
|
|
@@ -36,9 +36,9 @@ export class TurnRunner {
|
|
|
36
36
|
state = await context.commit(commitToolResults(state, pending.turnId, pending.stepId, progress.results), "tool-results");
|
|
37
37
|
pending.plan.publishSettlements(context.observe);
|
|
38
38
|
const claimed = await context.claimInterrupts(state, pending.turnId);
|
|
39
|
-
return this.advance(claimed.state, pending.turnId, pending.stepNumber + 1, claimed.arrivals, progress.results, context);
|
|
39
|
+
return this.advance(claimed.state, pending.turnId, pending.stepNumber + 1, claimed.arrivals, progress.results, context, pending.output);
|
|
40
40
|
}
|
|
41
|
-
async advance(initialState, turnId, firstStep, arrivals, initialResults, context) {
|
|
41
|
+
async advance(initialState, turnId, firstStep, arrivals, initialResults, context, output) {
|
|
42
42
|
let state = initialState;
|
|
43
43
|
let stepArrivals = arrivals;
|
|
44
44
|
let toolResults = initialResults;
|
|
@@ -58,6 +58,7 @@ export class TurnRunner {
|
|
|
58
58
|
signal: context.signal,
|
|
59
59
|
session: this.session,
|
|
60
60
|
states: context.states,
|
|
61
|
+
output,
|
|
61
62
|
recordModelRequested: (next, active) => context.commit(next, "model-requested", active),
|
|
62
63
|
});
|
|
63
64
|
context.assertCurrent();
|
|
@@ -68,6 +69,7 @@ export class TurnRunner {
|
|
|
68
69
|
turnId,
|
|
69
70
|
stepId,
|
|
70
71
|
stepNumber,
|
|
72
|
+
...(output === undefined ? {} : { output }),
|
|
71
73
|
}
|
|
72
74
|
: undefined;
|
|
73
75
|
if (run.candidate) {
|
package/dist/types/manifest.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import type { BoundMiddleware } from "./middleware.js";
|
|
1
|
+
import type { BoundMiddleware, MiddlewareContributions } from "./middleware.js";
|
|
2
2
|
import type { BuildDiagnostic } from "./shared.js";
|
|
3
|
+
export interface MiddlewareManifest extends MiddlewareContributions {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
}
|
|
3
6
|
export interface AgentManifest {
|
|
4
7
|
readonly id: string;
|
|
5
8
|
readonly name: string;
|
|
6
|
-
readonly middleware: readonly
|
|
7
|
-
readonly id: string;
|
|
8
|
-
}[];
|
|
9
|
+
readonly middleware: readonly MiddlewareManifest[];
|
|
9
10
|
}
|
|
10
11
|
export type BuildResult<Agent> = {
|
|
11
12
|
readonly ok: true;
|
|
@@ -72,15 +72,24 @@ export type CapabilityItems<Item> = readonly Item[] | Readonly<{
|
|
|
72
72
|
/** A named capability that may supply static model surface and one typed middleware handler. */
|
|
73
73
|
export interface CapabilityDeclaration<State = never> {
|
|
74
74
|
readonly id: string;
|
|
75
|
-
readonly tools?: CapabilityItems<ToolDefinition<ToolDefinition["
|
|
75
|
+
readonly tools?: CapabilityItems<ToolDefinition<ToolDefinition["inputSchema"], State>>;
|
|
76
76
|
readonly instructions?: CapabilityItems<string>;
|
|
77
77
|
readonly model?: ModelDirective;
|
|
78
78
|
readonly state?: CapabilityState<State>;
|
|
79
79
|
readonly middleware?: StepMiddleware<State>;
|
|
80
80
|
}
|
|
81
|
+
export interface MiddlewareContributions {
|
|
82
|
+
readonly instructions?: readonly string[];
|
|
83
|
+
readonly tools?: readonly {
|
|
84
|
+
readonly name: string;
|
|
85
|
+
readonly description?: string;
|
|
86
|
+
}[];
|
|
87
|
+
readonly model?: Pick<ModelDirective, "id" | "controls">;
|
|
88
|
+
}
|
|
81
89
|
export interface BoundMiddleware {
|
|
82
90
|
readonly id: string;
|
|
83
91
|
readonly handle: StepMiddleware;
|
|
84
92
|
readonly state?: CapabilityState<unknown>;
|
|
93
|
+
readonly contributions?: MiddlewareContributions;
|
|
85
94
|
}
|
|
86
95
|
export {};
|
package/dist/types/model.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ContextItem, DeferredOutcome, JsonObject } from "./shared.js";
|
|
1
|
+
import type { ContextItem, DeferredOutcome, JsonObject, JsonValue } from "./shared.js";
|
|
2
2
|
import type { InputEvent, TranscriptEntry } from "./session.js";
|
|
3
3
|
import type { BoundToolDefinition, ToolResult } from "./tool.js";
|
|
4
4
|
export interface ModelToolCall {
|
|
@@ -12,6 +12,9 @@ export type ModelOutputBlock = {
|
|
|
12
12
|
} | {
|
|
13
13
|
readonly type: "reasoning";
|
|
14
14
|
readonly text: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly type: "json";
|
|
17
|
+
readonly value: JsonValue;
|
|
15
18
|
} | {
|
|
16
19
|
readonly type: "tool-call";
|
|
17
20
|
readonly id: string;
|
|
@@ -58,34 +61,27 @@ export interface ModelConfigurationContributor {
|
|
|
58
61
|
readonly middlewareId: string;
|
|
59
62
|
readonly slot: string;
|
|
60
63
|
readonly order: number;
|
|
61
|
-
readonly digest: string;
|
|
62
64
|
readonly reason?: string;
|
|
63
65
|
}
|
|
64
66
|
export interface ModelConfigurationTool {
|
|
65
67
|
readonly name: string;
|
|
66
68
|
readonly description?: string;
|
|
67
69
|
readonly inputSchema: JsonObject;
|
|
68
|
-
readonly
|
|
70
|
+
readonly outputSchema?: JsonObject;
|
|
69
71
|
readonly contributor: ModelConfigurationContributor;
|
|
70
72
|
}
|
|
71
73
|
export interface ModelConfigurationInstruction {
|
|
72
74
|
readonly text: string;
|
|
73
|
-
readonly digest: string;
|
|
74
75
|
readonly contributor: ModelConfigurationContributor;
|
|
75
76
|
}
|
|
76
77
|
export interface ModelConfigurationSnapshot {
|
|
77
78
|
readonly version: 1;
|
|
78
79
|
readonly model?: ModelDirective;
|
|
79
80
|
readonly instructions: readonly ModelConfigurationInstruction[];
|
|
80
|
-
/** Bound tools are retained for execution
|
|
81
|
+
/** Bound tools are retained for execution. */
|
|
81
82
|
readonly tools: readonly BoundToolDefinition[];
|
|
82
83
|
readonly toolContracts: readonly ModelConfigurationTool[];
|
|
83
84
|
readonly contributors: readonly ModelConfigurationContributor[];
|
|
84
|
-
readonly digests: Readonly<{
|
|
85
|
-
readonly logical: string;
|
|
86
|
-
readonly model: string;
|
|
87
|
-
readonly request: string;
|
|
88
|
-
}>;
|
|
89
85
|
}
|
|
90
86
|
/** A middleware-owned declaration for this model call's runtime context. */
|
|
91
87
|
export interface ContextMutationOptions {
|
|
@@ -96,14 +92,12 @@ export interface ContextContributor {
|
|
|
96
92
|
readonly middlewareId: string;
|
|
97
93
|
readonly slot: string;
|
|
98
94
|
readonly order: number;
|
|
99
|
-
readonly digest: string;
|
|
100
95
|
readonly reason?: string;
|
|
101
96
|
}
|
|
102
|
-
/** Canonical runtime context for one model call.
|
|
97
|
+
/** Canonical runtime context for one model call. */
|
|
103
98
|
export interface ContextSnapshot {
|
|
104
99
|
readonly items: readonly ContextItem[];
|
|
105
100
|
readonly contributors: readonly ContextContributor[];
|
|
106
|
-
readonly digest: string;
|
|
107
101
|
}
|
|
108
102
|
export interface ModelRequest {
|
|
109
103
|
readonly sessionId: string;
|
|
@@ -119,10 +113,16 @@ export interface ModelRequest {
|
|
|
119
113
|
readonly toolResults: readonly ToolResult[];
|
|
120
114
|
/** Tools are normalized and immutable by the time a Model sees them. */
|
|
121
115
|
readonly tools: readonly BoundToolDefinition[];
|
|
116
|
+
/** Optional portable contract for this turn's terminal JSON result. */
|
|
117
|
+
readonly outputSchema?: JsonObject;
|
|
122
118
|
}
|
|
123
119
|
export type PromptContentPart = {
|
|
124
120
|
readonly type: "text";
|
|
125
121
|
readonly text: string;
|
|
122
|
+
} | {
|
|
123
|
+
readonly type: "media";
|
|
124
|
+
readonly mediaType: string;
|
|
125
|
+
readonly reference: JsonValue;
|
|
126
126
|
} | {
|
|
127
127
|
readonly type: "tool-call";
|
|
128
128
|
readonly id: string;
|
|
@@ -157,11 +157,19 @@ export interface ModelCall {
|
|
|
157
157
|
readonly model?: ModelDirective;
|
|
158
158
|
readonly prompt: readonly PromptItem[];
|
|
159
159
|
readonly tools: readonly ModelCallTool[];
|
|
160
|
+
/** Optional portable contract for this turn's terminal JSON result. */
|
|
161
|
+
readonly outputSchema?: JsonObject;
|
|
160
162
|
readonly sessionId: string;
|
|
161
163
|
}
|
|
162
164
|
export interface ModelAdapterContext {
|
|
163
165
|
readonly request: ModelRequest;
|
|
164
166
|
readonly invocationId: string;
|
|
165
167
|
readonly signal: AbortSignal;
|
|
168
|
+
/** Publishes one JSON-safe provider request derived from the canonical ModelCall. */
|
|
169
|
+
reportPreparedCall(prepared: ModelPreparedCall): void;
|
|
170
|
+
}
|
|
171
|
+
export interface ModelPreparedCall {
|
|
172
|
+
readonly adapter: string;
|
|
173
|
+
readonly call: JsonValue;
|
|
166
174
|
}
|
|
167
175
|
export type ModelAdapter = (call: ModelCall, context: ModelAdapterContext) => Promise<ModelCandidate | string | DeferredOutcome>;
|
package/dist/types/session.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import type { ModelCall, ModelCandidate } from "./model.js";
|
|
2
2
|
import type { JsonObject, JsonValue, Observer, Tripwire } from "./shared.js";
|
|
3
|
-
import type { RequiredInteraction, ToolExecutionResume, ToolOwner, ToolResult } from "./tool.js";
|
|
3
|
+
import type { RequiredInteraction, SchemaOutput, ToolExecutionResume, ToolOwner, ToolResult, ToolSchemaSource } from "./tool.js";
|
|
4
4
|
export type InputEvent = {
|
|
5
|
-
readonly kind: "user-message";
|
|
5
|
+
readonly kind: "user-message" | "interrupt";
|
|
6
6
|
readonly text: string;
|
|
7
7
|
readonly metadata?: JsonObject;
|
|
8
8
|
} | {
|
|
9
|
-
readonly kind: "interrupt";
|
|
10
|
-
readonly
|
|
9
|
+
readonly kind: "user-message" | "interrupt";
|
|
10
|
+
readonly content: readonly UserContentPart[];
|
|
11
|
+
/** Undefined for content-bearing events; retained for text-event narrowing compatibility. */
|
|
12
|
+
readonly text?: undefined;
|
|
11
13
|
readonly metadata?: JsonObject;
|
|
12
14
|
} | {
|
|
13
15
|
readonly kind: "approve";
|
|
@@ -18,7 +20,7 @@ export type InputEvent = {
|
|
|
18
20
|
readonly interactionId: string;
|
|
19
21
|
readonly value: JsonValue;
|
|
20
22
|
};
|
|
21
|
-
export type SessionEvent = {
|
|
23
|
+
export type SessionEvent<Output = string> = {
|
|
22
24
|
readonly type: "input";
|
|
23
25
|
readonly event: InputEvent;
|
|
24
26
|
readonly turnId: string;
|
|
@@ -29,7 +31,7 @@ export type SessionEvent = {
|
|
|
29
31
|
readonly candidate: ModelCandidate;
|
|
30
32
|
} | {
|
|
31
33
|
readonly type: "final";
|
|
32
|
-
readonly output:
|
|
34
|
+
readonly output: Output;
|
|
33
35
|
readonly turnId: string;
|
|
34
36
|
} | {
|
|
35
37
|
readonly type: "interaction.required";
|
|
@@ -58,14 +60,14 @@ export type SessionEvent = {
|
|
|
58
60
|
readonly type: "session.stopped";
|
|
59
61
|
readonly sessionId: string;
|
|
60
62
|
};
|
|
61
|
-
export interface InputCompletion {
|
|
63
|
+
export interface InputCompletion<Output = string> {
|
|
62
64
|
readonly inputId: string;
|
|
63
65
|
readonly status: "completed" | "waiting" | "rejected" | "cancelled" | "stopped";
|
|
64
|
-
readonly events: readonly SessionEvent[];
|
|
66
|
+
readonly events: readonly SessionEvent<Output>[];
|
|
65
67
|
}
|
|
66
|
-
export interface InputHandle {
|
|
68
|
+
export interface InputHandle<Output = string> {
|
|
67
69
|
readonly inputId: string;
|
|
68
|
-
readonly completed: Promise<InputCompletion
|
|
70
|
+
readonly completed: Promise<InputCompletion<Output>>;
|
|
69
71
|
}
|
|
70
72
|
export interface SessionOptions {
|
|
71
73
|
readonly id?: string;
|
|
@@ -91,9 +93,25 @@ export type SessionRunOptions = SessionOptions | SeededSessionOptions;
|
|
|
91
93
|
export interface InputOptions {
|
|
92
94
|
readonly signal?: AbortSignal;
|
|
93
95
|
}
|
|
96
|
+
/** Per-turn, locally-enforced terminal JSON contract. */
|
|
97
|
+
export interface OutputInputOptions<Schema extends ToolSchemaSource = ToolSchemaSource> extends InputOptions {
|
|
98
|
+
readonly outputSchema?: Schema;
|
|
99
|
+
}
|
|
100
|
+
/** Ordered, model-visible user content. Media references stay host-owned JSON values. */
|
|
101
|
+
export type UserContentPart = {
|
|
102
|
+
readonly type: "text";
|
|
103
|
+
readonly text: string;
|
|
104
|
+
} | {
|
|
105
|
+
readonly type: "media";
|
|
106
|
+
readonly mediaType: string;
|
|
107
|
+
readonly reference: JsonValue;
|
|
108
|
+
};
|
|
94
109
|
export type MessageInput = string | {
|
|
95
110
|
readonly text: string;
|
|
96
111
|
readonly metadata?: JsonObject;
|
|
112
|
+
} | {
|
|
113
|
+
readonly content: readonly UserContentPart[];
|
|
114
|
+
readonly metadata?: JsonObject;
|
|
97
115
|
};
|
|
98
116
|
export type InteractionReply = Extract<InputEvent, {
|
|
99
117
|
kind: "approve" | "respond";
|
|
@@ -121,7 +139,7 @@ export interface TranscriptFinalEntry {
|
|
|
121
139
|
readonly kind: "final";
|
|
122
140
|
readonly turnId: string;
|
|
123
141
|
readonly stepId: string;
|
|
124
|
-
readonly output:
|
|
142
|
+
readonly output: JsonValue;
|
|
125
143
|
}
|
|
126
144
|
export type TranscriptEntry = TranscriptInputEntry | TranscriptCandidateEntry | TranscriptToolsEntry | TranscriptFinalEntry;
|
|
127
145
|
export interface SessionSnapshot {
|
|
@@ -197,10 +215,13 @@ export interface SessionRecorder {
|
|
|
197
215
|
export interface Session {
|
|
198
216
|
readonly id: string;
|
|
199
217
|
readonly state: SessionSnapshot;
|
|
200
|
-
input(event:
|
|
218
|
+
input<Schema extends ToolSchemaSource>(event: MessageInput, options: OutputInputOptions<Schema> & {
|
|
219
|
+
readonly outputSchema: Schema;
|
|
220
|
+
}): InputHandle<SchemaOutput<Schema>>;
|
|
221
|
+
input(event: SessionInput, options?: InputOptions): InputHandle<string>;
|
|
201
222
|
interrupt(event: MessageInput, options?: InputOptions): InputHandle;
|
|
202
223
|
continue(options?: InputOptions): InputHandle;
|
|
203
|
-
stream(): AsyncIterable<SessionEvent
|
|
224
|
+
stream(): AsyncIterable<SessionEvent<JsonValue>>;
|
|
204
225
|
observe(listener: Observer): () => void;
|
|
205
226
|
stop(reason?: string): Promise<void>;
|
|
206
227
|
}
|
package/dist/types/shared.d.ts
CHANGED
|
@@ -33,7 +33,10 @@ export interface ObserveToolSnapshot {
|
|
|
33
33
|
readonly middlewareId: string;
|
|
34
34
|
readonly slot: string;
|
|
35
35
|
};
|
|
36
|
-
readonly
|
|
36
|
+
readonly inputSchema: {
|
|
37
|
+
readonly jsonSchema: JsonObject;
|
|
38
|
+
};
|
|
39
|
+
readonly outputSchema?: {
|
|
37
40
|
readonly jsonSchema: JsonObject;
|
|
38
41
|
};
|
|
39
42
|
}
|
|
@@ -55,7 +58,7 @@ export interface ObserveSealedCall {
|
|
|
55
58
|
export interface ObserveModelRequested {
|
|
56
59
|
/** The exact immutable logical input supplied to the ModelAdapter. */
|
|
57
60
|
readonly call: ModelCall;
|
|
58
|
-
/** Canonical configuration facts and attribution
|
|
61
|
+
/** Canonical configuration facts and attribution. */
|
|
59
62
|
readonly configuration: ObserveModelConfigurationSnapshot;
|
|
60
63
|
/** Current-step runtime context and attribution. */
|
|
61
64
|
readonly context: ContextSnapshot;
|
|
@@ -104,6 +107,16 @@ export type ObserveEvent = {
|
|
|
104
107
|
readonly inputId?: string;
|
|
105
108
|
readonly requestedModelId?: string;
|
|
106
109
|
readonly attributes: ObserveModelRequested;
|
|
110
|
+
} | {
|
|
111
|
+
readonly type: "model.prepared";
|
|
112
|
+
readonly turnId: string;
|
|
113
|
+
readonly stepId: string;
|
|
114
|
+
readonly inputId?: string;
|
|
115
|
+
readonly requestedModelId?: string;
|
|
116
|
+
readonly attributes: {
|
|
117
|
+
readonly adapter: string;
|
|
118
|
+
readonly call: JsonValue;
|
|
119
|
+
};
|
|
107
120
|
} | {
|
|
108
121
|
readonly type: "model.completed";
|
|
109
122
|
readonly turnId: string;
|
|
@@ -206,7 +219,7 @@ export type ObserveEvent = {
|
|
|
206
219
|
readonly stepId: string;
|
|
207
220
|
readonly inputId?: string;
|
|
208
221
|
readonly attributes: {
|
|
209
|
-
readonly output:
|
|
222
|
+
readonly output: JsonValue;
|
|
210
223
|
};
|
|
211
224
|
} | {
|
|
212
225
|
readonly type: "interaction.required";
|