veryfront 0.1.877 → 0.1.878
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/esm/deno.js +1 -1
- package/esm/src/eval/agent-service/durable-run-canaries/cli-runner.d.ts +21 -0
- package/esm/src/eval/agent-service/durable-run-canaries/cli-runner.d.ts.map +1 -0
- package/esm/src/eval/agent-service/durable-run-canaries/cli-runner.js +66 -0
- package/esm/src/eval/agent-service/durable-run-canaries/environment.d.ts +14 -0
- package/esm/src/eval/agent-service/durable-run-canaries/environment.d.ts.map +1 -0
- package/esm/src/eval/agent-service/durable-run-canaries/environment.js +15 -0
- package/esm/src/eval/agent-service/durable-run-canaries/index.d.ts +5 -0
- package/esm/src/eval/agent-service/durable-run-canaries/index.d.ts.map +1 -0
- package/esm/src/eval/agent-service/durable-run-canaries/index.js +4 -0
- package/esm/src/eval/agent-service/durable-run-canaries/runner.d.ts +118 -0
- package/esm/src/eval/agent-service/durable-run-canaries/runner.d.ts.map +1 -0
- package/esm/src/eval/agent-service/durable-run-canaries/runner.js +391 -0
- package/esm/src/eval/agent-service/durable-run-canaries/validation.d.ts +12 -0
- package/esm/src/eval/agent-service/durable-run-canaries/validation.d.ts.map +1 -0
- package/esm/src/eval/agent-service/durable-run-canaries/validation.js +71 -0
- package/esm/src/eval/agent-service/live-evals/api-client.d.ts +102 -0
- package/esm/src/eval/agent-service/live-evals/api-client.d.ts.map +1 -0
- package/esm/src/eval/agent-service/live-evals/api-client.js +313 -0
- package/esm/src/eval/agent-service/live-evals/cli-runner.d.ts +40 -0
- package/esm/src/eval/agent-service/live-evals/cli-runner.d.ts.map +1 -0
- package/esm/src/eval/agent-service/live-evals/cli-runner.js +144 -0
- package/esm/src/eval/agent-service/live-evals/environment.d.ts +15 -0
- package/esm/src/eval/agent-service/live-evals/environment.d.ts.map +1 -0
- package/esm/src/eval/agent-service/live-evals/environment.js +20 -0
- package/esm/src/eval/agent-service/live-evals/formatting.d.ts +15 -0
- package/esm/src/eval/agent-service/live-evals/formatting.d.ts.map +1 -0
- package/esm/src/eval/agent-service/live-evals/formatting.js +75 -0
- package/esm/src/eval/agent-service/live-evals/index.d.ts +12 -0
- package/esm/src/eval/agent-service/live-evals/index.d.ts.map +1 -0
- package/esm/src/eval/agent-service/live-evals/index.js +11 -0
- package/esm/src/eval/agent-service/live-evals/metadata.d.ts +34 -0
- package/esm/src/eval/agent-service/live-evals/metadata.d.ts.map +1 -0
- package/esm/src/eval/agent-service/live-evals/metadata.js +116 -0
- package/esm/src/eval/agent-service/live-evals/performance.d.ts +19 -0
- package/esm/src/eval/agent-service/live-evals/performance.d.ts.map +1 -0
- package/esm/src/eval/agent-service/live-evals/performance.js +22 -0
- package/esm/src/eval/agent-service/live-evals/preflight.d.ts +12 -0
- package/esm/src/eval/agent-service/live-evals/preflight.d.ts.map +1 -0
- package/esm/src/eval/agent-service/live-evals/preflight.js +27 -0
- package/esm/src/eval/agent-service/live-evals/report.d.ts +55 -0
- package/esm/src/eval/agent-service/live-evals/report.d.ts.map +1 -0
- package/esm/src/eval/agent-service/live-evals/report.js +79 -0
- package/esm/src/eval/agent-service/live-evals/request.d.ts +31 -0
- package/esm/src/eval/agent-service/live-evals/request.d.ts.map +1 -0
- package/esm/src/eval/agent-service/live-evals/request.js +48 -0
- package/esm/src/eval/agent-service/live-evals/result.d.ts +56 -0
- package/esm/src/eval/agent-service/live-evals/result.d.ts.map +1 -0
- package/esm/src/eval/agent-service/live-evals/result.js +36 -0
- package/esm/src/eval/agent-service/live-evals/runner.d.ts +135 -0
- package/esm/src/eval/agent-service/live-evals/runner.d.ts.map +1 -0
- package/esm/src/eval/agent-service/live-evals/runner.js +396 -0
- package/esm/src/eval/agent-service.d.ts +2 -0
- package/esm/src/eval/agent-service.d.ts.map +1 -1
- package/esm/src/eval/agent-service.js +2 -0
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
package/esm/deno.js
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type LiveEvalApiContext } from "../live-evals/api-client.js";
|
|
2
|
+
import { createDurableRunCanaryRunner, type DurableRunCanaryCase, type DurableRunCanaryRunnerConfig } from "./runner.js";
|
|
3
|
+
type EnvRecord = Record<string, string | undefined>;
|
|
4
|
+
/** Input payload for durable run canary cli case factory. */
|
|
5
|
+
export interface DurableRunCanaryCliCaseFactoryInput {
|
|
6
|
+
context: LiveEvalApiContext;
|
|
7
|
+
requestTimeoutMs: number;
|
|
8
|
+
}
|
|
9
|
+
/** Input payload for run durable run canary cli. */
|
|
10
|
+
export interface RunDurableRunCanaryCliInput {
|
|
11
|
+
env: EnvRecord;
|
|
12
|
+
agentId: string;
|
|
13
|
+
createCases: (input: DurableRunCanaryCliCaseFactoryInput) => DurableRunCanaryCase[];
|
|
14
|
+
cwd?: string;
|
|
15
|
+
log?: (message: string) => void;
|
|
16
|
+
createRunner?: (config: DurableRunCanaryRunnerConfig) => ReturnType<typeof createDurableRunCanaryRunner>;
|
|
17
|
+
}
|
|
18
|
+
/** Run durable run canary cli. */
|
|
19
|
+
export declare function runDurableRunCanaryCli(input: RunDurableRunCanaryCliInput): Promise<number>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=cli-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-runner.d.ts","sourceRoot":"","sources":["../../../../../src/src/eval/agent-service/durable-run-canaries/cli-runner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,OAAO,EACL,4BAA4B,EAC5B,KAAK,oBAAoB,EAEzB,KAAK,4BAA4B,EAClC,MAAM,aAAa,CAAC;AAErB,KAAK,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAEpD,6DAA6D;AAC7D,MAAM,WAAW,mCAAmC;IAClD,OAAO,EAAE,kBAAkB,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,oDAAoD;AACpD,MAAM,WAAW,2BAA2B;IAC1C,GAAG,EAAE,SAAS,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,CAAC,KAAK,EAAE,mCAAmC,KAAK,oBAAoB,EAAE,CAAC;IACpF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,YAAY,CAAC,EAAE,CACb,MAAM,EAAE,4BAA4B,KACjC,UAAU,CAAC,OAAO,4BAA4B,CAAC,CAAC;CACtD;AAcD,kCAAkC;AAClC,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAAC,MAAM,CAAC,CAwEjB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { mkdir, writeTextFile } from "../../../platform/compat/fs.js";
|
|
2
|
+
import { dirname, resolve } from "../../../platform/compat/path/index.js";
|
|
3
|
+
import { cwd as getProcessCwd } from "../../../platform/compat/process.js";
|
|
4
|
+
import { resolveDurableRunCanaryEnvironment } from "./environment.js";
|
|
5
|
+
import { createDurableRunCanaryRunner, } from "./runner.js";
|
|
6
|
+
function createTimestampedReportPath(input) {
|
|
7
|
+
return resolve(input.cwd, ".omx/logs", input.directory, `${new Date().toISOString().replaceAll(":", "-").replaceAll(".", "-")}.json`);
|
|
8
|
+
}
|
|
9
|
+
/** Run durable run canary cli. */
|
|
10
|
+
export async function runDurableRunCanaryCli(input) {
|
|
11
|
+
const log = input.log ?? console.log;
|
|
12
|
+
const cwd = input.cwd ?? getProcessCwd();
|
|
13
|
+
const { apiUrl, authToken, projectId, requestTimeoutMs, keepSuccessfulEvidence } = resolveDurableRunCanaryEnvironment(input.env);
|
|
14
|
+
const reportPath = input.env.DURABLE_CANARY_REPORT_PATH ??
|
|
15
|
+
createTimestampedReportPath({ cwd, directory: "durable-run-staging-canaries" });
|
|
16
|
+
if (!authToken) {
|
|
17
|
+
throw new Error("Missing VERYFRONT_TOKEN");
|
|
18
|
+
}
|
|
19
|
+
if (!projectId) {
|
|
20
|
+
throw new Error("Missing AG_UI_EVAL_PROJECT_ID");
|
|
21
|
+
}
|
|
22
|
+
const context = {
|
|
23
|
+
apiUrl,
|
|
24
|
+
authToken,
|
|
25
|
+
projectId,
|
|
26
|
+
};
|
|
27
|
+
const createRunner = input.createRunner ?? createDurableRunCanaryRunner;
|
|
28
|
+
const { runCase } = createRunner({
|
|
29
|
+
apiUrl,
|
|
30
|
+
authToken,
|
|
31
|
+
agentId: input.agentId,
|
|
32
|
+
projectId,
|
|
33
|
+
requestTimeoutMs,
|
|
34
|
+
keepSuccessfulEvidence,
|
|
35
|
+
});
|
|
36
|
+
const testCases = input.createCases({
|
|
37
|
+
context,
|
|
38
|
+
requestTimeoutMs,
|
|
39
|
+
});
|
|
40
|
+
log(`Durable run canaries -> ${apiUrl}`);
|
|
41
|
+
log(`Project scope -> ${projectId}`);
|
|
42
|
+
const results = [];
|
|
43
|
+
for (const testCase of testCases) {
|
|
44
|
+
log(`\n[run] ${testCase.label}`);
|
|
45
|
+
const result = await runCase(testCase);
|
|
46
|
+
results.push(result);
|
|
47
|
+
log(`[${result.status}] ${result.id}: ${result.details}`);
|
|
48
|
+
}
|
|
49
|
+
const summary = {
|
|
50
|
+
passed: results.filter((result) => result.status === "pass").length,
|
|
51
|
+
failed: results.filter((result) => result.status === "fail").length,
|
|
52
|
+
};
|
|
53
|
+
await mkdir(dirname(reportPath), { recursive: true });
|
|
54
|
+
await writeTextFile(reportPath, JSON.stringify({
|
|
55
|
+
generatedAt: new Date().toISOString(),
|
|
56
|
+
apiUrl,
|
|
57
|
+
projectId,
|
|
58
|
+
results,
|
|
59
|
+
summary,
|
|
60
|
+
}, null, 2));
|
|
61
|
+
log("\nSummary");
|
|
62
|
+
log(`passed: ${summary.passed}`);
|
|
63
|
+
log(`failed: ${summary.failed}`);
|
|
64
|
+
log(`report: ${reportPath}`);
|
|
65
|
+
return summary.failed > 0 ? 1 : 0;
|
|
66
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type AgentServiceConfigInput } from "../../../agent/service/config.js";
|
|
2
|
+
/** Public API contract for durable run canary environment. */
|
|
3
|
+
export interface DurableRunCanaryEnvironment {
|
|
4
|
+
apiUrl: string;
|
|
5
|
+
authToken: string;
|
|
6
|
+
projectId: string;
|
|
7
|
+
requestTimeoutMs: number;
|
|
8
|
+
keepSuccessfulEvidence: boolean;
|
|
9
|
+
}
|
|
10
|
+
/** Default value for durable run canary timeout ms. */
|
|
11
|
+
export declare const DEFAULT_DURABLE_RUN_CANARY_TIMEOUT_MS = 240000;
|
|
12
|
+
/** Resolves durable run canary environment. */
|
|
13
|
+
export declare function resolveDurableRunCanaryEnvironment(env?: AgentServiceConfigInput): DurableRunCanaryEnvironment;
|
|
14
|
+
//# sourceMappingURL=environment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../../../../src/src/eval/agent-service/durable-run-canaries/environment.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,uBAAuB,EAE7B,MAAM,kCAAkC,CAAC;AAE1C,8DAA8D;AAC9D,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,EAAE,OAAO,CAAC;CACjC;AAED,uDAAuD;AACvD,eAAO,MAAM,qCAAqC,SAAU,CAAC;AAE7D,+CAA+C;AAC/C,wBAAgB,kCAAkC,CAChD,GAAG,GAAE,uBAA4B,GAChC,2BAA2B,CAY7B"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { parseAgentServiceConfig, } from "../../../agent/service/config.js";
|
|
2
|
+
/** Default value for durable run canary timeout ms. */
|
|
3
|
+
export const DEFAULT_DURABLE_RUN_CANARY_TIMEOUT_MS = 240_000;
|
|
4
|
+
/** Resolves durable run canary environment. */
|
|
5
|
+
export function resolveDurableRunCanaryEnvironment(env = {}) {
|
|
6
|
+
return {
|
|
7
|
+
apiUrl: typeof env.VERYFRONT_API_URL === "string"
|
|
8
|
+
? env.VERYFRONT_API_URL
|
|
9
|
+
: parseAgentServiceConfig(env).VERYFRONT_API_URL,
|
|
10
|
+
authToken: typeof env.VERYFRONT_TOKEN === "string" ? env.VERYFRONT_TOKEN : "",
|
|
11
|
+
projectId: typeof env.AG_UI_EVAL_PROJECT_ID === "string" ? env.AG_UI_EVAL_PROJECT_ID : "",
|
|
12
|
+
requestTimeoutMs: Number(env.DURABLE_CANARY_TIMEOUT_MS ?? DEFAULT_DURABLE_RUN_CANARY_TIMEOUT_MS),
|
|
13
|
+
keepSuccessfulEvidence: env.DURABLE_CANARY_KEEP_SUCCESS === "1",
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { type DurableRunCanaryCliCaseFactoryInput, runDurableRunCanaryCli, type RunDurableRunCanaryCliInput, } from "./cli-runner.js";
|
|
2
|
+
export { DEFAULT_DURABLE_RUN_CANARY_TIMEOUT_MS, type DurableRunCanaryEnvironment, resolveDurableRunCanaryEnvironment, } from "./environment.js";
|
|
3
|
+
export { createDurableRunCanaryApiClient, createDurableRunCanaryRunner, type DurableRunCanaryApiClient, type DurableRunCanaryApiConfig, type DurableRunCanaryCase, type DurableRunCanaryCreateRootRunInput, type DurableRunCanaryMessage, type DurableRunCanaryPreparedCase, type DurableRunCanaryResult, type DurableRunCanaryRunnerConfig, durableRunCanaryRunnerInternals, type DurableRunCanaryRunSummary, type DurableRunCanarySendUserMessageInput, type DurableRunCanaryStartRunInput, getDurableRunCanaryMessageSchema, parseDurableRunCanaryRunSummary, } from "./runner.js";
|
|
4
|
+
export { assertCompleted, assertNoMalformedCreateFileToolCalls, collectAssistantText, findAssistantMessage, stringifyUnknown, } from "./validation.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/src/eval/agent-service/durable-run-canaries/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,mCAAmC,EACxC,sBAAsB,EACtB,KAAK,2BAA2B,GACjC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,qCAAqC,EACrC,KAAK,2BAA2B,EAChC,kCAAkC,GACnC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,+BAA+B,EAC/B,4BAA4B,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,KAAK,kCAAkC,EACvC,KAAK,uBAAuB,EAC5B,KAAK,4BAA4B,EACjC,KAAK,sBAAsB,EAC3B,KAAK,4BAA4B,EACjC,+BAA+B,EAC/B,KAAK,0BAA0B,EAC/B,KAAK,oCAAoC,EACzC,KAAK,6BAA6B,EAClC,gCAAgC,EAChC,+BAA+B,GAChC,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,eAAe,EACf,oCAAoC,EACpC,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { runDurableRunCanaryCli, } from "./cli-runner.js";
|
|
2
|
+
export { DEFAULT_DURABLE_RUN_CANARY_TIMEOUT_MS, resolveDurableRunCanaryEnvironment, } from "./environment.js";
|
|
3
|
+
export { createDurableRunCanaryApiClient, createDurableRunCanaryRunner, durableRunCanaryRunnerInternals, getDurableRunCanaryMessageSchema, parseDurableRunCanaryRunSummary, } from "./runner.js";
|
|
4
|
+
export { assertCompleted, assertNoMalformedCreateFileToolCalls, collectAssistantText, findAssistantMessage, stringifyUnknown, } from "./validation.js";
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { InferSchema } from "../../../extensions/schema/index.js";
|
|
2
|
+
/** Configuration used by durable run canary API. */
|
|
3
|
+
export interface DurableRunCanaryApiConfig {
|
|
4
|
+
apiUrl: string;
|
|
5
|
+
authToken: string;
|
|
6
|
+
agentId: string;
|
|
7
|
+
projectId: string | null;
|
|
8
|
+
branchId?: string | null;
|
|
9
|
+
requestTimeoutMs: number;
|
|
10
|
+
fetch?: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
11
|
+
}
|
|
12
|
+
/** Input payload for durable run canary create root run. */
|
|
13
|
+
export interface DurableRunCanaryCreateRootRunInput {
|
|
14
|
+
conversationId: string;
|
|
15
|
+
runId: string;
|
|
16
|
+
}
|
|
17
|
+
/** Input payload for durable run canary send user message. */
|
|
18
|
+
export interface DurableRunCanarySendUserMessageInput {
|
|
19
|
+
conversationId: string;
|
|
20
|
+
prompt: string;
|
|
21
|
+
}
|
|
22
|
+
/** Input payload for durable run canary start run. */
|
|
23
|
+
export interface DurableRunCanaryStartRunInput extends DurableRunCanaryCreateRootRunInput {
|
|
24
|
+
messageId: string;
|
|
25
|
+
prompt: string;
|
|
26
|
+
userMessageId: string;
|
|
27
|
+
}
|
|
28
|
+
/** Zod schema for get durable run canary message. */
|
|
29
|
+
export declare const getDurableRunCanaryMessageSchema: () => import("../../../internal-agents/schema.js").Schema<{
|
|
30
|
+
id: string;
|
|
31
|
+
role: "tool" | "user" | "assistant" | "system";
|
|
32
|
+
parts: ({
|
|
33
|
+
type: string;
|
|
34
|
+
} & {} & Record<string, unknown>)[];
|
|
35
|
+
} & {
|
|
36
|
+
status?: string | undefined;
|
|
37
|
+
} & Record<string, unknown>>;
|
|
38
|
+
/** Message shape for durable run canary. */
|
|
39
|
+
export type DurableRunCanaryMessage = InferSchema<ReturnType<typeof getDurableRunCanaryMessageSchema>>;
|
|
40
|
+
/** Public API contract for durable run canary run summary. */
|
|
41
|
+
export interface DurableRunCanaryRunSummary {
|
|
42
|
+
runId: string;
|
|
43
|
+
conversationId: string;
|
|
44
|
+
messageId: string;
|
|
45
|
+
agentId: string;
|
|
46
|
+
status: string;
|
|
47
|
+
latestEventId: number;
|
|
48
|
+
latestExternalEventSequence: number | null;
|
|
49
|
+
waitingToolCallId: string | null;
|
|
50
|
+
waitingToolName: string | null;
|
|
51
|
+
terminalErrorCode: string | null;
|
|
52
|
+
terminalErrorMessage: string | null;
|
|
53
|
+
startedAt: string | null;
|
|
54
|
+
finishedAt: string | null;
|
|
55
|
+
}
|
|
56
|
+
/** Parses durable run canary run summary. */
|
|
57
|
+
export declare function parseDurableRunCanaryRunSummary(value: unknown): DurableRunCanaryRunSummary;
|
|
58
|
+
/** Public API contract for durable run canary API client. */
|
|
59
|
+
export interface DurableRunCanaryApiClient {
|
|
60
|
+
createDurableRootRun: (input: DurableRunCanaryCreateRootRunInput) => Promise<void>;
|
|
61
|
+
getRunSummary: (input: DurableRunCanaryCreateRootRunInput) => Promise<DurableRunCanaryRunSummary>;
|
|
62
|
+
listMessagesForCanary: (input: {
|
|
63
|
+
conversationId: string;
|
|
64
|
+
}) => Promise<DurableRunCanaryMessage[]>;
|
|
65
|
+
sendUserMessageForCanary: (input: DurableRunCanarySendUserMessageInput) => Promise<DurableRunCanaryMessage>;
|
|
66
|
+
startDurableRun: (input: DurableRunCanaryStartRunInput) => Promise<void>;
|
|
67
|
+
}
|
|
68
|
+
/** Create durable run canary API client. */
|
|
69
|
+
export declare function createDurableRunCanaryApiClient(config: DurableRunCanaryApiConfig): DurableRunCanaryApiClient;
|
|
70
|
+
/** Result returned from durable run canary. */
|
|
71
|
+
export interface DurableRunCanaryResult {
|
|
72
|
+
id: string;
|
|
73
|
+
label: string;
|
|
74
|
+
status: "pass" | "fail";
|
|
75
|
+
details: string;
|
|
76
|
+
durationMs: number;
|
|
77
|
+
conversationId: string;
|
|
78
|
+
runId: string;
|
|
79
|
+
artifactPaths?: string[];
|
|
80
|
+
}
|
|
81
|
+
/** Public API contract for durable run canary prepared case. */
|
|
82
|
+
export interface DurableRunCanaryPreparedCase {
|
|
83
|
+
artifactPaths?: string[] | ((runId: string) => string[]);
|
|
84
|
+
cleanup: (input?: {
|
|
85
|
+
runId: string;
|
|
86
|
+
}) => Promise<void>;
|
|
87
|
+
conversationId: string;
|
|
88
|
+
prompt: string;
|
|
89
|
+
startSidecar?: () => Promise<(() => Promise<void>) | void>;
|
|
90
|
+
title: string;
|
|
91
|
+
validate: (input: {
|
|
92
|
+
messages: DurableRunCanaryMessage[];
|
|
93
|
+
run: DurableRunCanaryRunSummary;
|
|
94
|
+
}) => Promise<void> | void;
|
|
95
|
+
}
|
|
96
|
+
/** Public API contract for durable run canary case. */
|
|
97
|
+
export interface DurableRunCanaryCase {
|
|
98
|
+
id: string;
|
|
99
|
+
label: string;
|
|
100
|
+
prepare: () => Promise<DurableRunCanaryPreparedCase>;
|
|
101
|
+
}
|
|
102
|
+
/** Configuration used by durable run canary runner. */
|
|
103
|
+
export interface DurableRunCanaryRunnerConfig extends DurableRunCanaryApiConfig {
|
|
104
|
+
keepSuccessfulEvidence: boolean;
|
|
105
|
+
}
|
|
106
|
+
declare function collectReferencedChildConversationIds(messages: DurableRunCanaryMessage[]): string[];
|
|
107
|
+
declare function isTerminalRunStatus(status: string): boolean;
|
|
108
|
+
/** Create durable run canary runner. */
|
|
109
|
+
export declare function createDurableRunCanaryRunner(config: DurableRunCanaryRunnerConfig, apiClient?: DurableRunCanaryApiClient): {
|
|
110
|
+
runCase: (testCase: DurableRunCanaryCase) => Promise<DurableRunCanaryResult>;
|
|
111
|
+
};
|
|
112
|
+
/** White-box helpers used by durable run canary tests. */
|
|
113
|
+
export declare const durableRunCanaryRunnerInternals: {
|
|
114
|
+
collectReferencedChildConversationIds: typeof collectReferencedChildConversationIds;
|
|
115
|
+
isTerminalRunStatus: typeof isTerminalRunStatus;
|
|
116
|
+
};
|
|
117
|
+
export {};
|
|
118
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../../../src/src/eval/agent-service/durable-run-canaries/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import * as dntShim from "../../../../_dnt.shims.js";
|
|
2
|
+
import { defineSchema } from "../../../schemas/index.js";
|
|
3
|
+
import { ensureBuiltinSchemaValidator } from "../../../extensions/builtin-extensions.js";
|
|
4
|
+
ensureBuiltinSchemaValidator();
|
|
5
|
+
/** Zod schema for get durable run canary message. */
|
|
6
|
+
export const getDurableRunCanaryMessageSchema = defineSchema((v) => v.object({
|
|
7
|
+
id: v.string(),
|
|
8
|
+
role: v.enum(["user", "assistant", "system", "tool"]),
|
|
9
|
+
status: v.string().optional(),
|
|
10
|
+
parts: v.array(v.object({ type: v.string() }).passthrough()).default([]),
|
|
11
|
+
}).passthrough());
|
|
12
|
+
const getSnakeRunSummarySchema = defineSchema((v) => v.object({
|
|
13
|
+
run_id: v.string(),
|
|
14
|
+
conversation_id: v.string().uuid(),
|
|
15
|
+
message_id: v.string().uuid(),
|
|
16
|
+
agent_id: v.string(),
|
|
17
|
+
status: v.string(),
|
|
18
|
+
latest_event_id: v.number().int().nonnegative(),
|
|
19
|
+
latest_external_event_sequence: v.number().int().nonnegative().optional(),
|
|
20
|
+
waiting_tool_call_id: v.string().nullable().optional(),
|
|
21
|
+
waiting_tool_name: v.string().nullable().optional(),
|
|
22
|
+
terminal_error_code: v.string().nullable().optional(),
|
|
23
|
+
terminal_error_message: v.string().nullable().optional(),
|
|
24
|
+
started_at: v.string().nullable().optional(),
|
|
25
|
+
finished_at: v.string().nullable().optional(),
|
|
26
|
+
}).passthrough());
|
|
27
|
+
const getCamelRunSummarySchema = defineSchema((v) => v.object({
|
|
28
|
+
runId: v.string(),
|
|
29
|
+
conversationId: v.string().uuid(),
|
|
30
|
+
messageId: v.string().uuid(),
|
|
31
|
+
agentId: v.string(),
|
|
32
|
+
status: v.string(),
|
|
33
|
+
latestEventId: v.number().int().nonnegative(),
|
|
34
|
+
latestExternalEventSequence: v.number().int().nonnegative().optional(),
|
|
35
|
+
waitingToolCallId: v.string().nullable().optional(),
|
|
36
|
+
waitingToolName: v.string().nullable().optional(),
|
|
37
|
+
terminalErrorCode: v.string().nullable().optional(),
|
|
38
|
+
terminalErrorMessage: v.string().nullable().optional(),
|
|
39
|
+
startedAt: v.string().nullable().optional(),
|
|
40
|
+
finishedAt: v.string().nullable().optional(),
|
|
41
|
+
}).passthrough());
|
|
42
|
+
const getDurableRunCanaryMessageListSchema = defineSchema((v) => v.object({
|
|
43
|
+
data: v.array(getDurableRunCanaryMessageSchema()),
|
|
44
|
+
}));
|
|
45
|
+
/** Parses durable run canary run summary. */
|
|
46
|
+
export function parseDurableRunCanaryRunSummary(value) {
|
|
47
|
+
const snake = getSnakeRunSummarySchema().safeParse(value);
|
|
48
|
+
if (snake.success) {
|
|
49
|
+
return {
|
|
50
|
+
runId: snake.data.run_id,
|
|
51
|
+
conversationId: snake.data.conversation_id,
|
|
52
|
+
messageId: snake.data.message_id,
|
|
53
|
+
agentId: snake.data.agent_id,
|
|
54
|
+
status: snake.data.status,
|
|
55
|
+
latestEventId: snake.data.latest_event_id,
|
|
56
|
+
latestExternalEventSequence: snake.data.latest_external_event_sequence ?? null,
|
|
57
|
+
waitingToolCallId: snake.data.waiting_tool_call_id ?? null,
|
|
58
|
+
waitingToolName: snake.data.waiting_tool_name ?? null,
|
|
59
|
+
terminalErrorCode: snake.data.terminal_error_code ?? null,
|
|
60
|
+
terminalErrorMessage: snake.data.terminal_error_message ?? null,
|
|
61
|
+
startedAt: snake.data.started_at ?? null,
|
|
62
|
+
finishedAt: snake.data.finished_at ?? null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const camel = getCamelRunSummarySchema().parse(value);
|
|
66
|
+
return {
|
|
67
|
+
runId: camel.runId,
|
|
68
|
+
conversationId: camel.conversationId,
|
|
69
|
+
messageId: camel.messageId,
|
|
70
|
+
agentId: camel.agentId,
|
|
71
|
+
status: camel.status,
|
|
72
|
+
latestEventId: camel.latestEventId,
|
|
73
|
+
latestExternalEventSequence: camel.latestExternalEventSequence ?? null,
|
|
74
|
+
waitingToolCallId: camel.waitingToolCallId ?? null,
|
|
75
|
+
waitingToolName: camel.waitingToolName ?? null,
|
|
76
|
+
terminalErrorCode: camel.terminalErrorCode ?? null,
|
|
77
|
+
terminalErrorMessage: camel.terminalErrorMessage ?? null,
|
|
78
|
+
startedAt: camel.startedAt ?? null,
|
|
79
|
+
finishedAt: camel.finishedAt ?? null,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function createJsonHeaders(config, headers) {
|
|
83
|
+
const result = new Headers(headers);
|
|
84
|
+
if (!result.has("Content-Type")) {
|
|
85
|
+
result.set("Content-Type", "application/json");
|
|
86
|
+
}
|
|
87
|
+
result.set("Authorization", `Bearer ${config.authToken}`);
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
function createFetch(config) {
|
|
91
|
+
return config.fetch ?? fetch;
|
|
92
|
+
}
|
|
93
|
+
function createApiUrl(config, path) {
|
|
94
|
+
const baseHref = config.apiUrl.endsWith("/") ? config.apiUrl : `${config.apiUrl}/`;
|
|
95
|
+
const relativePath = path.startsWith("/") ? path.slice(1) : path;
|
|
96
|
+
return new URL(relativePath, baseHref);
|
|
97
|
+
}
|
|
98
|
+
function buildCreateRootRunTargetFields(config) {
|
|
99
|
+
if (!config.projectId) {
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
if (config.branchId) {
|
|
103
|
+
return {
|
|
104
|
+
source_target_kind: "preview_branch",
|
|
105
|
+
runtime_target_kind: "preview_branch",
|
|
106
|
+
source_target_branch_id: config.branchId,
|
|
107
|
+
runtime_target_branch_id: config.branchId,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
source_target_kind: "project",
|
|
112
|
+
runtime_target_kind: "main_branch",
|
|
113
|
+
runtime_target_branch_id: null,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function buildCreateRootRunBody(config, input) {
|
|
117
|
+
return {
|
|
118
|
+
kind: "agent",
|
|
119
|
+
owner: {
|
|
120
|
+
kind: "conversation",
|
|
121
|
+
id: input.conversationId,
|
|
122
|
+
},
|
|
123
|
+
public_id: input.runId,
|
|
124
|
+
request: {
|
|
125
|
+
mode: "agent",
|
|
126
|
+
agent_id: config.agentId,
|
|
127
|
+
initial_status: "pending",
|
|
128
|
+
...buildCreateRootRunTargetFields(config),
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function buildStartRunBody(config, input) {
|
|
133
|
+
return {
|
|
134
|
+
kind: "agent",
|
|
135
|
+
owner: {
|
|
136
|
+
kind: "conversation",
|
|
137
|
+
id: input.conversationId,
|
|
138
|
+
},
|
|
139
|
+
public_id: input.runId,
|
|
140
|
+
request: {
|
|
141
|
+
mode: "agent",
|
|
142
|
+
agent_id: config.agentId,
|
|
143
|
+
input: {
|
|
144
|
+
messages: [
|
|
145
|
+
{
|
|
146
|
+
id: input.userMessageId,
|
|
147
|
+
role: "user",
|
|
148
|
+
parts: [{ type: "text", text: input.prompt }],
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
context: {
|
|
152
|
+
conversation_id: input.conversationId,
|
|
153
|
+
project_id: config.projectId,
|
|
154
|
+
branch_id: config.branchId ?? null,
|
|
155
|
+
},
|
|
156
|
+
durable_root_run: {
|
|
157
|
+
run_id: input.runId,
|
|
158
|
+
message_id: input.messageId,
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/** Create durable run canary API client. */
|
|
165
|
+
export function createDurableRunCanaryApiClient(config) {
|
|
166
|
+
const request = createFetch(config);
|
|
167
|
+
async function apiFetch(path, init, parse) {
|
|
168
|
+
const response = await request(createApiUrl(config, path), {
|
|
169
|
+
...init,
|
|
170
|
+
headers: createJsonHeaders(config, init?.headers),
|
|
171
|
+
signal: AbortSignal.timeout(config.requestTimeoutMs),
|
|
172
|
+
});
|
|
173
|
+
if (!response.ok) {
|
|
174
|
+
throw new Error(`API ${init?.method ?? "GET"} ${path} failed: ${response.status} ${await response.text()}`);
|
|
175
|
+
}
|
|
176
|
+
const payload = await response.json();
|
|
177
|
+
return parse ? parse(payload) : payload;
|
|
178
|
+
}
|
|
179
|
+
async function sendUserMessageForCanary(input) {
|
|
180
|
+
return apiFetch(`/conversations/${input.conversationId}/messages`, {
|
|
181
|
+
method: "POST",
|
|
182
|
+
body: JSON.stringify({
|
|
183
|
+
role: "user",
|
|
184
|
+
parts: [{ type: "text", text: input.prompt }],
|
|
185
|
+
}),
|
|
186
|
+
}, (value) => getDurableRunCanaryMessageSchema().parse(value));
|
|
187
|
+
}
|
|
188
|
+
async function createDurableRootRun(input) {
|
|
189
|
+
await apiFetch("/runs", {
|
|
190
|
+
method: "POST",
|
|
191
|
+
body: JSON.stringify(buildCreateRootRunBody(config, input)),
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
async function startDurableRun(input) {
|
|
195
|
+
await apiFetch("/runs", {
|
|
196
|
+
method: "POST",
|
|
197
|
+
body: JSON.stringify(buildStartRunBody(config, input)),
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
async function getRunSummary(input) {
|
|
201
|
+
const response = await apiFetch(`/conversations/${input.conversationId}/runs/${input.runId}`);
|
|
202
|
+
return parseDurableRunCanaryRunSummary(response);
|
|
203
|
+
}
|
|
204
|
+
async function listMessagesForCanary(input) {
|
|
205
|
+
const payload = await apiFetch(`/conversations/${input.conversationId}/messages?limit=100`, undefined, (value) => getDurableRunCanaryMessageListSchema().parse(value));
|
|
206
|
+
return payload.data;
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
createDurableRootRun,
|
|
210
|
+
getRunSummary,
|
|
211
|
+
listMessagesForCanary,
|
|
212
|
+
sendUserMessageForCanary,
|
|
213
|
+
startDurableRun,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
217
|
+
function isRecord(value) {
|
|
218
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
219
|
+
}
|
|
220
|
+
function collectChildConversationIdsFromValue(value, childConversationIds, depth = 0) {
|
|
221
|
+
if (depth > 8) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (typeof value === "string") {
|
|
225
|
+
try {
|
|
226
|
+
collectChildConversationIdsFromValue(JSON.parse(value), childConversationIds, depth + 1);
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (Array.isArray(value)) {
|
|
234
|
+
for (const entry of value) {
|
|
235
|
+
collectChildConversationIdsFromValue(entry, childConversationIds, depth + 1);
|
|
236
|
+
}
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (!isRecord(value)) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
for (const key of ["childConversationId", "child_conversation_id"]) {
|
|
243
|
+
const childConversationId = value[key];
|
|
244
|
+
if (typeof childConversationId === "string" && UUID_PATTERN.test(childConversationId)) {
|
|
245
|
+
childConversationIds.add(childConversationId);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
for (const nestedValue of Object.values(value)) {
|
|
249
|
+
collectChildConversationIdsFromValue(nestedValue, childConversationIds, depth + 1);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function collectReferencedChildConversationIds(messages) {
|
|
253
|
+
const childConversationIds = new Set();
|
|
254
|
+
for (const message of messages) {
|
|
255
|
+
for (const part of message.parts) {
|
|
256
|
+
if (!isRecord(part) || (part.type !== "tool_result" && part.type !== "tool-result")) {
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
collectChildConversationIdsFromValue(part.output, childConversationIds);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return [...childConversationIds];
|
|
263
|
+
}
|
|
264
|
+
function sleep(ms) {
|
|
265
|
+
return new Promise((resolve) => {
|
|
266
|
+
dntShim.setTimeout(resolve, ms);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
function isTerminalRunStatus(status) {
|
|
270
|
+
return status === "completed" || status === "failed" || status === "cancelled";
|
|
271
|
+
}
|
|
272
|
+
function createDurableRunCanaryRunId() {
|
|
273
|
+
return `run_${dntShim.crypto.randomUUID()}`;
|
|
274
|
+
}
|
|
275
|
+
async function waitForRunSummaryVisibility(input) {
|
|
276
|
+
const deadline = Date.now() + 30_000;
|
|
277
|
+
while (Date.now() < deadline) {
|
|
278
|
+
try {
|
|
279
|
+
return await input.getRunSummary(input);
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
if (!(error instanceof Error) || !error.message.includes(" 404 ")) {
|
|
283
|
+
throw error;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
await sleep(500);
|
|
287
|
+
}
|
|
288
|
+
throw new Error(`Run ${input.runId} did not become visible in time`);
|
|
289
|
+
}
|
|
290
|
+
async function waitForTerminalRun(input) {
|
|
291
|
+
const deadline = Date.now() + input.requestTimeoutMs;
|
|
292
|
+
while (Date.now() < deadline) {
|
|
293
|
+
const run = await input.getRunSummary(input);
|
|
294
|
+
if (isTerminalRunStatus(run.status)) {
|
|
295
|
+
return run;
|
|
296
|
+
}
|
|
297
|
+
await sleep(1_500);
|
|
298
|
+
}
|
|
299
|
+
throw new Error(`Timed out waiting for run ${input.runId} to reach a terminal state`);
|
|
300
|
+
}
|
|
301
|
+
/** Create durable run canary runner. */
|
|
302
|
+
export function createDurableRunCanaryRunner(config, apiClient = createDurableRunCanaryApiClient(config)) {
|
|
303
|
+
const getRunSummary = apiClient.getRunSummary;
|
|
304
|
+
async function listMessagesWithReferencedChildren(conversationId) {
|
|
305
|
+
const messages = await apiClient.listMessagesForCanary({ conversationId });
|
|
306
|
+
const childConversationIds = collectReferencedChildConversationIds(messages);
|
|
307
|
+
const childMessages = await Promise.all(childConversationIds.map((childConversationId) => apiClient.listMessagesForCanary({ conversationId: childConversationId })));
|
|
308
|
+
return [...messages, ...childMessages.flat()];
|
|
309
|
+
}
|
|
310
|
+
async function runCase(testCase) {
|
|
311
|
+
const startedAt = Date.now();
|
|
312
|
+
const prepared = await testCase.prepare();
|
|
313
|
+
let runId = "unknown";
|
|
314
|
+
const stopSidecar = await prepared.startSidecar?.();
|
|
315
|
+
const resolveArtifactPaths = (currentRunId) => typeof prepared.artifactPaths === "function"
|
|
316
|
+
? prepared.artifactPaths(currentRunId)
|
|
317
|
+
: prepared.artifactPaths;
|
|
318
|
+
try {
|
|
319
|
+
const userMessage = await apiClient.sendUserMessageForCanary({
|
|
320
|
+
conversationId: prepared.conversationId,
|
|
321
|
+
prompt: prepared.prompt,
|
|
322
|
+
});
|
|
323
|
+
runId = createDurableRunCanaryRunId();
|
|
324
|
+
await apiClient.createDurableRootRun({
|
|
325
|
+
conversationId: prepared.conversationId,
|
|
326
|
+
runId,
|
|
327
|
+
});
|
|
328
|
+
const visibleRun = await waitForRunSummaryVisibility({
|
|
329
|
+
conversationId: prepared.conversationId,
|
|
330
|
+
getRunSummary,
|
|
331
|
+
runId,
|
|
332
|
+
});
|
|
333
|
+
await apiClient.startDurableRun({
|
|
334
|
+
conversationId: prepared.conversationId,
|
|
335
|
+
messageId: visibleRun.messageId,
|
|
336
|
+
prompt: prepared.prompt,
|
|
337
|
+
runId,
|
|
338
|
+
userMessageId: userMessage.id,
|
|
339
|
+
});
|
|
340
|
+
const terminalRun = await waitForTerminalRun({
|
|
341
|
+
conversationId: prepared.conversationId,
|
|
342
|
+
getRunSummary,
|
|
343
|
+
requestTimeoutMs: config.requestTimeoutMs,
|
|
344
|
+
runId,
|
|
345
|
+
});
|
|
346
|
+
const messages = await listMessagesWithReferencedChildren(prepared.conversationId);
|
|
347
|
+
await prepared.validate({
|
|
348
|
+
messages,
|
|
349
|
+
run: terminalRun,
|
|
350
|
+
});
|
|
351
|
+
const artifactPaths = resolveArtifactPaths(runId);
|
|
352
|
+
if (!config.keepSuccessfulEvidence) {
|
|
353
|
+
await prepared.cleanup({ runId });
|
|
354
|
+
}
|
|
355
|
+
return {
|
|
356
|
+
id: testCase.id,
|
|
357
|
+
label: testCase.label,
|
|
358
|
+
status: "pass",
|
|
359
|
+
details: "OK",
|
|
360
|
+
durationMs: Date.now() - startedAt,
|
|
361
|
+
conversationId: prepared.conversationId,
|
|
362
|
+
runId,
|
|
363
|
+
...(artifactPaths?.length ? { artifactPaths } : {}),
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
catch (error) {
|
|
367
|
+
const artifactPaths = resolveArtifactPaths(runId);
|
|
368
|
+
return {
|
|
369
|
+
id: testCase.id,
|
|
370
|
+
label: testCase.label,
|
|
371
|
+
status: "fail",
|
|
372
|
+
details: error instanceof Error ? error.message : String(error),
|
|
373
|
+
durationMs: Date.now() - startedAt,
|
|
374
|
+
conversationId: prepared.conversationId,
|
|
375
|
+
runId,
|
|
376
|
+
...(artifactPaths?.length ? { artifactPaths } : {}),
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
finally {
|
|
380
|
+
await stopSidecar?.();
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
runCase,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
/** White-box helpers used by durable run canary tests. */
|
|
388
|
+
export const durableRunCanaryRunnerInternals = {
|
|
389
|
+
collectReferencedChildConversationIds,
|
|
390
|
+
isTerminalRunStatus,
|
|
391
|
+
};
|