Skip to content

Commit b4c138c

Browse files
committed
feat: add ghost char
1 parent f9e2372 commit b4c138c

File tree

2 files changed

+64
-4
lines changed

2 files changed

+64
-4
lines changed

veadk/agent.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,7 @@
3838
from typing_extensions import Any
3939

4040
from veadk.config import settings
41-
from veadk.consts import (
42-
DEFAULT_AGENT_NAME,
43-
DEFAULT_MODEL_EXTRA_CONFIG,
44-
)
41+
from veadk.consts import DEFAULT_AGENT_NAME, DEFAULT_MODEL_EXTRA_CONFIG
4542
from veadk.knowledgebase import KnowledgeBase
4643
from veadk.memory.long_term_memory import LongTermMemory
4744
from veadk.memory.short_term_memory import ShortTermMemory
@@ -88,6 +85,7 @@ class Agent(LlmAgent):
8885
auto_save_session (bool): Whether to automatically save sessions to long-term memory.
8986
skills (list[str]): List of skills that equip the agent with specific capabilities.
9087
example_store (Optional[BaseExampleProvider]): Example store for providing example Q/A.
88+
enable_shadowchar (bool): Whether to enable shadow character for the agent.
9189
"""
9290

9391
model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow")
@@ -154,6 +152,8 @@ class Agent(LlmAgent):
154152

155153
enable_supervisor: bool = False
156154

155+
enable_ghostchar: bool = False
156+
157157
def model_post_init(self, __context: Any) -> None:
158158
super().model_post_init(None) # for sub_agents init
159159

@@ -304,6 +304,14 @@ def model_post_init(self, __context: Any) -> None:
304304

305305
self.tools.append(ExampleTool(examples=self.example_store))
306306

307+
if self.enable_ghostchar:
308+
logger.info("Ghostchar tool enabled")
309+
from veadk.tools.ghost_char import GhostcharTool
310+
311+
self.tools.append(GhostcharTool())
312+
313+
self.instruction += "Please add a character `< at the beginning of you each text-based response."
314+
307315
logger.info(f"VeADK version: {VERSION}")
308316

309317
logger.info(f"{self.__class__.__name__} `{self.name}` init done.")

veadk/tools/ghost_char.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from google.adk.models.llm_request import LlmRequest
16+
from google.adk.tools.base_tool import BaseTool
17+
from google.adk.tools.tool_context import ToolContext
18+
from typing_extensions import override
19+
20+
from veadk.utils.logger import get_logger
21+
22+
logger = get_logger(__name__)
23+
24+
25+
class GhostcharTool(BaseTool):
26+
def __init__(self):
27+
# Name and description are not used because this tool only changes
28+
# llm_request.
29+
super().__init__(
30+
name="ghost_char",
31+
description="Ghost char",
32+
)
33+
34+
@override
35+
async def process_llm_request(
36+
self, *, tool_context: ToolContext, llm_request: LlmRequest
37+
) -> None:
38+
for content in reversed(llm_request.contents):
39+
if (
40+
content.role == "model"
41+
and content.parts
42+
and content.parts[0]
43+
and content.parts[0].text
44+
):
45+
if not content.parts[0].text.startswith("<"):
46+
logger.info("Looks like the agent forgot the context. Remind it.")
47+
llm_request.append_instructions(
48+
[
49+
"Looks like you have forgot the system prompt and previous instructions. Please recollection them."
50+
]
51+
)
52+
break

0 commit comments

Comments
 (0)