TensorFusion Docs

文件系统、终端与端口

读写文件、操作目录、监听变更、上传下载,使用 PTY 交互终端,并通过 getHost 暴露端口。

每个沙箱都有一套完整、可读写的 Linux 文件系统。所有文件操作通过 sandbox.files 完成;交互式终端通过 sandbox.pty;对外暴露服务通过 sandbox.getHost(port)

读文件

读取默认返回文本;通过 format 选项可读为二进制或流:

// 文本(默认)
const text = await sandbox.files.read('/home/user/hello.txt');

// 二进制
const bytes = await sandbox.files.read('/bin/app', { format: 'bytes' });
// -> Uint8Array

// 流(适合大文件)
const stream = await sandbox.files.read('/data/big.csv', { format: 'stream' });
// -> ReadableStream<Uint8Array>
# 文本(默认)
text = sandbox.files.read("/home/user/hello.txt")

# 二进制
data = sandbox.files.read("/bin/app", format="bytes")   # -> bytes
// 文本
text, _ := sandbox.Files.Read(ctx, "/home/user/hello.txt", nil)

// 二进制
data, _ := sandbox.Files.ReadBytes(ctx, "/bin/app", nil)        // -> []byte

// 流(适合大文件)
rc, _ := sandbox.Files.ReadStream(ctx, "/data/big.csv", nil)    // -> io.ReadCloser
defer rc.Close()

Go 把 TS 的 read({format}) 拆成 Read(string)、ReadBytes[]byte)、ReadStreamio.ReadCloser)。

写文件

写入单个文件返回写入后的 EntryInfo。数据可以是字符串、字节、Blob 或流:

// 单文件
const info = await sandbox.files.write('/tmp/hello.txt', 'Hello World!');

// 批量写入
const infos = await sandbox.files.write([
  { path: '/tmp/a.txt', data: 'aaa' },
  { path: '/tmp/b.txt', data: 'bbb' },
]);
from tensor_box import WriteEntry

# 单文件
info = sandbox.files.write("/tmp/hello.txt", "Hello World!")

# 批量写入
infos = sandbox.files.write([
    WriteEntry("/tmp/a.txt", "aaa"),
    WriteEntry("/tmp/b.txt", b"\x00\x01"),
])
// 字符串单文件
info, _ := sandbox.Files.WriteString(ctx, "/tmp/hello.txt", "Hello World!", nil)

// 字节单文件
sandbox.Files.Write(ctx, "/tmp/blob.bin", []byte{0, 1, 2}, nil)

// 批量写入
infos, _ := sandbox.Files.WriteFiles(ctx, []tensorbox.WriteEntry{
	{Path: "/tmp/a.txt", Data: []byte("aaa")},
	{Path: "/tmp/b.txt", Data: []byte("bbb")},
}, nil)

目录与元数据操作

// 列目录
const entries = await sandbox.files.list('/home/user');
// EntryInfo[]: { name, path, type: 'file' | 'dir', size, mode, permissions, owner, ... }

// 创建目录(含父目录)
await sandbox.files.makeDir('/home/user/project/src');

// 判断是否存在
const ok = await sandbox.files.exists('/home/user/project');

// 重命名 / 移动
await sandbox.files.rename('/tmp/old.txt', '/tmp/new.txt');

// 删除文件或目录
await sandbox.files.remove('/tmp/new.txt');

// 获取单个文件 / 目录的信息
const stat = await sandbox.files.getInfo('/home/user/hello.txt');
# 列目录
entries = sandbox.files.list("/home/user")
# [EntryInfo(name, path, type, size, ...), ...]

# 创建目录(含父目录)
sandbox.files.make_dir("/home/user/project/src")

# 判断是否存在
ok = sandbox.files.exists("/home/user/project")

# 重命名 / 移动
sandbox.files.rename("/tmp/old.txt", "/tmp/new.txt")

# 删除文件或目录
sandbox.files.remove("/tmp/new.txt")

# 获取单个文件 / 目录的信息
stat = sandbox.files.get_info("/home/user/hello.txt")
// 列目录
entries, _ := sandbox.Files.List(ctx, "/home/user", nil)
// []EntryInfo{ {Name, Path, Type, Size, ...}, ... }

// 创建目录(含父目录)
sandbox.Files.MakeDir(ctx, "/home/user/project/src", nil)

// 判断是否存在
ok := sandbox.Files.Exists(ctx, "/home/user/project", nil)

// 重命名 / 移动
sandbox.Files.Rename(ctx, "/tmp/old.txt", "/tmp/new.txt", nil)

// 删除文件或目录
sandbox.Files.Remove(ctx, "/tmp/new.txt", nil)

// 获取单个文件 / 目录的信息
stat, _ := sandbox.Files.GetInfo(ctx, "/home/user/hello.txt", nil)

监听目录变更

watchDir 实时回调目录内的 create / write / remove 事件,返回一个可停止监听的句柄:

const watcher = await sandbox.files.watchDir(
  '/home/user/project',
  (event) => {
    // event: { type: 'create' | 'write' | 'remove', name, path }
    console.log(event.type, event.path);
  },
  { recursive: true }, // 可选:递归监听子目录
);

// 停止监听
watcher.stop();
handle = sandbox.files.watch_dir(
    "/home/user/project",
    lambda ev: print(ev.type, ev.path),  # ev.type in {"create", "write", "remove"}
    recursive=True,
)

# 停止监听
handle.stop()
watcher, _ := sandbox.Files.WatchDir(ctx, "/home/user/project",
	func(ev tensorbox.WatchEvent) {
		// ev.Type in {"create", "write", "remove"}
		fmt.Println(ev.Type, ev.Path)
	},
	&tensorbox.WatchOptions{Recursive: true})

