合并 master 并保留外部生成 worker 模式

合入 master 的拼消消、微信能力、OpenSSL 3.2 和 SpacetimeDB 2.4.1 更新
保留外部内容生成 queue/inline、worker lease 与动态扩缩容口径
补齐拼图后台图片生成队列轮询和运行态返回恢复
同步容器、生产运维和 Hermes 共享记忆中的 worker 文档
This commit is contained in:
2026-06-09 16:55:32 +08:00
497 changed files with 66318 additions and 13329 deletions

View File

@@ -1,4 +1,4 @@
use std::{
use std::{
collections::BTreeMap,
time::{Instant, SystemTime, UNIX_EPOCH},
};
@@ -22,7 +22,7 @@ use module_puzzle::{PuzzleGeneratedImageCandidate, PuzzleRuntimeLevelStatus};
use platform_llm::{LlmMessage, LlmMessageContentPart, LlmTextRequest};
use platform_oss::{LegacyAssetPrefix, OssSignedGetObjectUrlRequest};
use platform_oss::{OssHeadObjectRequest, OssObjectAccess, OssPutObjectRequest};
use serde_json::{Map, Value, json};
use serde_json::{Value, json};
use shared_contracts::{
creation_audio::CreationAudioAsset,
puzzle_agent::{
@@ -57,7 +57,7 @@ use spacetime_client::{
PuzzleAgentSessionRecord, PuzzleAgentSuggestedActionRecord, PuzzleAnchorItemRecord,
PuzzleAnchorPackRecord, PuzzleAudioAssetRecord, PuzzleCreatorIntentRecord,
PuzzleDraftCompileFailureRecordInput, PuzzleDraftLevelRecord, PuzzleFormDraftRecord,
PuzzleFormDraftSaveRecordInput, PuzzleGalleryCardRecord, PuzzleGeneratedImageCandidateRecord,
PuzzleFormDraftSaveRecordInput, PuzzleGeneratedImageCandidateRecord,
PuzzleGeneratedImagesSaveRecordInput, PuzzleLeaderboardEntryRecord,
PuzzleLeaderboardSubmitRecordInput, PuzzleLevelGenerationFailureRecordInput,
PuzzlePublishRecordInput, PuzzleRecommendedNextWorkRecord, PuzzleResultDraftRecord,
@@ -109,6 +109,10 @@ use crate::{
puzzle_gallery_cache::{build_puzzle_gallery_window_response, puzzle_gallery_cached_json},
request_context::RequestContext,
state::{AppState, PuzzleApiState},
wechat::subscribe_message::{
GenerationResultSubscribeMessage, GenerationResultSubscribeMessageStatus,
send_generation_result_subscribe_message_after_completion,
},
work_author::resolve_puzzle_work_author_by_user_id,
work_play_tracking::{WorkPlayTrackingDraft, record_puzzle_work_play_start_after_success},
};
@@ -134,6 +138,36 @@ const PUZZLE_UI_BACKGROUND_PROMPT_FALLBACK_MARKER: &str =
const PUZZLE_VECTOR_ENGINE_SQUARE_IMAGE_SIZE: &str = "1024x1024";
const PUZZLE_VECTOR_ENGINE_PORTRAIT_IMAGE_SIZE: &str = "1024x1536";
fn has_puzzle_cover_image_src(value: &Option<String>) -> bool {
value
.as_deref()
.map(str::trim)
.is_some_and(|value| !value.is_empty())
}
fn mark_puzzle_initial_generation_started_snapshot(
mut session: PuzzleAgentSessionRecord,
) -> PuzzleAgentSessionRecord {
session.stage = "image_refining".to_string();
session.progress_percent = session.progress_percent.max(88);
if let Some(draft) = session.draft.as_mut() {
let draft_needs_cover = !has_puzzle_cover_image_src(&draft.cover_image_src);
if let Some(primary_level) = draft.levels.first_mut() {
if !has_puzzle_cover_image_src(&primary_level.cover_image_src) {
primary_level.generation_status = "generating".to_string();
}
draft.generation_status = primary_level.generation_status.clone();
draft.candidates = primary_level.candidates.clone();
draft.selected_candidate_id = primary_level.selected_candidate_id.clone();
draft.cover_image_src = primary_level.cover_image_src.clone();
draft.cover_asset_id = primary_level.cover_asset_id.clone();
} else if draft_needs_cover {
draft.generation_status = "generating".to_string();
}
}
session
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct ExternalGenerationWriteLeaseGuard {
pub(crate) job_id: Option<String>,