fix(hands): add max_concurrent + timeout_secs fields + hand timeout enforcement
Some checks failed
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

M3-04/M3-05 audit fixes:
- HandConfig: add max_concurrent (u32) and timeout_secs (u64) with serde defaults
- Kernel execute_hand: enforce timeout via tokio::time::timeout, cancel on expiry
- All 9 hand implementations: add max_concurrent: 0, timeout_secs: 0
- Agent createClone: pass soul field through to kernel
- Fix duplicate soul block in agent_create command
This commit is contained in:
iven
2026-04-04 18:41:15 +08:00
parent a644988ca3
commit 59f660b93b
14 changed files with 93 additions and 2 deletions

View File

@@ -26,6 +26,8 @@ pub struct CreateAgentRequest {
pub description: Option<String>,
#[serde(default)]
pub system_prompt: Option<String>,
#[serde(default)]
pub soul: Option<String>,
#[serde(default = "default_provider")]
pub provider: String,
#[serde(default = "default_model")]
@@ -88,6 +90,10 @@ pub async fn agent_create(
.with_max_tokens(request.max_tokens)
.with_temperature(request.temperature);
if let Some(soul) = request.soul {
config = config.with_soul(soul);
}
if let Some(workspace) = request.workspace {
config.workspace = Some(workspace);
}

View File

@@ -36,6 +36,7 @@ export function installAgentMethods(ClientClass: { prototype: KernelClient }): v
name: request.name,
description: request.description,
systemPrompt: request.systemPrompt,
soul: request.soul,
provider: request.provider || 'anthropic',
model: request.model || 'claude-sonnet-4-20250514',
maxTokens: request.maxTokens || 4096,
@@ -77,12 +78,24 @@ export function installAgentMethods(ClientClass: { prototype: KernelClient }): v
model?: string;
personality?: string;
communicationStyle?: string;
scenarios?: string[];
emoji?: string;
notes?: string;
[key: string]: unknown;
}): Promise<{ clone: any }> {
// Build soul content from personality data
const soulParts: string[] = [];
if (opts.personality) soulParts.push(`## 性格\n${opts.personality}`);
if (opts.communicationStyle) soulParts.push(`## 沟通风格\n${opts.communicationStyle}`);
if (opts.scenarios?.length) soulParts.push(`## 使用场景\n${opts.scenarios.join(', ')}`);
if (opts.notes) soulParts.push(`## 备注\n${opts.notes}`);
const soul = soulParts.length > 0 ? soulParts.join('\n\n') : undefined;
const response = await this.createAgent({
name: opts.name,
description: opts.role,
model: opts.model,
soul,
});
const clone = {
id: response.id,
@@ -91,6 +104,8 @@ export function installAgentMethods(ClientClass: { prototype: KernelClient }): v
model: opts.model,
personality: opts.personality,
communicationStyle: opts.communicationStyle,
emoji: opts.emoji,
scenarios: opts.scenarios,
createdAt: new Date().toISOString(),
};
return { clone };

View File

@@ -32,6 +32,7 @@ export interface CreateAgentRequest {
name: string;
description?: string;
systemPrompt?: string;
soul?: string;
provider?: string;
model?: string;
maxTokens?: number;