UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

75 lines • 3.56 kB
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= import { enoent } from "../../errors/fs.js"; import { makeRead } from "../hierarchy/read.js"; import { jsonBytes, jsonlBytes } from "../render/json.js"; import { fetchDatasetItems, fetchDatasetRuns, fetchOrEnoent, fetchPrompt, fetchTrace, } from "./client.js"; import { detectScope } from "./scope.js"; function inSession(trace, sessionId) { const observations = Array.isArray(trace.observations) ? trace.observations : []; const roots = [trace, ...observations.filter((o) => o.isRootObservation === true)]; return roots.some((r) => r.sessionId === sessionId); } /** * The trace a trace path names, or ENOENT. * * A trace is addressed by its id whatever the listing holds: the listing * stops at `defaultTraceLimit` and `defaultFromTimestamp`, and an older * trace is still the project's. Under `sessions/<id>/` the trace must have a * root observation in that session, the rule its listing uses, so a path * cannot name another session's trace. Mirrors python's `fetch_trace_file`. */ export async function fetchTraceFile(accessor, match, path) { const data = await fetchOrEnoent(fetchTrace(accessor.transport, match.slots.trace_id ?? ''), path); const sessionId = match.slots.session_id; if (sessionId !== undefined && !inSession(data, sessionId)) throw enoent(path); return data; } async function readTrace(accessor, match, path) { return jsonBytes(await fetchTraceFile(accessor, match, path)); } async function readPromptVersion(accessor, match, path) { // The scope's codec only matches plain ASCII integers, so the parse here // cannot fail. const version = Number.parseInt(match.slots.version ?? '', 10); const data = await fetchOrEnoent(fetchPrompt(accessor.transport, match.slots.prompt_name ?? '', version), path); return jsonBytes(data); } async function readDatasetItems(accessor, match, path) { const items = await fetchOrEnoent(fetchDatasetItems(accessor.transport, match.slots.dataset_name ?? ''), path); return jsonlBytes(items); } async function readDatasetRun(accessor, match, path) { const runName = match.slots.run_name ?? ''; const runs = await fetchOrEnoent(fetchDatasetRuns(accessor.transport, match.slots.dataset_name ?? '', runName), path); const matched = runs.filter((r) => r.name === runName); const first = matched[0]; if (first === undefined) throw enoent(path); // A .jsonl path must render as line-delimited JSON, not an indented // document: readers that split on newlines (jq) otherwise choke on the // first bare brace. return jsonlBytes([first]); } export const read = makeRead(detectScope, { trace: readTrace, session_trace: readTrace, prompt_version: readPromptVersion, dataset_items: readDatasetItems, dataset_run: readDatasetRun, }); //# sourceMappingURL=read.js.map