release: v1.4.0

This commit is contained in:
coso
2026-04-06 22:50:50 +08:00
parent acc573818d
commit 7c06f84e16
467 changed files with 23371 additions and 15151 deletions
@@ -3,7 +3,7 @@
//! 负责在工作区内生成稳定路径、落盘 JSON 快照,并给前端 workbench
//! 提供可直接消费的 snapshot metadata。
use crate::commands::content_cmd::THEME_WORKBENCH_DOCUMENT_META_KEY;
use crate::commands::content_cmd::GENERAL_WORKBENCH_DOCUMENT_META_KEY;
use crate::content::{ContentManager, ContentUpdateRequest};
use crate::database::DbConnection;
use crate::services::artifact_document_validator::{
@@ -29,7 +29,7 @@ pub struct PersistedArtifactDocument {
pub absolute_path: PathBuf,
pub serialized_document: String,
pub snapshot_metadata: Map<String, Value>,
pub theme_workbench_document_state: Map<String, Value>,
pub general_workbench_document_state: Map<String, Value>,
pub content_body: String,
pub title: String,
pub kind: String,
@@ -274,8 +274,8 @@ pub fn persist_artifact_document_from_text(
&source_links,
version_diff.as_ref(),
);
let theme_workbench_document_state =
build_theme_workbench_document_state(&version_history, current_version.id.as_str());
let general_workbench_document_state =
build_general_workbench_document_state(&version_history, current_version.id.as_str());
let content_body = build_content_body_from_document(&enriched_document);
Ok(PersistedArtifactDocument {
@@ -286,7 +286,7 @@ pub fn persist_artifact_document_from_text(
absolute_path,
serialized_document,
snapshot_metadata,
theme_workbench_document_state,
general_workbench_document_state,
content_body,
title: outcome.title,
kind: outcome.kind,
@@ -423,7 +423,7 @@ fn resolve_topic_branch_status(status: &str) -> Option<&'static str> {
}
}
fn build_theme_workbench_document_state(
fn build_general_workbench_document_state(
version_history: &[ArtifactVersionSummary],
current_version_id: &str,
) -> Map<String, Value> {
@@ -628,8 +628,8 @@ pub fn sync_persisted_artifact_document_to_content(
}
}
next_metadata.insert(
THEME_WORKBENCH_DOCUMENT_META_KEY.to_string(),
Value::Object(persisted.theme_workbench_document_state.clone()),
GENERAL_WORKBENCH_DOCUMENT_META_KEY.to_string(),
Value::Object(persisted.general_workbench_document_state.clone()),
);
manager.update(
@@ -1426,7 +1426,7 @@ mod tests {
.contains("\"currentVersionDiff\""));
assert_eq!(
persisted_second
.theme_workbench_document_state
.general_workbench_document_state
.get("currentVersionId")
.and_then(Value::as_str),
Some("artifact-document:artifact:analysis:demo:v2")
@@ -1512,7 +1512,7 @@ mod tests {
let metadata = updated.metadata.expect("metadata should exist");
assert_eq!(
metadata
.get(THEME_WORKBENCH_DOCUMENT_META_KEY)
.get(GENERAL_WORKBENCH_DOCUMENT_META_KEY)
.and_then(Value::as_object)
.and_then(|value| value.get("currentVersionId"))
.and_then(Value::as_str),
@@ -5,6 +5,9 @@
use serde_json::{Map, Value};
const GENERAL_WORKBENCH_SESSION_MODE: &str = "general_workbench";
const LEGACY_GENERAL_WORKBENCH_SESSION_MODE_ALIAS: &str = "theme_workbench";
const ARTIFACT_MEANINGFUL_KEYS: &[&str] = &[
"artifact_mode",
"artifactMode",
@@ -31,6 +34,16 @@ fn normalize_text(value: Option<&str>) -> Option<String> {
.map(str::to_string)
}
fn normalize_session_mode_text(value: Option<&str>) -> Option<String> {
match normalize_text(value)?.as_str() {
GENERAL_WORKBENCH_SESSION_MODE | LEGACY_GENERAL_WORKBENCH_SESSION_MODE_ALIAS => {
Some(GENERAL_WORKBENCH_SESSION_MODE.to_string())
}
"default" => Some("default".to_string()),
_ => None,
}
}
fn root_object(request_metadata: Option<&Value>) -> Option<&Map<String, Value>> {
request_metadata?.as_object()
}
@@ -51,6 +64,40 @@ fn extract_harness_string(request_metadata: Option<&Value>, keys: &[&str]) -> Op
.and_then(|value| normalize_text(Some(value)))
}
fn extract_harness_session_mode(request_metadata: Option<&Value>) -> Option<String> {
normalize_session_mode_text(
extract_harness_string(request_metadata, &["session_mode", "sessionMode"]).as_deref(),
)
}
fn normalize_harness_session_mode_field(request_metadata: Value) -> Value {
let Some(normalized_session_mode) = extract_harness_session_mode(Some(&request_metadata))
else {
return request_metadata;
};
let mut request_metadata = request_metadata;
let Some(root) = request_metadata.as_object_mut() else {
return request_metadata;
};
if let Some(harness) = root.get_mut("harness").and_then(Value::as_object_mut) {
harness.insert(
"session_mode".to_string(),
Value::String(normalized_session_mode),
);
harness.remove("sessionMode");
return request_metadata;
}
root.insert(
"session_mode".to_string(),
Value::String(normalized_session_mode),
);
root.remove("sessionMode");
request_metadata
}
fn is_flat_artifact_metadata_key(key: &str) -> bool {
matches!(
key,
@@ -117,8 +164,8 @@ fn infer_source_policy(kind: Option<&str>) -> Option<&'static str> {
}
fn should_enable_artifact_draft(request_metadata: Option<&Value>) -> bool {
if extract_harness_string(request_metadata, &["session_mode", "sessionMode"]).as_deref()
!= Some("theme_workbench")
if extract_harness_session_mode(request_metadata).as_deref()
!= Some(GENERAL_WORKBENCH_SESSION_MODE)
{
return false;
}
@@ -183,6 +230,7 @@ pub fn normalize_request_metadata_with_artifact_defaults(
content_id_fallback: Option<&str>,
) -> Option<Value> {
let request_metadata = request_metadata?;
let request_metadata = normalize_harness_session_mode_field(request_metadata);
let request_metadata = backfill_harness_string_if_missing(
request_metadata,
&["theme", "harness_theme", "harnessTheme"],
@@ -294,11 +342,11 @@ mod tests {
use serde_json::json;
#[test]
fn should_infer_theme_workbench_artifact_defaults_from_harness() {
fn should_infer_general_workbench_artifact_defaults_from_harness() {
let metadata = json!({
"harness": {
"theme": "general",
"session_mode": "theme_workbench",
"session_mode": "general_workbench",
"content_id": "content-1"
}
});
@@ -356,7 +404,7 @@ mod tests {
let metadata = json!({
"harness": {
"theme": "general",
"session_mode": "theme_workbench",
"session_mode": "general_workbench",
"turn_purpose": "content_review",
"content_id": "content-1"
}
@@ -422,7 +470,7 @@ mod tests {
let metadata = json!({
"harness": {
"theme": "general",
"session_mode": "theme_workbench"
"session_mode": "general_workbench"
}
});
@@ -461,7 +509,7 @@ mod tests {
let normalized = normalize_request_metadata_with_artifact_defaults(
Some(metadata),
Some("general"),
Some("theme_workbench"),
Some("general_workbench"),
None,
None,
None,
@@ -476,7 +524,7 @@ mod tests {
normalized
.pointer("/harness/session_mode")
.and_then(Value::as_str),
Some("theme_workbench")
Some("general_workbench")
);
assert_eq!(
normalized
@@ -491,7 +539,7 @@ mod tests {
let metadata = json!({
"harness": {
"theme": "general",
"session_mode": "theme_workbench",
"session_mode": "general_workbench",
"content_id": "content-social-1"
}
});