@struktoai/mirage-agents 0.0.1-alpha.1

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 ADDED
@@ -0,0 +1,230 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/mirage-og-light@2x.png" alt="Mirage: A Unified Virtual File System for AI Agents" width="900">
3
+ </p>
4
+
5
+ Mirage is **a Unified Virtual File System for AI Agents**: a single tree that mounts services and data sources like S3, Google Drive, Slack, Gmail, and Redis side-by-side as one filesystem.
6
+
7
+ AI agents reach every backend with the same handful of Unix-like tools, and pipelines compose across services as naturally as on a local disk. It's a simulated environment, agents see one filesystem underneath. Any LLM that already knows bash can use Mirage out of the box, with zero new vocabulary.
8
+
9
+ ```ts
10
+ const ws = new Workspace({
11
+ '/data': new RAMResource(),
12
+ '/s3': new S3Resource({ bucket: 'logs' }),
13
+ '/slack': new SlackResource({}),
14
+ '/github': new GitHubResource({}),
15
+ })
16
+
17
+ await ws.execute('grep alert /slack/general/*.json | wc -l')
18
+ await ws.execute('cat /github/mirage/README.md')
19
+ await ws.execute('cp /s3/report.csv /data/local.csv')
20
+ ```
21
+
22
+ ## About
23
+
24
+ - **One filesystem, every backend.** Every service speaks the same filesystem semantics, so agents reason about one abstraction instead of N SDKs and M MCPs, leaning on the filesystem and bash vocabulary LLMs are most fluent in.
25
+ - **Multiple resources, one filesystem:** RAM, Disk, Redis, S3 / R2 / OCI / Supabase / GCS, Gmail / GDrive / GDocs / GSheets / GSlides, GitHub / Linear / Notion / Trello, Slack / Discord / Telegram / Email, MongoDB, SSH, and more, mounted side-by-side under a single root.
26
+ - **Familiar bash tools across every mount.** Agents reuse the same handful of Unix-like tools instead of learning a new API per service, and pipelines compose across services as naturally as on a local disk, the exact corpus modern LLMs are most heavily trained on.
27
+ - **Portable workspaces:** clone, snapshot, and version your environment. Move agent runs between machines without restarting or reconfiguring the system.
28
+ - **Embed in your apps and services:** Python and TypeScript SDKs let you give your AI agents a virtual filesystem directly inside FastAPI, Express, browser apps, or any async runtime, no separate process required. Clone, snapshot, and version the workspace from inside your code.
29
+ - **Works with major agent application frameworks:** OpenAI Agents SDK, Vercel AI SDK (TypeScript), LangChain, Pydantic AI, CAMEL, and OpenHands.
30
+ - **Lightweight CLI + daemon:** plugs into coding agents like Claude Code and Codex so they reach every mounted resource through familiar bash, getting more useful work done per turn.
31
+
32
+ ## Architecture
33
+
34
+ <p align="center">
35
+ <picture>
36
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/mirage-arch-dark.svg">
37
+ <img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/mirage-arch-light.svg" alt="Mirage architecture: AI Agent and Application → Mirage Bash and VFS → Dispatcher &amp; Cache → Infrastructure and Remote" width="900">
38
+ </picture>
39
+ </p>
40
+
41
+ ## Installation
42
+
43
+ ### Prerequisites
44
+
45
+ - **Python** ≥ 3.12 for the `mirage-ai` package and the `mirage` CLI
46
+ - **Node.js** ≥ 20 for the TypeScript SDK
47
+ - **macOS** or **Linux** (FUSE-based mounts require platform support)
48
+
49
+ ### Python
50
+
51
+ ```bash
52
+ uv add mirage-ai
53
+ ```
54
+
55
+ This installs both the `mirage` library and the `mirage` CLI binary.
56
+
57
+ ### TypeScript
58
+
59
+ Pick the package that matches your runtime:
60
+
61
+ ```bash
62
+ npm install @struktoai/mirage-node # Node.js servers and CLIs
63
+ npm install @struktoai/mirage-browser # browser / edge runtimes
64
+ npm install @struktoai/mirage-core # runtime-agnostic primitives
65
+ ```
66
+
67
+ `@struktoai/mirage-node` and `@struktoai/mirage-browser` both pull in `@struktoai/mirage-core` automatically.
68
+
69
+ ### CLI
70
+
71
+ ```bash
72
+ curl -fsSL https://strukto.ai/install.sh | sh
73
+ ```
74
+
75
+ Or via your package manager of choice:
76
+
77
+ ```bash
78
+ brew install mirage
79
+ ```
80
+
81
+ ```bash
82
+ uvx mirage-ai
83
+ ```
84
+
85
+ ```bash
86
+ npx @struktoai/mirage-cli
87
+ ```
88
+
89
+ ## Quickstart (Python)
90
+
91
+ ```python
92
+ from mirage import Workspace
93
+ from mirage.resource.gdocs import GDocsConfig, GDocsResource
94
+ from mirage.resource.ram import RAMResource
95
+ from mirage.resource.s3 import S3Config, S3Resource
96
+ from mirage.resource.slack import SlackConfig, SlackResource
97
+
98
+ ws = Workspace({
99
+ "/data": RAMResource(),
100
+ "/s3": S3Resource(S3Config(bucket="my-bucket")),
101
+ "/slack": SlackResource(SlackConfig()),
102
+ "/docs": GDocsResource(GDocsConfig()),
103
+ })
104
+
105
+ await ws.execute("cp /s3/report.csv /data/report.csv")
106
+ await ws.execute("grep alert /s3/data/log.jsonl | wc -l")
107
+
108
+ ws.snapshot("demo.tar")
109
+ ```
110
+
111
+ ## Quickstart (TypeScript)
112
+
113
+ ```ts
114
+ import {
115
+ Workspace,
116
+ RAMResource,
117
+ S3Resource,
118
+ SlackResource,
119
+ GDocsResource,
120
+ } from '@struktoai/mirage-browser'
121
+
122
+ const ws = new Workspace({
123
+ '/data': new RAMResource(),
124
+ '/s3': new S3Resource({ bucket: 'my-bucket' }),
125
+ '/slack': new SlackResource({}),
126
+ '/docs': new GDocsResource({}),
127
+ })
128
+
129
+ await ws.execute('cp /s3/report.csv /data/report.csv')
130
+ await ws.execute('grep alert /s3/data/log.jsonl | wc -l')
131
+ ```
132
+
133
+ ## Quickstart (CLI)
134
+
135
+ ```bash
136
+ mirage workspace create ws.yaml --id demo
137
+ mirage execute --workspace_id demo --command "cp /s3/report.csv /data/report.csv"
138
+ mirage provision --workspace_id demo --command "cat /s3/data/large.jsonl"
139
+ mirage workspace snapshot demo demo.tar
140
+ mirage workspace load demo.tar --id demo-restored
141
+ ```
142
+
143
+ ## Agent Frameworks
144
+
145
+ Mirage drops into the major agent application frameworks as a sandbox or tool layer. Your agent runs against the same mount tree it would in bash, so swapping the model or runtime never changes the surface.
146
+
147
+ ### OpenAI Agents SDK (Python)
148
+
149
+ The `MirageSandboxClient` plugs a `Workspace` into the OpenAI Agents SDK as a sandbox: bash commands the agent runs execute against your mounts.
150
+
151
+ ```python
152
+ from agents import Runner
153
+ from agents.run import RunConfig
154
+ from agents.sandbox import SandboxAgent, SandboxRunConfig
155
+
156
+ from mirage.agents.openai_agents import MirageSandboxClient
157
+
158
+ client = MirageSandboxClient(ws)
159
+ agent = SandboxAgent(
160
+ name="Mirage Sandbox Agent",
161
+ model="gpt-5.4-nano",
162
+ instructions=ws.file_prompt,
163
+ )
164
+
165
+ result = await Runner.run(
166
+ agent,
167
+ "Summarize /s3/data/report.parquet into /report.txt.",
168
+ run_config=RunConfig(sandbox=SandboxRunConfig(client=client)),
169
+ )
170
+ ```
171
+
172
+ ### Vercel AI SDK (TypeScript)
173
+
174
+ `mirageTools(ws)` exposes the workspace as a typed AI SDK tool set, so any model wired into the AI SDK can read and write across mounts, in Node or the browser.
175
+
176
+ ```ts
177
+ import { generateText } from 'ai'
178
+ import { openai } from '@ai-sdk/openai'
179
+ import { mirageTools } from '@struktoai/mirage-agents/vercel'
180
+ import { buildSystemPrompt } from '@struktoai/mirage-agents/openai'
181
+
182
+ const { text } = await generateText({
183
+ model: openai('gpt-5.4-nano'),
184
+ system: buildSystemPrompt({ mountInfo: { '/': 'In-memory filesystem' } }),
185
+ prompt: "Use readFile to read /docs/paper.pdf, then describe what's in it.",
186
+ tools: mirageTools(ws),
187
+ })
188
+ ```
189
+
190
+ LangChain, Pydantic AI, CAMEL, OpenHands, and Mastra adapters live alongside these.
191
+
192
+ ## Cache
193
+
194
+ Every `Workspace` ships with a **two-layer cache** so repeated work against remote backends (S3, GDrive, Slack, …) hits local state instead of the network:
195
+
196
+ - **Index cache.** Listings and metadata. The first directory walk hits the API; subsequent ones serve from the index until TTL expires.
197
+ - **File cache.** Object bytes. The first read streams from origin; later pipelines read from cache.
198
+ - **Pluggable backends.** Each layer is a store with two built-ins:
199
+ - **RAM** (default): in-process, zero setup, 512 MB file cache and 10-minute index TTL. Best for single-process apps and notebooks.
200
+ - **Redis**: shared across workers, processes, and machines. Best for serverless, multi-replica services, or when you want cache state to survive restarts.
201
+
202
+ ```ts
203
+ import { RedisFileCacheStore, RedisIndexCacheStore, Workspace } from 'mirage/node'
204
+
205
+ const ws = new Workspace(
206
+ { '/s3': new S3Resource({ bucket: 'my-bucket' }) },
207
+ {
208
+ cache: new RedisFileCacheStore({ url: 'redis://localhost:6379/0', limit: '8GB' }),
209
+ index: new RedisIndexCacheStore({ url: 'redis://localhost:6379/0', ttl: 600 }),
210
+ },
211
+ )
212
+ ```
213
+
214
+ ```ts
215
+ import { S3Resource, Workspace } from 'mirage/node'
216
+
217
+ const ws = new Workspace({ '/s3': new S3Resource({ bucket: 'my-bucket' }) })
218
+
219
+ // 1. Index miss → S3 LIST. Listing stored in index cache.
220
+ await ws.execute('ls /s3/data/')
221
+
222
+ // 2. Index hit → 0 network calls.
223
+ await ws.execute('find /s3/data/ -name "*.jsonl"')
224
+
225
+ // 3. File miss → S3 GET. Bytes stored in file cache.
226
+ await ws.execute('cat /s3/data/log.jsonl | wc -l')
227
+
228
+ // 4. File hit → 0 network calls.
229
+ await ws.execute('grep alert /s3/data/log.jsonl')
230
+ ```
@@ -0,0 +1,38 @@
1
+ // src/prompt.ts
2
+ var MIRAGE_SYSTEM_PROMPT = `Your filesystem is powered by Mirage \u2014 a virtual filesystem that mounts cloud storage, local files, and in-memory data as a unified file tree.
3
+
4
+ All file paths live under /mirage/. Do not access paths outside this folder.
5
+
6
+ Capabilities beyond standard filesystem:
7
+ - cat on .parquet, .orc, .feather files returns a formatted table
8
+ - head -n 5 on data files returns the first 5 rows/seconds
9
+ - grep works natively on CSV, JSON, Parquet \u2014 not just text
10
+ - Pipes work: cat data.parquet | grep error | sort | uniq | wc -l
11
+ - head, tail, cut, wc, sort, uniq, tee, xargs are all available
12
+
13
+ You can write Python code and execute it. The workspace is pre-configured with your data sources mounted at their respective paths.
14
+
15
+ Use the execute tool for complex operations. Use read_file/write_file/edit_file for simple file operations.
16
+ `;
17
+ function buildSystemPrompt(opts = {}) {
18
+ const parts = [MIRAGE_SYSTEM_PROMPT];
19
+ if (opts.workspace !== void 0) {
20
+ parts.push("Mounted data sources:\n" + opts.workspace.filePrompt);
21
+ } else if (opts.mountInfo !== void 0 && Object.keys(opts.mountInfo).length > 0) {
22
+ parts.push("\nMounted data sources:");
23
+ for (const [prefix, description] of Object.entries(opts.mountInfo)) {
24
+ parts.push(`- ${prefix} \u2014 ${description}`);
25
+ }
26
+ parts.push("");
27
+ }
28
+ if (opts.extraInstructions !== void 0 && opts.extraInstructions.length > 0) {
29
+ parts.push(opts.extraInstructions);
30
+ }
31
+ return parts.join("\n");
32
+ }
33
+
34
+ export {
35
+ MIRAGE_SYSTEM_PROMPT,
36
+ buildSystemPrompt
37
+ };
38
+ //# sourceMappingURL=chunk-KAHWIK63.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/prompt.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Workspace } from '@struktoai/mirage-core'\n\nexport const MIRAGE_SYSTEM_PROMPT = `Your filesystem is powered by Mirage — a virtual filesystem that mounts cloud storage, local files, and in-memory data as a unified file tree.\n\nAll file paths live under /mirage/. Do not access paths outside this folder.\n\nCapabilities beyond standard filesystem:\n- cat on .parquet, .orc, .feather files returns a formatted table\n- head -n 5 on data files returns the first 5 rows/seconds\n- grep works natively on CSV, JSON, Parquet — not just text\n- Pipes work: cat data.parquet | grep error | sort | uniq | wc -l\n- head, tail, cut, wc, sort, uniq, tee, xargs are all available\n\nYou can write Python code and execute it. The workspace is pre-configured with your data sources mounted at their respective paths.\n\nUse the execute tool for complex operations. Use read_file/write_file/edit_file for simple file operations.\n`\n\nexport interface BuildSystemPromptOptions {\n workspace?: Workspace\n mountInfo?: Record<string, string>\n extraInstructions?: string\n}\n\nexport function buildSystemPrompt(opts: BuildSystemPromptOptions = {}): string {\n const parts: string[] = [MIRAGE_SYSTEM_PROMPT]\n if (opts.workspace !== undefined) {\n parts.push('Mounted data sources:\\n' + opts.workspace.filePrompt)\n } else if (opts.mountInfo !== undefined && Object.keys(opts.mountInfo).length > 0) {\n parts.push('\\nMounted data sources:')\n for (const [prefix, description] of Object.entries(opts.mountInfo)) {\n parts.push(`- ${prefix} — ${description}`)\n }\n parts.push('')\n }\n if (opts.extraInstructions !== undefined && opts.extraInstructions.length > 0) {\n parts.push(opts.extraInstructions)\n }\n return parts.join('\\n')\n}\n"],"mappings":";AAgBO,IAAM,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsB7B,SAAS,kBAAkB,OAAiC,CAAC,GAAW;AAC7E,QAAM,QAAkB,CAAC,oBAAoB;AAC7C,MAAI,KAAK,cAAc,QAAW;AAChC,UAAM,KAAK,4BAA4B,KAAK,UAAU,UAAU;AAAA,EAClE,WAAW,KAAK,cAAc,UAAa,OAAO,KAAK,KAAK,SAAS,EAAE,SAAS,GAAG;AACjF,UAAM,KAAK,yBAAyB;AACpC,eAAW,CAAC,QAAQ,WAAW,KAAK,OAAO,QAAQ,KAAK,SAAS,GAAG;AAClE,YAAM,KAAK,KAAK,MAAM,WAAM,WAAW,EAAE;AAAA,IAC3C;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AACA,MAAI,KAAK,sBAAsB,UAAa,KAAK,kBAAkB,SAAS,GAAG;AAC7E,UAAM,KAAK,KAAK,iBAAiB;AAAA,EACnC;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,30 @@
1
+ import { Workspace } from '@struktoai/mirage-node';
2
+ import { SandboxBackendProtocolV2, ExecuteResponse, LsResult, ReadResult, ReadRawResult, WriteResult, EditResult, GrepResult, GlobResult, FileUploadResponse, FileDownloadResponse } from 'deepagents';
3
+ export { B as BuildSystemPromptOptions, M as MIRAGE_SYSTEM_PROMPT, b as buildSystemPrompt } from '../prompt-CbBVJuUY.js';
4
+ import '@struktoai/mirage-core';
5
+
6
+ interface LangchainWorkspaceOptions {
7
+ sandboxId?: string;
8
+ }
9
+ declare class LangchainWorkspace implements SandboxBackendProtocolV2 {
10
+ readonly id: string;
11
+ private readonly ws;
12
+ constructor(workspace: Workspace, options?: LangchainWorkspaceOptions);
13
+ execute(command: string): Promise<ExecuteResponse>;
14
+ ls(path: string): Promise<LsResult>;
15
+ read(filePath: string, offset?: number, limit?: number): Promise<ReadResult>;
16
+ readRaw(filePath: string): Promise<ReadRawResult>;
17
+ write(filePath: string, content: string): Promise<WriteResult>;
18
+ edit(filePath: string, oldString: string, newString: string, replaceAll?: boolean): Promise<EditResult>;
19
+ grep(pattern: string, path?: string | null, glob?: string | null): Promise<GrepResult>;
20
+ glob(pattern: string, path?: string): Promise<GlobResult>;
21
+ uploadFiles(files: readonly (readonly [string, Uint8Array])[]): Promise<FileUploadResponse[]>;
22
+ downloadFiles(paths: readonly string[]): Promise<FileDownloadResponse[]>;
23
+ }
24
+
25
+ interface MessageLike {
26
+ content?: unknown;
27
+ }
28
+ declare function extractText(messages: readonly MessageLike[]): string[];
29
+
30
+ export { LangchainWorkspace, type LangchainWorkspaceOptions, extractText };
@@ -0,0 +1,306 @@
1
+ import {
2
+ MIRAGE_SYSTEM_PROMPT,
3
+ buildSystemPrompt
4
+ } from "../chunk-KAHWIK63.js";
5
+
6
+ // src/langchain/convert.ts
7
+ function ioToExecuteResponse(io) {
8
+ const stdout = io.stdoutText;
9
+ const stderr = io.stderrText;
10
+ let output = stdout;
11
+ if (stderr.length > 0) {
12
+ output = stdout.length > 0 ? `${stdout}
13
+ ${stderr}` : stderr;
14
+ }
15
+ return { output, exitCode: io.exitCode, truncated: false };
16
+ }
17
+ function ioToGrepMatches(io) {
18
+ const stdout = io.stdoutText.trim();
19
+ if (stdout.length === 0) return [];
20
+ const matches = [];
21
+ for (const line of stdout.split("\n")) {
22
+ const firstColon = line.indexOf(":");
23
+ if (firstColon < 0) continue;
24
+ const secondColon = line.indexOf(":", firstColon + 1);
25
+ if (secondColon < 0) continue;
26
+ const path = line.slice(0, firstColon);
27
+ const lineNumStr = line.slice(firstColon + 1, secondColon);
28
+ const text = line.slice(secondColon + 1);
29
+ const lineNum = Number.parseInt(lineNumStr, 10);
30
+ if (Number.isNaN(lineNum)) continue;
31
+ matches.push({ path, line: lineNum, text });
32
+ }
33
+ return matches;
34
+ }
35
+ function ioToFileInfos(io) {
36
+ const stdout = io.stdoutText.trim();
37
+ if (stdout.length === 0) return [];
38
+ const infos = [];
39
+ for (const raw of stdout.split("\n")) {
40
+ const entry = raw.trim();
41
+ if (entry.length === 0) continue;
42
+ const isDir = entry.endsWith("/");
43
+ infos.push({ path: isDir ? entry.slice(0, -1) : entry, is_dir: isDir });
44
+ }
45
+ return infos;
46
+ }
47
+
48
+ // src/langchain/backend.ts
49
+ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
50
+ "txt",
51
+ "md",
52
+ "json",
53
+ "jsonl",
54
+ "yaml",
55
+ "yml",
56
+ "csv",
57
+ "tsv",
58
+ "xml",
59
+ "html",
60
+ "htm",
61
+ "js",
62
+ "mjs",
63
+ "cjs",
64
+ "ts",
65
+ "tsx",
66
+ "jsx",
67
+ "py",
68
+ "rb",
69
+ "rs",
70
+ "go",
71
+ "java",
72
+ "c",
73
+ "cpp",
74
+ "h",
75
+ "hpp",
76
+ "sh",
77
+ "bash",
78
+ "zsh",
79
+ "fish",
80
+ "sql",
81
+ "log",
82
+ "env",
83
+ "ini",
84
+ "toml",
85
+ "conf",
86
+ "cfg"
87
+ ]);
88
+ function shellQuote(s) {
89
+ if (/^[A-Za-z0-9_./-]+$/.test(s)) return s;
90
+ return `'${s.replaceAll(`'`, `'\\''`)}'`;
91
+ }
92
+ function parentOf(path) {
93
+ const trimmed = path.replace(/\/+$/, "");
94
+ const idx = trimmed.lastIndexOf("/");
95
+ if (idx <= 0) return "/";
96
+ return trimmed.slice(0, idx);
97
+ }
98
+ async function ensureParent(ws, path) {
99
+ const parent = parentOf(path);
100
+ if (parent === "/" || parent === "") return;
101
+ if (await ws.fs.exists(parent)) return;
102
+ await ensureParent(ws, parent);
103
+ try {
104
+ await ws.fs.mkdir(parent);
105
+ } catch (err) {
106
+ if (!await ws.fs.exists(parent)) throw err;
107
+ }
108
+ }
109
+ function extOf(path) {
110
+ const dot = path.lastIndexOf(".");
111
+ if (dot < 0) return "";
112
+ return path.slice(dot + 1).toLowerCase();
113
+ }
114
+ var MIRAGE_RENDERED_AS_TEXT = /* @__PURE__ */ new Set(["parquet", "h5", "hdf5", "feather"]);
115
+ function mimeFor(path) {
116
+ const ext = extOf(path);
117
+ if (ext === "json" || ext === "jsonl") return "application/json";
118
+ if (ext === "csv") return "text/csv";
119
+ if (ext === "html" || ext === "htm") return "text/html";
120
+ if (ext === "md") return "text/markdown";
121
+ if (TEXT_EXTENSIONS.has(ext)) return "text/plain";
122
+ if (MIRAGE_RENDERED_AS_TEXT.has(ext)) return "text/plain";
123
+ if (ext === "png") return "image/png";
124
+ if (ext === "jpg" || ext === "jpeg") return "image/jpeg";
125
+ if (ext === "pdf") return "application/pdf";
126
+ return "application/octet-stream";
127
+ }
128
+ function isTextMime(mimeType) {
129
+ return mimeType.startsWith("text/") || mimeType === "application/json";
130
+ }
131
+ var ANTHROPIC_BINARY_MIMES = /* @__PURE__ */ new Set([
132
+ "application/pdf",
133
+ "image/jpeg",
134
+ "image/png",
135
+ "image/gif",
136
+ "image/webp"
137
+ ]);
138
+ var LangchainWorkspace = class {
139
+ id;
140
+ ws;
141
+ constructor(workspace, options = {}) {
142
+ this.ws = workspace;
143
+ this.id = options.sandboxId ?? "mirage";
144
+ }
145
+ async execute(command) {
146
+ const io = await this.ws.execute(command);
147
+ return ioToExecuteResponse(io);
148
+ }
149
+ async ls(path) {
150
+ let entries;
151
+ try {
152
+ entries = await this.ws.fs.readdir(path);
153
+ } catch (err) {
154
+ return { error: err instanceof Error ? err.message : String(err) };
155
+ }
156
+ const files = [];
157
+ for (const entry of entries) {
158
+ const isDir = await this.ws.fs.isDir(entry);
159
+ files.push({ path: entry, is_dir: isDir });
160
+ }
161
+ return { files };
162
+ }
163
+ async read(filePath, offset = 0, limit = 500) {
164
+ const mimeType = mimeFor(filePath);
165
+ let bytes;
166
+ try {
167
+ bytes = await this.ws.fs.readFile(filePath);
168
+ } catch (err) {
169
+ return { error: err instanceof Error ? err.message : String(err) };
170
+ }
171
+ if (!isTextMime(mimeType)) {
172
+ if (ANTHROPIC_BINARY_MIMES.has(mimeType)) {
173
+ return { content: bytes, mimeType };
174
+ }
175
+ return {
176
+ error: `Binary file '${filePath}' (${mimeType}, ${String(bytes.length)} bytes). Use shell commands (head, file, wc, od) via execute() to inspect.`
177
+ };
178
+ }
179
+ const text = new TextDecoder("utf-8").decode(bytes);
180
+ const lines = text.split("\n");
181
+ if (offset >= lines.length) {
182
+ return {
183
+ error: `Line offset ${String(offset)} exceeds file length (${String(lines.length)} lines)`
184
+ };
185
+ }
186
+ const end = Math.min(offset + limit, lines.length);
187
+ return { content: lines.slice(offset, end).join("\n"), mimeType };
188
+ }
189
+ async readRaw(filePath) {
190
+ let stat;
191
+ let bytes;
192
+ try {
193
+ stat = await this.ws.fs.stat(filePath);
194
+ bytes = await this.ws.fs.readFile(filePath);
195
+ } catch (err) {
196
+ return { error: err instanceof Error ? err.message : String(err) };
197
+ }
198
+ const mimeType = mimeFor(filePath);
199
+ const content = isTextMime(mimeType) ? new TextDecoder("utf-8").decode(bytes) : bytes;
200
+ const modified = stat.modified ?? (/* @__PURE__ */ new Date()).toISOString();
201
+ const data = {
202
+ content,
203
+ mimeType,
204
+ created_at: modified,
205
+ modified_at: modified
206
+ };
207
+ return { data };
208
+ }
209
+ async write(filePath, content) {
210
+ if (await this.ws.fs.exists(filePath)) {
211
+ return { error: `Error: file '${filePath}' already exists` };
212
+ }
213
+ await ensureParent(this.ws, filePath);
214
+ await this.ws.fs.writeFile(filePath, content);
215
+ return { path: filePath };
216
+ }
217
+ async edit(filePath, oldString, newString, replaceAll = false) {
218
+ let current;
219
+ try {
220
+ current = await this.ws.fs.readFileText(filePath);
221
+ } catch {
222
+ return { error: `Error: file '${filePath}' not found` };
223
+ }
224
+ const count = current.split(oldString).length - 1;
225
+ if (count === 0) {
226
+ return { error: `Error: string not found in file: '${oldString}'` };
227
+ }
228
+ if (count > 1 && !replaceAll) {
229
+ return {
230
+ error: `Error: string '${oldString}' appears ${String(count)} times. Use replaceAll=true`
231
+ };
232
+ }
233
+ const next = replaceAll ? current.split(oldString).join(newString) : current.replace(oldString, newString);
234
+ await this.ws.fs.writeFile(filePath, next);
235
+ return { path: filePath, occurrences: replaceAll ? count : 1 };
236
+ }
237
+ async grep(pattern, path, glob) {
238
+ const parts = ["grep", "-rn"];
239
+ if (glob !== void 0 && glob !== null && glob.length > 0) {
240
+ parts.push("--include", shellQuote(glob));
241
+ }
242
+ parts.push(shellQuote(pattern));
243
+ parts.push(shellQuote(path ?? "/"));
244
+ const io = await this.ws.execute(parts.join(" "));
245
+ return { matches: ioToGrepMatches(io) };
246
+ }
247
+ async glob(pattern, path = "/") {
248
+ const name = pattern.includes("/") ? pattern.split("/").pop() ?? pattern : pattern;
249
+ const io = await this.ws.execute(`find ${shellQuote(path)} -name ${shellQuote(name)}`);
250
+ return { files: ioToFileInfos(io) };
251
+ }
252
+ async uploadFiles(files) {
253
+ const results = [];
254
+ for (const [path, data] of files) {
255
+ await ensureParent(this.ws, path);
256
+ await this.ws.fs.writeFile(path, data);
257
+ results.push({ path, error: null });
258
+ }
259
+ return results;
260
+ }
261
+ async downloadFiles(paths) {
262
+ const results = [];
263
+ for (const path of paths) {
264
+ try {
265
+ const content = await this.ws.fs.readFile(path);
266
+ results.push({ path, content, error: null });
267
+ } catch {
268
+ results.push({ path, content: null, error: "file_not_found" });
269
+ }
270
+ }
271
+ return results;
272
+ }
273
+ };
274
+
275
+ // src/langchain/messages.ts
276
+ function isTextBlock(value) {
277
+ if (typeof value !== "object" || value === null) return false;
278
+ const block = value;
279
+ return block.type === "text" && typeof block.text === "string";
280
+ }
281
+ function extractText(messages) {
282
+ const texts = [];
283
+ for (const msg of messages) {
284
+ if (!("content" in msg) || msg.content === void 0 || msg.content === null) continue;
285
+ const content = msg.content;
286
+ if (typeof content === "string") {
287
+ if (content.trim().length > 0) texts.push(content);
288
+ continue;
289
+ }
290
+ if (Array.isArray(content)) {
291
+ for (const block of content) {
292
+ if (isTextBlock(block) && block.text.trim().length > 0) {
293
+ texts.push(block.text);
294
+ }
295
+ }
296
+ }
297
+ }
298
+ return texts;
299
+ }
300
+ export {
301
+ LangchainWorkspace,
302
+ MIRAGE_SYSTEM_PROMPT,
303
+ buildSystemPrompt,
304
+ extractText
305
+ };
306
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/langchain/convert.ts","../../src/langchain/backend.ts","../../src/langchain/messages.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { ExecuteResponse, FileInfo, GrepMatch } from 'deepagents'\n\ninterface IOLike {\n stdoutText: string\n stderrText: string\n exitCode: number | null\n}\n\nexport function ioToExecuteResponse(io: IOLike): ExecuteResponse {\n const stdout = io.stdoutText\n const stderr = io.stderrText\n let output = stdout\n if (stderr.length > 0) {\n output = stdout.length > 0 ? `${stdout}\\n${stderr}` : stderr\n }\n return { output, exitCode: io.exitCode, truncated: false }\n}\n\nexport function ioToGrepMatches(io: IOLike): GrepMatch[] {\n const stdout = io.stdoutText.trim()\n if (stdout.length === 0) return []\n const matches: GrepMatch[] = []\n for (const line of stdout.split('\\n')) {\n const firstColon = line.indexOf(':')\n if (firstColon < 0) continue\n const secondColon = line.indexOf(':', firstColon + 1)\n if (secondColon < 0) continue\n const path = line.slice(0, firstColon)\n const lineNumStr = line.slice(firstColon + 1, secondColon)\n const text = line.slice(secondColon + 1)\n const lineNum = Number.parseInt(lineNumStr, 10)\n if (Number.isNaN(lineNum)) continue\n matches.push({ path, line: lineNum, text })\n }\n return matches\n}\n\nexport function ioToFileInfos(io: IOLike): FileInfo[] {\n const stdout = io.stdoutText.trim()\n if (stdout.length === 0) return []\n const infos: FileInfo[] = []\n for (const raw of stdout.split('\\n')) {\n const entry = raw.trim()\n if (entry.length === 0) continue\n const isDir = entry.endsWith('/')\n infos.push({ path: isDir ? entry.slice(0, -1) : entry, is_dir: isDir })\n }\n return infos\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Workspace } from '@struktoai/mirage-node'\nimport type {\n EditResult,\n ExecuteResponse,\n FileData,\n FileDownloadResponse,\n FileInfo,\n FileUploadResponse,\n GlobResult,\n GrepResult,\n LsResult,\n ReadRawResult,\n ReadResult,\n SandboxBackendProtocolV2 as SandboxBackendProtocol,\n WriteResult,\n} from 'deepagents'\nimport { ioToExecuteResponse, ioToFileInfos, ioToGrepMatches } from './convert.ts'\n\nconst TEXT_EXTENSIONS = new Set([\n 'txt',\n 'md',\n 'json',\n 'jsonl',\n 'yaml',\n 'yml',\n 'csv',\n 'tsv',\n 'xml',\n 'html',\n 'htm',\n 'js',\n 'mjs',\n 'cjs',\n 'ts',\n 'tsx',\n 'jsx',\n 'py',\n 'rb',\n 'rs',\n 'go',\n 'java',\n 'c',\n 'cpp',\n 'h',\n 'hpp',\n 'sh',\n 'bash',\n 'zsh',\n 'fish',\n 'sql',\n 'log',\n 'env',\n 'ini',\n 'toml',\n 'conf',\n 'cfg',\n])\n\nfunction shellQuote(s: string): string {\n if (/^[A-Za-z0-9_./-]+$/.test(s)) return s\n return `'${s.replaceAll(`'`, `'\\\\''`)}'`\n}\n\nfunction parentOf(path: string): string {\n const trimmed = path.replace(/\\/+$/, '')\n const idx = trimmed.lastIndexOf('/')\n if (idx <= 0) return '/'\n return trimmed.slice(0, idx)\n}\n\nasync function ensureParent(ws: Workspace, path: string): Promise<void> {\n const parent = parentOf(path)\n if (parent === '/' || parent === '') return\n if (await ws.fs.exists(parent)) return\n await ensureParent(ws, parent)\n try {\n await ws.fs.mkdir(parent)\n } catch (err) {\n if (!(await ws.fs.exists(parent))) throw err\n }\n}\n\nfunction extOf(path: string): string {\n const dot = path.lastIndexOf('.')\n if (dot < 0) return ''\n return path.slice(dot + 1).toLowerCase()\n}\n\nconst MIRAGE_RENDERED_AS_TEXT = new Set(['parquet', 'h5', 'hdf5', 'feather'])\n\nfunction mimeFor(path: string): string {\n const ext = extOf(path)\n if (ext === 'json' || ext === 'jsonl') return 'application/json'\n if (ext === 'csv') return 'text/csv'\n if (ext === 'html' || ext === 'htm') return 'text/html'\n if (ext === 'md') return 'text/markdown'\n if (TEXT_EXTENSIONS.has(ext)) return 'text/plain'\n if (MIRAGE_RENDERED_AS_TEXT.has(ext)) return 'text/plain'\n if (ext === 'png') return 'image/png'\n if (ext === 'jpg' || ext === 'jpeg') return 'image/jpeg'\n if (ext === 'pdf') return 'application/pdf'\n return 'application/octet-stream'\n}\n\nfunction isTextMime(mimeType: string): boolean {\n return mimeType.startsWith('text/') || mimeType === 'application/json'\n}\n\nconst ANTHROPIC_BINARY_MIMES = new Set([\n 'application/pdf',\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n])\n\nexport interface LangchainWorkspaceOptions {\n sandboxId?: string\n}\n\nexport class LangchainWorkspace implements SandboxBackendProtocol {\n readonly id: string\n private readonly ws: Workspace\n\n constructor(workspace: Workspace, options: LangchainWorkspaceOptions = {}) {\n this.ws = workspace\n this.id = options.sandboxId ?? 'mirage'\n }\n\n async execute(command: string): Promise<ExecuteResponse> {\n const io = await this.ws.execute(command)\n return ioToExecuteResponse(io)\n }\n\n async ls(path: string): Promise<LsResult> {\n let entries: string[]\n try {\n entries = await this.ws.fs.readdir(path)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n const files: FileInfo[] = []\n for (const entry of entries) {\n const isDir = await this.ws.fs.isDir(entry)\n files.push({ path: entry, is_dir: isDir })\n }\n return { files }\n }\n\n async read(filePath: string, offset = 0, limit = 500): Promise<ReadResult> {\n const mimeType = mimeFor(filePath)\n let bytes: Uint8Array\n try {\n bytes = await this.ws.fs.readFile(filePath)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n if (!isTextMime(mimeType)) {\n if (ANTHROPIC_BINARY_MIMES.has(mimeType)) {\n return { content: bytes, mimeType }\n }\n return {\n error: `Binary file '${filePath}' (${mimeType}, ${String(bytes.length)} bytes). Use shell commands (head, file, wc, od) via execute() to inspect.`,\n }\n }\n const text = new TextDecoder('utf-8').decode(bytes)\n const lines = text.split('\\n')\n if (offset >= lines.length) {\n return {\n error: `Line offset ${String(offset)} exceeds file length (${String(lines.length)} lines)`,\n }\n }\n const end = Math.min(offset + limit, lines.length)\n return { content: lines.slice(offset, end).join('\\n'), mimeType }\n }\n\n async readRaw(filePath: string): Promise<ReadRawResult> {\n let stat: Awaited<ReturnType<Workspace['fs']['stat']>>\n let bytes: Uint8Array\n try {\n stat = await this.ws.fs.stat(filePath)\n bytes = await this.ws.fs.readFile(filePath)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n const mimeType = mimeFor(filePath)\n const content: string | Uint8Array = isTextMime(mimeType)\n ? new TextDecoder('utf-8').decode(bytes)\n : bytes\n const modified = stat.modified ?? new Date().toISOString()\n const data: FileData = {\n content,\n mimeType,\n created_at: modified,\n modified_at: modified,\n }\n return { data }\n }\n\n async write(filePath: string, content: string): Promise<WriteResult> {\n if (await this.ws.fs.exists(filePath)) {\n return { error: `Error: file '${filePath}' already exists` }\n }\n await ensureParent(this.ws, filePath)\n await this.ws.fs.writeFile(filePath, content)\n return { path: filePath }\n }\n\n async edit(\n filePath: string,\n oldString: string,\n newString: string,\n replaceAll = false,\n ): Promise<EditResult> {\n let current: string\n try {\n current = await this.ws.fs.readFileText(filePath)\n } catch {\n return { error: `Error: file '${filePath}' not found` }\n }\n const count = current.split(oldString).length - 1\n if (count === 0) {\n return { error: `Error: string not found in file: '${oldString}'` }\n }\n if (count > 1 && !replaceAll) {\n return {\n error: `Error: string '${oldString}' appears ${String(count)} times. Use replaceAll=true`,\n }\n }\n const next = replaceAll\n ? current.split(oldString).join(newString)\n : current.replace(oldString, newString)\n await this.ws.fs.writeFile(filePath, next)\n return { path: filePath, occurrences: replaceAll ? count : 1 }\n }\n\n async grep(pattern: string, path?: string | null, glob?: string | null): Promise<GrepResult> {\n const parts: string[] = ['grep', '-rn']\n if (glob !== undefined && glob !== null && glob.length > 0) {\n parts.push('--include', shellQuote(glob))\n }\n parts.push(shellQuote(pattern))\n parts.push(shellQuote(path ?? '/'))\n const io = await this.ws.execute(parts.join(' '))\n return { matches: ioToGrepMatches(io) }\n }\n\n async glob(pattern: string, path = '/'): Promise<GlobResult> {\n const name = pattern.includes('/') ? (pattern.split('/').pop() ?? pattern) : pattern\n const io = await this.ws.execute(`find ${shellQuote(path)} -name ${shellQuote(name)}`)\n return { files: ioToFileInfos(io) }\n }\n\n async uploadFiles(\n files: readonly (readonly [string, Uint8Array])[],\n ): Promise<FileUploadResponse[]> {\n const results: FileUploadResponse[] = []\n for (const [path, data] of files) {\n await ensureParent(this.ws, path)\n await this.ws.fs.writeFile(path, data)\n results.push({ path, error: null })\n }\n return results\n }\n\n async downloadFiles(paths: readonly string[]): Promise<FileDownloadResponse[]> {\n const results: FileDownloadResponse[] = []\n for (const path of paths) {\n try {\n const content = await this.ws.fs.readFile(path)\n results.push({ path, content, error: null })\n } catch {\n results.push({ path, content: null, error: 'file_not_found' })\n }\n }\n return results\n }\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\ninterface MessageLike {\n content?: unknown\n}\n\ninterface ContentBlock {\n type?: string\n text?: string\n}\n\nfunction isTextBlock(value: unknown): value is { type: 'text'; text: string } {\n if (typeof value !== 'object' || value === null) return false\n const block = value as ContentBlock\n return block.type === 'text' && typeof block.text === 'string'\n}\n\nexport function extractText(messages: readonly MessageLike[]): string[] {\n const texts: string[] = []\n for (const msg of messages) {\n if (!('content' in msg) || msg.content === undefined || msg.content === null) continue\n const content = msg.content\n if (typeof content === 'string') {\n if (content.trim().length > 0) texts.push(content)\n continue\n }\n if (Array.isArray(content)) {\n for (const block of content) {\n if (isTextBlock(block) && block.text.trim().length > 0) {\n texts.push(block.text)\n }\n }\n }\n }\n return texts\n}\n"],"mappings":"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","names":[]}