- ð ç®åœ
- 1. Capability æŠè§
- 2. CameraCapability
- 3. GalleryCapability
- 4. SettingsCapability
- 5. NavigationCapability
- 6. SystemCapability
- 7. AutoTagCapability
- 8. AiOptimizeCapability
- 9. RemoteControlCapability
- 10. BeautyCapabilityïŒé Agent çŒæïŒ
- éåœ AïŒæ°å¢ Capability æå
- éåœ BïŒCapability çåœåšæè§è
PicMe Agent Capability 泚å衚
蟹ç声æïŒBoundary StatementïŒ - æ¬ææ¡£å®ä¹ææ Agent Capability çæ³šå衚ãåœä»€æ å°ãæ§è¡é»èŸãæ°å¢ Capability å®ç°æå以åçåœåšæè§èã - æ¶æè®Ÿè®¡ä»¥
../02-ARCHITECTURE/AGENT_ARCHITECTURE.md䞺åã - 亀äºè§è以../01-PRODUCT/FEATURES.md䞺åã
æš¡åå®äœ: Agent èœå泚å衚ãåœä»€æ å°ãå®ç°æåäžçåœåšæè§è
äž»èŠç»Žæ€è
: [RD] å
šæ å·¥çšåž
é
读对象: RDãAI Agent
çæ¬: 1.2
æåæŽæ°: 2026-07-08
ð ç®åœ
- Capability æŠè§
- CameraCapability
- GalleryCapability
- SettingsCapability
- NavigationCapability
- SystemCapability
- AutoTagCapability
- AiOptimizeCapability
- RemoteControlCapability
- BeautyCapabilityïŒé Agent çŒæïŒ
- éåœ AïŒæ°å¢ Capability æå
- éåœ BïŒCapability çåœåšæè§è
1. Capability æŠè§
| Capability | name | 掻è·åºæ¯ | åœä»€æ° | ç¶æ | çåœåšæ |
|---|---|---|---|---|---|
| CameraCapability | camera |
CAMERA | 12 | â å·²èœå° | 页é¢çº§ïŒCameraScreenïŒ |
| GalleryCapability | gallery |
GALLERY | 7 | â å·²èœå° | åºçšçº§åäŸ + é¡µé¢ delegate |
| SettingsCapability | settings |
SETTINGS | 5 | â å·²èœå° | åºçšçº§åäŸ + é¡µé¢ delegate |
| NavigationCapability | navigation |
ALL | 2 | â å·²èœå° | Activity 级ïŒMainActivityïŒ |
| SystemCapability | system |
ALL | 2 | â å·²èœå° | Activity/Service 级 |
| AutoTagCapability | auto_tag |
GALLERY | 4 | â å·²èœå° | åºçšçº§ |
| AiOptimizeCapability | ai_optimize |
GALLERY, CHAT | 1 | â å·²èœå° | åºçšçº§ |
| RemoteControlCapability | remote_control |
ALL | 0 | â å·²èœå° | åºçšçº§åäŸïŒäžèµ° AgentCommand è·¯ç± |
| BeautyCapability | â | â | â | â å·²èœå° | æµè¯/çšåºå APIïŒäžæ³šåå° Agent çŒæ |
åæŽè¯ŽæïŒ2026-07-06ïŒïŒ - æ°å¢
AutoTagCapabilityãAiOptimizeCapabilityãRemoteControlCapability- ç§»é€AccessibilityCapabilityïŒåœå代ç åºäžäžååšå¯¹åºå®ç°ïŒ - ç§»é€EditCapabilityïŒçŒèŸé¡µç¬ç«è·¯ç±å°æªèœå°ïŒ -CameraCapabilityåœä»€ä» 11 䞪å¢å å° 12 äžªïŒæ°å¢delayïŒ
1.1 åºæ¯ - èœåæ å°
| åºæ¯ | å¯çš Capability |
|---|---|
CAMERA |
CameraCapability, NavigationCapability, SystemCapability |
GALLERY |
GalleryCapability, AutoTagCapability, AiOptimizeCapability, NavigationCapability, SystemCapability |
SETTINGS |
SettingsCapability, NavigationCapability, SystemCapability |
CHAT |
AiOptimizeCapability, NavigationCapability, SystemCapability |
DEBUG |
NavigationCapability, SystemCapability |
UNKNOWN |
NavigationCapability, SystemCapability, RemoteControlCapability |
2. CameraCapability
è莣: çžæºæ§å¶ãçŸé¢è°èãæ»€éåæ¢ãæææš¡åŒç®¡çãå»¶è¿æç
§
掻è·åºæ¯: CAMERA
æä»¶: app/src/main/java/com/mamba/picme/features/camera/capability/CameraCapability.kt
ç¶æ: â
å·²èœå°
2.1 æ¯æåœä»€
| åœä»€ | åæ° | æè¿° | ç€ºäŸ |
|---|---|---|---|
capture |
- | æç § | âæç §â |
toggle_recording |
- | åŒå§/忢åœå | âåŒå§åœåâ/â忢åœåâ |
flip_camera |
- | 翻蜬æå倎 | â翻蜬é倎â |
adjust_zoom |
factor: Float |
åçŠè°è | âæŸå€§äž€åâ â 2.0x |
adjust_exposure |
offset: Int |
æå è°è (+/-) | âè°äº®äžç¹â â +2 |
switch_mode |
mode: String |
åæ¢æææš¡åŒ | â倿¯æš¡åŒâ |
adjust_beauty |
type: String, value: Int |
è°èçŸé¢åæ° | âç£šç® 50â |
switch_filter |
filterType: String |
åæ¢æ»€é | âå·è°æ»€éâ |
switch_style |
styleType: String |
忢飿 Œç¹æ | âå¡é飿 Œâ |
switch_scene |
scene: String |
åæ¢åºæ¯æš¡åŒ | â人ååºæ¯â |
switch_ratio |
ratio: String |
忢ç»å¹ æ¯äŸ | â16:9â |
delay |
delay_ms: Int |
å»¶è¿æ§è¡ïŒå¯ç»åå ¶ä»åœä»€ïŒ | â3ç§åæç §â |
2.2 çŸé¢åæ°èåŽ
| åæ° | èåŽ | é»è®€åŒ |
|---|---|---|
| ç£šç® | 0-100 | 35 |
| çŸçœ | 0-100 | 25 |
| çŠèž | -50~+50 | 0 |
| å€§çŒ | 0-100 | 20 |
| åè² | 0-100 | 40 |
| è ®çº¢ | 0-100 | 20 |
| çæ¯ | 0-100 | 15 |
2.3 çåœåšæ
- 页é¢çº§ïŒç±
CameraScreenåå»ºåææ CameraScreen Enter â CameraCapability() å建 â æ³šåå° CapabilityHostCameraScreen Exit â CapabilityHost 泚é â CameraCapability 被 GC åæ¶
3. GalleryCapability
è莣: çžåæ¥çãå é€ãå享ãæçŽ¢ãæ¹ééæ©ãæ¶è
掻è·åºæ¯: GALLERY
æä»¶: app/src/main/java/com/mamba/picme/features/gallery/capability/GalleryCapability.kt
ç¶æ: â
å·²èœå°
3.1 æ¯æåœä»€
| åœä»€ | åæ° | æè¿° | ç€ºäŸ |
|---|---|---|---|
view_media |
media_id: String? |
æ¥çç §ç/è§é¢ | âçè¿åŒ ç §çâ |
delete_media |
media_ids: List<String> |
å é€ç §ç/è§é¢ | âå é€è¿åŒ â |
share_media |
media_ids: List<String> |
åäº«ç §ç/è§é¢ | âå享è¿åŒ â |
favorite_media |
media_id: String, favorite: Boolean |
æ¶è/åæ¶æ¶è | âæ¶èè¿åŒ â |
search_media |
query: String |
æçŽ¢ç §ç | âæŸæšå€©çç §çâ |
select_media |
media_id: String, selected: Boolean |
æ¹ééæ© | âå€éè¿åŒ â |
switch_view_mode |
mode: String |
忢è§åŸæš¡åŒ | âçœæ Œè§åŸâ |
3.2 çåœåšæ
- åºçšçº§åäŸ + é¡µé¢ delegateïŒåš
Application.onCreate()äžæ³šåäžæ¬¡ - çžå页颿¿æŽ»æ¶ç»å® delegateïŒçŠ»åŒæ¶è§£ç»
- æ¯æè·šé¡µé¢æä»€æéïŒé¡µé¢åæ¬¡æ¿æŽ»æ¶æ§è¡åŸ å€çåœä»€
4. SettingsCapability
è莣: äž»é¢åæ¢ãè¯èšè®Ÿçœ®ãæš¡å管çã人èžåŒæåæ¢ãè°è¯é项
掻è·åºæ¯: SETTINGS
æä»¶: app/src/main/java/com/mamba/picme/features/settings/capability/SettingsCapability.kt
ç¶æ: â
å·²èœå°
4.1 æ¯æåœä»€
| åœä»€ | åæ° | æè¿° | ç€ºäŸ |
|---|---|---|---|
change_theme |
theme: String |
åæ¢äž»é¢ïŒlight/dark/systemïŒ | âæ·±è²æš¡åŒâ |
change_language |
language: String |
忢è¯èšïŒzh/enïŒ | âè±æçé¢â |
download_model |
model_id: String |
äžèœœ AI æš¡å | âäžèœœçŸé¢æš¡åâ |
switch_face_engine |
engine: String |
åæ¢äººèžåŒæïŒmediapipe/mnn/customïŒ | âçš MediaPipeâ |
toggle_setting |
key: String, enabled: Boolean |
åŒå ³è®Ÿçœ®é¡¹ | âåŒå¯è°è¯æš¡åŒâ |
4.2 çåœåšæ
- åºçšçº§åäŸ + é¡µé¢ delegate
- è®Ÿçœ®é¡µé¢æ¿æŽ»æ¶ç»å® delegateïŒçŠ»åŒæ¶è§£ç»
5. NavigationCapability
è莣: 页é¢åæ¢ãè¿åäžäžé¡µ
掻è·åºæ¯: ALL (ææåºæ¯)
æä»¶: app/src/main/java/com/mamba/picme/domain/agent/capability/NavigationCapability.kt
ç¶æ: â
å·²èœå°
5.1 æ¯æåœä»€
| åœä»€ | åæ° | æè¿° | ç€ºäŸ |
|---|---|---|---|
navigate_to |
destination: String |
忢尿å®é¡µé¢ | âå»çžåâ/âæåŒè®Ÿçœ®â |
go_back |
- | è¿åäžäžé¡µ | âè¿åâ/âåå»â |
5.2 页颿 å°
| æåŸå ³é®è¯ | ç®æ é¡µé¢ |
|---|---|
| âçžæºâ, âæç §â | camera |
| âçžåâ, âç §çâ, âgalleryâ | gallery |
| â讟眮â, â讟å®â | settings |
| âè倩â, â对è¯â | chat |
| âè°è¯â | debug |
| âæš¡åäžå¿â | model_center |
5.3 çåœåšæ
- Activity 级ïŒç±
MainActivityåå»ºåææ - åæ¶åš
MainActivityäžéè¿AgentOrchestrator.registerCapability()泚åå°å šå±CapabilityRegistry
6. SystemCapability
è莣: å¯åšå
¶ä»åºçšãæåŒç³»ç»è®Ÿçœ®
掻è·åºæ¯: ALL (ææåºæ¯)
æä»¶: app/src/main/java/com/mamba/picme/domain/agent/capability/SystemCapability.kt
ç¶æ: â
å·²èœå°
6.1 æ¯æåœä»€
| åœä»€ | åæ° | æè¿° | ç€ºäŸ |
|---|---|---|---|
launch_app |
package_name: String?, app_name: String? |
å¯åšåºçš | âæåŒåŸ®ä¿¡â |
open_system_settings |
setting: String |
æåŒç³»ç»è®Ÿçœ® | âæåŒWiFi讟眮â |
6.2 çåœåšæ
- åš
MainActivityåFloatingChatBubbleServiceäžå建并泚å - æé åœæ°æ³šå
¥
Context
7. AutoTagCapability
è莣: å°æ çŸç³»ç»äœäžº Agent å¯çŒæç Capability æŽé²ïŒæ¯æè§Šåå
šéæ çŸæ«æãæ¥è¯¢ç
§çæ çŸãè·åè¿åºŠãåæ¶æ«æ
掻è·åºæ¯: GALLERY
æä»¶: app/src/main/java/com/mamba/picme/domain/agent/capability/AutoTagCapability.kt
ç¶æ: â
å·²èœå°
7.1 æ¯æåœä»€
| åœä»€ | åæ° | æè¿° | ç€ºäŸ |
|---|---|---|---|
scan_all_tags |
- | è§Šåå šéæ çŸæ«æ | âæ«æææç §çæ çŸâ |
get_photo_tags |
photo_id: Long |
æ¥è¯¢æå®ç §ççæ çŸ | âæ¥çè¿åŒ ç §ççæ çŸâ |
get_tag_progress |
- | è·ååœåæ«æè¿åºŠ | âæ çŸæ«æè¿åºŠâ |
cancel_tag_scan |
- | åæ¶åœåæ«æ | âåæ¶æ çŸæ«æâ |
7.2 çåœåšæ
- åºçšçº§ïŒå§æç»
TagScanOrchestratoræ§è¡ - æææ«æç»äžèµ° orchestratorïŒç¡®ä¿äž UI æ§å¶é¡µè¿åºŠåæº
8. AiOptimizeCapability
è莣: AI äžé®äŒååŸçïŒåæç
§çåºæ¯å¹¶èªåšæšèçŸé¢ã滀éãè°èåæ°
掻è·åºæ¯: GALLERY, CHAT
æä»¶: app/src/main/java/com/mamba/picme/domain/agent/capability/optimize/AiOptimizeCapability.kt
ç¶æ: â
å·²èœå°
8.1 æ¯æåœä»€
| åœä»€ | åæ° | æè¿° | ç€ºäŸ |
|---|---|---|---|
ai_optimize |
image_uri: String, mode: String? |
AI äžé®äŒååŸç | âäŒåè¿åŒ ç §çâ |
åæ°è¯ŽæïŒ - image_uri: åŸ
äŒååŸççæ¬å°æä»¶ URIïŒå¿
å¡«ïŒ - mode: fastïŒæ¬å°åºæ¯åæ + æ¬å°é¢è®ŸïŒé»è®€ïŒæ smartïŒäºç«¯è§è§æš¡åæšèïŒéçšæ·ææïŒ
8.2 çåœåšæ
- åºçšçº§ïŒåš
Application.onCreate()äžæ³šå - å®é
äŒåé»èŸå§æç»
AiOptimizeUseCase
9. RemoteControlCapability
è莣: IM è¿çšæ§å¶ïŒç®¡ç讟å€ç»å®äžè¿çšåœä»€æ§è¡ç¶æ
掻è·åºæ¯: ALL
æä»¶: app/src/main/java/com/mamba/picme/domain/agent/capability/RemoteControlCapability.kt
ç¶æ: â
å·²èœå°
9.1 æ¯æåœä»€
æ AgentCommand è·¯ç±åœä»€ãRemoteControlCapability äžéè¿ AgentCommand å¯å°ç±»åååœä»€ïŒææç®¡çæäœéè¿å
¬åŒ API ç± RemoteCommandDispatcher çŽæ¥è°çšã
execute() å§ç»è¿å METHOD_NOT_FOUNDã
9.2 å ¬åŒç®¡ç API
| API | 诎æ |
|---|---|
updateBinding(token, relayUrl, userId, deviceName) |
æŽæ°è®Ÿå€ç»å®ç¶æ |
clearBinding() |
æž é€è®Ÿå€ç»å® |
setAutoConfirm(enabled) |
讟眮èªåšç¡®è®€æš¡åŒ |
buildStatusString() |
æå»ºè®Ÿå€ç¶ææè¿° |
9.3 çåœåšæ
- åºçšçº§åäŸïŒåš
Application.onCreate()äžåå»ºïŒæ°žäžæ³šé - è¿çšç»ææ¶
onDestroy()æž çç¶æ
10. BeautyCapabilityïŒé Agent çŒæïŒ
è莣: æäŸçŸé¢è°èçæ ååçšåºåèœåïŒæ¯æç产代ç åæµè¯çŽæ¥è°çš
æä»¶: app/src/main/java/com/mamba/picme/capability/BeautyCapability.kt
ç¶æ: â
å·²èœå°
10.1 æ¯ææäœ
| æäœ | åæ° | æè¿° |
|---|---|---|
adjustSmoothing |
smoothness: Float |
è°æŽç£šç® |
adjustWhitening |
whitening: Float |
è°æŽçŸçœ |
adjustSlimFace |
slimFace: Float |
è°æŽçŠèž |
adjustBigEyes |
bigEyes: Float |
è°æŽå€§çŒ |
applyAllEffects |
settings: BeautySettings |
åºçšææçŸé¢ææ |
batchTest |
paramSets: List<BeautySettings> |
æ¹éæµè¯å€ç»åæ° |
10.2 诎æ
BeautyCapabilityäžæ³šåå°CapabilityRegistryïŒäžäœäžº Agent å¯çŒæèœå- äŸæµè¯åŒæãèªåšåæµè¯æäžå¡ä»£ç çŽæ¥è°çš
- è¥æªæ¥éèŠ Agent æ§å¶çŸé¢åæ°ïŒåºéè¿
CameraCapability.adjust_beautyåœä»€
éåœ AïŒæ°å¢ Capability æå
1. æ°å¢ Capability æµçš
æ¥éª€ 1: å®ä¹ Capability æ¥å£å®ç°
class YourNewCapability : Capability {
// 1. å®ä¹èœåæ è¯
override val name = "your_feature"
override val description = "åèœçç®çæè¿°ïŒçšäº System Prompt"
// 2. å£°ææŽ»è·åºæ¯
override fun activeScenes() = listOf(
SceneManager.Scene.YOUR_SCENE
)
// 3. ååºæ¯æçåœä»€
override fun supportedCommands() = listOf(
"command_1",
"command_2",
"text_reply"
)
// 4. å®ç°åœä»€æ§è¡é»èŸ
override suspend fun execute(
command: AgentCommand,
context: AgentContext,
pageContext: PageContext?
): Result<AgentAction> {
return when (command) {
is AgentCommand.YourCommand -> {
// æ§è¡å
·äœé»èŸ
performYourAction(command)
Result.success(AgentAction.Success(command))
}
is AgentCommand.TextReply -> {
Result.success(AgentAction.Text(command.message))
}
else -> {
Result.success(AgentAction.Error("äžæ¯æçåœä»€ïŒ${command::class.simpleName}"))
}
}
}
private fun performYourAction(cmd: AgentCommand.YourCommand): AgentAction {
// TODO: å®ç°äœ çäžå¡é»èŸ
// 泚æïŒäžèŠçŽæ¥äŸèµ UI å±ïŒäœ¿çšåè°æ³šå
¥
}
}æ¥éª€ 2: 泚åå° CapabilityRegistry
// åš Application æ ViewModel åå§åæ¶
val capabilityRegistry = CapabilityRegistry().apply {
register(YourNewCapability())
// ç¡®ä¿ NavigationCapability å§ç»æ³šå
register(NavigationCapability(onNavigate = {...}, onBack = {...}))
}æ¥éª€ 3: æ©å± AgentCommand
sealed class AgentCommand {
// ... ç°æåœä»€
// æ°å¢åœä»€
data class YourCommand(val param1: String, val param2: Int) : AgentCommand()
}æ¥éª€ 4: æŽæ° PromptBuilder
class PromptBuilder(private val sceneManager: SceneManager) {
fun buildSystemPrompt(
capabilities: List<Capability>,
context: AgentContext
): String {
return buildString {
appendLine(basePrompt)
appendLine()
appendLine("åœå页é¢ïŒ${sceneManager.currentScene.value.name}")
appendLine()
appendLine("å¯çšåèœ:")
capabilities.forEach { cap ->
appendLine("- ${cap.name}: ${cap.description}")
cap.supportedCommands().forEach { cmd ->
appendLine(" ⢠$cmd")
}
}
}
}
}æ¥éª€ 5: æ·»å èªç¶è¯èšæ å°ïŒå¯éïŒ
object NaturalLanguageMapper {
fun parseToCommand(input: String): AgentCommand? {
return when {
input.contains("äœ çåèœ") -> AgentCommand.YourCommand("default", 0)
input.contains("åæ° 1") -> AgentCommand.YourCommand("value1", 42)
else -> null
}
}
}2. Capability æ¥å£è¯Šè§£
name: String
çšé: èœåçå¯äžæ è¯ç¬Š
èŠæ±: å°å忝 + äžåçº¿ïŒæ ç©ºæ Œ
瀺äŸ: "camera", "gallery", "your_feature"
description: String
çšé: çšäº System Prompt çèªæè¿°
èŠæ±: ç®æŽæäºïŒäžè¶
è¿ 50 å
瀺äŸ: "çžæºæ§å¶ïŒæç
§ãåœåãçŸé¢ã滀é"
activeScenes(): List<SceneManager.Scene>
çšé: 声æè¯¥èœååšåªäºåºæ¯å¯çš
èŠæ±: å¿
é¡»è¿åé空å衚
瀺äŸ:
override fun activeScenes() = listOf(
SceneManager.Scene.CAMERA,
SceneManager.Scene.DEBUG
)supportedCommands(): List<String>
çšé: ååºæææ¯æçåœä»€åç§°
èŠæ±: å¿
é¡»å
å« "text_reply"
瀺äŸ:
override fun supportedCommands() = listOf(
"perform_action",
"cancel_action",
"text_reply"
)execute(...): Result<AgentAction>
çšé: æ§è¡è§£æåçåœä»€
åæ°: - command: è§£æåçç»æååœä»€ - context: å
šå±äžäžæïŒå¯¹è¯åå²ãçšæ·ä¿¡æ¯çïŒ - pageContext: 页é¢ç¹å®äžäžæïŒåŠåœåéäžçç
§çïŒ
è¿ååŒ: - Result.success(AgentAction.Success) - æ§è¡æå - Result.success(AgentAction.Error(reason)) - æ§è¡å€±èŽ¥ - Result.success(AgentAction.Text(message)) - ææ¬åå€
3. åœä»€è§£æåšæ©å±
æ©å± Sealed Class
sealed class AgentCommand {
data class YourCommand(
val param1: String,
val param2: Int,
val optionalParam: String? = null
) : AgentCommand()
}JSON è§£æè§å
å¿
é¡»äœ¿çš kotlinx.serializationïŒçŠæ¢æ£å:
import kotlinx.serialization.json.*
fun parseJsonResponse(jsonString: String): List<AgentCommand> {
return Json.decodeFromString<List<YourCommand>>(jsonString)
.map { AgentCommand.YourCommand(it.param1, it.param2) }
}é误å€ç
override suspend fun execute(
command: AgentCommand,
context: AgentContext,
pageContext: PageContext?
): Result<AgentAction> {
return try {
when (command) {
is AgentCommand.YourCommand -> {
// åæ°éªè¯
if (command.param2 < 0 || command.param2 > 100) {
return Result.success(AgentAction.Error("param2 å¿
é¡»åš 0-100 èåŽ"))
}
// æ§è¡é»èŸ
performAction(command)
Result.success(AgentAction.Success(command))
}
else -> Result.success(AgentAction.Error("äžæ¯æçåœä»€"))
}
} catch (e: Exception) {
Log.e("YourCapability", "æ§è¡å€±èŽ¥", e)
Result.success(AgentAction.Error("æ§è¡åŒåžžïŒ${e.message}"))
}
}4. 页é¢äžäžæéæ
å®ä¹ PageContext
sealed class PageContext {
data class YourContext(
val currentData: YourData?,
val selectedItems: List<YourItem>,
val extraInfo: Map<String, Any>?
) : PageContext()
object None : PageContext()
}è·å PageContext
override suspend fun execute(
command: AgentCommand,
context: AgentContext,
pageContext: PageContext?
): Result<AgentAction> {
val yourContext = pageContext as? PageContext.YourContext
return when (command) {
is AgentCommand.YourCommand -> {
val data = command.param1?.let { findDataById(it) }
?: yourContext?.currentData
data?.let { performAction(it, command) }
Result.success(AgentAction.Success(command))
}
else -> Result.success(AgentAction.Error("äžæ¯æçåœä»€"))
}
}UI å±æäŸ Context
@Composable
fun YourScreen(
viewModel: YourViewModel
) {
val pageContext by viewModel.pageContext.collectAsState()
GlobalAgentPanel(
orchestrator = agentOrchestrator,
pageContextProvider = { pageContext }
)
}5. æµè¯äžéªè¯
åå æµè¯
class YourCapabilityTest {
private lateinit var capability: YourCapability
@Before
fun setup() {
capability = YourCapability(
onPerformAction = { param1, param2 ->
// Mock é»èŸ
}
)
}
@Test
fun `test valid command executes successfully`() {
val command = AgentCommand.YourCommand("valid", 50)
val context = AgentContext()
val pageContext = PageContext.None
val result = capability.execute(command, context, pageContext)
assert(result.getOrNull() is AgentAction.Success)
}
@Test
fun `test invalid parameter returns error`() {
val command = AgentCommand.YourCommand("valid", 150) // Out of range
val context = AgentContext()
val pageContext = PageContext.None
val result = capability.execute(command, context, pageContext)
assert(result.getOrNull() is AgentAction.Error)
assert(result.getOrNull()?.message?.contains("èåŽ") == true)
}
@Test
fun `test text_reply returns message`() {
val command = AgentCommand.TextReply("Hello")
val context = AgentContext()
val pageContext = PageContext.None
val result = capability.execute(command, context, pageContext)
assert(result.getOrNull() is AgentAction.Text)
assert((result.getOrNull() as AgentAction.Text).message == "Hello")
}
}éææµè¯
class YourCapabilityIntegrationTest {
@Test
fun `test end-to-end command flow`() = runTest {
// 1. æš¡æçšæ·èŸå
¥
val userInput = "æ§è¡äœ çåèœïŒåæ° 1 䞺 testïŒåæ° 2 䞺 75"
// 2. æå»º Orchestrator
val orchestrator = AgentOrchestrator(
llmEngine = mockLlmEngine,
capabilityRegistry = registry
)
// 3. æ§è¡è§£æäžæ§è¡
val result = orchestrator.processUserInput(userInput, createContext())
// 4. éªè¯ç»æ
assertTrue(result.isSuccess)
verify(mockService).performAction("test", 75)
}
}QA éªæ¶æž å
6. åžžè§é·é±
â é·é± 1: 硬çŒç System Prompt
é误:
class YourCapability : Capability {
private val systemPrompt = """
äœ æ¯ PicMe 婿...
å¯çšåèœïŒyour_feature
⢠command_1
""".trimIndent()
}æ£ç¡®:
class PromptBuilder(private val sceneManager: SceneManager) {
fun buildSystemPrompt(capabilities: List<Capability>): String {
// åšææå»ºïŒæ¯ææä»¶å
}
}â é·é± 2: çŽæ¥äŸèµ UI å±
é误:
class YourCapability : Capability {
override suspend fun execute(..., pageContext: PageContext?) {
// â çŽæ¥è°çš UI æ¹æ³
uiController.updateView(data)
}
}æ£ç¡®:
class YourCapability(
private val onUpdateView: ((Data) -> Unit)? = null
) : Capability {
override suspend fun execute(...) {
// â
éè¿åè°æ³šå
¥
onUpdateView?.invoke(data)
}
}â é·é± 3: äœ¿çšæ£åè§£æ JSON
é误:
fun parseJson(json: String): YourCommand {
val param1 = json Regex "\"param1\": \"([^\"]+)\"" groupValues[1]
// â æ æ³å€çåµå¥/蜬ä¹
}æ£ç¡®:
fun parseJson(json: String): YourCommand {
return Json.decodeFromString(json)
// â
ç±»åå®å
šïŒæ¯æå€æç»æ
}â é·é± 4: å¿è®°æ³šå Command æ å°
é误:
// æ°å¢ YourCommand åæªæŽæ° CapabilityRegistry
class CapabilityRegistry {
fun mapCommand(name: String): AgentCommand? {
return when (name) {
"command_1" -> ExistingCommand()
// â éæŒ YourCommand
}
}
}æ£ç¡®:
class CapabilityRegistry {
fun mapCommand(name: String): AgentCommand? {
return when (name) {
"command_1" -> ExistingCommand()
"your_command" -> YourCommand() // â
åæ¥æŽæ°
}
}
}â é·é± 5: 応ç¥çº¿çšå®å š
é误:
class YourCapability : Capability {
private var counter = 0 // â é线çšå®å
š
override suspend fun execute(...) {
counter++ // å¹¶åä¿®æ¹
}
}æ£ç¡®:
class YourCapability : Capability {
private val counter = AtomicInteger(0) // â
ååæäœ
override suspend fun execute(...) {
counter.incrementAndGet()
}
}7. Checklist
代ç å®¡æ¥æž å
ææ¡£åæ¥æž å
éåœ BïŒCapability çåœåšæè§è
ç¶æ: èæ¡
å建: 2026-06-06
æŽæ°: 2026-06-06
äœè : [RD] å šæ å·¥çšåž
è¯å®¡: [CR] è§è宿€è
1. è®Ÿè®¡ç®æ
| ç®æ | äŒå 级 | 诎æ |
|---|---|---|
| é¶å åæ³æŒ | P0 | Capability äžåŸææ Activity/Fragment/Screen ç区åŒçš |
| çåœåšæå¯¹éœ | P0 | Capability ççåœåšæå¿ é¡»äžé¡µé¢çåœåšæäž¥æ Œå¯¹éœ |
| ç»åäŒäºåäŸ | P0 | äŒå 䜿çšäŸèµæ³šå ¥åç»åïŒé¿å å šå±åäŸ |
| 跚页é¢åœä»€ | P1 | æ¯æä»ä»»æé¡µé¢åéåœä»€å°ç®æ é¡µé¢ |
| äœåè | P1 | é¿å åå°èœ®è¯¢åæ æç¶ææ£æ¥ |
2. åœåæ¶æé®é¢
2.1 é®é¢æž å
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â é®é¢ 1: åäŸææé¡µé¢åŒçšïŒå
åæ³æŒé£é©ïŒ â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ€
â CameraCapability.getInstance() ââ⺠WeakReference<Delegate> â
â â² é®é¢: WeakReference åªèœçŒè§£ïŒäžèœæ ¹æ²» â
â â² é®é¢: å¿å Delegate å®ç°éåŒææ CameraScreen çéå
åé â
â â² é®é¢: åäŸçåœåšæ > Activity çåœåšæ â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â é®é¢ 2: DisposableEffect æ¶åºç«äºïŒdelegate ç»å®åç«å³è§£ç»ïŒ â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ€
â CameraScreen éç» ââ⺠DisposableEffect.onDispose() â
â â² é®é¢: Compose éç»é¢ç¹ïŒonDispose è¢«è¿æ©è°çš â
â â² é®é¢: 富èªåšç»æéŽïŒæ§é¡µé¢ DisposableEffect å
dispose â
â â² é®é¢: æ°é¡µé¢ DisposableEffect å enterïŒååšæ¶éŽçªå£ â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â é®é¢ 3: Application 级泚ååµåïŒæ æ³åšææ©å±ïŒ â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ€
â Application.onCreate() ââ⺠registry.register(capability) â
â â² é®é¢: 泚ååæ æ³æ³šéïŒæ æ³çææ Capability â
â â² é®é¢: ææ Capability åžžé©»å
åïŒå¢å åºç¡å
åå çš â
â â² é®é¢: åå
æµè¯éèŠæž
çå
šå±ç¶æïŒå¢å æµè¯å€æåºŠ â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â é®é¢ 4: SceneManager äž Compose çåœåšæè±è â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ€
â MainActivity 讟眮 scene ââ⺠SceneManager.transitionTo() â
â CameraScreen DisposableEffect ââ⺠bindDelegate() â
â â² é®é¢: 䞀䞪系ç»ç¬ç«è¿è¡ïŒååšç¶æäžäžèŽçªå£ â
â â² é®é¢: SceneManager åŒçšè®¡æ°å€æïŒå®¹æåºé â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
2.2 å åæ³æŒè·¯åŸåæ
// åœå代ç ïŒæ³æŒè·¯åŸïŒ
class CameraCapability : BaseCapability() {
companion object {
private var instance: CameraCapability? = null // éæåŒçšïŒæ°žäžéæŸ
fun getInstance() = instance!!
}
private var delegateRef: WeakReference<Delegate>? = null
}
// CameraScreen.kt
DisposableEffect(Unit) {
val cameraCapability = CameraCapability.getInstance() // è·ååäŸ
cameraCapability.bindDelegate(object : CameraCapability.Delegate {
override fun onSwitchRatio(ratio: String) {
aspectRatio = ratio // å¿åç±»éåŒææ CameraScreen ç aspectRatio
}
// ... å
¶ä»æ¹æ³åæ ·ææ CameraScreen çç¶æåŒçš
})
// å³äœ¿ WeakReference 被æž
çïŒåäŸä»ç¶å掻ïŒäžå¿åç±»çç±»å 蜜åšåŒçšéŸå€æ
}3. æ°æ¶æè®Ÿè®¡
3.1 æ žå¿åå
åå 1: 页é¢çº§ CapabilityïŒPage-Scoped CapabilityïŒ
// â
æ°è®Ÿè®¡: Capability é页é¢å建å鿝
@Composable
fun CameraScreen(
viewModel: MediaViewModel,
// Capability éè¿åæ°æ³šå
¥ïŒèéå
šå±åäŸ
cameraCapability: CameraCapability = remember { CameraCapability() }
) {
// CameraCapability çŽæ¥ææç¶æïŒæ é delegate æš¡åŒ
DisposableEffect(Unit) {
// 泚åå°åœå页é¢ç Capability éå
LocalCapabilityHost.current.register(cameraCapability)
onDispose {
LocalCapabilityHost.current.unregister(cameraCapability)
}
}
}åå 2: ç»åäŒäºåäŸïŒComposition over SingletonïŒ
// â æ§è®Ÿè®¡: åäŸè®¿é®
val registry = CapabilityRegistry.getInstance()
registry.register(CameraCapability.getInstance())
// â
æ°è®Ÿè®¡: äŸèµæ³šå
¥
class MainActivity : ComponentActivity() {
private val navigationCapability = NavigationCapability() // Activity 级
override fun onCreate(savedInstanceState: Bundle?) {
setContent {
val capabilityHost = rememberCapabilityHost(navigationCapability)
CompositionLocalProvider(LocalCapabilityHost provides capabilityHost) {
NavHost(...) { ... }
}
}
}
}åå 3: ç¶æå èïŒState CohesionïŒ
// â æ§è®Ÿè®¡: ç¶æåæ£åš Screen å Capability ä¹éŽ
class CameraScreen {
var aspectRatio by remember { mutableIntStateOf(AspectRatio.RATIO_FULL) }
// Capability éè¿ delegate åè°ä¿®æ¹ Screen ç¶æ
}
// â
æ°è®Ÿè®¡: Capability ææèªå·±çç¶æ
class CameraCapability {
var aspectRatio by mutableIntStateOf(AspectRatio.RATIO_FULL)
private set
fun switchRatio(ratio: String) {
aspectRatio = parseRatio(ratio)
}
}3.2 æ¶æåå±
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Layer 1: ApplicationïŒå
šå±é
çœ®ïŒæ ç¶æïŒ â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
â â - LogModuleConfig é»è®€åŒ â â
â â - BeautyEngine å
šå±åå§åïŒä»
äžæ¬¡ïŒ â â
â â - äžææä»»äœ Capability å®äŸ â â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ€
â Layer 2: ActivityïŒå¯Œèªçº§ CapabilityïŒ â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
â â NavigationCapability ââ ç»å® NavController â â
â â - çåœåšæ: Activity.onCreate() ~ Activity.onDestroy() â â
â â - äœçšå: ææé¡µé¢å
±äº«åäžäžª NavigationCapability â â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ€
â Layer 3: ScreenïŒé¡µé¢çº§ CapabilityïŒ â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
â â CameraCapability ââ ç»å® Camera ç¶æ â â
â â - çåœåšæ: Screen Enter ~ Screen Exit â â
â â - äœçšå: ä»
åœå CameraScreen â â
â â - ç¶æ: aspectRatio, lensFacing, beautySettings... â â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ€
â Layer 4: ViewModelïŒäžå¡é»èŸïŒè·šé
çœ®åæŽåæŽ»ïŒ â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
â â MediaViewModel ââ åªäœæ°æ®ç®¡ç â â
â â - çåœåšæ: Activity é
çœ®åæŽåæŽ» â â
â â - äžææ Capability åŒçšïŒéè¿åè°éä¿¡ïŒ â â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
3.3 Capability çåœåšæåç±»
| ç±»å | çåœåšæ | å žåç€ºäŸ | å建äœçœ® | 鿝äœçœ® |
|---|---|---|---|---|
| åºçšçº§ | Application | BeautyEngine |
Application.onCreate() |
æ°žäžéæ¯ |
| 掻åšçº§ | Activity | NavigationCapability |
Activity.onCreate() |
Activity.onDestroy() |
| 页é¢çº§ | Screen | CameraCapability |
Screen éŠæ¬¡éç» |
Screen ä»ç»åæ ç§»é€ |
| çšäŸçº§ | UseCase | AiAgentUseCase |
éèŠæ¶å建 |
äžåäœ¿çšæ¶éæŸ |
4. 诊ç»è®Ÿè®¡
4.1 CapabilityHostïŒCapability 容åšïŒ
/**
* Capability 宿䞻
*
* 管çåœåäœçšåå
ææ Capability çæ³šååæ¥è¯¢ã
* æ¯æå±çº§æ¥æŸïŒåŠæåœå宿䞻æŸäžå°ïŒäŒå§æç»ç¶å®¿äž»ã
*/
class CapabilityHost(
private val parent: CapabilityHost? = null
) {
private val capabilities = mutableMapOf<String, Capability>()
fun register(capability: Capability) {
capabilities[capability.name] = capability
}
fun unregister(capability: Capability) {
capabilities.remove(capability.name)
}
fun find(name: String): Capability? {
return capabilities[name] ?: parent?.find(name)
}
fun findForScene(scene: SceneManager.Scene): List<Capability> {
return capabilities.values.filter {
it.activeScenes().contains(scene) || it.activeScenes().isEmpty()
}
}
}
// Compose éæ
val LocalCapabilityHost = compositionLocalOf<CapabilityHost> {
error("CapabilityHost not provided")
}
@Composable
fun rememberCapabilityHost(vararg capabilities: Capability): CapabilityHost {
val parent = LocalCapabilityHost.current
return remember(capabilities) {
CapabilityHost(parent).apply {
capabilities.forEach { register(it) }
}
}
}4.2 页é¢çº§ CameraCapability
/**
* çžæºæ§å¶ CapabilityïŒé¡µé¢çº§ïŒ
*
* ç± CameraScreen åå»ºåææïŒScreen 鿝æ¶èªåšéæŸã
* äžåäœ¿çš delegate æš¡åŒïŒç¶æçŽæ¥å
èåš Capability äžã
*/
class CameraCapability : BaseCapability() {
override val name: String = "camera"
override val description: String = "æ§å¶çžæºææãçŸé¢åæ°ã滀é..."
// ç¶æçŽæ¥å
èåš Capability äž
var aspectRatio by mutableIntStateOf(AspectRatio.RATIO_FULL)
private set
var lensFacing by mutableIntStateOf(CameraSelector.LENS_FACING_BACK)
private set
var beautySettings by mutableStateOf(BeautySettings(enabled = false))
private set
// åœä»€æ§è¡çŽæ¥ä¿®æ¹å
éšç¶æ
override suspend fun execute(
command: AgentCommand,
context: AgentContext,
pageContext: PageContext?
): Result<AgentAction> {
return when (command) {
is AgentCommand.SwitchRatio -> {
aspectRatio = parseRatio(command.ratio)
Result.success(AgentAction.Success(...))
}
// ... å
¶ä»åœä»€
}
}
override fun isAvailable(): Boolean = true // 页é¢çº§ Capability åªèŠååšå°±å¯çš
}4.3 Screen äž Capability çç»å®
@Composable
fun CameraScreen(
viewModel: MediaViewModel,
onNavigateToGallery: () -> Unit,
onNavigateToSettings: () -> Unit,
) {
// å建页é¢çº§ Capability
val cameraCapability = remember { CameraCapability() }
// 泚åå°åœå CapabilityHost
val host = LocalCapabilityHost.current
DisposableEffect(cameraCapability) {
host.register(cameraCapability)
onDispose { host.unregister(cameraCapability) }
}
// å° Capability çç¶æç»å®å° UI
val aspectRatio = cameraCapability.aspectRatio
val lensFacing = cameraCapability.lensFacing
// UI äœ¿çš Capability ç¶æ
CameraPreviewContent(
aspectRatio = aspectRatio,
lensFacing = lensFacing,
// ...
)
}4.4 跚页é¢åœä»€å€ç
/**
* 跚页é¢åœä»€ç± NavigationCapability ç»äžå€ç
*
* 富èªå°ç®æ 页é¢åïŒç®æ 页é¢ç Capability èªç¶å¯çšã
* æ é倿çæéå蜮询æºå¶ã
*/
class NavigationCapability(
private val navController: NavController
) : BaseCapability() {
override val name: String = "navigation"
override suspend fun execute(
command: AgentCommand,
context: AgentContext,
pageContext: PageContext?
): Result<AgentAction> {
return when (command) {
is AgentCommand.NavigateTo -> {
// 富èªå°ç®æ 页é¢
navController.navigate(command.destination)
// 富èªå®æåïŒç®æ 页é¢ç Capability äŒèªåšæ¥ç®¡åç»åœä»€
Result.success(AgentAction.Success(...))
}
// ...
}
}
}5. è¿ç§»è·¯åŸ
5.1 é¶æ®µ 1: åŒå ¥ CapabilityHostïŒååå Œå®¹ïŒ
// 1. æ·»å CapabilityHost å CompositionLocal
// 2. ä¿®æ¹ CapabilityRegistry æ¯æä» CapabilityHost æ¥è¯¢
// 3. CameraScreen åæ¶æ³šåå°åäŸå CapabilityHost
class CapabilityRegistry {
fun dispatch(command: AgentCommand, context: AgentContext): Result<AgentAction> {
// äŒå
ä» CapabilityHost æ¥æŸ
val host = LocalCapabilityHost.currentOrNull
val capability = host?.findForCommand(command)
?: findCapabilityForCommand(command)
// ...
}
}5.2 é¶æ®µ 2: ç§»é€åäŸïŒç Žåæ§åæŽïŒ
// 1. ç§»é€ CameraCapability.getInstance()
// 2. ç§»é€ Application äžç initializeCapabilities()
// 3. MainActivity å建 NavigationCapability 并泚å
¥
// 4. å Screen å建èªå·±ç Capability5.3 é¶æ®µ 3: æž çåºåŒä»£ç
// 1. ç§»é€ SceneManager çåŒçšè®¡æ°æºå¶
// 2. ç§»é€ CapabilityRegistry çåœä»€éå
// 3. ç§»é€ææ WeakReference delegate æš¡åŒ6. å å圱åè¯äŒ°
| ææ | æ§æ¶æ | æ°æ¶æ | åå |
|---|---|---|---|
| åžžé©» Capability æ° | 4ïŒæ°žäžéæŸïŒ | 1ïŒNavigationïŒ | -75% |
| CameraCapability å åå çš | åžžé©» | ä» åšçžæºé¡µ | æéåé |
| å¿å Delegate å®äŸ | 1/页é¢ïŒæ³æŒé£é©ïŒ | 0 | å®å šæ¶é€ |
| åœä»€éå蜮询 | 500ms éŽé | æ | èç CPU |
| SceneManager åŒçšè®¡æ° | 倿 | ç®å | éäœå€æåºŠ |
7. 红线åè§æ£æ¥
| 红线 | åè§ç¶æ | 诎æ |
|---|---|---|
| [PRIVACY] | â | æ åæŽ |
| [PERF] | â | åå°åžžé©»å åååå°èœ®è¯¢ |
| [I18N] | â | æ åæŽ |
| [DOC-SYNC] | â | æ¬ææ¡£åæ¥æ¶æåæŽ |
| [AGENT-FIRST] | â | æŸåŒçåœåšæãæäžŸç¶æãèªæè¿°ç±»å |
åèææ¡£: - AGENTS.md â Agent First æ¶æåå - AGENT_ARCHITECTURE.md â Agent æ¶æè®Ÿè®¡ - COMMAND_REFERENCE.md â åœä»€è¯æ³åè