Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2625424
Fix E2B template chunk upload
Oct 4, 2026
bf01f0f
Merge pull request #7 from sandbaseai/codex/e2b-chunk-upload
sam2tom Oct 4, 2026
7ac004f
Fix E2B builder sibling imports
Oct 4, 2026
63656a5
Merge pull request #8 from sandbaseai/codex/e2b-builder-import-path
sam2tom Oct 4, 2026
23f1fa4
Merge branch 'MiniMax-AI:main' into main
sam2tom Oct 7, 2026
af2e840
docs: add Japanese README (#639)
jellyjelly814 Oct 10, 2026
4d9f263
perf(runtime): reduce managed Session startup waits
Oct 10, 2026
96bcbcd
test(core): account for capability-driven scheduler wakeups
Oct 10, 2026
582fc68
feat(observability): trace managed Session startup boundaries
Oct 10, 2026
25c503e
Preserve native sessions across compute replacement (#641)
SaladDay Oct 10, 2026
f3b50ee
feat(sandbox): support native E2B suspension and retained capacity
Oct 10, 2026
45621ae
Document independent workspace recovery (#645)
SaladDay Oct 10, 2026
cf765b1
Merge native E2B suspension prerequisite into startup tracing
Oct 10, 2026
16f19da
Merge upstream native Session recovery with retained E2B lifecycle
Oct 10, 2026
baf30a8
Merge upstream-aligned E2B prerequisite into startup tracing
Oct 10, 2026
40766bf
Document workspace capacity isolation limits (#648)
SaladDay Oct 10, 2026
ba4047d
Queue sessions for available compute (#646)
SaladDay Oct 10, 2026
c8dd06a
Honor initialization execution budget (#647)
SaladDay Oct 10, 2026
a442026
Preserve Runtime PATH in login shells (#649)
SaladDay Oct 10, 2026
9c85f25
Retain compute transition failure observations (#650)
SaladDay Oct 10, 2026
4a72318
Preserve snapshots until retention expiry (#653)
SaladDay Oct 10, 2026
274ee05
Preserve resident executors during suspension (#651)
SaladDay Oct 10, 2026
4970339
Upgrade microsandbox to the official 0.7.8 release (#652)
SaladDay Oct 10, 2026
2bba238
Allow reconnect after settled initialization uncertainty (#658)
SaladDay Oct 10, 2026
951b755
Classify workspace storage exhaustion as unavailable (#657)
SaladDay Oct 10, 2026
601da24
Restore retained checkpoints across compatible nodes (#655)
SaladDay Oct 10, 2026
1c3f27d
Merge branch 'MiniMax-AI:main' into main
sam2tom Oct 11, 2026
51fe8d2
Merge latest upstream main into E2B lifecycle optimization
Oct 11, 2026
697724c
Merge current E2B lifecycle and upstream into startup tracing
Oct 11, 2026
d795e31
Merge synced main into beta preserving production fixes
Oct 11, 2026
d52e129
Merge updated E2B optimization and tracing into beta
Oct 11, 2026
a166c82
Fix retained checkpoint demand and node accounting queries
Oct 11, 2026
53e4e12
Merge commit 'a166c822' into codex/e2b-trace-main-sync-20261011
Oct 11, 2026
4c2e416
Merge commit '53e4e12c' into codex/e2b-beta-main-sync-20261011
Oct 11, 2026
7edd85a
Test beta upgrade through checkpoint compatibility schema
Oct 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
87 changes: 83 additions & 4 deletions .github/workflows/e2b-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ on:
type: string
required: false

resume_build:
description: Existing unsubmitted templateID:build_UUID after an upload failure; requires ref
type: string
required: false

permissions:
contents: read

Expand Down Expand Up @@ -63,13 +68,18 @@ jobs:
env:
SOURCE_BRANCH: ${{ inputs.source_branch }}
REQUESTED_REF: ${{ inputs.ref }}
RESUME_BUILD: ${{ inputs.resume_build }}
run: |
set -euo pipefail
case "$SOURCE_BRANCH" in main|beta) ;; *) exit 1 ;; esac
if [ -n "$REQUESTED_REF" ] && [[ ! "$REQUESTED_REF" =~ ^[0-9a-f]{40}$ ]]; then
echo '::error::ref must be a full lowercase commit SHA.'
exit 1
fi
if [ -n "$RESUME_BUILD" ]; then
[ -n "$REQUESTED_REF" ] || { echo '::error::Recovery requires the original source SHA.'; exit 1; }
[[ "$RESUME_BUILD" =~ ^[a-zA-Z0-9_-]+:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ ]] || exit 1
fi
git fetch --no-tags origin "refs/heads/$SOURCE_BRANCH:refs/remotes/origin/$SOURCE_BRANCH"
revision="$(git rev-parse "${REQUESTED_REF:-origin/$SOURCE_BRANCH}^{commit}")"
git merge-base --is-ancestor "$revision" "origin/$SOURCE_BRANCH" || {
Expand Down Expand Up @@ -146,6 +156,8 @@ jobs:
printf '%s\n' "$image" > "$output_root/runtime-image.id"
- name: Build one immutable E2B template
env:
RESUME_BUILD: ${{ inputs.resume_build }}
SOURCE_COMMIT: ${{ steps.source.outputs.revision }}
E2B_API_KEY: ${{ secrets.E2B_API_KEY }}
E2B_API_URL: ${{ vars.E2B_API_URL }}
run: |
Expand All @@ -156,10 +168,76 @@ jobs:
printf '%s' "$E2B_API_KEY" > "$key"
unset E2B_API_KEY
mkdir -p "$RUNNER_TEMP/e2b-result"
"$RUNNER_TEMP/e2b-sdk/bin/python" source/services/core/deploy/e2b/build-template.py \
"$RUNNER_TEMP/e2b-sdk/bin/python" - source/services/core/deploy/e2b/build-template.py \
--image "$(cat "$HOME/.oac/build/e2b-runtime/runtime-image.id")" \
--name "sandbase-oac-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT" \
--api-key-file "$key" --output "$RUNNER_TEMP/e2b-result/template.json"
--api-key-file "$key" --output "$RUNNER_TEMP/e2b-result/template.json" <<'PY'
import hashlib, json, os, pathlib, runpy, sys
from types import SimpleNamespace
from e2b.template.main import TemplateBuilder
import e2b.template_sync.main as sdk

output = pathlib.Path(os.environ['RUNNER_TEMP']) / 'e2b-result'
original_copy = TemplateBuilder.copy
def copy(self, src, dest, *args, **kwargs):
if str(src) != 'runtime.tar.gz':
return original_copy(self, src, dest, *args, **kwargs)
if dest != '/root/runtime.tar.gz' or args or kwargs != {'user': 'root'}:
raise RuntimeError('Runtime archive copy contract changed')
context = pathlib.Path(self._template._file_context_path)
digest = hashlib.sha256()
parts = []
with (context / src).open('rb') as stream:
for index in range(256):
block = stream.read(32 * 1024 * 1024)
if not block:
break
digest.update(block)
name = f'runtime.part{index:04d}'
(context / name).write_bytes(block)
self = original_copy(self, name, '/root/' + name, user='root')
parts.append('/root/' + name)
if stream.read(1):
raise RuntimeError('Runtime archive exceeds 8 GiB')
if not parts:
raise RuntimeError('Runtime archive is empty')
(output / 'upload.json').write_text(json.dumps({
'chunks': len(parts), 'chunk_bytes': 32 * 1024 * 1024,
'runtime_sha256': digest.hexdigest()}, indent=2) + '\n')
command = ('cat ' + ' '.join(parts) + ' > /root/runtime.tar.gz && '
'echo "' + digest.hexdigest() + ' /root/runtime.tar.gz" | sha256sum -c - && '
'rm ' + ' '.join(parts))
return self.run_cmd(command, user='root')
TemplateBuilder.copy = copy

original_request = sdk.request_build
def request(client, **kwargs):
selector = os.environ.get('RESUME_BUILD', '')
if selector:
template_id, build_id = selector.split(':')
# Inspect the raw response before the SDK's typed parser.
response = client.get_httpx_client().get(
f'/templates/{template_id}/builds/{build_id}/status')
response.raise_for_status()
state = response.json()
if (state.get('templateID') != template_id or state.get('buildID') != build_id
or state.get('status') != 'waiting' or state.get('logEntries')
or state.get('logs')):
raise RuntimeError('Recovery requires an unsubmitted waiting build with no logs')
result = SimpleNamespace(template_id=template_id, build_id=build_id, tags=[])
else:
result = original_request(client, **kwargs)
receipt = {'template': result.template_id + ':' + result.build_id,
'source_commit': os.environ['SOURCE_COMMIT'],
'api_url': os.environ['E2B_API_URL'], 'resumed': bool(selector)}
(output / 'build-request.json').write_text(json.dumps(receipt, indent=2) + '\n')
return result
sdk.request_build = request
builder = sys.argv[1]
sys.path.insert(0, str(pathlib.Path(builder).resolve().parent))
sys.argv = sys.argv[1:]
runpy.run_path(builder, run_name='__main__')
PY
- name: Record the build identity
env:
SOURCE_COMMIT: ${{ steps.source.outputs.revision }}
Expand All @@ -179,8 +257,9 @@ jobs:
out.write('One combined Runtime template built. No Core configuration or production deployment was changed.\n')
PY
- uses: actions/upload-artifact@v6
if: always()
with:
name: e2b-template-${{ steps.source.outputs.revision }}-${{ github.run_id }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/e2b-result/template.json
if-no-files-found: error
path: ${{ runner.temp }}/e2b-result/*.json
if-no-files-found: warn
retention-days: 90
11 changes: 4 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -166,23 +166,20 @@ build-mcode-runtime:

.PHONY: build-microsandbox-provider check-microsandbox-provider
build-microsandbox-provider:
@test "$$(go env GOOS)" = linux || { echo 'The microsandbox provider helper requires Linux' >&2; exit 1; }
@set -e; output="$${OAC_DEV_HOME:-$$HOME/.oac}/build/microsandbox-provider"; \
[[ "$$output" == /* ]] || { echo 'Provider output directory must be absolute' >&2; exit 1; }; \
mkdir -p "$$output"; \
cd services/core/tools/microsandbox-provider; \
GOWORK=off CGO_ENABLED=1 go build -mod=readonly -trimpath -o "$$output/oac-microsandbox-provider" .
python3 scripts/build-microsandbox-provider.py build "$${OAC_DEV_HOME:-$$HOME/.oac}/build/microsandbox-provider/oac-microsandbox-provider"

check-microsandbox-provider:
python3 scripts/build-microsandbox-provider.test.py
go test -mod=readonly ./services/core/internal/sandbox/microsandbox/... -count=1
@if [[ "$$(go env GOOS)" == linux ]]; then \
cd services/core/tools/microsandbox-provider && GOWORK=off CGO_ENABLED=1 go test -mod=readonly ./... -count=1; \
python3 scripts/build-microsandbox-provider.py test; \
else \
printf 'Skipping the Linux-only microsandbox SDK helper tests; the full Linux gate is required before release.\n'; \
fi

.PHONY: check-distribution build-core-distribution
check-distribution:
PYTHONDONTWRITEBYTECODE=1 python3 services/core/deploy/runtime_profile_test.py
node --test scripts/build-native-catalog.test.mjs
go test ./services/web ./services/core/cmd/oac -count=1
PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s deploy/node -p 'test_*.py'
Expand Down
78 changes: 78 additions & 0 deletions README.ja.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<div align="center">

![OpenAgentCore — One core. Many agents.](docs/assets/openagentcore-banner.jpeg)

# OpenAgentCore

複数のネイティブ実行エンジンに対応し、自分のインフラにデプロイできる OpenAI Agents API のオープンソース実装です。

[公式サイト](https://openagentcore.dev/) · [インストール](#インストール) · [API を使う](https://openagentcore.dev/docs/getting-started/quickstart) · [ドキュメント](https://openagentcore.dev/docs/getting-started/) · [コントリビューション](CONTRIBUTING.md)

[English](README.md) · [简体中文](README.zh-CN.md) · **日本語**

</div>

## コンポーネントの関係

![OpenAgentCore のアーキテクチャ](docs/assets/architecture.png)

アプリケーションと管理者は、次の Core API を使用します。

| API | パス | 利用者 |
| --- | --- | --- |
| **[Agents API](https://openagentcore.dev/docs/api/public-agent-api)** | `/v1` | アプリケーション。[OpenAI の Agents API](https://developers.openai.com/api/docs/guides/agents-api/overview) と同じプロトコルを使用 |
| **[Core API](https://openagentcore.dev/contracts/agents-api/admin-api)** | `/core/v1` | 管理者。Web 経由で利用 |

Core は実行状態を永続化し、Runtime は Environment 内で選択した Harness を実行します。各コンポーネントは定義されたプロトコルで接続されているため、個別に置き換えられます。詳しくは[アーキテクチャガイド](https://openagentcore.dev/docs/architecture)をご覧ください。

## OpenAgentCore とは

OpenAgentCore は、自分のインフラ上で AI エージェントを実行し、[OpenAI Agents API](https://developers.openai.com/api/docs/guides/agents-api/overview) を提供します。

- **OpenAI と同じ API。** [公式 OpenAI SDK](https://developers.openai.com/api/docs/guides/agents/sdk) または直接の HTTP リクエストで、接続先を変更するだけで利用できます。新しいクライアントを覚える必要はありません。
- **エージェントを選択可能。** 各 [Session](https://openagentcore.dev/docs/api/public-agent-api) は、[Codex](https://github.com/openai/codex)、[Claude Code](https://code.claude.com/docs/en/overview)、[MiniMax Code](https://github.com/MiniMax-AI/minimax-code) のいずれかの[ネイティブ Harness](https://openagentcore.dev/contracts/agents-api/harness-onboarding) を実行し、[設定したモデルプロバイダー](https://openagentcore.dev/contracts/agents-api/model-execution)を使用します。
- **実行するマシンを選択可能。** エージェントは、[マネージドサンドボックス](https://openagentcore.dev/contracts/agents-api/sandbox-deployment)([Docker](https://www.docker.com/)、[microsandbox](https://github.com/zerocore-ai/microsandbox)、[E2B](https://e2b.dev/))でも、自分の Linux、macOS、Windows マシンでも動作します。
- **すべてのコンポーネントを置き換え可能。** [サンドボックス](https://openagentcore.dev/docs/sandbox-provider)、[Harness](https://openagentcore.dev/contracts/agents-api/harness-onboarding)、[モデルプロバイダー](https://openagentcore.dev/contracts/agents-api/model-execution)は、[定義されたプロトコル](AGENTS.md#protocols-at-every-boundary)を通じて接続されます。

## スクリーンショット

| 概要 | エージェントの監視 |
| --- | --- |
| ![デプロイの概要](docs/assets/console-overview-en.webp) | ![エージェントの監視](docs/assets/console-agent-metrics-en.webp) |

## インストール

[前提条件](https://openagentcore.dev/docs/getting-started/install#prerequisites)に従って Docker をセットアップした Linux または macOS で、次のコマンドを実行します。

```sh
curl -fsSL https://github.com/MiniMax-AI/OpenAgentCore/releases/latest/download/install.sh | bash
```

Windows PowerShell の場合:

```powershell
irm https://github.com/MiniMax-AI/OpenAgentCore/releases/latest/download/install.ps1 | iex
```

続いて、以下の手順で設定します。

1. インストーラーが生成した Core key で **Web(管理コンソール)にサインイン**し、**ドメインと HTTPS を設定**します。
2. **デフォルトモデルを設定**し、**Project API key を発行**します。
3. ノード、E2B、または自分のマシンを**実行リソースとして追加**します。
4. OpenAI SDK で **[最初の Session を実行](https://openagentcore.dev/docs/getting-started/quickstart)** します。

[インストールガイド](https://openagentcore.dev/docs/getting-started/install)では、各手順に加え、HTTPS の設定とローカルで手軽に試す方法を説明しています。リッスンアドレスやポートなどの設定は、[インストールオプション](https://openagentcore.dev/docs/getting-started/install-options)をご覧ください。

## ドキュメント

| 目的 | 参照先 |
| --- | --- |
| インストールと運用 | [インストールガイド](https://openagentcore.dev/docs/getting-started/install)、続いて[運用ガイド](https://openagentcore.dev/docs/getting-started/operations) |
| API を使ったアプリケーション開発 | [クイックスタート](https://openagentcore.dev/docs/getting-started/quickstart)、続いて [Agents API ガイド](https://openagentcore.dev/docs/api/public-agent-api) |
| 完成したアプリケーションの確認 | [サンプル](https://openagentcore.dev/docs/examples) |
| 自分のマシンでエージェントを実行 | [セルフホスト実行](https://openagentcore.dev/docs/getting-started/self-hosted) |
| Harness の機能と制限の確認 | [Harness の機能](https://openagentcore.dev/contracts/agents-api/harness-capabilities) |
| 設計の理解 | [アーキテクチャガイド](https://openagentcore.dev/docs/architecture) |
| 新しいサンドボックス、Harness などのコンポーネントの追加 | [開発ガイド](https://openagentcore.dev/docs/development) |

すべてのドキュメントは[ドキュメント一覧](https://openagentcore.dev/docs/getting-started/)から参照できます。コードを変更する前に、[コントリビューションガイド](CONTRIBUTING.md)をお読みください。
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ An open-source, self-hosted implementation of the OpenAI Agents API with multipl

[Website](https://openagentcore.dev/) · [Install](#install) · [Call the API](https://openagentcore.dev/docs/getting-started/quickstart) · [Documentation](https://openagentcore.dev/docs/getting-started/) · [Contributing](CONTRIBUTING.md)

**English** · [简体中文](README.zh-CN.md)
**English** · [简体中文](README.zh-CN.md) · [日本語](README.ja.md)

</div>

Expand Down
2 changes: 1 addition & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ OpenAI Agents API 的开源实现,支持多种原生执行引擎,可部署

[官网](https://openagentcore.dev/zh/) · [安装](#安装) · [调用 API](https://openagentcore.dev/zh/docs/getting-started/quickstart) · [文档](https://openagentcore.dev/zh/docs/getting-started/) · [参与贡献](CONTRIBUTING.md)

[English](README.md) · **简体中文**
[English](README.md) · **简体中文** · [日本語](README.ja.md)

</div>

Expand Down
22 changes: 11 additions & 11 deletions apps/daemon/internal/agent/claudesdk/declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var Declaration = agent.Declaration{Info: proto.SupportedAgentKind{Kind: "claude
Streaming: proto.CapabilitySupported,
Usage: proto.CapabilitySupported,
Resume: proto.CapabilitySupported,
RetainedNativeHistory: proto.CapabilityUnsupported,
NativeSessionRecovery: proto.CapabilityUnsupported,
Steering: proto.CapabilitySupported,
MessageItems: proto.CapabilitySupported,
Expand Down Expand Up @@ -68,40 +69,38 @@ func discoverWithCheck(parent context.Context, options agent.DiscoveryOptions, d
if !filepath.IsAbs(entrypoint) {
return fail(fmt.Errorf("%s must be absolute", claudeSDKEntrypointEnv))
}
profileDir, err := paths.ProfileDir(options.Profile)
if err != nil {
if err := paths.ValidateProfile(options.Profile); err != nil {
return fail(err)
}
if !filepath.IsAbs(profileDir) {
return fail(fmt.Errorf("Claude SDK state requires an absolute OAC_RUNTIME_HOME"))
if !filepath.IsAbs(options.RuntimeRoot) || filepath.Clean(options.RuntimeRoot) != options.RuntimeRoot {
return fail(fmt.Errorf("Claude SDK requires an explicit Runtime root"))
}
node := os.Getenv(claudeSDKNodeEnv)
if node == "" {
node = "node"
}
node, err = exec.LookPath(node)
node, err := exec.LookPath(node)
if err != nil {
return fail(fmt.Errorf("Claude SDK Node executable is unavailable"))
}
node, err = filepath.Abs(node)
if err != nil {
return fail(err)
}
config = Config{Node: node, Entrypoint: entrypoint, StateDir: filepath.Join(profileDir, "runtime", "claude-sdk")}
if !filepath.IsAbs(options.StateRoot) || filepath.Clean(options.StateRoot) != options.StateRoot {
return fail(fmt.Errorf("Claude SDK requires an explicit state root"))
}
config = Config{Node: node, Entrypoint: entrypoint, StateDir: filepath.Join(options.StateRoot, "daemon", options.Profile, "runtime", "claude-sdk")}
binding, err := localworkspace.Load()
if err != nil {
return fail(err)
}
if binding != nil {
root, err := paths.Root()
if err != nil {
return fail(err)
}
config.Node, err = filepath.EvalSymlinks(node)
if err != nil {
return fail(err)
}
config, err = ConfigureLocal(config, root, os.Getenv("OAC_RUNTIME_WORKSPACE"), binding.NetworkPolicy())
config, err = ConfigureLocal(config, options.StateRoot, options.RuntimeRoot, os.Getenv("OAC_RUNTIME_WORKSPACE"), binding.NetworkPolicy())
if err != nil {
return fail(err)
}
Expand All @@ -118,6 +117,7 @@ func discoverWithCheck(parent context.Context, options agent.DiscoveryOptions, d
caps.EnvironmentNone, caps.FunctionTools = proto.CapabilityUnsupported, proto.CapabilityFromBool(info.SupportsWorkspaceFunctions())
caps.LocalEnvironment, caps.WorkspaceReadPreparation = proto.CapabilitySupported, proto.CapabilitySupported
caps.NativeSessionRecovery = proto.CapabilitySupported
caps.RetainedNativeHistory = proto.CapabilityFromBool(info.SDK == "0.3.269" && info.Native == "2.1.269 (Claude Code)")
}
out.Info.Available, out.Info.Version = true, info.SDK
out.Info.Capabilities.MessageImages = proto.CapabilityFromBool(info.SupportsMessageImages())
Expand Down
Loading
Loading