@nylorun/harness 0.11.0-beta → 0.11.1-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 +6 -0
- package/dist/model/adapters.js +14 -3
- package/dist/model/normalize.js +15 -3
- package/dist/session/seed.js +2 -2
- package/dist/step/canonicalize.js +3 -0
- package/dist/step/project.js +6 -2
- package/dist/types/model.d.ts +9 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.11.1-beta
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d27242c: Preserve opaque provider continuation metadata through assistant conversation history. Gemini tool calls now retain thought signatures when sending tool results back to the model, including signed empty text and reasoning blocks. Only the originating provider and model receive their signatures.
|
|
8
|
+
|
|
3
9
|
## 0.11.0-beta
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/dist/model/adapters.js
CHANGED
|
@@ -3,7 +3,7 @@ import { copyJsonObject } from "../utils/immutable.js";
|
|
|
3
3
|
import { preparedModel } from "./prepared.js";
|
|
4
4
|
/** Translate a Harness call to the OpenAI Chat Completions request shape. */
|
|
5
5
|
export function toChatCompletions(call) {
|
|
6
|
-
const messages = call.prompt.map((item) => {
|
|
6
|
+
const messages = withoutProviderReasoning(call.prompt).map((item) => {
|
|
7
7
|
if (item.kind === "instructions")
|
|
8
8
|
return { role: "system", content: textOf(item) };
|
|
9
9
|
if (item.kind === "tool-result")
|
|
@@ -93,7 +93,7 @@ export function chatCompletionsAdapter(send) {
|
|
|
93
93
|
/** Translate a Harness call to the OpenAI Responses request shape. */
|
|
94
94
|
export function toResponses(call) {
|
|
95
95
|
const instructions = call.prompt.filter((item) => item.kind === "instructions").map(textOf);
|
|
96
|
-
const input = call.prompt.flatMap((item) => {
|
|
96
|
+
const input = withoutProviderReasoning(call.prompt).flatMap((item) => {
|
|
97
97
|
if (item.kind === "instructions")
|
|
98
98
|
return [];
|
|
99
99
|
if (item.kind === "tool-result")
|
|
@@ -201,7 +201,7 @@ export function toMessages(call, defaultMaxOutputTokens) {
|
|
|
201
201
|
if (call.outputSchema !== undefined)
|
|
202
202
|
throw new HarnessError("model.unsupported-output-schema", "Anthropic Messages output schemas require a custom prepared adapter");
|
|
203
203
|
const instructions = call.prompt.filter((item) => item.kind === "instructions").map(textOf);
|
|
204
|
-
const messages = call.prompt.flatMap((item) => {
|
|
204
|
+
const messages = withoutProviderReasoning(call.prompt).flatMap((item) => {
|
|
205
205
|
if (item.kind === "instructions")
|
|
206
206
|
return [];
|
|
207
207
|
if (item.kind === "tool-result")
|
|
@@ -543,3 +543,14 @@ function invalidResponse(message, path, cause) {
|
|
|
543
543
|
details: { path },
|
|
544
544
|
});
|
|
545
545
|
}
|
|
546
|
+
// These portable translators do not interpret another adapter's signed reasoning.
|
|
547
|
+
function withoutProviderReasoning(prompt) {
|
|
548
|
+
return prompt.flatMap((item) => {
|
|
549
|
+
if (item.kind !== "message" ||
|
|
550
|
+
item.role !== "assistant" ||
|
|
551
|
+
!item.content.some((part) => part.type === "reasoning"))
|
|
552
|
+
return [item];
|
|
553
|
+
const content = item.content.filter((part) => part.type !== "reasoning");
|
|
554
|
+
return content.length === 0 ? [] : [{ ...item, content }];
|
|
555
|
+
});
|
|
556
|
+
}
|
package/dist/model/normalize.js
CHANGED
|
@@ -119,11 +119,11 @@ function normalizeBlock(value, index) {
|
|
|
119
119
|
throw invalidCandidate(`Model output[${index}] must be an object`, `output[${index}]`);
|
|
120
120
|
const block = value;
|
|
121
121
|
if (block.type === "text" || block.type === "reasoning") {
|
|
122
|
-
rejectUnknownKeys(value, ["type", "text"], `Model output[${index}]`);
|
|
122
|
+
rejectUnknownKeys(value, ["type", "text", "providerMetadata"], `Model output[${index}]`);
|
|
123
123
|
const text = value.text;
|
|
124
124
|
if (typeof text !== "string")
|
|
125
125
|
throw invalidCandidate(`Model output[${index}].text must be a string`, `output[${index}].text`);
|
|
126
|
-
return Object.freeze({ type: block.type, text });
|
|
126
|
+
return Object.freeze({ type: block.type, text, ...providerMetadata(value, index) });
|
|
127
127
|
}
|
|
128
128
|
if (block.type === "json") {
|
|
129
129
|
rejectUnknownKeys(value, ["type", "value"], `Model output[${index}]`);
|
|
@@ -140,7 +140,7 @@ function normalizeBlock(value, index) {
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
if (block.type === "tool-call") {
|
|
143
|
-
rejectUnknownKeys(value, ["type", "id", "name", "args", "raw"], `Model output[${index}]`);
|
|
143
|
+
rejectUnknownKeys(value, ["type", "id", "name", "args", "raw", "providerMetadata"], `Model output[${index}]`);
|
|
144
144
|
const raw = value;
|
|
145
145
|
if (raw.id !== undefined && typeof raw.id !== "string")
|
|
146
146
|
throw invalidCandidate(`Model output[${index}].id must be a string`, `output[${index}].id`);
|
|
@@ -159,6 +159,7 @@ function normalizeBlock(value, index) {
|
|
|
159
159
|
throw invalidCandidate(`Model output[${index}].raw must be a string`, `output[${index}].raw`);
|
|
160
160
|
return Object.freeze({
|
|
161
161
|
type: "tool-call",
|
|
162
|
+
...providerMetadata(value, index),
|
|
162
163
|
id: typeof raw.id === "string" ? raw.id : "",
|
|
163
164
|
name: typeof raw.name === "string" ? raw.name : "",
|
|
164
165
|
args,
|
|
@@ -240,3 +241,14 @@ function isFiniteNumber(value) {
|
|
|
240
241
|
function isNonNegativeInteger(value) {
|
|
241
242
|
return typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
242
243
|
}
|
|
244
|
+
function providerMetadata(value, index) {
|
|
245
|
+
const metadata = value.providerMetadata;
|
|
246
|
+
if (metadata === undefined)
|
|
247
|
+
return {};
|
|
248
|
+
try {
|
|
249
|
+
return { providerMetadata: copyJsonObject(metadata, "providerMetadata") };
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
throw invalidCandidate(`Model output[${index}].providerMetadata must be a JSON object`, `output[${index}].providerMetadata`, error);
|
|
253
|
+
}
|
|
254
|
+
}
|
package/dist/session/seed.js
CHANGED
|
@@ -246,7 +246,7 @@ function validateSeedCandidate(value, index) {
|
|
|
246
246
|
fail(`Candidate output ${blockIndex} at transcript ${index} must be an object`);
|
|
247
247
|
const block = value;
|
|
248
248
|
if (block.type === "text" || block.type === "reasoning") {
|
|
249
|
-
exactKeys(block, ["type", "text"], `Candidate output ${blockIndex}`);
|
|
249
|
+
exactKeys(block, ["type", "text", "providerMetadata"], `Candidate output ${blockIndex}`);
|
|
250
250
|
if (typeof block.text !== "string")
|
|
251
251
|
fail(`Candidate output ${blockIndex} text must be a string`);
|
|
252
252
|
return;
|
|
@@ -257,7 +257,7 @@ function validateSeedCandidate(value, index) {
|
|
|
257
257
|
return;
|
|
258
258
|
}
|
|
259
259
|
if (block.type === "tool-call") {
|
|
260
|
-
exactKeys(block, ["type", "id", "name", "args", "raw"], `Candidate output ${blockIndex}`);
|
|
260
|
+
exactKeys(block, ["type", "id", "name", "args", "raw", "providerMetadata"], `Candidate output ${blockIndex}`);
|
|
261
261
|
requiredString(block.id, `Candidate output ${blockIndex} id`);
|
|
262
262
|
requiredString(block.name, `Candidate output ${blockIndex} name`);
|
|
263
263
|
if (block.raw !== undefined && typeof block.raw !== "string")
|
|
@@ -38,6 +38,9 @@ export function canonicalizeOutput(output) {
|
|
|
38
38
|
id: call.id,
|
|
39
39
|
name: call.name,
|
|
40
40
|
args: call.args,
|
|
41
|
+
...(block.providerMetadata === undefined
|
|
42
|
+
? {}
|
|
43
|
+
: { providerMetadata: block.providerMetadata }),
|
|
41
44
|
...(block.raw === undefined ? {} : { raw: block.raw }),
|
|
42
45
|
});
|
|
43
46
|
})),
|
package/dist/step/project.js
CHANGED
|
@@ -64,8 +64,9 @@ function projectEntry(entry) {
|
|
|
64
64
|
}
|
|
65
65
|
if (entry.kind === "candidate") {
|
|
66
66
|
const content = entry.candidate.output.flatMap((block) => {
|
|
67
|
-
if (block.type === "text"
|
|
68
|
-
|
|
67
|
+
if (block.type === "text" ||
|
|
68
|
+
(block.type === "reasoning" && block.providerMetadata !== undefined))
|
|
69
|
+
return [Object.freeze({ ...block })];
|
|
69
70
|
if (block.type === "json")
|
|
70
71
|
return [textPart(JSON.stringify(block.value))];
|
|
71
72
|
if (block.type === "tool-call")
|
|
@@ -75,6 +76,9 @@ function projectEntry(entry) {
|
|
|
75
76
|
id: block.id,
|
|
76
77
|
name: block.name,
|
|
77
78
|
args: copyJson(block.args),
|
|
79
|
+
...(block.providerMetadata === undefined
|
|
80
|
+
? {}
|
|
81
|
+
: { providerMetadata: copyJson(block.providerMetadata) }),
|
|
78
82
|
}),
|
|
79
83
|
];
|
|
80
84
|
return [];
|
package/dist/types/model.d.ts
CHANGED
|
@@ -9,14 +9,17 @@ export interface ModelToolCall {
|
|
|
9
9
|
export type ModelOutputBlock = {
|
|
10
10
|
readonly type: "text";
|
|
11
11
|
readonly text: string;
|
|
12
|
+
readonly providerMetadata?: JsonObject;
|
|
12
13
|
} | {
|
|
13
14
|
readonly type: "reasoning";
|
|
14
15
|
readonly text: string;
|
|
16
|
+
readonly providerMetadata?: JsonObject;
|
|
15
17
|
} | {
|
|
16
18
|
readonly type: "json";
|
|
17
19
|
readonly value: JsonValue;
|
|
18
20
|
} | {
|
|
19
21
|
readonly type: "tool-call";
|
|
22
|
+
readonly providerMetadata?: JsonObject;
|
|
20
23
|
readonly id: string;
|
|
21
24
|
readonly name: string;
|
|
22
25
|
readonly args: JsonObject;
|
|
@@ -117,14 +120,20 @@ export interface ModelRequest {
|
|
|
117
120
|
readonly outputSchema?: JsonObject;
|
|
118
121
|
}
|
|
119
122
|
export type PromptContentPart = {
|
|
123
|
+
readonly type: "reasoning";
|
|
124
|
+
readonly text: string;
|
|
125
|
+
readonly providerMetadata?: JsonObject;
|
|
126
|
+
} | {
|
|
120
127
|
readonly type: "text";
|
|
121
128
|
readonly text: string;
|
|
129
|
+
readonly providerMetadata?: JsonObject;
|
|
122
130
|
} | {
|
|
123
131
|
readonly type: "media";
|
|
124
132
|
readonly mediaType: string;
|
|
125
133
|
readonly reference: JsonValue;
|
|
126
134
|
} | {
|
|
127
135
|
readonly type: "tool-call";
|
|
136
|
+
readonly providerMetadata?: JsonObject;
|
|
128
137
|
readonly id: string;
|
|
129
138
|
readonly name: string;
|
|
130
139
|
readonly args: JsonObject;
|