fix: 7 项 E2E Bug 修复 — Dashboard 404 / 记忆去重 / 记忆注入 / invoice_id / Prompt 版本
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

P0:
- BUG-H1: Dashboard 路由 /api/v1/stats/dashboard → /api/v1/admin/dashboard

P1:
- BUG-H2: viking_add 预检查 content_hash 去重,返回 "deduped" 状态;SqliteStorage 启动时回填已有条目 content_hash
- BUG-M5: saas-relay-client 发送前调用 viking_inject_prompt 注入跨会话记忆

P2:
- BUG-M1: PaymentResult 添加 invoice_id 字段,query_payment_status 返回 invoice_id
- BUG-M2: UpdatePromptRequest 添加内容字段,更新时自动创建新版本并递增 current_version
- BUG-M3: viking_find scope 参数文档化(设计行为,调用方需传 agent scope)
- BUG-M4: Dashboard 路由缺失已修复,handler 层 require_admin 已正确返回 403

P3 (确认已修复/非代码问题):
- BUG-L1: pain_seed_categories 已统一,无 pain_seeds 残留
- BUG-L2: pipeline_create 参数格式正确,E2E 测试方法问题
This commit is contained in:
iven
2026-04-17 03:31:06 +08:00
parent 1309101a94
commit a504a40395
9 changed files with 138 additions and 7 deletions

View File

@@ -189,6 +189,36 @@ pub async fn viking_add(uri: String, content: String) -> Result<VikingAddResult,
// Expected format: agent://{agent_id}/{type}/{category}
let (agent_id, memory_type, category) = parse_uri(&uri)?;
// Pre-check for duplicates via content hash
use std::hash::{Hash, Hasher};
let normalized_content = content.trim().to_lowercase();
let content_hash = {
let mut hasher = std::collections::hash_map::DefaultHasher::new();
normalized_content.hash(&mut hasher);
format!("{:016x}", hasher.finish())
};
let agent_scope = uri.split('/').nth(2).unwrap_or("");
let scope_prefix = format!("agent://{agent_scope}/");
// Check for existing entry with the same content hash in the same agent scope
let pool = storage.pool();
let existing: Option<(String,)> = sqlx::query_as(
"SELECT uri FROM memories WHERE content_hash = ? AND uri LIKE ? LIMIT 1"
)
.bind(&content_hash)
.bind(format!("{}%", scope_prefix))
.fetch_optional(pool)
.await
.map_err(|e| format!("Dedup check failed: {}", e))?;
if existing.is_some() {
return Ok(VikingAddResult {
uri,
status: "deduped".to_string(),
});
}
let entry = MemoryEntry::new(&agent_id, memory_type, &category, content);
storage

View File

@@ -16,6 +16,39 @@ import { createLogger } from './logger';
const log = createLogger('SaaSRelayGateway');
// ---------------------------------------------------------------------------
// Memory injection helper — injects relevant memories into system prompt
// before sending to SaaS relay (mirrors MemoryMiddleware in Tauri kernel path)
// ---------------------------------------------------------------------------
/**
* Attempt to inject relevant memories into the system prompt via Tauri IPC.
* Falls back gracefully in non-Tauri contexts (browser mode).
*/
async function injectMemories(
agentId: string | undefined,
basePrompt: string,
userInput: string,
): Promise<string> {
try {
// Dynamic import — only available in Tauri context
const { invoke } = await import('@tauri-apps/api/core');
const enhanced = await invoke<string>('viking_inject_prompt', {
agentId: agentId ?? 'default',
basePrompt,
userInput,
maxTokens: 500,
});
if (enhanced && enhanced !== basePrompt) {
log.debug('Memory injection succeeded for relay request');
return enhanced;
}
} catch {
// Non-Tauri context or viking not initialized — skip silently
}
return basePrompt;
}
// ---------------------------------------------------------------------------
// Frontend DataMasking — mirrors Rust DataMasking middleware for SaaS Relay
// ---------------------------------------------------------------------------
@@ -180,6 +213,17 @@ export function createSaaSRelayGatewayClient(
? [...history, { role: 'user' as const, content: maskedMessage }]
: [{ role: 'user' as const, content: maskedMessage }];
// BUG-M5 fix: Inject relevant memories into system prompt via Tauri IPC.
// This mirrors the MemoryMiddleware that runs in the kernel path.
const enhancedSystemPrompt = await injectMemories(
opts?.agentId,
'',
message,
);
if (enhancedSystemPrompt) {
messages.unshift({ role: 'system', content: enhancedSystemPrompt });
}
const model = getModel();
if (!model) {
callbacks.onError('No model available — please check SaaS relay configuration');