feat: add Chinese UI, Responses models, and mirrored Windows setup
CI / Python 3.12 / ubuntu-latest (push) Canceled after 0s
CI / Python 3.12 / windows-latest (push) Canceled after 0s
CI / Frontend tests and production build (push) Canceled after 0s
CI / Build and smoke-test Python packages (push) Canceled after 0s

Localize the web console and persist custom model and capability settings.
Use OpenAI Responses exclusively and move runtime limits into environment configuration.
Bootstrap uv and the virtual environment on Windows, support optional China mirrors,
and package source distributions without environments, build output, or credentials.

Update regression tests and repository quality checks for the new behavior.
This commit is contained in:
chenmingxuan committed 2026-09-22 19:16:17 +08:00
1 parent 371aa6df56
commit 2ddec53954
183 files changed
+3427 -11857

No files matched your search

@@ -25,7 +25,7 @@ limitations under the License.
(click)="agentService.activeTab.set('tasks')"
>
<span class="material-symbols-outlined tab-icon">list_alt</span>
<span class="tab-text">Task Queue</span>
<span class="tab-text">任务队列</span>
</button>
<button
class="tab-selector-btn"
@@ -33,7 +33,7 @@ limitations under the License.
(click)="agentService.activeTab.set('notes')"
>
<span class="material-symbols-outlined tab-icon">description</span>
<span class="tab-text">Notes & Plans</span>
<span class="tab-text">笔记与计划</span>
</button>
</div>
@@ -42,8 +42,8 @@ limitations under the License.
<button
class="btn-clear-history"
(click)="clearHistory()"
title="Clear all tasks and history"
aria-label="Clear all tasks and history"
title="清空所有任务与历史"
aria-label="清空所有任务与历史"
[disabled]="isSubmitting()"
>
<span class="material-symbols-outlined">delete</span>
@@ -62,7 +62,8 @@ limitations under the License.
</div>
@if (activeQueue().length === 0) {
<div class="empty-section-placeholder">
No active or queued tasks.
没有正在执行或排队的任务。
</div>
}
@for (session of activeQueue(); track trackSession($index, session)) {
@@ -77,7 +78,7 @@ limitations under the License.
@if (getTaskStatus(session) === 'running') {
<span class="status-dot"></span>
}
{{ getTaskStatus(session) | uppercase }}
{{ getTaskStatus(session) | uiLabel }}
</span>
<div class="task-card-header-actions">
@if (getDeviceSerial(session)) {
@@ -95,8 +96,8 @@ limitations under the License.
type="button"
class="btn-stop-card"
(click)="stopTask(session.session_id, $event)"
title="Stop this task"
aria-label="Stop this task"
title="停止此任务"
aria-label="停止此任务"
>
<span class="material-symbols-outlined">stop_circle</span>
</button>
@@ -106,8 +107,8 @@ limitations under the License.
type="button"
class="btn-delete-card"
(click)="deleteTask(session.session_id, $event)"
title="Delete this task"
aria-label="Delete this task"
title="删除此任务"
aria-label="删除此任务"
[disabled]="isSubmitting()"
>
<span class="material-symbols-outlined">delete</span>
@@ -116,7 +117,7 @@ limitations under the License.
</div>
</div>
<div class="task-goal" title="{{ session.initial_goal }}">
{{ session.initial_goal || 'Unnamed Task' }}
{{ session.initial_goal || '未命名任务' }}
</div>
<div class="task-card-footer">
<span class="task-id" [title]="session.session_id">ID: {{ session.session_id }}</span>
@@ -132,7 +133,8 @@ limitations under the License.
<div class="history-list-wrapper">
@if (historyTasks().length === 0) {
<div class="empty-section-placeholder">
No past tasks.
暂无历史任务。
</div>
}
@for (session of historyTasks(); track trackSession($index, session)) {
@@ -147,7 +149,7 @@ limitations under the License.
@if (getTaskStatus(session) === 'running') {
<span class="status-dot"></span>
}
{{ getTaskStatus(session) | uppercase }}
{{ getTaskStatus(session) | uiLabel }}
</span>
<div class="task-card-header-actions">
@if (getDeviceSerial(session)) {
@@ -165,8 +167,8 @@ limitations under the License.
type="button"
class="btn-delete-card"
(click)="deleteTask(session.session_id, $event)"
title="Delete this task"
aria-label="Delete this task"
title="删除此任务"
aria-label="删除此任务"
[disabled]="isSubmitting()"
>
<span class="material-symbols-outlined">delete</span>
@@ -175,7 +177,7 @@ limitations under the License.
</div>
</div>
<div class="task-goal" title="{{ session.initial_goal }}">
{{ session.initial_goal || 'Unnamed Task' }}
{{ session.initial_goal || '未命名任务' }}
</div>
<div class="task-card-footer">
<span class="task-id" [title]="session.session_id">ID: {{ session.session_id }}</span>
@@ -212,8 +214,8 @@ limitations under the License.
<div class="empty-notes-icon">
<span class="material-symbols-outlined">description</span>
</div>
<h4 class="empty-notes-title">No Notes & Plans</h4>
<p class="empty-notes-subtitle">No notes or structured plans were recorded for this session.</p>
<h4 class="empty-notes-title">暂无笔记与计划</h4>
<p class="empty-notes-subtitle">此会话尚未记录笔记或结构化计划。</p>
</div>
}
<!-- Notes Content Viewer (Clean card blocks matching the second screenshot style) -->
@@ -377,4 +379,3 @@ limitations under the License.
}
</main>
</div>
@@ -1,3 +1,4 @@
import { UiLabelPipe } from '../../utils/ui-label.pipe';
/**
* Copyright 2026 Google LLC
*
@@ -27,7 +28,7 @@ export type { MarkdownSegment, MarkdownLine, NoteMilestone, ParsedNote };
@Component({
selector: 'app-chat-interface',
standalone: true,
imports: [CommonModule, FormsModule],
imports: [UiLabelPipe, CommonModule, FormsModule],
templateUrl: './chat-interface.component.html',
styleUrl: './chat-interface.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush
@@ -95,7 +96,7 @@ export class ChatInterfaceComponent {
error: (err) => {
console.error('Failed to submit task:', err);
this.isSubmitting.set(false);
this.errorMessage.set(err.error?.detail || 'The runner is busy. Please wait for the current task to finish.');
this.errorMessage.set(err.error?.detail || "执行器忙碌,请等待当前任务结束。");
// Auto-dismiss error banner after 5 seconds
setTimeout(() => {
this.errorMessage.set(null);
@@ -133,7 +134,7 @@ export class ChatInterfaceComponent {
* Clear all database data/history to start fresh
*/
public clearHistory(): void {
if (!confirm('Are you sure you want to clear all tasks and history? This cannot be undone.')) {
if (!confirm("确定清空所有任务和历史记录?此操作无法撤销。")) {
return;
}
this.isSubmitting.set(true);
@@ -145,7 +146,7 @@ export class ChatInterfaceComponent {
error: (err: any) => {
console.error('Failed to clear history:', err);
this.isSubmitting.set(false);
this.errorMessage.set(err.error?.detail || 'Failed to clear history.');
this.errorMessage.set(err.error?.detail || "清空历史记录失败。");
}
});
}
@@ -155,7 +156,7 @@ export class ChatInterfaceComponent {
*/
public deleteTask(sessionId: string, event: MouseEvent): void {
event.stopPropagation();
if (!confirm(`Are you sure you want to delete this task? This cannot be undone.`)) {
if (!confirm("确定删除此任务?此操作无法撤销。")) {
return;
}
this.isSubmitting.set(true);
@@ -165,9 +166,9 @@ export class ChatInterfaceComponent {
this.isSubmitting.set(false);
},
error: (err: any) => {
console.error(`Failed to delete task ${sessionId}:`, err);
console.error(`删除任务失败:${sessionId}:`, err);
this.isSubmitting.set(false);
this.errorMessage.set(err.error?.detail || 'Failed to delete task.');
this.errorMessage.set(err.error?.detail || "删除任务失败。");
}
});
}