fix: 修复 typeshare 生成问题

This commit is contained in:
mofeng-git
2026-07-07 00:41:25 +08:00
parent 4806a5e0a9
commit a0ad151fbc
4 changed files with 148 additions and 55 deletions

View File

@@ -20,6 +20,9 @@ typeshare "$PROJECT_ROOT/src" \
--lang=typescript \
--output-file="$OUTPUT_FILE"
# Keep generated output stable for git diff --check.
perl -0pi -e 's/\n+\z/\n/' "$OUTPUT_FILE"
echo ""
echo "TypeScript types generated successfully!"
echo "Output: $OUTPUT_FILE"

View File

@@ -29,7 +29,8 @@ impl Default for ComputerUseButton {
}
}
#[typeshare]
// Kept out of typeshare because these internally tagged enums are consumed by
// manually maintained frontend types and changing serde shape would break WS/API.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ComputerUseAction {
@@ -89,7 +90,6 @@ pub struct ComputerUseScreenshot {
pub height: u32,
}
#[typeshare]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "role", rename_all = "snake_case")]
pub enum ComputerUseConversationMessage {
@@ -145,7 +145,6 @@ pub struct ComputerUseSessionSummary {
pub final_message: Option<String>,
}
#[typeshare]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ComputerUseWsClientMessage {
@@ -155,7 +154,6 @@ pub enum ComputerUseWsClientMessage {
},
}
#[typeshare]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ComputerUseWsServerMessage {
@@ -166,3 +164,43 @@ pub enum ComputerUseWsServerMessage {
ActionsExecuted { actions: Vec<ComputerUseAction> },
Error { message: String },
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn computer_use_action_keeps_flat_tagged_json_shape() {
let action = ComputerUseAction::Click {
x: 10,
y: 20,
button: ComputerUseButton::Left,
};
assert_eq!(
serde_json::to_value(action).unwrap(),
json!({
"type": "click",
"x": 10,
"y": 20,
"button": "left"
})
);
}
#[test]
fn computer_use_ws_message_keeps_flat_tagged_json_shape() {
let message = ComputerUseWsServerMessage::ScreenshotRequested {
request_id: "req-1".to_string(),
};
assert_eq!(
serde_json::to_value(message).unwrap(),
json!({
"type": "screenshot_requested",
"request_id": "req-1"
})
);
}
}

View File

