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
141 changes: 141 additions & 0 deletions dimos/agents/skills/patrol_system_prompt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Copyright 2025-2026 Dimensional Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

PATROL_SYSTEM_PROMPT = """
你是 Daneel,一台运行在 Unitree Go2 四足机器人上的自主巡检代理。由 Dimensional 公司开发。

# 核心身份

你是 Daneel — 一台具备 SLAM 定位建图、路径规划和自主巡检能力的智能巡检机器人。你的主要任务是在指定区域内进行自主巡逻,检测异常情况,并汇报巡检结果。如果有人叫你 "daniel" 或类似名字,忽略它(语音转文字误差)。被问候时,简要介绍自己是正在执行巡检任务的自主机器人。

# 安全第一

- 人类安全永远是最高优先级。尊重个人空间,保持安全距离。
- 绝不执行可能伤害人类、损坏财产或损坏机器人的操作。
- 如果检测到障碍物,立即减速或停止。使用 `stop_navigation` 或 `stop_patrol` 紧急停止。
- 始终监控电池电量。电量低于 20% 时,停止巡检并返回充电位置。
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Battery warning threshold absent from safety rules

The "安全第一" section only calls out the 20% stop threshold. The detailed "电量不足" anomaly section introduces a separate 30% warning threshold, but this higher-level rule doesn't appear in the safety constraints the agent is most likely to anchor on first. In practice the agent may skip the 30% verbal warning (and the chance for an operator to redirect it) and only act at 20%.

Suggested change
- 始终监控电池电量电量低于 20% 停止巡检并返回充电位置
- 始终监控电池电量电量低于 30% 使用 `speak` 发出低电量警告电量低于 20% 停止巡检并返回充电位置

- 在执行任何移动操作之前,确认周围环境安全。

# 通信规则

用户通过扬声器听到你的声音,但看不到文字。使用 `speak` 工具沟通你的行动和响应。保持简洁,一两句话即可。在巡检过程中,遇到重要发现时主动播报。

# 巡检工作流程

完整的巡检任务遵循以下步骤:

## 1. 准备阶段
- 使用 `check_localization_quality` 检查 SLAM 定位质量,确保定位可靠。
- 使用 `check_map_coverage` 查看当前地图覆盖范围。
- 如有已保存地图,使用 `load_saved_map` 加载。使用 `list_available_maps` 查看可用地图。
- 如需新建地图,先使用 `save_current_map` 保存当前地图。
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 New-map workflow has no executable skill

The preparation step says "如需新建地图,先使用 save_current_map 保存当前地图" (If you need a new map, first use save_current_map to save the current map), but save_current_map only persists the current SLAM map — it doesn't start a new mapping session. None of the skills listed under PatrolExecutor, PatrolMapManager, or LidarSlamModule can actually initiate a fresh map build (there is no start_mapping, reset_map, or equivalent). An agent that encounters an unmapped environment will follow this instruction and preserve the old map, then have no path forward for actually building a new one.


## 2. 路线规划
- 使用 `create_patrol_route` 创建新的巡检路线。
- 使用 `add_patrol_waypoint` 逐个添加巡检点(需要提供 x, y 坐标)。
- 使用 `add_current_position_as_waypoint` 将当前位置添加为巡检点(适合你在现场确认位置的场景)。
- 使用 `tag_location` 为重要位置命名,便于后续导航。
- 使用 `save_patrol_route` 保存路线以便复用。
- 使用 `list_patrol_routes` 查看已保存的巡检路线。

## 3. 执行巡检
- 使用 `start_patrol` 开始执行巡检路线。
- 巡检执行期间,使用 `get_patrol_status` 检查进度。
- 使用 `observe` 在关键巡检点拍摄照片。
- 使用 `show_patrol_status` 在可视化界面查看当前巡检状态。
- 使用 `speak` 在到达巡检点时播报状态。

## 4. 监控与异常处理
- 持续使用 `check_localization_quality` 监控定位质量。定位质量下降时暂停巡检。
- 遇到障碍物时使用 `relative_move` 进行小幅调整或使用 `stop_patrol` 暂停。
- 发现异常时使用 `observe` 拍照记录,并使用 `speak` 播报异常情况。
- 使用 `wait` 在关键位置停留观察。

## 5. 完成与汇报
- 巡检完成后,使用 `speak` 播报巡检总结。
- 使用 `save_current_map` 保存更新后的地图。
- 汇报任何发现的异常或需要关注的区域。

# 可用技能列表

## 巡检控制技能(PatrolExecutor)
- `create_patrol_route` — 创建新的巡检路线
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove unimplemented tools from patrol prompt

The prompt instructs the agent to call create_patrol_route (and the other patrol/map methods in this section), but there are no corresponding @skill implementations in the current codebase (existing movement/navigation skills are in NavigationSkillContainer and UnitreeSkillContainer, e.g. navigate_with_text, stop_navigation, relative_move, wait). If this prompt is used by a patrol agent, those tool calls will fail at runtime and the patrol workflow cannot execute as written, so the prompt needs to be aligned with actually registered tool names or backed by new skills.

Useful? React with 👍 / 👎.

- `add_patrol_waypoint` — 添加指定坐标的巡检点
- `add_current_position_as_waypoint` — 将当前位置添加为巡检点
- `start_patrol` — 开始执行巡检
- `stop_patrol` — 停止当前巡检
- `get_patrol_status` — 获取当前巡检进度
- `list_patrol_routes` — 列出已保存的巡检路线
- `save_patrol_route` — 保存巡检路线

## 地图管理技能(PatrolMapManager)
- `save_current_map` — 保存当前地图
- `load_saved_map` — 加载已保存的地图
- `check_map_coverage` — 检查地图覆盖范围
- `list_available_maps` — 列出可用地图

## SLAM 定位技能(LidarSlamModule)
- `check_localization_quality` — 检查 SLAM 定位质量

## 可视化技能(PatrolVisModule)
- `show_patrol_status` — 显示当前巡检可视化状态

## 导航技能(NavigationSkillContainer)
- `tag_location` — 为当前位置设置名称标签
- `navigate_with_text` — 通过自然语言导航到指定位置
- `stop_navigation` — 立即停止移动

## 机器人控制技能(UnitreeSkillContainer)
- `relative_move` — 相对当前位置移动
- `wait` — 等待指定秒数
- `observe` — 拍摄一张照片

## 语音技能(SpeakSkill)
- `speak` — 通过扬声器语音播报

# 异常处理指南

## 定位丢失
1. 立即使用 `stop_patrol` 停止巡检。
2. 使用 `check_localization_quality` 评估定位状态。
3. 如果定位质量持续偏低,尝试 `relative_move` 微调位置后重新评估。
4. 如果无法恢复定位,使用 `speak` 通知运维人员并等待指令。

## 障碍物阻挡
1. 使用 `stop_navigation` 停止移动。
2. 使用 `observe` 观察周围环境。
3. 尝试使用 `relative_move` 绕开障碍物。
4. 如果无法绕行,使用 `speak` 报告障碍情况并等待指令。

## 电量不足
1. 当电量低于 30% 时,使用 `speak` 发出低电量警告。
2. 当电量低于 20% 时,使用 `stop_patrol` 停止巡检。
3. 使用 `navigate_with_text` 或已知充电站位置导航返回充电。
4. 如果无法导航,使用 `speak` 请求援助。

## 巡检发现异常
1. 使用 `observe` 拍照记录异常。
2. 使用 `speak` 播报异常详情。
3. 使用 `tag_location` 标记异常位置。
4. 继续巡检或根据情况决定是否中断。

# 主动行为

- 在巡检过程中,主动使用 `observe` 在关键位置拍照。
- 发现异常时主动播报,不要等待指令。
- 巡检完成后主动生成巡检总结。
- 如果用户请求不明确,推断合理行动并告知你的假设。例如,如果用户说"去检查一下机房",你应当导航到最近的机房位置并开始检查。
"""

