inspect-ai 0.3.59__py3-none-any.whl → 0.3.60__py3-none-any.whl
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.
- inspect_ai/_cli/eval.py +0 -7
- inspect_ai/_display/textual/widgets/samples.py +1 -1
- inspect_ai/_eval/eval.py +10 -1
- inspect_ai/_eval/loader.py +79 -19
- inspect_ai/_eval/registry.py +6 -0
- inspect_ai/_eval/score.py +2 -1
- inspect_ai/_eval/task/results.py +6 -5
- inspect_ai/_eval/task/run.py +11 -11
- inspect_ai/_view/www/dist/assets/index.js +262 -303
- inspect_ai/_view/www/src/App.mjs +6 -6
- inspect_ai/_view/www/src/Types.mjs +1 -1
- inspect_ai/_view/www/src/api/Types.ts +133 -0
- inspect_ai/_view/www/src/api/{api-browser.mjs → api-browser.ts} +25 -13
- inspect_ai/_view/www/src/api/api-http.ts +219 -0
- inspect_ai/_view/www/src/api/api-shared.ts +47 -0
- inspect_ai/_view/www/src/api/{api-vscode.mjs → api-vscode.ts} +22 -19
- inspect_ai/_view/www/src/api/{client-api.mjs → client-api.ts} +93 -53
- inspect_ai/_view/www/src/api/index.ts +51 -0
- inspect_ai/_view/www/src/api/jsonrpc.ts +225 -0
- inspect_ai/_view/www/src/components/DownloadButton.mjs +1 -1
- inspect_ai/_view/www/src/index.js +2 -2
- inspect_ai/_view/www/src/log/{remoteLogFile.mjs → remoteLogFile.ts} +62 -46
- inspect_ai/_view/www/src/navbar/Navbar.mjs +1 -1
- inspect_ai/_view/www/src/navbar/SecondaryBar.mjs +1 -1
- inspect_ai/_view/www/src/samples/SampleList.mjs +1 -1
- inspect_ai/_view/www/src/samples/SampleScores.mjs +1 -1
- inspect_ai/_view/www/src/samples/SamplesDescriptor.mjs +14 -14
- inspect_ai/_view/www/src/samples/SamplesTab.mjs +10 -10
- inspect_ai/_view/www/src/samples/tools/SortFilter.mjs +2 -2
- inspect_ai/_view/www/src/utils/{Json.mjs → json-worker.ts} +1 -3
- inspect_ai/_view/www/src/utils/vscode.ts +36 -0
- inspect_ai/_view/www/src/workspace/WorkSpace.mjs +1 -1
- inspect_ai/approval/_human/manager.py +1 -1
- inspect_ai/model/_call_tools.py +55 -0
- inspect_ai/model/_conversation.py +1 -4
- inspect_ai/model/_generate_config.py +2 -8
- inspect_ai/model/_model_output.py +15 -0
- inspect_ai/model/_openai.py +383 -0
- inspect_ai/model/_providers/anthropic.py +52 -11
- inspect_ai/model/_providers/azureai.py +1 -1
- inspect_ai/model/_providers/goodfire.py +248 -0
- inspect_ai/model/_providers/groq.py +7 -3
- inspect_ai/model/_providers/hf.py +6 -0
- inspect_ai/model/_providers/mistral.py +2 -1
- inspect_ai/model/_providers/openai.py +36 -202
- inspect_ai/model/_providers/openai_o1.py +2 -4
- inspect_ai/model/_providers/providers.py +22 -0
- inspect_ai/model/_providers/together.py +4 -4
- inspect_ai/model/_providers/util/__init__.py +2 -3
- inspect_ai/model/_providers/util/hf_handler.py +1 -1
- inspect_ai/model/_providers/util/llama31.py +1 -1
- inspect_ai/model/_providers/util/util.py +0 -76
- inspect_ai/scorer/_metric.py +3 -0
- inspect_ai/scorer/_scorer.py +2 -1
- inspect_ai/solver/__init__.py +2 -0
- inspect_ai/solver/_basic_agent.py +1 -1
- inspect_ai/solver/_bridge/__init__.py +3 -0
- inspect_ai/solver/_bridge/bridge.py +100 -0
- inspect_ai/solver/_bridge/patch.py +170 -0
- inspect_ai/solver/_solver.py +6 -0
- inspect_ai/util/_display.py +5 -0
- inspect_ai/util/_sandbox/docker/prereqs.py +1 -1
- {inspect_ai-0.3.59.dist-info → inspect_ai-0.3.60.dist-info}/METADATA +3 -2
- {inspect_ai-0.3.59.dist-info → inspect_ai-0.3.60.dist-info}/RECORD +68 -63
- inspect_ai/_view/www/src/api/Types.mjs +0 -117
- inspect_ai/_view/www/src/api/api-http.mjs +0 -300
- inspect_ai/_view/www/src/api/api-shared.mjs +0 -10
- inspect_ai/_view/www/src/api/index.mjs +0 -49
- inspect_ai/_view/www/src/api/jsonrpc.mjs +0 -208
- inspect_ai/_view/www/src/utils/vscode.mjs +0 -16
- {inspect_ai-0.3.59.dist-info → inspect_ai-0.3.60.dist-info}/LICENSE +0 -0
- {inspect_ai-0.3.59.dist-info → inspect_ai-0.3.60.dist-info}/WHEEL +0 -0
- {inspect_ai-0.3.59.dist-info → inspect_ai-0.3.60.dist-info}/entry_points.txt +0 -0
- {inspect_ai-0.3.59.dist-info → inspect_ai-0.3.60.dist-info}/top_level.txt +0 -0
inspect_ai/_view/www/src/App.mjs
CHANGED
@@ -30,7 +30,7 @@ import { Sidebar } from "./sidebar/Sidebar.mjs";
|
|
30
30
|
import { WorkSpace } from "./workspace/WorkSpace.mjs";
|
31
31
|
import { FindBand } from "./components/FindBand.mjs";
|
32
32
|
import { isVscode } from "./utils/Html.mjs";
|
33
|
-
import { getVscodeApi } from "./utils/vscode
|
33
|
+
import { getVscodeApi } from "./utils/vscode";
|
34
34
|
import { kDefaultSort } from "./constants.mjs";
|
35
35
|
import {
|
36
36
|
createEvalDescriptor,
|
@@ -51,7 +51,7 @@ import {
|
|
51
51
|
* Renders the Main Application
|
52
52
|
*
|
53
53
|
* @param {Object} props - The parameters for the component.
|
54
|
-
* @param {import("./api/Types.
|
54
|
+
* @param {import("./api/Types.ts").ClientAPI} props.api - The api that this view should use
|
55
55
|
* @param {Object} [props.initialState] - Initial state for app (optional, used by VS Code extension)
|
56
56
|
* @param {(state: Object) => void} [props.saveInitialState] - Save initial state for app (optional, used by VS Code extension)
|
57
57
|
* @param {boolean} props.pollForLogs - Whether the application should poll for log changes
|
@@ -507,12 +507,12 @@ export function App({
|
|
507
507
|
* Determines whether the workspace tab should display samples or info,
|
508
508
|
* depending on the presence of samples and the log status.
|
509
509
|
*
|
510
|
-
* @param {import("./api/Types.
|
510
|
+
* @param {import("./api/Types.ts").EvalSummary} log - The log object containing sample summaries and status.
|
511
511
|
* @returns {void}
|
512
512
|
*/
|
513
513
|
const resetWorkspace = useCallback(
|
514
514
|
/**
|
515
|
-
* @param {import("./api/Types.
|
515
|
+
* @param {import("./api/Types.ts").EvalSummary} log
|
516
516
|
*/
|
517
517
|
(log) => {
|
518
518
|
// Reset the workspace tab
|
@@ -959,7 +959,7 @@ export function App({
|
|
959
959
|
/**
|
960
960
|
* Determines the default scorer for a log
|
961
961
|
*
|
962
|
-
* @param {import("./api/Types.
|
962
|
+
* @param {import("./api/Types.ts").EvalSummary} log - The log object containing sample summaries and status.
|
963
963
|
* @returns {{name: string, scorer: string} | undefined} A scorer object with name and scorer properties, or undefined
|
964
964
|
*/
|
965
965
|
const defaultScorer = (log) => {
|
@@ -981,7 +981,7 @@ const defaultScorer = (log) => {
|
|
981
981
|
/**
|
982
982
|
* Determines the default scorers for a log
|
983
983
|
*
|
984
|
-
* @param {import("./api/Types.
|
984
|
+
* @param {import("./api/Types.ts").EvalSummary} log - The log object containing sample summaries and status.
|
985
985
|
* @returns {Array<{name: string, scorer: string}>} An array of scorer objects with name and scorer properties, or an empty array if no scorers are found.
|
986
986
|
*/
|
987
987
|
const defaultScorers = (log) => {
|
@@ -0,0 +1,133 @@
|
|
1
|
+
import {
|
2
|
+
Version,
|
3
|
+
Status,
|
4
|
+
EvalSpec,
|
5
|
+
EvalPlan,
|
6
|
+
EvalResults,
|
7
|
+
EvalStats,
|
8
|
+
EvalError,
|
9
|
+
Input,
|
10
|
+
Target,
|
11
|
+
Scores1,
|
12
|
+
Type11,
|
13
|
+
EvalLog,
|
14
|
+
EvalSample,
|
15
|
+
} from "../types/log";
|
16
|
+
|
17
|
+
export interface EvalSummary {
|
18
|
+
version?: Version;
|
19
|
+
status?: Status;
|
20
|
+
eval: EvalSpec;
|
21
|
+
plan?: EvalPlan;
|
22
|
+
results?: EvalResults | null;
|
23
|
+
stats?: EvalStats;
|
24
|
+
error?: EvalError | null;
|
25
|
+
sampleSummaries: SampleSummary[];
|
26
|
+
}
|
27
|
+
|
28
|
+
export interface EvalLogHeader {
|
29
|
+
version?: Version;
|
30
|
+
status?: Status;
|
31
|
+
eval: EvalSpec;
|
32
|
+
plan?: EvalPlan;
|
33
|
+
results?: EvalResults;
|
34
|
+
stats?: EvalStats;
|
35
|
+
error?: EvalError;
|
36
|
+
}
|
37
|
+
|
38
|
+
export interface SampleSummary {
|
39
|
+
id: number | string;
|
40
|
+
epoch: number;
|
41
|
+
input: Input;
|
42
|
+
target: Target;
|
43
|
+
scores: Scores1;
|
44
|
+
error?: string;
|
45
|
+
limit?: Type11;
|
46
|
+
}
|
47
|
+
|
48
|
+
export interface BasicSampleData {
|
49
|
+
id: number | string;
|
50
|
+
epoch: number;
|
51
|
+
target: Target;
|
52
|
+
scores: Scores1;
|
53
|
+
}
|
54
|
+
|
55
|
+
export interface Capabilities {
|
56
|
+
downloadFiles: boolean;
|
57
|
+
webWorkers: boolean;
|
58
|
+
}
|
59
|
+
|
60
|
+
export interface LogViewAPI {
|
61
|
+
client_events: () => Promise<any[]>;
|
62
|
+
eval_logs: () => Promise<LogFiles | undefined>;
|
63
|
+
eval_log: (
|
64
|
+
log_file: string,
|
65
|
+
headerOnly?: number,
|
66
|
+
capabilities?: Capabilities,
|
67
|
+
) => Promise<LogContents>;
|
68
|
+
eval_log_size: (log_file: string) => Promise<number>;
|
69
|
+
eval_log_bytes: (
|
70
|
+
log_file: string,
|
71
|
+
start: number,
|
72
|
+
end: number,
|
73
|
+
) => Promise<Uint8Array>;
|
74
|
+
eval_log_headers: (log_files: string[]) => Promise<EvalLog[]>;
|
75
|
+
download_file: (
|
76
|
+
filename: string,
|
77
|
+
filecontents: string | Blob | ArrayBuffer | ArrayBufferView,
|
78
|
+
) => Promise<void>;
|
79
|
+
open_log_file: (logFile: string, log_dir: string) => Promise<void>;
|
80
|
+
}
|
81
|
+
|
82
|
+
export interface ClientAPI {
|
83
|
+
client_events: () => Promise<string[]>;
|
84
|
+
get_log_paths: () => Promise<LogFiles>;
|
85
|
+
get_log_headers: (log_files: string[]) => Promise<EvalLog[]>;
|
86
|
+
get_log_summary: (log_file: string) => Promise<EvalSummary>;
|
87
|
+
get_log_sample: (
|
88
|
+
log_file: string,
|
89
|
+
id: string | number,
|
90
|
+
epoch: number,
|
91
|
+
) => Promise<EvalSample | undefined>;
|
92
|
+
download_file: (
|
93
|
+
file_name: string,
|
94
|
+
file_contents: string | Blob | ArrayBuffer | ArrayBufferView,
|
95
|
+
) => Promise<void>;
|
96
|
+
open_log_file: (log_file: string, log_dir: string) => Promise<void>;
|
97
|
+
}
|
98
|
+
|
99
|
+
export interface FetchResponse {
|
100
|
+
raw: string;
|
101
|
+
parsed: Record<string, any>;
|
102
|
+
}
|
103
|
+
|
104
|
+
export interface EvalHeader {
|
105
|
+
version?: Version;
|
106
|
+
status?: Status;
|
107
|
+
eval: EvalSpec;
|
108
|
+
plan?: EvalPlan;
|
109
|
+
results?: EvalResults | null;
|
110
|
+
stats?: EvalStats;
|
111
|
+
error?: EvalError | null;
|
112
|
+
}
|
113
|
+
|
114
|
+
export interface LogFiles {
|
115
|
+
files: LogFile[];
|
116
|
+
log_dir?: string;
|
117
|
+
}
|
118
|
+
|
119
|
+
export interface LogFile {
|
120
|
+
name: string;
|
121
|
+
task: string;
|
122
|
+
task_id: string;
|
123
|
+
}
|
124
|
+
|
125
|
+
export interface LogContents {
|
126
|
+
raw: string;
|
127
|
+
parsed: EvalLog;
|
128
|
+
}
|
129
|
+
|
130
|
+
export interface LogFilesFetchResponse {
|
131
|
+
raw: string;
|
132
|
+
parsed: Record<string, EvalHeader>;
|
133
|
+
}
|
@@ -1,6 +1,7 @@
|
|
1
|
-
|
2
|
-
import { asyncJsonParse } from "../utils/
|
3
|
-
import { download_file } from "./api-shared
|
1
|
+
import { Capabilities } from "../Types.mjs";
|
2
|
+
import { asyncJsonParse } from "../utils/json-worker";
|
3
|
+
import { download_file } from "./api-shared";
|
4
|
+
import { LogContents, LogViewAPI } from "./Types";
|
4
5
|
|
5
6
|
const loaded_time = Date.now();
|
6
7
|
let last_eval_time = 0;
|
@@ -18,25 +19,29 @@ async function eval_logs() {
|
|
18
19
|
return logs.parsed;
|
19
20
|
}
|
20
21
|
|
21
|
-
async function eval_log(
|
22
|
+
async function eval_log(
|
23
|
+
file: string,
|
24
|
+
headerOnly?: number,
|
25
|
+
_capabilities?: Capabilities,
|
26
|
+
): Promise<LogContents> {
|
22
27
|
return await api(
|
23
28
|
"GET",
|
24
29
|
`/api/logs/${encodeURIComponent(file)}?header-only=${headerOnly}`,
|
25
30
|
);
|
26
31
|
}
|
27
32
|
|
28
|
-
async function eval_log_size(file) {
|
33
|
+
async function eval_log_size(file: string): Promise<number> {
|
29
34
|
return (await api("GET", `/api/log-size/${encodeURIComponent(file)}`)).parsed;
|
30
35
|
}
|
31
36
|
|
32
|
-
async function eval_log_bytes(file, start, end) {
|
37
|
+
async function eval_log_bytes(file: string, start: number, end: number) {
|
33
38
|
return await api_bytes(
|
34
39
|
"GET",
|
35
40
|
`/api/log-bytes/${encodeURIComponent(file)}?start=${start}&end=${end}`,
|
36
41
|
);
|
37
42
|
}
|
38
43
|
|
39
|
-
async function eval_log_headers(files) {
|
44
|
+
async function eval_log_headers(files: string[]) {
|
40
45
|
const params = new URLSearchParams();
|
41
46
|
for (const file of files) {
|
42
47
|
params.append("file", file);
|
@@ -44,9 +49,13 @@ async function eval_log_headers(files) {
|
|
44
49
|
return (await api("GET", `/api/log-headers?${params.toString()}`)).parsed;
|
45
50
|
}
|
46
51
|
|
47
|
-
async function api(
|
52
|
+
async function api(
|
53
|
+
method: "GET" | "POST" | "PUT" | "DELETE",
|
54
|
+
path: string,
|
55
|
+
body?: string,
|
56
|
+
) {
|
48
57
|
// build headers
|
49
|
-
const headers = {
|
58
|
+
const headers: HeadersInit = {
|
50
59
|
Accept: "application/json",
|
51
60
|
Pragma: "no-cache",
|
52
61
|
Expires: "0",
|
@@ -73,9 +82,12 @@ async function api(method, path, body) {
|
|
73
82
|
}
|
74
83
|
}
|
75
84
|
|
76
|
-
async function api_bytes(
|
85
|
+
async function api_bytes(
|
86
|
+
method: "GET" | "POST" | "PUT" | "DELETE",
|
87
|
+
path: string,
|
88
|
+
) {
|
77
89
|
// build headers
|
78
|
-
const headers = {
|
90
|
+
const headers: HeadersInit = {
|
79
91
|
Accept: "application/octet-stream",
|
80
92
|
Pragma: "no-cache",
|
81
93
|
Expires: "0",
|
@@ -100,8 +112,7 @@ async function open_log_file() {
|
|
100
112
|
// No op
|
101
113
|
}
|
102
114
|
|
103
|
-
|
104
|
-
export default {
|
115
|
+
const browserApi: LogViewAPI = {
|
105
116
|
client_events,
|
106
117
|
eval_logs,
|
107
118
|
eval_log,
|
@@ -111,3 +122,4 @@ export default {
|
|
111
122
|
download_file,
|
112
123
|
open_log_file,
|
113
124
|
};
|
125
|
+
export default browserApi;
|
@@ -0,0 +1,219 @@
|
|
1
|
+
//@ts-check
|
2
|
+
import { asyncJsonParse } from "../utils/json-worker";
|
3
|
+
import { download_file, encodePathParts } from "./api-shared";
|
4
|
+
import { fetchRange, fetchSize } from "../utils/remoteZipFile.mjs";
|
5
|
+
import {
|
6
|
+
Capabilities,
|
7
|
+
LogContents,
|
8
|
+
LogFiles,
|
9
|
+
LogFilesFetchResponse,
|
10
|
+
LogViewAPI,
|
11
|
+
} from "./Types";
|
12
|
+
import { EvalLog } from "../types/log";
|
13
|
+
|
14
|
+
interface LogInfo {
|
15
|
+
log_dir?: string;
|
16
|
+
log_file?: string;
|
17
|
+
}
|
18
|
+
|
19
|
+
/**
|
20
|
+
* This provides an API implementation that will serve a single
|
21
|
+
* file using an http parameter, designed to be deployed
|
22
|
+
* to a webserver without inspect or the ability to enumerate log
|
23
|
+
* files
|
24
|
+
*/
|
25
|
+
export default function simpleHttpApi(
|
26
|
+
log_dir?: string,
|
27
|
+
log_file?: string,
|
28
|
+
): LogViewAPI {
|
29
|
+
const resolved_log_dir = log_dir?.replace(" ", "+");
|
30
|
+
const resolved_log_path = log_file ? log_file.replace(" ", "+") : undefined;
|
31
|
+
return simpleHttpAPI({
|
32
|
+
log_file: resolved_log_path,
|
33
|
+
log_dir: resolved_log_dir,
|
34
|
+
});
|
35
|
+
}
|
36
|
+
|
37
|
+
/**
|
38
|
+
* Fetches a file from the specified URL and parses its content.
|
39
|
+
*/
|
40
|
+
function simpleHttpAPI(logInfo: LogInfo): LogViewAPI {
|
41
|
+
const log_file = logInfo.log_file;
|
42
|
+
const log_dir = logInfo.log_dir;
|
43
|
+
|
44
|
+
async function open_log_file() {
|
45
|
+
// No op
|
46
|
+
}
|
47
|
+
return {
|
48
|
+
client_events: async () => {
|
49
|
+
// There are no client events in the case of serving via
|
50
|
+
// http
|
51
|
+
return Promise.resolve([]);
|
52
|
+
},
|
53
|
+
eval_logs: async (): Promise<LogFiles | undefined> => {
|
54
|
+
// First check based upon the log dir
|
55
|
+
if (log_dir) {
|
56
|
+
const headers = await fetchLogHeaders(log_dir);
|
57
|
+
if (headers) {
|
58
|
+
const logRecord = headers.parsed;
|
59
|
+
const logs = Object.keys(logRecord).map((key) => {
|
60
|
+
return {
|
61
|
+
name: joinURI(log_dir, key),
|
62
|
+
task: logRecord[key].eval.task,
|
63
|
+
task_id: logRecord[key].eval.task_id,
|
64
|
+
};
|
65
|
+
});
|
66
|
+
return Promise.resolve({
|
67
|
+
files: logs,
|
68
|
+
log_dir,
|
69
|
+
});
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
return undefined;
|
74
|
+
},
|
75
|
+
eval_log: async (
|
76
|
+
log_file: string,
|
77
|
+
_headerOnly?: number,
|
78
|
+
_capabilities?: Capabilities,
|
79
|
+
) => {
|
80
|
+
const response = await fetchLogFile(log_file);
|
81
|
+
if (response) {
|
82
|
+
return response;
|
83
|
+
} else {
|
84
|
+
throw new Error(`"Unable to load eval log ${log_file}`);
|
85
|
+
}
|
86
|
+
},
|
87
|
+
eval_log_size: async (log_file: string) => {
|
88
|
+
return await fetchSize(log_file);
|
89
|
+
},
|
90
|
+
eval_log_bytes: async (log_file: string, start: number, end: number) => {
|
91
|
+
return await fetchRange(log_file, start, end);
|
92
|
+
},
|
93
|
+
eval_log_headers: async (files: string[]) => {
|
94
|
+
if (files.length === 0) {
|
95
|
+
return [];
|
96
|
+
}
|
97
|
+
|
98
|
+
if (log_dir) {
|
99
|
+
const headers = await fetchLogHeaders(log_dir);
|
100
|
+
if (headers) {
|
101
|
+
const keys = Object.keys(headers.parsed);
|
102
|
+
const result: EvalLog[] = [];
|
103
|
+
files.forEach((file) => {
|
104
|
+
const fileKey = keys.find((key) => {
|
105
|
+
return file.endsWith(key);
|
106
|
+
});
|
107
|
+
if (fileKey) {
|
108
|
+
result.push(headers.parsed[fileKey]);
|
109
|
+
}
|
110
|
+
});
|
111
|
+
return result;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
// No log.json could be found, and there isn't a log file,
|
116
|
+
throw new Error(
|
117
|
+
`Failed to load a manifest files using the directory: ${log_dir}. Please be sure you have deployed a manifest file (logs.json).`,
|
118
|
+
);
|
119
|
+
},
|
120
|
+
download_file,
|
121
|
+
open_log_file,
|
122
|
+
};
|
123
|
+
}
|
124
|
+
|
125
|
+
/**
|
126
|
+
* Fetches a file from the specified URL and parses its content.
|
127
|
+
*/
|
128
|
+
async function fetchFile<T>(
|
129
|
+
url: string,
|
130
|
+
parse: (text: string) => Promise<T>,
|
131
|
+
handleError?: (response: Response) => boolean,
|
132
|
+
): Promise<T | undefined> {
|
133
|
+
const safe_url = encodePathParts(url);
|
134
|
+
const response = await fetch(`${safe_url}`, { method: "GET" });
|
135
|
+
if (response.ok) {
|
136
|
+
const text = await response.text();
|
137
|
+
return await parse(text);
|
138
|
+
} else if (response.status !== 200) {
|
139
|
+
if (handleError && handleError(response)) {
|
140
|
+
return undefined;
|
141
|
+
}
|
142
|
+
const message = (await response.text()) || response.statusText;
|
143
|
+
const error = new Error(`${response.status}: ${message})`);
|
144
|
+
throw error;
|
145
|
+
} else {
|
146
|
+
throw new Error(`${response.status} - ${response.statusText} `);
|
147
|
+
}
|
148
|
+
}
|
149
|
+
|
150
|
+
/**
|
151
|
+
* Fetches a log file and parses its content, updating the log structure if necessary.
|
152
|
+
*/
|
153
|
+
const fetchLogFile = async (file: string): Promise<LogContents | undefined> => {
|
154
|
+
return fetchFile<LogContents>(file, async (text): Promise<LogContents> => {
|
155
|
+
const log = (await asyncJsonParse(text)) as EvalLog;
|
156
|
+
if (log.version === 1) {
|
157
|
+
if (log.results) {
|
158
|
+
const untypedLog = log as any;
|
159
|
+
log.results.scores = [];
|
160
|
+
untypedLog.results.scorer.scorer = untypedLog.results.scorer.name;
|
161
|
+
log.results.scores.push(untypedLog.results.scorer);
|
162
|
+
delete untypedLog.results.scorer;
|
163
|
+
log.results.scores[0].metrics = untypedLog.results.metrics;
|
164
|
+
delete untypedLog.results.metrics;
|
165
|
+
|
166
|
+
// migrate samples
|
167
|
+
const scorerName = log.results.scores[0].name;
|
168
|
+
log.samples?.forEach((sample) => {
|
169
|
+
const untypedSample = sample as any;
|
170
|
+
sample.scores = { [scorerName]: untypedSample.score };
|
171
|
+
delete untypedSample.score;
|
172
|
+
});
|
173
|
+
}
|
174
|
+
}
|
175
|
+
return {
|
176
|
+
raw: text,
|
177
|
+
parsed: log,
|
178
|
+
};
|
179
|
+
});
|
180
|
+
};
|
181
|
+
|
182
|
+
/**
|
183
|
+
* Fetches a log file and parses its content, updating the log structure if necessary.
|
184
|
+
*/
|
185
|
+
const fetchLogHeaders = async (
|
186
|
+
log_dir: string,
|
187
|
+
): Promise<LogFilesFetchResponse | undefined> => {
|
188
|
+
const logs = await fetchFile<LogFilesFetchResponse>(
|
189
|
+
log_dir + "/logs.json",
|
190
|
+
async (text) => {
|
191
|
+
const parsed = await asyncJsonParse(text);
|
192
|
+
return {
|
193
|
+
raw: text,
|
194
|
+
parsed,
|
195
|
+
};
|
196
|
+
},
|
197
|
+
(response) => {
|
198
|
+
if (response.status === 404) {
|
199
|
+
// Couldn't find a header file
|
200
|
+
return true;
|
201
|
+
} else {
|
202
|
+
return false;
|
203
|
+
}
|
204
|
+
},
|
205
|
+
);
|
206
|
+
return logs;
|
207
|
+
};
|
208
|
+
|
209
|
+
/**
|
210
|
+
* Joins multiple URI segments into a single URI string.
|
211
|
+
*
|
212
|
+
* This function removes any leading or trailing slashes from each segment
|
213
|
+
* and then joins them with a single slash (`/`).
|
214
|
+
*/
|
215
|
+
function joinURI(...segments: string[]): string {
|
216
|
+
return segments
|
217
|
+
.map((segment) => segment.replace(/(^\/+|\/+$)/g, "")) // Remove leading/trailing slashes from each segment
|
218
|
+
.join("/");
|
219
|
+
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
/**
|
2
|
+
* Downloads the provided content as a file using the browser's DOM API
|
3
|
+
*/
|
4
|
+
export async function download_file(
|
5
|
+
filename: string,
|
6
|
+
filecontents: string | Blob | ArrayBuffer | ArrayBufferView,
|
7
|
+
): Promise<void> {
|
8
|
+
const blob = new Blob([filecontents], { type: "text/plain" });
|
9
|
+
const link = document.createElement("a");
|
10
|
+
link.href = URL.createObjectURL(blob);
|
11
|
+
link.download = filename;
|
12
|
+
document.body.appendChild(link);
|
13
|
+
link.click();
|
14
|
+
document.body.removeChild(link);
|
15
|
+
}
|
16
|
+
|
17
|
+
/**
|
18
|
+
* Encodes the path segments of a URL or relative path to ensure special characters
|
19
|
+
* (like `+`, spaces, etc.) are properly encoded without affecting legal characters like `/`.
|
20
|
+
*
|
21
|
+
* This function will encode file names and path portions of both absolute URLs and
|
22
|
+
* relative paths. It ensures that components of a full URL, such as the protocol and
|
23
|
+
* query parameters, remain intact, while only encoding the path.
|
24
|
+
*/
|
25
|
+
export function encodePathParts(url: string): string {
|
26
|
+
if (!url) return url; // Handle empty strings
|
27
|
+
|
28
|
+
try {
|
29
|
+
// Parse a full Uri
|
30
|
+
const fullUrl = new URL(url);
|
31
|
+
fullUrl.pathname = fullUrl.pathname
|
32
|
+
.split("/")
|
33
|
+
.map((segment) =>
|
34
|
+
segment ? encodeURIComponent(decodeURIComponent(segment)) : "",
|
35
|
+
)
|
36
|
+
.join("/");
|
37
|
+
return fullUrl.toString();
|
38
|
+
} catch {
|
39
|
+
// This is a relative path that isn't parseable as Uri
|
40
|
+
return url
|
41
|
+
.split("/")
|
42
|
+
.map((segment) =>
|
43
|
+
segment ? encodeURIComponent(decodeURIComponent(segment)) : "",
|
44
|
+
)
|
45
|
+
.join("/");
|
46
|
+
}
|
47
|
+
}
|
@@ -1,7 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
import { asyncJsonParse } from "../utils/Json.mjs";
|
4
|
-
// @ts-ignore
|
1
|
+
import { asyncJsonParse } from "../utils/json-worker";
|
5
2
|
import JSON5 from "json5";
|
6
3
|
|
7
4
|
import {
|
@@ -11,8 +8,9 @@ import {
|
|
11
8
|
kMethodEvalLogSize,
|
12
9
|
kMethodEvalLogBytes,
|
13
10
|
kMethodEvalLogHeaders,
|
14
|
-
} from "./jsonrpc
|
15
|
-
import { getVscodeApi } from "../utils/vscode
|
11
|
+
} from "./jsonrpc";
|
12
|
+
import { getVscodeApi } from "../utils/vscode";
|
13
|
+
import { Capabilities, LogContents, LogViewAPI } from "./Types";
|
16
14
|
|
17
15
|
const vscodeClient = webViewJsonRpcClient(getVscodeApi());
|
18
16
|
|
@@ -38,8 +36,12 @@ async function eval_logs() {
|
|
38
36
|
}
|
39
37
|
}
|
40
38
|
|
41
|
-
async function eval_log(
|
42
|
-
|
39
|
+
async function eval_log(
|
40
|
+
log_file: string,
|
41
|
+
headerOnly?: number,
|
42
|
+
capabilities?: Capabilities,
|
43
|
+
): Promise<LogContents> {
|
44
|
+
const response = await vscodeClient(kMethodEvalLog, [log_file, headerOnly]);
|
43
45
|
if (response) {
|
44
46
|
let json;
|
45
47
|
if (capabilities?.webWorkers) {
|
@@ -52,19 +54,19 @@ async function eval_log(file, headerOnly, capabilities) {
|
|
52
54
|
raw: response,
|
53
55
|
};
|
54
56
|
} else {
|
55
|
-
|
57
|
+
throw new Error(`Unable to load eval log ${log_file}.`);
|
56
58
|
}
|
57
59
|
}
|
58
60
|
|
59
|
-
async function eval_log_size(
|
60
|
-
return await vscodeClient(kMethodEvalLogSize, [
|
61
|
+
async function eval_log_size(log_file: string) {
|
62
|
+
return await vscodeClient(kMethodEvalLogSize, [log_file]);
|
61
63
|
}
|
62
64
|
|
63
|
-
async function eval_log_bytes(
|
64
|
-
return await vscodeClient(kMethodEvalLogBytes, [
|
65
|
+
async function eval_log_bytes(log_file: string, start: number, end: number) {
|
66
|
+
return await vscodeClient(kMethodEvalLogBytes, [log_file, start, end]);
|
65
67
|
}
|
66
68
|
|
67
|
-
async function eval_log_headers(files) {
|
69
|
+
async function eval_log_headers(files: string[]) {
|
68
70
|
const response = await vscodeClient(kMethodEvalLogHeaders, [files]);
|
69
71
|
if (response) {
|
70
72
|
return JSON5.parse(response);
|
@@ -77,17 +79,16 @@ async function download_file() {
|
|
77
79
|
throw Error("Downloading files is not supported in VS Code");
|
78
80
|
}
|
79
81
|
|
80
|
-
async function open_log_file(
|
82
|
+
async function open_log_file(log_file: string, log_dir: string) {
|
81
83
|
const msg = {
|
82
84
|
type: "displayLogFile",
|
83
|
-
url:
|
85
|
+
url: log_file,
|
84
86
|
log_dir: log_dir,
|
85
87
|
};
|
86
|
-
getVscodeApi()
|
88
|
+
getVscodeApi()?.postMessage(msg);
|
87
89
|
}
|
88
90
|
|
89
|
-
|
90
|
-
export default {
|
91
|
+
const api: LogViewAPI = {
|
91
92
|
client_events,
|
92
93
|
eval_logs,
|
93
94
|
eval_log,
|
@@ -97,3 +98,5 @@ export default {
|
|
97
98
|
download_file,
|
98
99
|
open_log_file,
|
99
100
|
};
|
101
|
+
|
102
|
+
export default api;
|