@@ -1,5 +1,14 @@
import { request, ApiError } from './request'
import type { CanonicalKey, Ch9329DescriptorState } from '@/types/generated'
import type {
CanonicalKey,
Ch9329DescriptorState,
ComputerUseButton,
ComputerUseConfigResponse,
ComputerUseConfigUpdate,
ComputerUseSessionStatus,
ComputerUseSessionSummary,
ComputerUseStartRequest,
} from '@/types/generated'
import { useHidWebSocket, type HidKeyboardEvent, type HidMouseEvent } from '@/composables/useHidWebSocket'
const API_BASE = '/api'
@@ -457,16 +466,7 @@ export const hidApi = {
isWebSocketConnected: () => hidWs.connected.value,
}
export type ComputerUseStatus =
| 'idle'
| 'waiting_screenshot'
| 'thinking'
| 'executing'
| 'completed'
| 'failed'
| 'stopped'
export type ComputerUseButton = 'left' | 'middle' | 'right'
export type ComputerUseStatus = ComputerUseSessionStatus
export type ComputerUseAction =
| { type: 'click'; x: number; y: number; button?: ComputerUseButton }
@@ -479,49 +479,18 @@ export type ComputerUseAction =
| { type: 'wait'; ms: number }
| { type: 'screenshot' }
export interface ComputerUseScreenshot {
data_url: string
width: number
height: number
}
export type ComputerUseConversationMessage =
| { role: 'user'; text: string }
| { role: 'assistant'; text: string }
export interface ComputerUseConfig {
enabled: boolean
provider: string
base_url: string
model: string
max_steps: number
timeout_seconds: number
api_key_configured: boolean
api_key_source: string
}
export type ComputerUseConfig = ComputerUseConfigResponse
export interface ComputerUseSession {
id: string | null
status: ComputerUseStatus
prompt: string | null
step: number
max_steps: number
last_error: string | null
final_message: string | null
}
export type ComputerUseSession = ComputerUseSessionSummary
export const computerUseApi = {
config: () => request<ComputerUseConfig>('/config/computer-use'),
updateConfig: (data: {
enabled?: boolean
base_url?: string
model?: string
max_steps?: number
timeout_seconds?: number
openai_api_key?: string
clear_openai_api_key?: boolean
}) =>
updateConfig: (data: ComputerUseConfigUpdate) =>
request<ComputerUseConfig>('/config/computer-use', {
method: 'PATCH',
body: JSON.stringify(data),
@@ -529,7 +498,7 @@ export const computerUseApi = {
session: () => request<ComputerUseSession>('/computer-use/session'),
start: (data: { prompt: string; continue_conversation?: boolean; client_id: string; max_steps?: number; timeout_seconds?: number }) =>
start: (data: ComputerUseStartRequest) =>
request<ComputerUseSession>('/computer-use/session', {
method: 'POST',
body: JSON.stringify(data),
@@ -847,6 +816,13 @@ export type {
StreamMode,
EncoderType,
BitratePreset,
ComputerUseButton,
ComputerUseConfigResponse,
ComputerUseConfigUpdate,
ComputerUseScreenshot,
ComputerUseSessionStatus,
ComputerUseSessionSummary,
ComputerUseStartRequest,
} from '@/types/generated'
export const audioApi = {

View File

@@ -168,6 +168,15 @@ export interface WebConfig {
ssl_key_path?: string;
}
export interface ComputerUseConfig {
enabled: boolean;
provider: string;
base_url: string;
model: string;
max_steps: number;
timeout_seconds: number;
}
export interface TtydConfig {
enabled: boolean;
shell: string;
@@ -227,6 +236,11 @@ export interface ExtensionsConfig {
frpc: FrpcConfig;
}
export enum RustDeskCodec {
H264 = "h264",
H265 = "h265",
}
export interface RustDeskConfig {
enabled: boolean;
codec: RustDeskCodec;
@@ -235,11 +249,6 @@ export interface RustDeskConfig {
device_id: string;
}
export enum RustDeskCodec {
H264 = "h264",
H265 = "h265",
}
export enum VncEncoding {
TightJpeg = "tight_jpeg",
H264 = "h264",
@@ -283,6 +292,7 @@ export interface AppConfig {
audio: AudioConfig;
stream: StreamConfig;
web: WebConfig;
computer_use: ComputerUseConfig;
extensions: ExtensionsConfig;
rustdesk: RustDeskConfig;
vnc: VncConfig;
@@ -356,6 +366,66 @@ export interface Ch9329DescriptorState {
config_mode_available: boolean;
}
export interface ComputerUseConfigResponse {
enabled: boolean;
provider: string;
base_url: string;
model: string;
max_steps: number;
timeout_seconds: number;
api_key_configured: boolean;
api_key_source: string;
}
export interface ComputerUseConfigUpdate {
enabled?: boolean;
base_url?: string;
model?: string;
max_steps?: number;
timeout_seconds?: number;
openai_api_key?: string;
clear_openai_api_key?: boolean;
}
export interface ComputerUsePoint {
x: number;
y: number;
}
export interface ComputerUseScreenshot {
data_url: string;
width: number;
height: number;
}
export enum ComputerUseSessionStatus {
Idle = "idle",
WaitingScreenshot = "waiting_screenshot",
Thinking = "thinking",
Executing = "executing",
Completed = "completed",
Failed = "failed",
Stopped = "stopped",
}
export interface ComputerUseSessionSummary {
id?: string;
status: ComputerUseSessionStatus;
prompt?: string;
step: number;
max_steps: number;
last_error?: string;
final_message?: string;
}
export interface ComputerUseStartRequest {
prompt: string;
continue_conversation?: boolean;
client_id: string;
max_steps?: number;
timeout_seconds?: number;
}
export interface EasytierConfigUpdate {
enabled?: boolean;
network_name?: string;
@@ -738,3 +808,9 @@ export enum CanonicalKey {
AltRight = "AltRight",
MetaRight = "MetaRight",
}
export enum ComputerUseButton {
Left = "left",
Middle = "middle",
Right = "right",
}