feat(chat): make Pi classroom runtime the default (#1628)

* feat(chat): make Pi classroom runtime the default

* chore(chat): align docs and E2E with Pi default
This commit is contained in:
LING DUAN
2026-09-22 11:41:13 +08:00
committed by GitHub
parent df16d7e322
commit 2a77a8a476
14 changed files with 73 additions and 37 deletions
+4 -3
View File
@@ -322,7 +322,7 @@ WEB_SEARCH_CLAUDE_MODELS=
# Server-only, default-OFF Native Spotlight capability; does not select the runtime.
# OPENMAIC_ENABLE_PI_NATIVE_CHILD_SPOTLIGHT=true
# --- Experimental Features ---------------------------------------------------
# --- Feature Flags -----------------------------------------------------------
# Boolean feature flags accept "true" or "1". NEXT_PUBLIC_* values are compiled
# into the browser bundle at build time, so changing them requires a rebuild.
@@ -343,8 +343,9 @@ WEB_SEARCH_CLAUDE_MODELS=
# Use @openmaic/renderer for the classroom playback canvas.
# NEXT_PUBLIC_MAIC_PLAYBACK_RENDERER_ENABLED=true
# Use the experimental Pi-based classroom chat runtime. Disabled by default.
# NEXT_PUBLIC_PI_CHAT_ENABLED=true
# Pi-based classroom chat is enabled by default. Set this build-time flag to
# false or 0 to roll back to the legacy classroom chat runtime.
# NEXT_PUBLIC_PI_CHAT_ENABLED=false
# Enable the unified PPT/Interactive courseware-reference entry in Pi playback.
# Pi chat and editor element references remain independent from this default-off build-time gate.
+1 -1
View File
@@ -339,11 +339,11 @@ jobs:
# Dedicated so a cold `next build` is not charged against Playwright's
# webServer readiness budget (120s). NEXT_PUBLIC_MAIC_EDITOR_ENABLED is a
# build-time flag and must be set here, not only on `pnpm start`.
# Leave NEXT_PUBLIC_PI_CHAT_ENABLED unset so E2E covers the shipped default.
- name: Build
run: pnpm build
env:
NEXT_PUBLIC_MAIC_EDITOR_ENABLED: 'true'
NEXT_PUBLIC_PI_CHAT_ENABLED: 'true'
NEXT_PUBLIC_COURSEWARE_REFERENCE_ENABLED: 'true'
- name: Run e2e tests
+3 -2
View File
@@ -2,8 +2,9 @@ import { attachInteractiveState } from '@/lib/chat/pi/interactive-state-evidence
/**
* Pi Director Chat API Endpoint
*
* POST /api/chat/pi - parallel PoC path for running the in-class multi-agent
* chain as a single server-side pi agent loop.
* POST /api/chat/pi - default path for running the in-class multi-agent chain
* as a single server-side Pi agent loop. The build-time flag can disable this
* route together with the corresponding client path for legacy rollback.
*/
import { NextRequest } from 'next/server';
+3 -3
View File
@@ -5,9 +5,9 @@ services:
args:
- ALPINE_MIRROR=${ALPINE_MIRROR:-}
- NPM_REGISTRY=${NPM_REGISTRY:-}
# NEXT_PUBLIC_* values are compiled into the browser bundle. Leave them
# empty unless the corresponding client feature is explicitly enabled;
# persistence and other build-time flags can be supplied on the command line.
# NEXT_PUBLIC_* values are compiled into the browser bundle. Empty values
# follow each feature's documented default; explicit build-time overrides
# can be supplied on the command line.
- ALLOWED_FRAME_ANCESTORS=${ALLOWED_FRAME_ANCESTORS:-}
- NEXT_PUBLIC_PERSISTENCE=${NEXT_PUBLIC_PERSISTENCE:-}
- NEXT_PUBLIC_PERSISTENCE_TOKEN=${NEXT_PUBLIC_PERSISTENCE_TOKEN:-}
+10 -5
View File
@@ -3,14 +3,18 @@
* Next.js inlines at build time so they are safe to read from client
* components. Server-only flags must not use the `NEXT_PUBLIC_` prefix.
*
* Truthy values: `'true'` or `'1'`. Anything else (including unset) is
* treated as disabled.
* Truthy values: `'true'` or `'1'`. Unless a flag documents a different
* default, anything else (including unset) is treated as disabled.
*/
function readBoolean(envValue: string | undefined): boolean {
return envValue === 'true' || envValue === '1';
}
function readDefaultOnBoolean(envValue: string | undefined): boolean {
return envValue === undefined || envValue === '' || readBoolean(envValue);
}
/**
* Server-only gate for durable background agent execution. This is evaluated
* at process runtime and is never exposed to the browser bundle.
@@ -83,11 +87,12 @@ export function isEditorRendererEnabled(): boolean {
}
/**
* Experimental Pi-based classroom chat runtime. Default OFF. The same public
* flag selects the client runtime and gates the corresponding server route.
* Pi-based classroom chat runtime. Default ON. The same public flag selects
* the client runtime and gates the corresponding server route. Operators can
* set it to `false` or `0` to roll back to the legacy classroom chat runtime.
*/
export function isPiChatEnabled(): boolean {
return readBoolean(process.env.NEXT_PUBLIC_PI_CHAT_ENABLED);
return readDefaultOnBoolean(process.env.NEXT_PUBLIC_PI_CHAT_ENABLED);
}
/**
@@ -210,14 +210,14 @@ DEFAULT_MODEL=openai:gpt-5.5
## feature flags (مفاتيح الميزات)
تُعتبر القيم `true` أو `1` مفعلة، وأي قيمة أخرى معطلة. تُحقن متغيرات `NEXT_PUBLIC_*` في وقت البناء للعميل، ويجب إعادة البناء بعد تعديلها:
تُعتبر القيم `true` أو `1` مفعلة، وما لم يُذكر خلاف ذلك تُعد أي قيمة أخرى معطلة. تُحقن متغيرات `NEXT_PUBLIC_*` في وقت البناء للعميل، ويجب إعادة البناء بعد تعديلها:
```bash
# محرر MAIC (وضع Pro)
NEXT_PUBLIC_MAIC_EDITOR_ENABLED=true
# وقت تشغيل محادثة Pi
NEXT_PUBLIC_PI_CHAT_ENABLED=true
# محادثة Pi مفعلة افتراضيًا؛ أزل التعليق عن السطر التالي للعودة إلى المسار القديم
# NEXT_PUBLIC_PI_CHAT_ENABLED=false
# مراجع مواد PPT والمشاهد التفاعلية أثناء تشغيل Pi (علامة وقت البناء؛ لا تؤثر في مراجع وضع التحرير)
NEXT_PUBLIC_COURSEWARE_REFERENCE_ENABLED=true
@@ -235,6 +235,8 @@ NEXT_PUBLIC_ENABLE_VIDEO_EXPORT=true
NEXT_PUBLIC_ENABLE_PPTX_IMPORT=true
```
تعتمد محادثة Pi على دعم النموذج لاستدعاء الأدوات/الدوال. إذا كان النموذج أو الموفر المحدد لا يدعم استدعاء الأدوات، فاضبط `NEXT_PUBLIC_PI_CHAT_ENABLED=false` (أو `0`) وأعد البناء لاستخدام مسار المحادثة القديم.
استيراد PPTX لا يزال تجريبيًا، والنتائج لم تُدمج بالكامل في تدفق بيانات الصف. جميع متغيرات `NEXT_PUBLIC_*` هي مفاتيح بناء؛ عند نشر Docker، يجب تمريرها كـ build args، لا يمكن فقط تعيينها في بيئة الحاوية.
## خيارات خادم أخرى
@@ -210,14 +210,14 @@ DEFAULT_MODEL=openai:gpt-5.5
## 機能フラグ
機能フラグは `true` または `1` を有効とし、それ以外は無効です。`NEXT_PUBLIC_*` はビルド時にクライアントに注入されるため、変更後は再ビルドが必要です。
機能フラグは `true` または `1` を有効とし、特記がない限りそれ以外は無効です。`NEXT_PUBLIC_*` はビルド時にクライアントに注入されるため、変更後は再ビルドが必要です。
```bash
# MAIC Editor(Pro モード)
NEXT_PUBLIC_MAIC_EDITOR_ENABLED=true
# Pi 対話ランタイム
NEXT_PUBLIC_PI_CHAT_ENABLED=true
# Pi 対話ランタイムはデフォルトで有効。従来経路へ戻す場合は次の行のコメントを解除
# NEXT_PUBLIC_PI_CHAT_ENABLED=false
# Pi 再生時の PPT・インタラクティブ教材参照(ビルド時フラグ。編集モードの参照には影響しません)
NEXT_PUBLIC_COURSEWARE_REFERENCE_ENABLED=true
@@ -235,6 +235,8 @@ NEXT_PUBLIC_ENABLE_VIDEO_EXPORT=true
NEXT_PUBLIC_ENABLE_PPTX_IMPORT=true
```
Pi 対話ランタイムではモデルのツール/関数呼び出し機能が必要です。選択したモデルまたは provider がツール呼び出しに対応していない場合は、`NEXT_PUBLIC_PI_CHAT_ENABLED=false`(または `0`)を設定して再ビルドし、従来の対話経路を使用してください。
PPTX インポートはまだ実験的で、解析結果は完全に授業データフローに統合されていません。`NEXT_PUBLIC_*` 変数はビルド時スイッチで、Docker では build args で渡す必要があり、コンテナ実行時環境変数だけでは反映されません。
## その他サーバーオプション
+5 -3
View File
@@ -210,14 +210,14 @@ Use `MODEL_ROUTES` to choose models for individual generation stages. Unconfigur
## Feature flags
Feature flags accept `true` or `1`; all other values are treated as disabled. `NEXT_PUBLIC_*` flags are injected into the client at build time, so changing them requires a rebuild:
Feature flags accept `true` or `1`; unless noted otherwise, all other values are treated as disabled. `NEXT_PUBLIC_*` flags are injected into the client at build time, so changing them requires a rebuild:
```bash
# MAIC Editor (Pro mode)
NEXT_PUBLIC_MAIC_EDITOR_ENABLED=true
# Pi chat runtime
NEXT_PUBLIC_PI_CHAT_ENABLED=true
# Pi chat is enabled by default; uncomment the next line for legacy rollback
# NEXT_PUBLIC_PI_CHAT_ENABLED=false
# PPT and Interactive courseware references in Pi playback (build-time; editor references are separate)
NEXT_PUBLIC_COURSEWARE_REFERENCE_ENABLED=true
@@ -235,6 +235,8 @@ NEXT_PUBLIC_ENABLE_VIDEO_EXPORT=true
NEXT_PUBLIC_ENABLE_PPTX_IMPORT=true
```
Pi chat requires model tool/function calling. If the selected model or provider does not support tool calls, set `NEXT_PUBLIC_PI_CHAT_ENABLED=false` (or `0`) and rebuild to use the legacy chat path.
PPTX import is still experimental, and its parsed output is not yet fully integrated into the classroom data flow. All `NEXT_PUBLIC_*` variables above are build-time flags. Docker deployments must also pass them as build args; setting them only as container runtime environment variables is not sufficient.
## Other server options
@@ -210,14 +210,14 @@ DEFAULT_MODEL=openai:gpt-5.5
## Feature flags
Значения `true` или `1` включают функцию, остальные — выключают. Переменные `NEXT_PUBLIC_*` внедряются в клиент при сборке, для их изменения нужна пересборка:
Значения `true` или `1` включают функцию; если не указано иное, остальные значения выключают её. Переменные `NEXT_PUBLIC_*` внедряются в клиент при сборке, для их изменения нужна пересборка:
```bash
# MAIC Editor (Pro режим)
NEXT_PUBLIC_MAIC_EDITOR_ENABLED=true
# Pi runtime диалог
NEXT_PUBLIC_PI_CHAT_ENABLED=true
# Pi runtime включён по умолчанию; раскомментируйте следующую строку для возврата к прежнему пути
# NEXT_PUBLIC_PI_CHAT_ENABLED=false
# Ссылки на материалы PPT и интерактивных сцен в режиме Pi (флаг времени сборки; режим редактирования не затрагивается)
NEXT_PUBLIC_COURSEWARE_REFERENCE_ENABLED=true
@@ -235,6 +235,8 @@ NEXT_PUBLIC_ENABLE_VIDEO_EXPORT=true
NEXT_PUBLIC_ENABLE_PPTX_IMPORT=true
```
Pi runtime требует поддержки вызова инструментов/функций моделью. Если выбранная модель или провайдер не поддерживает вызов инструментов, установите `NEXT_PUBLIC_PI_CHAT_ENABLED=false` (или `0`) и пересоберите приложение, чтобы использовать прежний путь чата.
Импорт PPTX пока экспериментален, результаты парсинга не интегрированы полностью в поток данных классов. Все `NEXT_PUBLIC_*` — флаги сборки, в Docker их нужно передавать как build args, нельзя просто задавать в runtime env vars.
## Другие серверные опции
@@ -210,14 +210,14 @@ DEFAULT_MODEL=openai:gpt-5.5
## 功能开关
功能开关的值为 `true` 或 `1`,其他值视为关闭。`NEXT_PUBLIC_*` 开关会在构建时注入客户端,修改后需要重新构建:
功能开关的值为 `true` 或 `1`;除非另有说明,其他值视为关闭。`NEXT_PUBLIC_*` 开关会在构建时注入客户端,修改后需要重新构建:
```bash
# MAIC Editor(Pro 模式)
NEXT_PUBLIC_MAIC_EDITOR_ENABLED=true
# Pi 对话运行时
NEXT_PUBLIC_PI_CHAT_ENABLED=true
# Pi 对话运行时默认开启;取消下一行的注释可回滚到旧版链路
# NEXT_PUBLIC_PI_CHAT_ENABLED=false
# Pi 播放态中的 PPT 与互动页课件引用(构建时开关;不影响编辑态引用)
NEXT_PUBLIC_COURSEWARE_REFERENCE_ENABLED=true
@@ -235,6 +235,8 @@ NEXT_PUBLIC_ENABLE_VIDEO_EXPORT=true
NEXT_PUBLIC_ENABLE_PPTX_IMPORT=true
```
Pi 对话运行时依赖模型的工具/函数调用能力。如果所选模型或 provider 不支持工具调用,请设置 `NEXT_PUBLIC_PI_CHAT_ENABLED=false`(或 `0`)并重新构建,以使用旧版对话链路。
PPTX 导入目前仍是实验性入口,解析结果尚未完整接入课堂数据流。以上 `NEXT_PUBLIC_*` 变量都是构建时开关;Docker 部署还需要通过 build args 传入,不能只写在容器运行时环境变量中。
## 其他服务端选项
@@ -210,14 +210,14 @@ DEFAULT_MODEL=openai:gpt-5.5
## 功能開關
功能開關的值可設為 `true` 或 `1`,其他值都視為關閉。`NEXT_PUBLIC_*` 開關會在建置時編譯至用戶端,修改後需要重新建置:
功能開關的值可設為 `true` 或 `1`;除非另有說明,其他值都視為關閉。`NEXT_PUBLIC_*` 開關會在建置時編譯至用戶端,修改後需要重新建置:
```bash
# MAIC Editor(Pro 模式)
NEXT_PUBLIC_MAIC_EDITOR_ENABLED=true
# Pi 對話執行時
NEXT_PUBLIC_PI_CHAT_ENABLED=true
# Pi 對話執行時預設開啟;取消下一行的註解可回復舊版鏈路
# NEXT_PUBLIC_PI_CHAT_ENABLED=false
# Pi 播放態中的 PPT 與互動頁課件引用(建置時開關;不影響編輯態引用)
NEXT_PUBLIC_COURSEWARE_REFERENCE_ENABLED=true
@@ -235,6 +235,8 @@ NEXT_PUBLIC_ENABLE_VIDEO_EXPORT=true
NEXT_PUBLIC_ENABLE_PPTX_IMPORT=true
```
Pi 對話執行時依賴模型的工具/函式呼叫能力。如果所選模型或 provider 不支援工具呼叫,請設定 `NEXT_PUBLIC_PI_CHAT_ENABLED=false`(或 `0`)並重新建置,以使用舊版對話鏈路。
PPTX 匯入目前仍是實驗性入口,解析結果尚未完整整合至課堂資料流。以上 `NEXT_PUBLIC_*` 變數都是建置時開關;Docker 部署還需要透過 build args 傳入,不能只寫在容器執行時環境變數中。
## 其他伺服器端選項
+1 -1
View File
@@ -35,7 +35,7 @@ export default defineConfig({
env: {
PORT: '3002',
NEXT_PUBLIC_MAIC_EDITOR_ENABLED: 'true',
NEXT_PUBLIC_PI_CHAT_ENABLED: 'true',
// Leave Pi chat unset so the browser suite exercises the shipped default.
NEXT_PUBLIC_COURSEWARE_REFERENCE_ENABLED: 'true',
},
},
+9 -3
View File
@@ -210,9 +210,12 @@ describe('isPiChatEnabled', () => {
}
});
it('defaults off when unset', () => {
it('defaults on when unset or empty', () => {
delete process.env[flag];
expect(isPiChatEnabled()).toBe(false);
expect(isPiChatEnabled()).toBe(true);
process.env[flag] = '';
expect(isPiChatEnabled()).toBe(true);
});
it("returns true for 'true' and '1'", () => {
@@ -223,10 +226,13 @@ describe('isPiChatEnabled', () => {
expect(isPiChatEnabled()).toBe(true);
});
it('returns false for other values', () => {
it("returns false for 'false', '0', and other values", () => {
process.env[flag] = 'false';
expect(isPiChatEnabled()).toBe(false);
process.env[flag] = '0';
expect(isPiChatEnabled()).toBe(false);
process.env[flag] = 'yes';
expect(isPiChatEnabled()).toBe(false);
});
+12 -1
View File
@@ -124,11 +124,22 @@ describe('POST /api/chat/pi model and thinking resolution', () => {
}
});
it('returns 404 without invoking the runtime when the feature flag is disabled', async () => {
it('uses the Pi route when the feature flag is unset', async () => {
delete process.env[PI_CHAT_FLAG];
const { POST } = await import('@/app/api/chat/pi/route');
const response = await POST(makeRequest(makeBody()));
expect(response.status).toBe(200);
await response.text();
expect(mocks.resolveModel).toHaveBeenCalledOnce();
expect(mocks.runPiDirectorLoop).toHaveBeenCalledOnce();
});
it('returns 404 without invoking the runtime when legacy rollback is explicit', async () => {
process.env[PI_CHAT_FLAG] = 'false';
const { POST } = await import('@/app/api/chat/pi/route');
const response = await POST(makeRequest(makeBody()));
expect(response.status).toBe(404);
await expect(response.json()).resolves.toMatchObject({
success: false,