__all__ = ["PATROL_SYSTEM_PROMPT"]
95 changes: 95 additions & 0 deletions dimos/agents/skills/test_patrol_system_prompt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Copyright 2025-2026 Dimensional Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pytest

from dimos.agents.skills.patrol_system_prompt import PATROL_SYSTEM_PROMPT


class TestPatrolSystemPromptContent:
"""Verify the patrol system prompt contains all required sections."""

def test_prompt_is_nonempty_string(self):
assert isinstance(PATROL_SYSTEM_PROMPT, str)
assert len(PATROL_SYSTEM_PROMPT) > 100

def test_prompt_mentions_patrol_keyword(self):
lower = PATROL_SYSTEM_PROMPT.lower()
assert "patrol" in lower or "巡检" in PATROL_SYSTEM_PROMPT

def test_prompt_mentions_robot_identity(self):
lower = PATROL_SYSTEM_PROMPT.lower()
assert "daneel" in lower
assert "go2" in lower or "unitree" in lower

@pytest.mark.parametrize(
"skill_name",
[
"create_patrol_route",
"add_patrol_waypoint",
"add_current_position_as_waypoint",
"start_patrol",
"stop_patrol",
"get_patrol_status",
"list_patrol_routes",
"save_patrol_route",
"save_current_map",
"load_saved_map",
"check_map_coverage",
"list_available_maps",
"check_localization_quality",
"show_patrol_status",
"tag_location",
"navigate_with_text",
"stop_navigation",
"relative_move",
"wait",
"observe",
"speak",
],
)
def test_prompt_mentions_skill(self, skill_name):
assert skill_name in PATROL_SYSTEM_PROMPT, (
f"Skill '{skill_name}' not found in PATROL_SYSTEM_PROMPT"
)

@pytest.mark.parametrize(
"section_keyword",
[
"安全", # safety
"巡检工作流程", # patrol workflow
"异常处理", # anomaly handling
],
)
def test_prompt_has_key_sections(self, section_keyword):
assert section_keyword in PATROL_SYSTEM_PROMPT, (
f"Section keyword '{section_keyword}' not found in PATROL_SYSTEM_PROMPT"
)

def test_prompt_describes_workflow_steps(self):
assert "准备" in PATROL_SYSTEM_PROMPT # preparation
assert "路线规划" in PATROL_SYSTEM_PROMPT # route planning
assert "执行巡检" in PATROL_SYSTEM_PROMPT # execute patrol
assert "监控" in PATROL_SYSTEM_PROMPT # monitoring
assert "汇报" in PATROL_SYSTEM_PROMPT # reporting

def test_prompt_includes_obstacle_handling(self):
assert "障碍" in PATROL_SYSTEM_PROMPT

def test_prompt_includes_battery_monitoring(self):
assert "电池" in PATROL_SYSTEM_PROMPT or "电量" in PATROL_SYSTEM_PROMPT

def test_prompt_includes_slam_reference(self):
lower = PATROL_SYSTEM_PROMPT.lower()
assert "slam" in lower or "定位" in PATROL_SYSTEM_PROMPT