新增外部生成任务结果查询
新增仅返回任务结果的 SpacetimeDB procedure 编辑器 Agent 回填改用结果查询接口 补齐客户端绑定与接口文档
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
- `acknowledge_external_generation_jobs_and_return`:按当前账号确认已终态任务的完成 / 失败提示,写入 `notification_acknowledged_at` 并追加审计事件。
|
||||
- `get_external_generation_queue_stats_and_return`:controller 读取队列积压、运行中任务和过期 lease 数量,用于计算 worker 目标实例数;该 procedure 只读 `external_generation_job`,不直接操作 systemd。
|
||||
- `get_external_generation_job_and_return`:按 `job_id` 读取单个任务状态,给 BFF 和生成页展示使用;必须只返回调用者有权读取的任务,不能暴露其它用户的 payload、错误详情或 worker 内部字段。
|
||||
- `get_external_generation_job_result_and_return`:仅供后端内部回填异步编辑器 Agent 工具调用;按 `job_id + owner_user_id` 返回 `status`、`last_error_message` 和已持久化的 `result_payload_json`,不返回请求 payload、lease 或其它 worker 字段。该 procedure 不替代上述状态读取接口,也不经 BFF 暴露给前端。
|
||||
|
||||
这个 Module 的 **Seam** 在 SpacetimeDB procedure + `spacetime-client` facade;`api-server` HTTP role 和 worker role 都只依赖这个 Interface。外部 provider、OSS、计费补偿、玩法草稿回写仍留在 `api-server` worker implementation 内,不进入 SpacetimeDB reducer。
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
use crate::editor_agent::resp_to_asset;
|
||||
use crate::http_error::AppError;
|
||||
use crate::state::AppState;
|
||||
use module_editor_agent::agent::tools::context::EditorToolContext;
|
||||
use module_editor_agent::agent::tools::edit_image::{
|
||||
EditImageTool, EditImageToolArgs, EditorImageEditResult,
|
||||
@@ -17,9 +20,6 @@ use module_editor_agent::agent::tools::generate_sound_effect::{
|
||||
};
|
||||
use module_editor_agent::agent::tools::generate_ui_design::GenerateUiDesignTool;
|
||||
use module_editor_agent::agent::tools::generate_video::{GenerateVideoTool, GenerateVideoToolArgs};
|
||||
use crate::editor_agent::resp_to_asset;
|
||||
use crate::http_error::AppError;
|
||||
use crate::state::AppState;
|
||||
use module_editor_agent::framework::tool::Tool;
|
||||
use serde_json::Value;
|
||||
use shared_contracts::assets::{EditorAudioGenerateResponse, EditorVideoGenerateResponse};
|
||||
@@ -50,7 +50,7 @@ pub async fn reconcile_editor_agent_tool_calls(
|
||||
for (message_index, job_id) in candidates {
|
||||
let job = match state
|
||||
.spacetime_client()
|
||||
.get_external_generation_job(ExternalGenerationJobGetRecordInput {
|
||||
.get_external_generation_job_result(ExternalGenerationJobGetRecordInput {
|
||||
job_id,
|
||||
owner_user_id: conversation.owner_user_id.clone(),
|
||||
})
|
||||
|
||||
@@ -307,6 +307,31 @@ impl SpacetimeClient {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_external_generation_job_result(
|
||||
&self,
|
||||
input: ExternalGenerationJobGetRecordInput,
|
||||
) -> Result<ExternalGenerationJobResultRecord, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"get_external_generation_job_result_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.get_external_generation_job_result_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(map_external_generation_job_result_procedure_result);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_external_generation_job_summary(
|
||||
&self,
|
||||
input: ExternalGenerationJobGetRecordInput,
|
||||
|
||||
@@ -58,6 +58,7 @@ pub use mapper::{
|
||||
ExternalGenerationJobEnqueueRecordInput, ExternalGenerationJobFailRecordInput,
|
||||
ExternalGenerationJobGetRecordInput, ExternalGenerationJobListRecord,
|
||||
ExternalGenerationJobListRecordInput, ExternalGenerationJobRecord,
|
||||
ExternalGenerationJobResultRecord,
|
||||
ExternalGenerationJobRenewLeaseRecordInput, ExternalGenerationJobSummaryListRecord,
|
||||
ExternalGenerationJobSummaryRecord, ExternalGenerationQueueStatsRecord,
|
||||
FeatureGateConfigRecord, JumpHopActionRequest, JumpHopActionResponse, JumpHopActionType,
|
||||
|
||||
@@ -111,7 +111,8 @@ pub use self::external_generation::{
|
||||
ExternalGenerationJobCompleteRecordInput, ExternalGenerationJobEnqueueRecordInput,
|
||||
ExternalGenerationJobFailRecordInput, ExternalGenerationJobGetRecordInput,
|
||||
ExternalGenerationJobListRecord, ExternalGenerationJobListRecordInput,
|
||||
ExternalGenerationJobRecord, ExternalGenerationJobRenewLeaseRecordInput,
|
||||
ExternalGenerationJobRecord, ExternalGenerationJobResultRecord,
|
||||
ExternalGenerationJobRenewLeaseRecordInput,
|
||||
ExternalGenerationJobSummaryListRecord, ExternalGenerationJobSummaryRecord,
|
||||
ExternalGenerationQueueStatsRecord,
|
||||
};
|
||||
@@ -255,7 +256,9 @@ pub(crate) use self::external_api_key::{
|
||||
};
|
||||
pub(crate) use self::external_generation::{
|
||||
map_external_generation_job_claim_result, map_external_generation_job_list_result,
|
||||
map_external_generation_job_procedure_result, map_external_generation_job_summary_list_result,
|
||||
map_external_generation_job_procedure_result,
|
||||
map_external_generation_job_result_procedure_result,
|
||||
map_external_generation_job_summary_list_result,
|
||||
map_external_generation_job_summary_procedure_result,
|
||||
map_external_generation_queue_stats_result,
|
||||
};
|
||||
|
||||
@@ -112,6 +112,24 @@ pub(crate) fn map_external_generation_job_procedure_result(
|
||||
Ok(map_external_generation_job_snapshot(job))
|
||||
}
|
||||
|
||||
pub(crate) fn map_external_generation_job_result_procedure_result(
|
||||
result: ExternalGenerationJobResultProcedureResult,
|
||||
) -> Result<ExternalGenerationJobResultRecord, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
let result = result.result.ok_or_else(|| {
|
||||
SpacetimeClientError::missing_snapshot("external_generation_job 结果快照")
|
||||
})?;
|
||||
Ok(ExternalGenerationJobResultRecord {
|
||||
job_id: result.job_id,
|
||||
status: result.status,
|
||||
last_error_message: result.last_error_message,
|
||||
result_payload_json: result.result_payload_json,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn map_external_generation_job_claim_result(
|
||||
result: ExternalGenerationJobProcedureResult,
|
||||
) -> Result<Vec<ExternalGenerationJobRecord>, SpacetimeClientError> {
|
||||
@@ -372,6 +390,14 @@ pub struct ExternalGenerationJobRecord {
|
||||
pub notification_acknowledged_at_micros: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ExternalGenerationJobResultRecord {
|
||||
pub job_id: String,
|
||||
pub status: String,
|
||||
pub last_error_message: Option<String>,
|
||||
pub result_payload_json: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ExternalGenerationJobListRecord {
|
||||
pub jobs: Vec<ExternalGenerationJobRecord>,
|
||||
|
||||
@@ -503,8 +503,10 @@ pub mod external_generation_job_list_input_type;
|
||||
pub mod external_generation_job_payload_compaction_input_type;
|
||||
pub mod external_generation_job_payload_compaction_procedure_result_type;
|
||||
pub mod external_generation_job_procedure_result_type;
|
||||
pub mod external_generation_job_result_procedure_result_type;
|
||||
pub mod external_generation_job_renew_lease_input_type;
|
||||
pub mod external_generation_job_snapshot_type;
|
||||
pub mod external_generation_job_result_snapshot_type;
|
||||
pub mod external_generation_job_summary_backfill_input_type;
|
||||
pub mod external_generation_job_summary_backfill_procedure_result_type;
|
||||
pub mod external_generation_job_summary_procedure_result_type;
|
||||
@@ -557,6 +559,7 @@ pub mod get_editor_generation_pricing_config_and_return_procedure;
|
||||
pub mod get_editor_project_and_return_procedure;
|
||||
pub mod get_editor_showcase_campaign_config_and_return_procedure;
|
||||
pub mod get_external_generation_job_and_return_procedure;
|
||||
pub mod get_external_generation_job_result_and_return_procedure;
|
||||
pub mod get_external_generation_job_summary_and_return_procedure;
|
||||
pub mod get_external_generation_queue_stats_and_return_procedure;
|
||||
pub mod get_feature_gate_config_procedure;
|
||||
@@ -1919,8 +1922,10 @@ pub use external_generation_job_list_input_type::ExternalGenerationJobListInput;
|
||||
pub use external_generation_job_payload_compaction_input_type::ExternalGenerationJobPayloadCompactionInput;
|
||||
pub use external_generation_job_payload_compaction_procedure_result_type::ExternalGenerationJobPayloadCompactionProcedureResult;
|
||||
pub use external_generation_job_procedure_result_type::ExternalGenerationJobProcedureResult;
|
||||
pub use external_generation_job_result_procedure_result_type::ExternalGenerationJobResultProcedureResult;
|
||||
pub use external_generation_job_renew_lease_input_type::ExternalGenerationJobRenewLeaseInput;
|
||||
pub use external_generation_job_snapshot_type::ExternalGenerationJobSnapshot;
|
||||
pub use external_generation_job_result_snapshot_type::ExternalGenerationJobResultSnapshot;
|
||||
pub use external_generation_job_summary_backfill_input_type::ExternalGenerationJobSummaryBackfillInput;
|
||||
pub use external_generation_job_summary_backfill_procedure_result_type::ExternalGenerationJobSummaryBackfillProcedureResult;
|
||||
pub use external_generation_job_summary_procedure_result_type::ExternalGenerationJobSummaryProcedureResult;
|
||||
@@ -1973,6 +1978,7 @@ pub use get_editor_generation_pricing_config_and_return_procedure::get_editor_ge
|
||||
pub use get_editor_project_and_return_procedure::get_editor_project_and_return;
|
||||
pub use get_editor_showcase_campaign_config_and_return_procedure::get_editor_showcase_campaign_config_and_return;
|
||||
pub use get_external_generation_job_and_return_procedure::get_external_generation_job_and_return;
|
||||
pub use get_external_generation_job_result_and_return_procedure::get_external_generation_job_result_and_return;
|
||||
pub use get_external_generation_job_summary_and_return_procedure::get_external_generation_job_summary_and_return;
|
||||
pub use get_external_generation_queue_stats_and_return_procedure::get_external_generation_queue_stats_and_return;
|
||||
pub use get_feature_gate_config_procedure::get_feature_gate_config;
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::external_generation_job_result_snapshot_type::ExternalGenerationJobResultSnapshot;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct ExternalGenerationJobResultProcedureResult {
|
||||
pub ok: bool,
|
||||
pub result: Option<ExternalGenerationJobResultSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for ExternalGenerationJobResultProcedureResult {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct ExternalGenerationJobResultSnapshot {
|
||||
pub job_id: String,
|
||||
pub status: String,
|
||||
pub last_error_message: Option<String>,
|
||||
pub result_payload_json: Option<String>,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for ExternalGenerationJobResultSnapshot {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::external_generation_job_get_input_type::ExternalGenerationJobGetInput;
|
||||
use super::external_generation_job_result_procedure_result_type::ExternalGenerationJobResultProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct GetExternalGenerationJobResultAndReturnArgs {
|
||||
pub input: ExternalGenerationJobGetInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for GetExternalGenerationJobResultAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `get_external_generation_job_result_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait get_external_generation_job_result_and_return {
|
||||
fn get_external_generation_job_result_and_return(&self, input: ExternalGenerationJobGetInput) {
|
||||
self.get_external_generation_job_result_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn get_external_generation_job_result_and_return_then(
|
||||
&self,
|
||||
input: ExternalGenerationJobGetInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<ExternalGenerationJobResultProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl get_external_generation_job_result_and_return for super::RemoteProcedures {
|
||||
fn get_external_generation_job_result_and_return_then(
|
||||
&self,
|
||||
input: ExternalGenerationJobGetInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<ExternalGenerationJobResultProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, ExternalGenerationJobResultProcedureResult>(
|
||||
"get_external_generation_job_result_and_return",
|
||||
GetExternalGenerationJobResultAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -271,6 +271,22 @@ pub struct ExternalGenerationJobProcedureResult {
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
// Private backend read for reconciliation; it intentionally excludes job request and lease data.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct ExternalGenerationJobResultSnapshot {
|
||||
pub job_id: String,
|
||||
pub status: String,
|
||||
pub last_error_message: Option<String>,
|
||||
pub result_payload_json: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct ExternalGenerationJobResultProcedureResult {
|
||||
pub ok: bool,
|
||||
pub result: Option<ExternalGenerationJobResultSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct ExternalGenerationJobSummarySnapshot {
|
||||
pub job_id: String,
|
||||
@@ -464,6 +480,23 @@ pub fn get_external_generation_job_and_return(
|
||||
}
|
||||
}
|
||||
|
||||
#[spacetimedb::procedure]
|
||||
pub fn get_external_generation_job_result_and_return(
|
||||
ctx: &mut ProcedureContext,
|
||||
input: ExternalGenerationJobGetInput,
|
||||
) -> ExternalGenerationJobResultProcedureResult {
|
||||
let caller = ctx.sender();
|
||||
match ctx.try_with_tx(|tx| {
|
||||
crate::editor_project_storage::require_editor_generation_runtime_service_identity(
|
||||
tx, caller,
|
||||
)?;
|
||||
get_external_generation_job_result_tx(tx, input.clone())
|
||||
}) {
|
||||
Ok(result) => single_external_generation_job_result_read_result(result),
|
||||
Err(message) => failed_external_generation_job_result_read_result(message),
|
||||
}
|
||||
}
|
||||
|
||||
#[spacetimedb::procedure]
|
||||
pub fn list_external_generation_jobs_and_return(
|
||||
ctx: &mut ProcedureContext,
|
||||
@@ -869,6 +902,14 @@ fn get_external_generation_job_tx(
|
||||
ctx: &ReducerContext,
|
||||
input: ExternalGenerationJobGetInput,
|
||||
) -> Result<ExternalGenerationJobSnapshot, String> {
|
||||
get_external_generation_job_summary_tx(ctx, input)
|
||||
.map(map_external_generation_job_summary_to_compat_snapshot)
|
||||
}
|
||||
|
||||
fn get_external_generation_job_result_tx(
|
||||
ctx: &ReducerContext,
|
||||
input: ExternalGenerationJobGetInput,
|
||||
) -> Result<ExternalGenerationJobResultSnapshot, String> {
|
||||
validate_required("external_generation_job.job_id", &input.job_id)?;
|
||||
validate_required(
|
||||
"external_generation_job.owner_user_id",
|
||||
@@ -885,7 +926,12 @@ fn get_external_generation_job_tx(
|
||||
if row.owner_user_id.trim() != owner_user_id {
|
||||
return Err("external_generation_job 不存在".to_string());
|
||||
}
|
||||
Ok(map_external_generation_job_row(row))
|
||||
Ok(ExternalGenerationJobResultSnapshot {
|
||||
job_id: row.job_id,
|
||||
status: row.status,
|
||||
last_error_message: row.last_error_message,
|
||||
result_payload_json: row.result_payload_json,
|
||||
})
|
||||
}
|
||||
|
||||
fn list_external_generation_jobs_tx(
|
||||
@@ -2128,6 +2174,26 @@ fn failed_external_generation_job_result(message: String) -> ExternalGenerationJ
|
||||
}
|
||||
}
|
||||
|
||||
fn single_external_generation_job_result_read_result(
|
||||
result: ExternalGenerationJobResultSnapshot,
|
||||
) -> ExternalGenerationJobResultProcedureResult {
|
||||
ExternalGenerationJobResultProcedureResult {
|
||||
ok: true,
|
||||
result: Some(result),
|
||||
error_message: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn failed_external_generation_job_result_read_result(
|
||||
message: String,
|
||||
) -> ExternalGenerationJobResultProcedureResult {
|
||||
ExternalGenerationJobResultProcedureResult {
|
||||
ok: false,
|
||||
result: None,
|
||||
error_message: Some(message),
|
||||
}
|
||||
}
|
||||
|
||||
fn single_external_generation_job_summary_result(
|
||||
job: ExternalGenerationJobSummarySnapshot,
|
||||
) -> ExternalGenerationJobSummaryProcedureResult {
|
||||
|
||||
Reference in New Issue
Block a user