Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import kotlinx.coroutines.launch
private const val TAG = "AGAgentChatTask"

// The default system prompt for the agent chat task with both skills and MCP tools.
internal const val DEFAULT_SYSTEM_PROMPT =
const val DEFAULT_SYSTEM_PROMPT =
"""
You are an AI assistant that helps users by answering questions and completing tasks using skills and tools. For EVERY new task, request, or question, you MUST execute the following steps in exact order. You MUST NOT skip any steps.

Expand Down Expand Up @@ -94,7 +94,7 @@ internal const val DEFAULT_SYSTEM_PROMPT =
private val DEFAULT_SYSTEM_PROMPT_TRIMMED = DEFAULT_SYSTEM_PROMPT.trimIndent()

// The default system prompt for the agent chat task with only skills.
internal const val DEFAULT_SYSTEM_PROMPT_SKILLS_ONLY =
const val DEFAULT_SYSTEM_PROMPT_SKILLS_ONLY =
"""
You are an AI assistant that helps users by answering questions and completes tasks using skills. For EVERY new task or request or question, you MUST execute the following steps in exact order. You MUST NOT skip any steps.

Expand All @@ -117,7 +117,7 @@ private val DEFAULT_SYSTEM_PROMPT_SKILLS_ONLY_TRIMMED =
DEFAULT_SYSTEM_PROMPT_SKILLS_ONLY.trimIndent()