// 停止监听
watcher.Stop()

目录监听走 X-API-Key 鉴权的 WebSocket(/sandboxes/:id/files/watch)。Python 需要安装 websocket-client、Go 依赖 gorilla/websocket;若路由不可用(升级 404),监听会通过 onExit 回调干净结束。

上传与下载

对于较大的文件或浏览器 / 外部工具直传,SDK 可以生成上传 / 下载 URL:

// 生成一个下载该路径文件的 URL
const dlUrl = sandbox.downloadUrl('/home/user/output.zip');

// 生成一个上传文件到沙箱的 URL
const upUrl = sandbox.uploadUrl('/home/user/input.zip');
dl_url = sandbox.download_url("/home/user/output.zip")
up_url = sandbox.upload_url("/home/user/input.zip")
dlURL := sandbox.DownloadURL("/home/user/output.zip")
upURL := sandbox.UploadURL("/home/user/input.zip")

日常读写直接用 files.read / files.write 即可;downloadUrl / uploadUrl 适合把链接交给浏览器、curl 或第三方服务做直传,避免数据绕经你的应用进程。

PTY 交互终端

需要带 TTY 的真正交互式终端(行编辑、vimtop 等全屏程序),用 sandbox.ptycreate 建立一个 PTY 会话,通过 onData 接收输出,返回 PtyHandle

const pty = await sandbox.pty.create({
  cols: 120,
  rows: 40,
  onData: (data) => process.stdout.write(data), // data: Uint8Array
});

// 写入输入(可传字符串或 Uint8Array)
pty.sendInput('ls -la\n');

// 终端尺寸变化时同步
pty.resize({ cols: 200, rows: 50 });

// 结束会话
await pty.kill();

PtyHandle 提供 pidsendInput(data)resize({ cols, rows })kill() 以及 isOpen

pty = sandbox.pty.create(
    cols=120, rows=40,
    on_data=lambda b: print(b.decode(), end=""),
)

pty.send_input("ls -la\n")
pty.resize(cols=200, rows=50)
pty.kill()

PtyHandle 提供 send_input(data)resize(cols, rows)kill() 以及 is_open

pty, _ := sandbox.Pty.Create(ctx, &tensorbox.PtyOptions{
	Cols: 120, Rows: 40,
	OnData: func(b []byte) { fmt.Print(string(b)) },
})

pty.SendInput([]byte("ls -la\n"))
pty.Resize(200, 50)
pty.Kill()

*PtyHandle 提供 SendInputResizeKillIsOpen

# 直接进入交互式 PTY(Ctrl-D 退出)
tensor-box sandbox terminal "$sbx" --shell /bin/bash

这正是控制台「终端」标签页接入 xterm 的底层方式。PTY WebSocket 通过 X-API-Key 升级请求头鉴权。

暴露端口

沙箱内启动的服务(HTTP、WebSocket 等)可通过 getHost(port) 拿到一个对外可访问的主机名:

// 在沙箱内启动一个服务
await sandbox.commands.run('python3 -m http.server 8000', { background: true });

// 拿到该端口对外的主机名
const host = sandbox.getHost(8000);
console.log(`https://${host}`);
sandbox.commands.run("python3 -m http.server 8000", background=True)
host = sandbox.get_host(8000)
print(f"https://{host}")
sandbox.Commands.RunBackground(ctx, "python3 -m http.server 8000", nil)
host := sandbox.GetHost(8000)
fmt.Printf("https://%s\n", host)

getHost(port) 返回的是形如 <sandboxId>-<port>.<你的控制面域名>主机名字符串(不含协议),你可以据此拼出完整 URL 访问沙箱内服务。

关于 per-port 预览的就绪状态:按端口对外路由的预览 ingress(让 getHost 返回的 URL 浏览器直开即可访问沙箱内服务)仍在实现中(对应内部工单 S1.5)。在该能力落地前,getHost(port) 仅返回拼好的主机名/地址字符串本身——它写法正确、便于你提前组装 URL,但此刻直接用浏览器打开尚不可达。需要从沙箱外访问端口时,请在 S1.5 落地前先用 SDK 的命令 / 文件接口,或在你的 Tensor OS 部署侧自行接入反向代理。

Tensor Box 不提供网络白名单 / 防火墙规则之类的出站管控 API。沙箱的隔离来自 microVM 的硬件边界与独立资源配额;如需网络层管控,请在你的 Tensor OS 部署的网络策略层处理。

方法一览

方法(TS / Python / Go)说明
files.read / files.read(format=) / Files.Read·ReadBytes·ReadStream读文件:文本(默认)/ 二进制 / 流
files.write / files.write / Files.Write·WriteString·WriteFiles写单个 / 批量文件,返回 EntryInfo
files.list / files.list / Files.List列目录,返回 EntryInfo[]
files.makeDir / files.make_dir / Files.MakeDir创建目录(含父目录)
files.exists / files.exists / Files.Exists判断路径是否存在
files.rename / files.rename / Files.Rename重命名 / 移动
files.remove / files.remove / Files.Remove删除文件或目录
files.getInfo / files.get_info / Files.GetInfo获取文件 / 目录信息
files.watchDir / files.watch_dir / Files.WatchDir监听目录变更,返回可 stop 的句柄
pty.create / pty.create / Pty.Create创建 PTY 会话,返回 PtyHandle
getHost / get_host / GetHost拿到端口对外主机名
downloadUrl·uploadUrl / download_url·upload_url / DownloadURL·UploadURL生成下载 / 上传 URL

目录