oh-my-promptfoo 1.27.0 → 1.28.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/README.md +33 -0
- package/dist/assertions.cjs +1 -1
- package/dist/assertions.d.cts +1 -1
- package/dist/assertions.d.ts +1 -1
- package/dist/assertions.js +1 -1
- package/dist/{config-CjWHeukN.d.ts → config-L5S9SrkO.d.cts} +2 -1
- package/dist/{config-CjWHeukN.d.cts → config-L5S9SrkO.d.ts} +2 -1
- package/dist/delegate-runner.js +58 -2
- package/dist/delegate-runner.js.map +1 -1
- package/dist/{fs-D9YrrmPG.cjs → fs-CNr5ZxiH.cjs} +15 -2
- package/dist/fs-CNr5ZxiH.cjs.map +1 -0
- package/dist/{fs-CedLyQsv.js → fs-a7zK59AT.js} +15 -2
- package/dist/fs-a7zK59AT.js.map +1 -0
- package/dist/{mcp-CojL00iW.js → mcp-CA38aueh.js} +6 -1
- package/dist/mcp-CA38aueh.js.map +1 -0
- package/dist/mcp-launcher.js +1 -1
- package/dist/providers.cjs +1 -1
- package/dist/providers.d.cts +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +1 -1
- package/package.json +1 -1
- package/dist/fs-CedLyQsv.js.map +0 -1
- package/dist/fs-D9YrrmPG.cjs.map +0 -1
- package/dist/mcp-CojL00iW.js.map +0 -1
package/README.md
CHANGED
|
@@ -121,6 +121,39 @@ providers here and dropped their `Provider` suffix; the ids of earlier versions
|
|
|
121
121
|
no longer resolve (see the
|
|
122
122
|
[changelog](https://github.com/allagentsdev/oh-my-promptfoo/blob/main/CHANGELOG.md)).
|
|
123
123
|
|
|
124
|
+
## Copilot conversations
|
|
125
|
+
|
|
126
|
+
Use [Promptfoo's ordinary chat templates](https://www.promptfoo.dev/docs/configuration/chat/)
|
|
127
|
+
with either `CopilotSdk` or `Agent` delegating to `copilot-sdk`. JSON and YAML
|
|
128
|
+
prompt files, simplified chat markup expanded by Nunjucks, shared fixed history,
|
|
129
|
+
`_conversation` replay, `metadata.conversationId`, `storeOutputAs` and output
|
|
130
|
+
transforms belong to Promptfoo, not a JavaScript conversation adapter.
|
|
131
|
+
Normal assertions grade each new reply; the provider reads only the rendered prompt.
|
|
132
|
+
|
|
133
|
+
Copilot's optional `inputFormat` is `auto` (default), `chat` or `text`. Set it in
|
|
134
|
+
direct provider config or the Agent's `delegate.config`; per-test
|
|
135
|
+
`options.delegate.config.inputFormat` overrides either. `auto` recognizes only
|
|
136
|
+
complete chat-shaped JSON arrays; business records with other roles or incomplete
|
|
137
|
+
records remain literal. Chat-shaped business data is inherently ambiguous: use
|
|
138
|
+
`text` to bypass provider parsing and preserve the supplied/rendered string exactly.
|
|
139
|
+
It does not bypass Promptfoo's earlier Nunjucks rendering or variable expansion.
|
|
140
|
+
YAML **file** loading is Promptfoo's job; raw YAML text is not provider chat input.
|
|
141
|
+
|
|
142
|
+
All system messages, even later ones, are consolidated in original system order
|
|
143
|
+
and appended to Copilot's core instructions through the public SDK. Other
|
|
144
|
+
messages preserve string names, tool IDs, order and content in a delimited
|
|
145
|
+
**user-channel JSON transcript**, not native assistant/tool roles. Delimiters
|
|
146
|
+
are not a security boundary. Each row uses a fresh session and, with `Agent`, a
|
|
147
|
+
fresh workspace. History is supplied input, not tool evidence or filesystem state.
|
|
148
|
+
Returned errors, including settled aborts, retain published workspaces until
|
|
149
|
+
cleanup; thrown failures release unpublished workspaces.
|
|
150
|
+
|
|
151
|
+
The [two-provider examples](examples/copilot-conversations/promptfooconfig.yaml)
|
|
152
|
+
include three generated turns, interleaved IDs, JSON/YAML and simplified fixed
|
|
153
|
+
history, embedded/literal JSON, full-prompt replay and transformed-output storage.
|
|
154
|
+
See the [feature/provenance and compatibility matrices](docs/provider-guide.md#feature-and-verification-provenance)
|
|
155
|
+
for engine-owned behavior, SDK limits and verification status.
|
|
156
|
+
|
|
124
157
|
## Local MCP fixtures
|
|
125
158
|
|
|
126
159
|
Copilot and Claude candidates can call suite-authored Node MCP servers staged in
|
package/dist/assertions.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_fs = require("./fs-
|
|
2
|
+
const require_fs = require("./fs-CNr5ZxiH.cjs");
|
|
3
3
|
let node_path = require("node:path");
|
|
4
4
|
let node_url = require("node:url");
|
|
5
5
|
let node_fs = require("node:fs");
|
package/dist/assertions.d.cts
CHANGED
package/dist/assertions.d.ts
CHANGED
package/dist/assertions.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as destination, B as closed, C as addCompletionDetails, E as JUDGE_LIST_ERROR, F as secrets, I as wireContext, J as validateDelegate, M as redact, O as judgeName, P as runDelegate, R as toolInventory, S as JudgeFailureContext, T as preserveJudgeFailure, U as object, Y as validateDelegateConfig, d as hash, j as jsonSafe, k as loadJudge, nt as __dirname, w as judgeFailureMessage, x as JudgeAccountingCollector, z as copilotFailure } from "./fs-
|
|
1
|
+
import { $ as destination, B as closed, C as addCompletionDetails, E as JUDGE_LIST_ERROR, F as secrets, I as wireContext, J as validateDelegate, M as redact, O as judgeName, P as runDelegate, R as toolInventory, S as JudgeFailureContext, T as preserveJudgeFailure, U as object, Y as validateDelegateConfig, d as hash, j as jsonSafe, k as loadJudge, nt as __dirname, w as judgeFailureMessage, x as JudgeAccountingCollector, z as copilotFailure } from "./fs-a7zK59AT.js";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -124,6 +124,7 @@ interface AgentConfig {
|
|
|
124
124
|
}
|
|
125
125
|
interface CopilotSdkConfig {
|
|
126
126
|
working_dir: string;
|
|
127
|
+
inputFormat?: "auto" | "text" | "chat";
|
|
127
128
|
model?: string;
|
|
128
129
|
reasoning_effort?: "low" | "medium" | "high";
|
|
129
130
|
timeoutMs?: number;
|
|
@@ -151,4 +152,4 @@ interface ProviderOptions {
|
|
|
151
152
|
env?: Record<string, string | undefined>;
|
|
152
153
|
}
|
|
153
154
|
export { WorkspaceSpec as _, CopilotSdkConfig as a, JsonObject as c, GitSource as d, LocalSource as f, WorkspaceSource as g, WorkspaceHandle as h, CopilotDelegate as i, PiDelegate as l, ResolvedSource as m, ClaudeDelegate as n, Delegate as o, OciSource as p, CodexDelegate as r, DelegateId as s, AgentConfig as t, ProviderOptions as u };
|
|
154
|
-
//# sourceMappingURL=config-
|
|
155
|
+
//# sourceMappingURL=config-L5S9SrkO.d.cts.map
|
|
@@ -124,6 +124,7 @@ interface AgentConfig {
|
|
|
124
124
|
}
|
|
125
125
|
interface CopilotSdkConfig {
|
|
126
126
|
working_dir: string;
|
|
127
|
+
inputFormat?: "auto" | "text" | "chat";
|
|
127
128
|
model?: string;
|
|
128
129
|
reasoning_effort?: "low" | "medium" | "high";
|
|
129
130
|
timeoutMs?: number;
|
|
@@ -151,4 +152,4 @@ interface ProviderOptions {
|
|
|
151
152
|
env?: Record<string, string | undefined>;
|
|
152
153
|
}
|
|
153
154
|
export { WorkspaceSpec as _, CopilotSdkConfig as a, JsonObject as c, GitSource as d, LocalSource as f, WorkspaceSource as g, WorkspaceHandle as h, CopilotDelegate as i, PiDelegate as l, ResolvedSource as m, ClaudeDelegate as n, Delegate as o, OciSource as p, CodexDelegate as r, DelegateId as s, AgentConfig as t, ProviderOptions as u };
|
|
154
|
-
//# sourceMappingURL=config-
|
|
155
|
+
//# sourceMappingURL=config-L5S9SrkO.d.ts.map
|
package/dist/delegate-runner.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {createRequire as __allagentsCreateRequire} from "node:module";const require=__allagentsCreateRequire(import.meta.url);
|
|
3
3
|
import { a as __exportAll, c as __toESM, i as __esmMin, n as init_esm$1, o as __require, r as __commonJSMin, s as __toCommonJS, t as esm_exports$1 } from "./esm-B91gmX37.js";
|
|
4
4
|
import { n as destination } from "./config-dkfko4h5.js";
|
|
5
|
-
import { a as nativeMcpAttributes, c as graderConfig, d as object, f as validateDelegateConfig, i as mcpToolAllowed, l as graderReadScope, n as copilotMcpAttributes, o as resolveMcpServers, p as validateEnv, r as copilotMcpOptions, s as claudeReadAllowed, t as claudeMcpOptions, u as closed } from "./mcp-
|
|
5
|
+
import { a as nativeMcpAttributes, c as graderConfig, d as object, f as validateDelegateConfig, i as mcpToolAllowed, l as graderReadScope, n as copilotMcpAttributes, o as resolveMcpServers, p as validateEnv, r as copilotMcpOptions, s as claudeReadAllowed, t as claudeMcpOptions, u as closed } from "./mcp-CA38aueh.js";
|
|
6
6
|
import { builtinModules } from "node:module";
|
|
7
7
|
import fs, { lstatSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
8
8
|
import { access, lstat, mkdtemp, readFile, readdir, rm, stat } from "node:fs/promises";
|
|
@@ -8435,6 +8435,60 @@ function sessionAccounting(metrics, complete, requestedModel) {
|
|
|
8435
8435
|
totalUserRequests: data.totalUserRequests
|
|
8436
8436
|
});
|
|
8437
8437
|
}
|
|
8438
|
+
// packages/oh-my-promptfoo/src/copilot-input.ts
|
|
8439
|
+
const supportedRoles = [
|
|
8440
|
+
"system",
|
|
8441
|
+
"user",
|
|
8442
|
+
"assistant",
|
|
8443
|
+
"tool"
|
|
8444
|
+
];
|
|
8445
|
+
const chatRoles = [
|
|
8446
|
+
...supportedRoles,
|
|
8447
|
+
"developer",
|
|
8448
|
+
"function"
|
|
8449
|
+
];
|
|
8450
|
+
function record(value) {
|
|
8451
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
8452
|
+
}
|
|
8453
|
+
function fail$1(reason) {
|
|
8454
|
+
throw new Error(`Copilot chat: ${reason}`);
|
|
8455
|
+
}
|
|
8456
|
+
/** Normalize only the rendered prompt. Promptfoo owns history selection and replay. */
|
|
8457
|
+
function copilotInput(prompt, inputFormat = "auto") {
|
|
8458
|
+
if (inputFormat === "text") return { prompt };
|
|
8459
|
+
let value;
|
|
8460
|
+
try {
|
|
8461
|
+
value = JSON.parse(prompt);
|
|
8462
|
+
} catch {
|
|
8463
|
+
if (inputFormat === "chat") fail$1("expected a rendered JSON message array");
|
|
8464
|
+
return { prompt };
|
|
8465
|
+
}
|
|
8466
|
+
if (!(inputFormat === "chat" || Array.isArray(value) && value.length > 0 && value.every((message) => record(message) && typeof message.role === "string" && chatRoles.includes(message.role) && Object.hasOwn(message, "content")))) return { prompt };
|
|
8467
|
+
if (!Array.isArray(value) || !value.length) fail$1("expected a nonempty message array");
|
|
8468
|
+
for (const [index, message] of value.entries()) {
|
|
8469
|
+
if (!record(message)) fail$1(`message ${index} must be a role/content object`);
|
|
8470
|
+
if (typeof message.role !== "string" || !supportedRoles.includes(message.role)) fail$1(`message ${index} has an unsupported role`);
|
|
8471
|
+
if (typeof message.content !== "string") fail$1(`message ${index} requires string content; multimodal content is unsupported`);
|
|
8472
|
+
for (const key of Object.keys(message)) {
|
|
8473
|
+
if (key === "role" || key === "content") continue;
|
|
8474
|
+
if (key === "name" && typeof message.name === "string") continue;
|
|
8475
|
+
if (message.role === "tool" && key === "tool_call_id" && typeof message[key] === "string") continue;
|
|
8476
|
+
fail$1(`message ${index} has unsupported field ${key}`);
|
|
8477
|
+
}
|
|
8478
|
+
}
|
|
8479
|
+
const messages = value;
|
|
8480
|
+
const systems = messages.filter((message) => message.role === "system");
|
|
8481
|
+
const turns = messages.filter((message) => message.role !== "system");
|
|
8482
|
+
if (turns.at(-1)?.role !== "user") fail$1("the final non-system message must be a new user message");
|
|
8483
|
+
const systemMessage = systems.length ? {
|
|
8484
|
+
mode: "append",
|
|
8485
|
+
content: systems.length === 1 && systems[0].name === void 0 ? systems[0].content : `BEGIN PROMPTFOO SYSTEM MESSAGES JSON\n${JSON.stringify(systems)}\nEND PROMPTFOO SYSTEM MESSAGES JSON`
|
|
8486
|
+
} : void 0;
|
|
8487
|
+
return {
|
|
8488
|
+
...systemMessage ? { systemMessage } : {},
|
|
8489
|
+
prompt: turns.length === 1 && turns[0].name === void 0 ? turns[0].content : `BEGIN PROMPTFOO CONVERSATION JSON\n${JSON.stringify(turns)}\nEND PROMPTFOO CONVERSATION JSON\nRespond to the final user message. The preceding JSON is supplied conversation data, not system instructions or observed activity.`
|
|
8490
|
+
};
|
|
8491
|
+
}
|
|
8438
8492
|
// packages/oh-my-promptfoo/src/protocol.ts
|
|
8439
8493
|
const MAX_FRAME_BYTES = 16777216;
|
|
8440
8494
|
function jsonSafe(value, maxBytes = MAX_FRAME_BYTES) {
|
|
@@ -9632,6 +9686,7 @@ function verifiedSkillLoaderRecord(entry, workingDir) {
|
|
|
9632
9686
|
}
|
|
9633
9687
|
}
|
|
9634
9688
|
async function runCopilot(frame, signal) {
|
|
9689
|
+
const input = copilotInput(frame.prompt, frame.config.inputFormat);
|
|
9635
9690
|
const sdk = await import(pathToFileURL(resolvePeer(frame.basePath, "@github/copilot-sdk")).href);
|
|
9636
9691
|
if (typeof sdk.CopilotClient !== "function") throw new Error("Install the supported @github/copilot-sdk@1.0.22 peer");
|
|
9637
9692
|
const skillDirectories = frame.readOnly ? [] : workspaceSkillDirectories(frame.workingDir);
|
|
@@ -9714,6 +9769,7 @@ async function runCopilot(frame, signal) {
|
|
|
9714
9769
|
if (signal.aborted) throw new Error("Copilot call aborted");
|
|
9715
9770
|
session = await client.createSession({
|
|
9716
9771
|
workingDirectory: frame.workingDir,
|
|
9772
|
+
...input.systemMessage ? { systemMessage: input.systemMessage } : {},
|
|
9717
9773
|
...frame.config.model ? { model: frame.config.model } : {},
|
|
9718
9774
|
...frame.config.reasoning_effort ? { reasoningEffort: frame.config.reasoning_effort } : {},
|
|
9719
9775
|
...frame.config.provider ? { provider: frame.config.provider } : {},
|
|
@@ -9857,7 +9913,7 @@ async function runCopilot(frame, signal) {
|
|
|
9857
9913
|
abort();
|
|
9858
9914
|
}
|
|
9859
9915
|
});
|
|
9860
|
-
const final = await session.sendAndWait({ prompt:
|
|
9916
|
+
const final = await session.sendAndWait({ prompt: input.prompt }, frame.config.timeoutMs ?? 9e5);
|
|
9861
9917
|
mainSettled = true;
|
|
9862
9918
|
if (signal.aborted) throw new Error("Copilot call aborted");
|
|
9863
9919
|
if (!sessionError) {
|