@openpond/harness 0.2.6 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRACT.md +35 -0
- package/dist/index.js +4 -0
- package/dist/provider-loop.js +70 -0
- package/dist/runtime-source.js +2 -0
- package/dist/source-execution.js +65 -0
- package/dist/source-package.js +144 -0
- package/dist/source-runtime.js +125 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/provider-loop.d.ts +53 -0
- package/dist/types/provider-loop.d.ts.map +1 -0
- package/dist/types/runtime-source.d.ts +2 -0
- package/dist/types/source-execution.d.ts +85 -0
- package/dist/types/source-execution.d.ts.map +1 -0
- package/dist/types/source-package.d.ts +198 -0
- package/dist/types/source-package.d.ts.map +1 -0
- package/dist/types/source-runtime.d.ts +114 -0
- package/dist/types/source-runtime.d.ts.map +1 -0
- package/package.json +6 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { runProviderRoundLoop } from "./provider-loop.js";
|
|
2
|
+
import { HARNESS_SOURCE_READ_TOOL_NAME } from "./source-runtime.js";
|
|
3
|
+
/** Shared rollout lifecycle. Hosts own model transport, environment effects and
|
|
4
|
+
* grading; this runtime owns released resource calls and conversation history. */
|
|
5
|
+
export async function executeHarnessRollout(input) {
|
|
6
|
+
const messages = [
|
|
7
|
+
{ role: "system", content: input.runtime?.systemPrompt ?? input.systemPrompt },
|
|
8
|
+
{ role: "user", content: input.userPrompt },
|
|
9
|
+
];
|
|
10
|
+
const tools = [...input.tools, ...(input.runtime?.tools ?? [])];
|
|
11
|
+
const policyResults = [];
|
|
12
|
+
const toolSequence = [];
|
|
13
|
+
const trace = [];
|
|
14
|
+
const finalStep = await runProviderRoundLoop({
|
|
15
|
+
turnId: input.turnId,
|
|
16
|
+
maxRounds: input.maxTurns,
|
|
17
|
+
signal: input.signal,
|
|
18
|
+
async runRound({ index: turnIndex, signal }) {
|
|
19
|
+
// Transport receives owned messages so a host cannot mutate retained history.
|
|
20
|
+
const completion = await input.policyRequest({ turnIndex, messages: structuredClone(messages), tools: structuredClone(tools) }, signal);
|
|
21
|
+
signal.throwIfAborted();
|
|
22
|
+
policyResults.push(completion.result);
|
|
23
|
+
messages.push({ role: "assistant", content: completion.content,
|
|
24
|
+
tool_calls: completion.toolCalls.map(call => ({ id: call.id, type: "function", function: { name: call.name, arguments: call.arguments } })) });
|
|
25
|
+
const sourceCalls = input.runtime ? completion.toolCalls.filter(call => call.name === HARNESS_SOURCE_READ_TOOL_NAME) : [];
|
|
26
|
+
const environmentCalls = input.runtime ? completion.toolCalls.filter(call => call.name !== HARNESS_SOURCE_READ_TOOL_NAME) : completion.toolCalls;
|
|
27
|
+
const sourceResults = sourceCalls.map(call => {
|
|
28
|
+
let output;
|
|
29
|
+
try {
|
|
30
|
+
output = input.runtime.readFile(JSON.parse(call.arguments));
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
output = { error: error instanceof Error ? error.message : "Harness source read failed." };
|
|
34
|
+
}
|
|
35
|
+
messages.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify(output) });
|
|
36
|
+
toolSequence.push(call.name);
|
|
37
|
+
return { id: call.id, name: call.name, output };
|
|
38
|
+
});
|
|
39
|
+
if (sourceCalls.length && !environmentCalls.length) {
|
|
40
|
+
trace.push({ turnIndex, content: completion.content, toolCalls: sourceCalls, toolResults: sourceResults, terminal: false });
|
|
41
|
+
return { type: "continue" };
|
|
42
|
+
}
|
|
43
|
+
const step = await input.step({ content: completion.content, toolCalls: environmentCalls }, signal);
|
|
44
|
+
signal.throwIfAborted();
|
|
45
|
+
for (const result of step.toolResults) {
|
|
46
|
+
messages.push({ role: "tool", tool_call_id: result.id, content: JSON.stringify(result.output) });
|
|
47
|
+
toolSequence.push(result.name);
|
|
48
|
+
}
|
|
49
|
+
if (step.userMessage)
|
|
50
|
+
messages.push({ role: "user", content: step.userMessage });
|
|
51
|
+
trace.push({ turnIndex, content: completion.content, toolCalls: completion.toolCalls,
|
|
52
|
+
toolResults: [...sourceResults, ...step.toolResults], terminal: step.terminal });
|
|
53
|
+
return step.terminal ? { type: "complete", result: step } : { type: "continue" };
|
|
54
|
+
},
|
|
55
|
+
async onExhausted() {
|
|
56
|
+
input.signal.throwIfAborted();
|
|
57
|
+
const step = await input.terminate("max_turns", input.signal);
|
|
58
|
+
if (!step.terminal)
|
|
59
|
+
throw new Error("Harness environment did not terminate after exhausting its turn budget.");
|
|
60
|
+
trace.push({ turnIndex: input.maxTurns, content: null, toolCalls: [], toolResults: [], terminal: true, terminationReason: "max_turns" });
|
|
61
|
+
return step;
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
return { messages, toolSequence, trace, policyResults, finalStep, runtimeReceipt: input.runtime?.receipt ?? null };
|
|
65
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { assertContentHash, contentHash, ImmutableAssetRefSchema, ImmutableReleaseRefSchema, ReleaseHashSchema, sha256, } from "./common.js";
|
|
3
|
+
import { AgentSnapshotSchema, HarnessReleaseSchema } from "./harness.js";
|
|
4
|
+
export const MAX_HARNESS_SOURCE_PACKAGE_BYTES = 25 * 1024 * 1024;
|
|
5
|
+
const HarnessSourceFileSchema = z.object({
|
|
6
|
+
path: ImmutableAssetRefSchema.shape.path,
|
|
7
|
+
base64: z.string().max(Math.ceil(MAX_HARNESS_SOURCE_PACKAGE_BYTES / 3) * 4),
|
|
8
|
+
}).strict();
|
|
9
|
+
const HarnessSourcePackageContentSchema = z.object({
|
|
10
|
+
schemaVersion: z.literal("openpond.harnessSourcePackage.v1"),
|
|
11
|
+
agentSnapshot: AgentSnapshotSchema,
|
|
12
|
+
harnessRelease: HarnessReleaseSchema,
|
|
13
|
+
files: z.array(HarnessSourceFileSchema).max(10_000),
|
|
14
|
+
}).strict();
|
|
15
|
+
export const HarnessSourcePackageSchema = HarnessSourcePackageContentSchema.extend({
|
|
16
|
+
contentHash: ReleaseHashSchema,
|
|
17
|
+
}).strict();
|
|
18
|
+
export const HarnessSourceSelectionSchema = z.object({
|
|
19
|
+
schemaVersion: z.literal("openpond.harnessSourceSelection.v1"),
|
|
20
|
+
mode: z.enum(["taskset_owned", "selected_release"]),
|
|
21
|
+
harnessRelease: ImmutableReleaseRefSchema,
|
|
22
|
+
sourcePackageHash: ReleaseHashSchema.nullable(),
|
|
23
|
+
}).strict().superRefine((selection, context) => {
|
|
24
|
+
if ((selection.mode === "selected_release") !== (selection.sourcePackageHash !== null)) {
|
|
25
|
+
context.addIssue({ code: "custom", path: ["sourcePackageHash"], message: "Only a selected release binds a source package." });
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
/** Resolve the source selected by a captured bundle; missing source cannot be
|
|
29
|
+
* interpreted as Taskset-owned execution when the bundle selected a release. */
|
|
30
|
+
export function resolveHarnessSourceSelection(input) {
|
|
31
|
+
const selection = HarnessSourceSelectionSchema.parse(input.selection);
|
|
32
|
+
if (selection.harnessRelease.id !== input.expectedRelease.id
|
|
33
|
+
|| selection.harnessRelease.contentHash !== input.expectedRelease.contentHash) {
|
|
34
|
+
throw new Error("Harness source selection differs from its run manifest.");
|
|
35
|
+
}
|
|
36
|
+
if (selection.mode === "taskset_owned") {
|
|
37
|
+
if (input.sourcePackage !== undefined && input.sourcePackage !== null)
|
|
38
|
+
throw new Error("Taskset-owned execution cannot include a selected Harness source package.");
|
|
39
|
+
return { selection, sourcePackage: null };
|
|
40
|
+
}
|
|
41
|
+
const sourcePackage = validateHarnessSourcePackage(input.sourcePackage, selection.harnessRelease);
|
|
42
|
+
if (sourcePackage.contentHash !== selection.sourcePackageHash)
|
|
43
|
+
throw new Error("Harness source selection differs from its captured package.");
|
|
44
|
+
return { selection, sourcePackage };
|
|
45
|
+
}
|
|
46
|
+
/** Capture the full released source. Runtime admission separately authorizes
|
|
47
|
+
* export and capabilities; a source package never makes private files visible
|
|
48
|
+
* to a policy merely by transporting them. */
|
|
49
|
+
export function createHarnessSourcePackage(input) {
|
|
50
|
+
if ([...input.files.values()].reduce((total, bytes) => total + bytes.byteLength, 0) > MAX_HARNESS_SOURCE_PACKAGE_BYTES) {
|
|
51
|
+
throw new Error("Harness source package exceeds its byte limit.");
|
|
52
|
+
}
|
|
53
|
+
const content = HarnessSourcePackageContentSchema.parse({
|
|
54
|
+
schemaVersion: "openpond.harnessSourcePackage.v1",
|
|
55
|
+
agentSnapshot: input.agentSnapshot,
|
|
56
|
+
harnessRelease: input.harnessRelease,
|
|
57
|
+
files: [...input.files].sort(([a], [b]) => a.localeCompare(b)).map(([path, bytes]) => ({
|
|
58
|
+
path,
|
|
59
|
+
base64: encode(bytes),
|
|
60
|
+
})),
|
|
61
|
+
});
|
|
62
|
+
return validateHarnessSourcePackage({ ...content, contentHash: contentHash(content) });
|
|
63
|
+
}
|
|
64
|
+
/** Validate both release objects, their complete asset closure and exact bytes.
|
|
65
|
+
* Rehashing the outer package cannot bless a substituted instruction or file. */
|
|
66
|
+
export function validateHarnessSourcePackage(value, expected) {
|
|
67
|
+
const source = HarnessSourcePackageSchema.parse(value);
|
|
68
|
+
assertContentHash(source, "Harness source package");
|
|
69
|
+
assertContentHash(source.agentSnapshot, "Harness source Agent snapshot");
|
|
70
|
+
assertContentHash(source.harnessRelease, "Harness source release");
|
|
71
|
+
const { agentSnapshot, harnessRelease } = source;
|
|
72
|
+
if (expected && (expected.id !== harnessRelease.id || expected.contentHash !== harnessRelease.contentHash)) {
|
|
73
|
+
throw new Error("Harness source package differs from the selected release.");
|
|
74
|
+
}
|
|
75
|
+
if (harnessRelease.agentSnapshot.id !== agentSnapshot.id
|
|
76
|
+
|| harnessRelease.agentSnapshot.contentHash !== agentSnapshot.contentHash) {
|
|
77
|
+
throw new Error("Harness source release does not bind its Agent snapshot.");
|
|
78
|
+
}
|
|
79
|
+
const assets = new Map();
|
|
80
|
+
const ids = new Set();
|
|
81
|
+
for (const asset of harnessRelease.files) {
|
|
82
|
+
if (asset.path.includes("\\") || asset.path.includes(":"))
|
|
83
|
+
throw new Error("Harness source requires portable relative file paths.");
|
|
84
|
+
if (assets.has(asset.path) || ids.has(asset.id))
|
|
85
|
+
throw new Error("Harness source contains duplicate asset paths or identities.");
|
|
86
|
+
assets.set(asset.path, asset);
|
|
87
|
+
ids.add(asset.id);
|
|
88
|
+
}
|
|
89
|
+
for (const asset of [harnessRelease.program, agentSnapshot.dependencyLock,
|
|
90
|
+
...agentSnapshot.instructions, ...agentSnapshot.skills, ...agentSnapshot.agents]) {
|
|
91
|
+
if (contentHash(assets.get(asset.path) ?? null) !== contentHash(asset)) {
|
|
92
|
+
throw new Error(`Harness source dependency ${asset.path} is absent or differs from its release inventory.`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
for (const asset of [...agentSnapshot.instructions, ...agentSnapshot.skills]) {
|
|
96
|
+
if (asset.visibility !== "policy")
|
|
97
|
+
throw new Error(`Harness policy source ${asset.path} is private.`);
|
|
98
|
+
}
|
|
99
|
+
const paths = new Set();
|
|
100
|
+
let totalBytes = 0;
|
|
101
|
+
for (const file of source.files) {
|
|
102
|
+
if (paths.has(file.path))
|
|
103
|
+
throw new Error("Harness source package contains duplicate files.");
|
|
104
|
+
paths.add(file.path);
|
|
105
|
+
const asset = assets.get(file.path);
|
|
106
|
+
if (!asset)
|
|
107
|
+
throw new Error(`Harness source file ${file.path} is not declared by its release.`);
|
|
108
|
+
const bytes = decode(file.base64);
|
|
109
|
+
totalBytes += bytes.byteLength;
|
|
110
|
+
if (totalBytes > MAX_HARNESS_SOURCE_PACKAGE_BYTES)
|
|
111
|
+
throw new Error("Harness source package exceeds its byte limit.");
|
|
112
|
+
if (bytes.byteLength !== asset.sizeBytes || sha256(bytes) !== asset.contentHash) {
|
|
113
|
+
throw new Error(`Harness source file ${file.path} differs from its immutable bytes.`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (paths.size !== assets.size)
|
|
117
|
+
throw new Error("Harness source package is missing released files.");
|
|
118
|
+
return source;
|
|
119
|
+
}
|
|
120
|
+
/** Return an owned byte snapshot, including visibility in the release inventory.
|
|
121
|
+
* A runtime must select policy assets explicitly rather than expose this map. */
|
|
122
|
+
export function harnessSourcePackageFiles(value, expected) {
|
|
123
|
+
const source = validateHarnessSourcePackage(value, expected);
|
|
124
|
+
return new Map(source.files.map(file => [file.path, decode(file.base64)]));
|
|
125
|
+
}
|
|
126
|
+
function encode(bytes) {
|
|
127
|
+
let binary = "";
|
|
128
|
+
for (let offset = 0; offset < bytes.length; offset += 8_192) {
|
|
129
|
+
binary += String.fromCharCode(...bytes.subarray(offset, offset + 8_192));
|
|
130
|
+
}
|
|
131
|
+
return btoa(binary);
|
|
132
|
+
}
|
|
133
|
+
function decode(base64) {
|
|
134
|
+
let binary;
|
|
135
|
+
try {
|
|
136
|
+
binary = atob(base64);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
throw new Error("Harness source file is not valid base64.");
|
|
140
|
+
}
|
|
141
|
+
if (btoa(binary) !== base64)
|
|
142
|
+
throw new Error("Harness source file is not canonical base64.");
|
|
143
|
+
return Uint8Array.from(binary, character => character.charCodeAt(0));
|
|
144
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { contentHash } from "./common.js";
|
|
3
|
+
import { harnessSourcePackageFiles, validateHarnessSourcePackage } from "./source-package.js";
|
|
4
|
+
export const HARNESS_SOURCE_READ_TOOL_NAME = "harness_read_file";
|
|
5
|
+
const ReadInputSchema = z.object({
|
|
6
|
+
path: z.string().min(1).max(2_000),
|
|
7
|
+
offset: z.number().int().nonnegative().default(0),
|
|
8
|
+
length: z.number().int().positive().max(65_536).default(16_384),
|
|
9
|
+
}).strict();
|
|
10
|
+
export const HARNESS_SOURCE_READ_TOOL = {
|
|
11
|
+
type: "function",
|
|
12
|
+
function: {
|
|
13
|
+
name: HARNESS_SOURCE_READ_TOOL_NAME,
|
|
14
|
+
description: "Read a byte range from a policy-visible file in the selected immutable Harness release. Paths are relative to that release; private files are unavailable.",
|
|
15
|
+
parameters: {
|
|
16
|
+
type: "object", properties: {
|
|
17
|
+
path: { type: "string" }, offset: { type: "integer", minimum: 0 },
|
|
18
|
+
length: { type: "integer", minimum: 1, maximum: 65_536 },
|
|
19
|
+
}, required: ["path"], additionalProperties: false,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
/** Compile released instructions and Skills into an admitted context. Resource
|
|
24
|
+
* reads use the captured package, never the current workspace or channel. */
|
|
25
|
+
export function createHarnessSourceRuntime(input) {
|
|
26
|
+
const source = validateHarnessSourcePackage(input.sourcePackage, input.expectedRelease);
|
|
27
|
+
const files = harnessSourcePackageFiles(source);
|
|
28
|
+
const { agentSnapshot, harnessRelease } = source;
|
|
29
|
+
const text = (path) => {
|
|
30
|
+
const bytes = files.get(path);
|
|
31
|
+
if (!bytes)
|
|
32
|
+
throw new Error(`Released Harness source is missing: ${path}`);
|
|
33
|
+
try {
|
|
34
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
throw new Error(`Released Harness instruction source is not UTF-8: ${path}`);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const program = z.object({ runtimeProtocol: z.literal("openpond.agent-runtime.v1") }).strict();
|
|
41
|
+
if (!program.safeParse(JSON.parse(text(harnessRelease.program.path))).success
|
|
42
|
+
|| harnessRelease.metadata.runtimeProtocol !== "openpond.agent-runtime.v1") {
|
|
43
|
+
throw new Error("Released Harness program requires a different execution adapter.");
|
|
44
|
+
}
|
|
45
|
+
if (agentSnapshot.agents.length)
|
|
46
|
+
throw new Error("This Harness runtime does not execute released subagent programs.");
|
|
47
|
+
const lock = z.object({ dependencies: z.record(z.string(), z.string()) }).strict()
|
|
48
|
+
.parse(JSON.parse(text(agentSnapshot.dependencyLock.path)));
|
|
49
|
+
for (const [name, version] of Object.entries(lock.dependencies)) {
|
|
50
|
+
if (input.dependencies?.[name] !== version)
|
|
51
|
+
throw new Error(`Released Harness dependency is unavailable: ${name}@${version}`);
|
|
52
|
+
}
|
|
53
|
+
const omittedCapabilities = [];
|
|
54
|
+
for (const requirement of agentSnapshot.capabilityRequirements) {
|
|
55
|
+
const available = input.capabilities?.find(capability => capability.id === requirement.id);
|
|
56
|
+
if (available && requirement.scopes.every(scope => available.scopes.includes(scope)))
|
|
57
|
+
continue;
|
|
58
|
+
if (requirement.required)
|
|
59
|
+
throw new Error(`Released Harness capability is unavailable: ${requirement.id}`);
|
|
60
|
+
omittedCapabilities.push(requirement.id);
|
|
61
|
+
}
|
|
62
|
+
if (input.tools.some(tool => tool.name === HARNESS_SOURCE_READ_TOOL_NAME))
|
|
63
|
+
throw new Error("Harness source reader conflicts with a runtime tool.");
|
|
64
|
+
for (const declared of [...agentSnapshot.toolDeclarations, ...harnessRelease.tools]) {
|
|
65
|
+
const available = input.tools.find(tool => tool.name === declared.name);
|
|
66
|
+
if (!available || contentHash(available.inputSchema) !== declared.inputSchemaHash
|
|
67
|
+
|| contentHash(declared.inputSchema) !== declared.inputSchemaHash) {
|
|
68
|
+
throw new Error(`Released Harness tool is unavailable or has a different schema: ${declared.name}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const policyFiles = harnessRelease.files.filter(asset => asset.visibility === "policy"
|
|
72
|
+
&& asset.path !== harnessRelease.program.path && asset.path !== agentSnapshot.dependencyLock.path);
|
|
73
|
+
const instructionSections = agentSnapshot.instructions.map(asset => `Released instruction (${asset.path}):\n${text(asset.path)}`);
|
|
74
|
+
const skillSections = agentSnapshot.skills.map(asset => `Released Skill (${asset.path}):\n${text(asset.path)}`);
|
|
75
|
+
const systemPrompt = [input.baseSystemPrompt,
|
|
76
|
+
...instructionSections,
|
|
77
|
+
skillSections.length ? "Apply the following released Skills when relevant to the task. Read their referenced resources from the selected release with harness_read_file." : "",
|
|
78
|
+
...skillSections,
|
|
79
|
+
policyFiles.length ? `Selected Harness files (paths relative to the release):\n${policyFiles.map(asset => asset.path).join("\n")}` : "",
|
|
80
|
+
].filter(Boolean).join("\n\n");
|
|
81
|
+
if (!Number.isSafeInteger(input.maxContextCharacters) || input.maxContextCharacters <= 0
|
|
82
|
+
|| systemPrompt.length > input.maxContextCharacters)
|
|
83
|
+
throw new Error("Released Harness context exceeds the runtime's admitted context limit.");
|
|
84
|
+
const readerFiles = new Map(policyFiles.map(asset => [asset.path, asset]));
|
|
85
|
+
const tools = policyFiles.length ? [HARNESS_SOURCE_READ_TOOL] : [];
|
|
86
|
+
const receipt = {
|
|
87
|
+
schemaVersion: "openpond.harnessSourceRuntimeReceipt.v1",
|
|
88
|
+
runtimeId: input.runtimeId,
|
|
89
|
+
harnessRelease: { id: harnessRelease.id, contentHash: harnessRelease.contentHash },
|
|
90
|
+
sourcePackageHash: source.contentHash,
|
|
91
|
+
systemPromptHash: contentHash(systemPrompt),
|
|
92
|
+
instructionAssets: agentSnapshot.instructions.map(asset => ({ path: asset.path, contentHash: asset.contentHash })),
|
|
93
|
+
skillAssets: agentSnapshot.skills.map(asset => ({ path: asset.path, contentHash: asset.contentHash })),
|
|
94
|
+
readableAssets: policyFiles.map(asset => ({ path: asset.path, contentHash: asset.contentHash })),
|
|
95
|
+
toolContractHash: contentHash([...input.tools.map(tool => tool.definition), ...tools]),
|
|
96
|
+
omittedCapabilities,
|
|
97
|
+
};
|
|
98
|
+
return {
|
|
99
|
+
systemPrompt,
|
|
100
|
+
tools,
|
|
101
|
+
receipt: { ...receipt, contentHash: contentHash(receipt) },
|
|
102
|
+
readFile(value) {
|
|
103
|
+
const request = ReadInputSchema.parse(value);
|
|
104
|
+
const asset = readerFiles.get(request.path);
|
|
105
|
+
if (!asset)
|
|
106
|
+
throw new Error("Harness source file is not policy-visible in the selected release.");
|
|
107
|
+
const bytes = files.get(request.path);
|
|
108
|
+
if (request.offset > bytes.length)
|
|
109
|
+
throw new Error("Harness source read offset exceeds the file size.");
|
|
110
|
+
const end = Math.min(bytes.length, request.offset + request.length);
|
|
111
|
+
const chunk = bytes.subarray(request.offset, end);
|
|
112
|
+
let content;
|
|
113
|
+
let encoding = "utf8";
|
|
114
|
+
try {
|
|
115
|
+
content = new TextDecoder("utf-8", { fatal: true }).decode(chunk);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
encoding = "base64";
|
|
119
|
+
content = btoa(Array.from(chunk, byte => String.fromCharCode(byte)).join(""));
|
|
120
|
+
}
|
|
121
|
+
return { path: asset.path, contentHash: asset.contentHash, mediaType: asset.mediaType,
|
|
122
|
+
sizeBytes: asset.sizeBytes, offset: request.offset, nextOffset: end, eof: end === bytes.length, encoding, content };
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -10,4 +10,8 @@ export * from "./refiner-detection.js";
|
|
|
10
10
|
export * from "./refinement-lifecycle.js";
|
|
11
11
|
export * from "./refiner-support.js";
|
|
12
12
|
export * from "./tools.js";
|
|
13
|
+
export * from "./source-package.js";
|
|
14
|
+
export * from "./source-runtime.js";
|
|
15
|
+
export * from "./provider-loop.js";
|
|
16
|
+
export * from "./source-execution.js";
|
|
13
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type ProviderRoundContext = {
|
|
2
|
+
index: number;
|
|
3
|
+
requestId: string;
|
|
4
|
+
signal: AbortSignal;
|
|
5
|
+
};
|
|
6
|
+
export type ProviderRoundDecision<TResult> = {
|
|
7
|
+
type: "continue";
|
|
8
|
+
} | {
|
|
9
|
+
type: "complete";
|
|
10
|
+
result: TResult;
|
|
11
|
+
};
|
|
12
|
+
export type ProviderStreamDelta<TToolCall = unknown, TContinuation = unknown> = {
|
|
13
|
+
text?: string;
|
|
14
|
+
reasoningText?: string;
|
|
15
|
+
usage?: unknown;
|
|
16
|
+
continuation?: TContinuation;
|
|
17
|
+
toolCalls?: readonly TToolCall[];
|
|
18
|
+
finishReason?: string | null;
|
|
19
|
+
};
|
|
20
|
+
export type ProviderRoundResult<TToolCall = unknown, TContinuation = unknown> = {
|
|
21
|
+
text: string;
|
|
22
|
+
reasoningText: string;
|
|
23
|
+
usage: unknown;
|
|
24
|
+
continuation: TContinuation | null;
|
|
25
|
+
toolCallBatches: TToolCall[][];
|
|
26
|
+
finishReason: string | null | undefined;
|
|
27
|
+
};
|
|
28
|
+
export declare function providerRoundSequence(input: {
|
|
29
|
+
turnId: string;
|
|
30
|
+
maxRounds: number;
|
|
31
|
+
signal: AbortSignal;
|
|
32
|
+
}): AsyncGenerator<ProviderRoundContext, void, unknown>;
|
|
33
|
+
/** Owns provider/tool round sequencing, completion, exhaustion, and aborts. */
|
|
34
|
+
export declare function runProviderRoundLoop<TResult>(input: {
|
|
35
|
+
turnId: string;
|
|
36
|
+
maxRounds: number;
|
|
37
|
+
signal: AbortSignal;
|
|
38
|
+
runRound(round: ProviderRoundContext): Promise<ProviderRoundDecision<TResult>>;
|
|
39
|
+
onExhausted(): Promise<TResult>;
|
|
40
|
+
}): Promise<TResult>;
|
|
41
|
+
/**
|
|
42
|
+
* Owns provider stream consumption and the normalized round result. The host
|
|
43
|
+
* supplies the provider request, usage recorder, and provider-specific delta
|
|
44
|
+
* shapes without duplicating the stream lifecycle.
|
|
45
|
+
*/
|
|
46
|
+
export declare function runProviderRound<TToolCall = unknown, TContinuation = unknown>(input: {
|
|
47
|
+
stream: AsyncIterable<ProviderStreamDelta<TToolCall, TContinuation>>;
|
|
48
|
+
signal: AbortSignal;
|
|
49
|
+
onDelta?(delta: ProviderStreamDelta<TToolCall, TContinuation>): void | Promise<void>;
|
|
50
|
+
onCompleted?(result: ProviderRoundResult<TToolCall, TContinuation>): Promise<void>;
|
|
51
|
+
onFailed?(error: unknown): Promise<void>;
|
|
52
|
+
}): Promise<ProviderRoundResult<TToolCall, TContinuation>>;
|
|
53
|
+
//# sourceMappingURL=provider-loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-loop.d.ts","sourceRoot":"","sources":["../../../../src/provider-loop.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,qBAAqB,CAAC,OAAO,IACrC;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAE1C,MAAM,MAAM,mBAAmB,CAAC,SAAS,GAAG,OAAO,EAAE,aAAa,GAAG,OAAO,IAAI;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,SAAS,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,mBAAmB,CAAC,SAAS,GAAG,OAAO,EAAE,aAAa,GAAG,OAAO,IAAI;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,aAAa,GAAG,IAAI,CAAC;IACnC,eAAe,EAAE,SAAS,EAAE,EAAE,CAAC;IAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACzC,CAAC;AAEF,wBAAuB,qBAAqB,CAAC,KAAK,EAAE;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;CACrB,GAAG,cAAc,CAAC,oBAAoB,EAAE,IAAI,EAAE,OAAO,CAAC,CAYtD;AAED,+EAA+E;AAC/E,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,KAAK,EAAE;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/E,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CACjC,GAAG,OAAO,CAAC,OAAO,CAAC,CAMnB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,GAAG,OAAO,EACnB,aAAa,GAAG,OAAO,EACvB,KAAK,EAAE;IACP,MAAM,EAAE,aAAa,CAAC,mBAAmB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;IACrE,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,CAAC,CAAC,KAAK,EAAE,mBAAmB,CAAC,SAAS,EAAE,aAAa,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrF,WAAW,CAAC,CAAC,MAAM,EAAE,mBAAmB,CAAC,SAAS,EAAE,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnF,QAAQ,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C,GAAG,OAAO,CAAC,mBAAmB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAmCzD"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { type createHarnessSourceRuntime } from "./source-runtime.js";
|
|
2
|
+
export type HarnessPolicyMessage = {
|
|
3
|
+
role: "system" | "user" | "assistant" | "tool";
|
|
4
|
+
content: string | null;
|
|
5
|
+
tool_call_id?: string;
|
|
6
|
+
tool_calls?: Array<{
|
|
7
|
+
id: string;
|
|
8
|
+
type: "function";
|
|
9
|
+
function: {
|
|
10
|
+
name: string;
|
|
11
|
+
arguments: string;
|
|
12
|
+
};
|
|
13
|
+
}>;
|
|
14
|
+
};
|
|
15
|
+
export type HarnessPolicyToolCall = {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
arguments: string;
|
|
19
|
+
};
|
|
20
|
+
export type HarnessEnvironmentStep = {
|
|
21
|
+
toolResults: Array<{
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
output: unknown;
|
|
25
|
+
}>;
|
|
26
|
+
userMessage: string | null;
|
|
27
|
+
terminal: boolean;
|
|
28
|
+
};
|
|
29
|
+
/** Shared rollout lifecycle. Hosts own model transport, environment effects and
|
|
30
|
+
* grading; this runtime owns released resource calls and conversation history. */
|
|
31
|
+
export declare function executeHarnessRollout<TPolicyResult, TStep extends HarnessEnvironmentStep>(input: {
|
|
32
|
+
turnId: string;
|
|
33
|
+
maxTurns: number;
|
|
34
|
+
signal: AbortSignal;
|
|
35
|
+
runtime: ReturnType<typeof createHarnessSourceRuntime> | null;
|
|
36
|
+
systemPrompt: string;
|
|
37
|
+
userPrompt: string;
|
|
38
|
+
tools: Array<Record<string, unknown>>;
|
|
39
|
+
policyRequest(request: {
|
|
40
|
+
turnIndex: number;
|
|
41
|
+
messages: HarnessPolicyMessage[];
|
|
42
|
+
tools: Array<Record<string, unknown>>;
|
|
43
|
+
}, signal: AbortSignal): Promise<{
|
|
44
|
+
result: TPolicyResult;
|
|
45
|
+
content: string | null;
|
|
46
|
+
toolCalls: HarnessPolicyToolCall[];
|
|
47
|
+
}>;
|
|
48
|
+
step(request: {
|
|
49
|
+
content: string | null;
|
|
50
|
+
toolCalls: HarnessPolicyToolCall[];
|
|
51
|
+
}, signal: AbortSignal): Promise<TStep>;
|
|
52
|
+
terminate(reason: "max_turns", signal: AbortSignal): Promise<TStep>;
|
|
53
|
+
}): Promise<{
|
|
54
|
+
messages: HarnessPolicyMessage[];
|
|
55
|
+
toolSequence: string[];
|
|
56
|
+
trace: Record<string, unknown>[];
|
|
57
|
+
policyResults: TPolicyResult[];
|
|
58
|
+
finalStep: TStep;
|
|
59
|
+
runtimeReceipt: {
|
|
60
|
+
contentHash: string;
|
|
61
|
+
schemaVersion: "openpond.harnessSourceRuntimeReceipt.v1";
|
|
62
|
+
runtimeId: string;
|
|
63
|
+
harnessRelease: {
|
|
64
|
+
id: string;
|
|
65
|
+
contentHash: string;
|
|
66
|
+
};
|
|
67
|
+
sourcePackageHash: string;
|
|
68
|
+
systemPromptHash: string;
|
|
69
|
+
instructionAssets: {
|
|
70
|
+
path: string;
|
|
71
|
+
contentHash: string;
|
|
72
|
+
}[];
|
|
73
|
+
skillAssets: {
|
|
74
|
+
path: string;
|
|
75
|
+
contentHash: string;
|
|
76
|
+
}[];
|
|
77
|
+
readableAssets: {
|
|
78
|
+
path: string;
|
|
79
|
+
contentHash: string;
|
|
80
|
+
}[];
|
|
81
|
+
toolContractHash: string;
|
|
82
|
+
omittedCapabilities: string[];
|
|
83
|
+
} | null;
|
|
84
|
+
}>;
|
|
85
|
+
//# sourceMappingURL=source-execution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-execution.d.ts","sourceRoot":"","sources":["../../../../src/source-execution.ts"],"names":[],"mappings":"AACA,OAAO,EAAiC,KAAK,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAErG,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;CACrG,CAAC;AACF,MAAM,MAAM,qBAAqB,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AACpF,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAClE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF;kFACkF;AAClF,wBAAsB,qBAAqB,CAAC,aAAa,EAAE,KAAK,SAAS,sBAAsB,EAAE,KAAK,EAAE;IACtG,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,UAAU,CAAC,OAAO,0BAA0B,CAAC,GAAG,IAAI,CAAC;IAC9D,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtC,aAAa,CAAC,OAAO,EAAE;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,oBAAoB,EAAE,CAAC;QACjC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;KACvC,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC;QAC/B,MAAM,EAAE,aAAa,CAAC;QACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,SAAS,EAAE,qBAAqB,EAAE,CAAC;KACpC,CAAC,CAAC;IACH,IAAI,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,qBAAqB,EAAE,CAAA;KAAE,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACnH,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;CACrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDA"}
|