class AgentChatTask @Inject constructor() : CustomTask {
private val agentTools = AgentTools()
private val agentTools: AgentTools = AgentToolsImpl()

override val task: Task =
Task(
Expand Down Expand Up @@ -242,13 +242,13 @@ fun injectSkillsAndMcpTools(
}

// Check whether the system prompt is the default one.
internal fun isDefaultSystemPrompt(prompt: String): Boolean {
fun isDefaultSystemPrompt(prompt: String): Boolean {
return prompt == DEFAULT_SYSTEM_PROMPT_TRIMMED ||
prompt == DEFAULT_SYSTEM_PROMPT_SKILLS_ONLY_TRIMMED
}

// Returns the effective default system prompt depending on whether MCP tools are enabled.
internal fun getEffectiveBaseSystemPrompt(currentPrompt: String, hasMcpTools: Boolean): String {
fun getEffectiveBaseSystemPrompt(currentPrompt: String, hasMcpTools: Boolean): String {
return if (isDefaultSystemPrompt(currentPrompt)) {
if (hasMcpTools) DEFAULT_SYSTEM_PROMPT_TRIMMED else DEFAULT_SYSTEM_PROMPT_SKILLS_ONLY_TRIMMED
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import com.google.ai.edge.gallery.common.RequestPermissionAgentAction
import com.google.ai.edge.gallery.common.SkillProgressAgentAction
import com.google.ai.edge.gallery.common.convertStringToJsonObject
import com.google.ai.edge.gallery.firebaseAnalytics
import com.google.ai.edge.gallery.proto.Skill
import com.google.ai.edge.litertlm.Tool
import com.google.ai.edge.litertlm.ToolParam
import com.google.ai.edge.litertlm.ToolSet
Expand All @@ -49,29 +50,80 @@ import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.runBlocking

private const val TAG = "AGAgentTools"
const val SKILL_INSTRUCTIONS_TEMPLATE = "---\nname: %s\ndescription: %s\n---\n\n%s"

open class AgentTools() : ToolSet {
lateinit var context: Context
lateinit var skillManagerViewModel: SkillManagerViewModel
lateinit var mcpManagerViewModel: McpManagerViewModel
lateinit var taskId: String
fun Skill.getSkillContent(): String {
return SKILL_INSTRUCTIONS_TEMPLATE.format(name, description, instructions)
}

interface AgentTools : ToolSet {
var context: Context
var skillManagerViewModel: SkillManagerViewModel
var mcpManagerViewModel: McpManagerViewModel
var taskId: String
val actionChannel: ReceiveChannel<AgentAction>
var resultImageToShow: CallJsSkillResultImage?
var resultWebviewToShow: CallJsSkillResultWebview?

@Tool(description = "Loads a skill.")
fun loadSkill(
@ToolParam(description = "The name of the skill to load.") skillName: String
): Map<String, String>

@Tool(description = "Run a MCP tool")
fun runMcpTool(
@ToolParam(description = "The name of the tool to run.") toolName: String,
@ToolParam(description = "The parameters passed to tool as input") input: String,
): Map<String, String>

@Tool(description = "Runs JS script")
fun runJs(
@ToolParam(description = "The name of skill") skillName: String,
@ToolParam(description = "The script name to run. Use 'index.html' if not provided by user")
scriptName: String,
@ToolParam(
description = "The data to pass to the script. Use empty string if not provided by user"
)
data: String,
): Map<String, Any>

@Tool(
description =
"Run an Android intent. It is used to interact with the app to perform certain actions."
)
fun runIntent(
@ToolParam(description = "The intent to run.") intent: String,
@ToolParam(
description = "A JSON string containing the parameter values required for the intent."
)
parameters: String,
): Map<String, String>

fun sendAgentAction(action: AgentAction)
}

open class AgentToolsImpl : AgentTools {
override lateinit var context: Context
override lateinit var skillManagerViewModel: SkillManagerViewModel
override lateinit var mcpManagerViewModel: McpManagerViewModel
override lateinit var taskId: String

private val _actionChannel = Channel<AgentAction>(Channel.UNLIMITED)
val actionChannel: ReceiveChannel<AgentAction> = _actionChannel
var resultImageToShow: CallJsSkillResultImage? = null
var resultWebviewToShow: CallJsSkillResultWebview? = null
override val actionChannel: ReceiveChannel<AgentAction> = _actionChannel
override var resultImageToShow: CallJsSkillResultImage? = null
override var resultWebviewToShow: CallJsSkillResultWebview? = null

/** Loads skill. */
@Tool(description = "Loads a skill.")
fun loadSkill(
override fun loadSkill(
@ToolParam(description = "The name of the skill to load.") skillName: String
): Map<String, String> {
return runBlocking(Dispatchers.Default) {
val skills = skillManagerViewModel.getSelectedSkills()
val skill = skills.find { it.name == skillName.trim() }
val skillContent =
if (skill != null) {
"---\nname: ${skill.name}\ndescription: ${skill.description}\n---\n\n${skill.instructions}"
skill.getSkillContent()
} else {
"Skill not found"
}
Expand Down Expand Up @@ -100,7 +152,7 @@ open class AgentTools() : ToolSet {
}

@Tool(description = "Run a MCP tool")
fun runMcpTool(
override fun runMcpTool(
@ToolParam(description = "The name of the tool to run.") toolName: String,
@ToolParam(description = "The parameters passed to tool as input") input: String,
): Map<String, String> {
Expand Down Expand Up @@ -223,7 +275,7 @@ open class AgentTools() : ToolSet {

/** Call JS skill */
@Tool(description = "Runs JS script")
fun runJs(
override fun runJs(
@ToolParam(description = "The name of skill") skillName: String,
@ToolParam(description = "The script name to run. Use 'index.html' if not provided by user")
scriptName: String,
Expand Down Expand Up @@ -359,7 +411,7 @@ open class AgentTools() : ToolSet {
description =
"Run an Android intent. It is used to interact with the app to perform certain actions."
)
fun runIntent(
override fun runIntent(
@ToolParam(description = "The intent to run.") intent: String,
@ToolParam(
description = "A JSON string containing the parameter values required for the intent."
Expand Down Expand Up @@ -403,7 +455,7 @@ open class AgentTools() : ToolSet {
return mapOf("error" to error, "status" to "failed")
}

fun sendAgentAction(action: AgentAction) {
override fun sendAgentAction(action: AgentAction) {
runBlocking(Dispatchers.Default) { _actionChannel.send(action) }
}

Expand Down
Loading
Loading