Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
6baa994
fix: video gen exclude edit_file
Feb 6, 2026
9c8205c
Merge branch 'main' of https://github.com/modelscope/ms-agent
Feb 9, 2026
94b833f
Merge branch 'main' of https://github.com/modelscope/ms-agent
Mar 5, 2026
11bcf06
enhance deep research v2
Mar 11, 2026
dd3f185
Merge branch 'main' of https://github.com/modelscope/ms-agent
Mar 12, 2026
693d9e9
feat: support search local paths through sirchmunk
Mar 15, 2026
05cb676
refactor: optimize architecture, restrict researcher report edits, up…
Mar 15, 2026
2977ba0
Update ms_agent/agent/llm_agent.py
suluyana Mar 16, 2026
879dba4
Apply suggestion from @gemini-code-assist[bot]
suluyana Mar 16, 2026
1dd49b6
fix local code executor; refine workflow and prompt (03)
Mar 17, 2026
c27347f
fix timeout; support for running subagent in process; support for pos…
Mar 19, 2026
5920dc4
refine readme for deep research; add run_benchmark.sh; fix counting c…
Mar 20, 2026
14cb873
Merge branch 'main' of https://github.com/modelscope/ms-agent into fe…
Mar 20, 2026
5202823
full modify?
Mar 20, 2026
24eb500
fix lint
Mar 20, 2026
986b34f
enrich researcher's reflection strategy to enhance stability
Mar 23, 2026
e6ad3e9
Merge branch 'main' of https://github.com/modelscope/ms-agent
Mar 24, 2026
88aaae6
Merge remote-tracking branch 'origin' into feat/tools
Mar 24, 2026
fec8bfe
mv localsearch to tools
Mar 24, 2026
b437bdc
thinking support beta; search_file_content fix
Mar 25, 2026
86a3ba8
support API key pool construction; support for reasoning model
Mar 27, 2026
8a32ce5
fix lint
Mar 27, 2026
393f23c
support for vertex type anthropic llm; refine reasoning output
Mar 27, 2026
49919ab
Merge branch 'main' of https://github.com/modelscope/ms-agent
Mar 31, 2026
e00c296
feat: add snapshot/rollback system to agent runtime
Apr 2, 2026
f08a15e
support for response api; optimize log output formatting
Apr 2, 2026
6bfb262
feat: merge SplitTask into AgentTool, add TaskManager infrastructure
Apr 2, 2026
db45457
feat: add run_in_background support to AgentTool
Apr 2, 2026
47bf056
feat: add TaskControlTool for LLM-accessible task management
Apr 3, 2026
e3b62dc
fix: hold strong reference to background watcher asyncio.Task to prev…
Apr 3, 2026
6286732
fix: cancel watcher tasks on AgentTool cleanup; export TaskControlToo…
Apr 3, 2026
c326139
fix: correct malformed XML in TaskManager._format_notification
Apr 3, 2026
b103ffa
test: add smoke tests for TaskManager, AgentTool dynamic spec, TaskCo…
Apr 3, 2026
7a96f8e
feat: stream sub-agent execution trace to file in real time
Apr 9, 2026
5825111
Merge branch 'main' of https://github.com/modelscope/ms-agent into fe…
Apr 9, 2026
6a1ba9f
fix lint
Apr 9, 2026
c6b1e3b
Merge branch 'main' of https://github.com/modelscope/ms-agent
Apr 10, 2026
2f2dbb0
Merge branch 'main' of https://github.com/modelscope/ms-agent
Apr 13, 2026
193e4a1
Merge remote-tracking branch 'origin' into feat/git
Apr 13, 2026
b3feb1a
feat: workspace policy, shell artifacts, TaskManager, grep/glob tools
Apr 13, 2026
ebbc72a
chore(projects): align configs with filesystem and workspace search t…
Apr 13, 2026
94ba0c3
refactor(tools): merge grep/glob into FileSystemTool
Apr 13, 2026
9841444
Merge branch 'feat/dr_reasoning' of https://github.com/alcholiclg/ms-…
Apr 13, 2026
ec5fb1a
feat(search): add Tavily engine, extract fetcher, and dr_bench wiring
Apr 20, 2026
cb75af3
fix(jina): align reader with websearch (meta fetch + playwright fallb…
Apr 20, 2026
87ae4ef
Merge origin/feat/git into bench/tavily-0413 (snapshot utils; keep be…
Apr 21, 2026
18a5683
chore(tools): use origin/feat/git filesystem_tool on bench/tavily-0413
Apr 21, 2026
e59618d
Merge feat/git into bench/tavily-0413; resolve prompts/reporter_callb…
Apr 22, 2026
ecf350b
fix(dr v2): align tavily yaml file_system include with grep/glob/edit…
Apr 22, 2026
7b49a52
Merge feat/agent-tool-overhaul into bench/tavily-0413
Apr 23, 2026
a5d4267
fix(filesystem): drop read-cache staleness gate for writes
Apr 23, 2026
00c8e86
fix(deep-research): harden tools, snapshots, and reporter/searcher co…
Apr 27, 2026
e5890f6
Merge branch 'bench/tavily-0413' into feat/tools
Apr 27, 2026
67668e9
fix lint
Apr 28, 2026
2d96611
Revert "fix lint"
Apr 28, 2026
34d5e92
fix lint
Apr 28, 2026
4d8129b
feat: harden tool system, agent rollback, and Python 3.9 compatibility
Jun 30, 2026
84aa0a6
feat: enable file_system and code_executor tools in default agent config
Jun 30, 2026
0d6053b
merge: integrate upstream/main into feat/self_improve
Jul 3, 2026
90dea45
fix: resolve 10 permission framework false positives (TB 2.1: 60.7% →…
Jul 8, 2026
6fc5354
fix: use Optional[str] for runtime type alias in path_extractors.py
Jul 8, 2026
952aff2
feat: add tb21-bench.sh benchmark management script
Jul 8, 2026
e613248
fix: restore accidentally deleted harbor_terminal_bench_agent.py
Jul 8, 2026
594b2c2
Delete ms_agent/benchmark/harbor_terminal_bench_agent.py
suluyana Jul 8, 2026
9a76a7b
fix: harden tool edge cases from code review feedback
Jul 9, 2026
461c46f
chore: untrack self_improve files from permission fix commit
Jul 9, 2026
d29b5f6
chore: untrack tb21-bench.sh from permission fix branch
Jul 9, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ MANIFEST
*.spec
release.sh
build.sh
scripts/tb21-bench.sh
*.html

# Installer logs
Expand Down
1 change: 1 addition & 0 deletions ms_agent/a2a/agent_card.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这个 PR 里有比较多的脚本在头部新增了 from __future__ import annotations,主要解决的问题是?如果暂时没有类型注解延迟求值需求的话是不是可以先不加这些。

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

主要解决兼容py3.9的问题

import os
from typing import Any, Dict, List

Expand Down
1 change: 1 addition & 0 deletions ms_agent/a2a/client.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
import os
from typing import Any, Dict, List, Optional

Expand Down
1 change: 1 addition & 0 deletions ms_agent/a2a/errors.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
from ms_agent.utils.logger import get_logger

logger = get_logger()
Expand Down
1 change: 1 addition & 0 deletions ms_agent/a2a/executor.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
import logging
import sys
from typing import Any
Expand Down
1 change: 1 addition & 0 deletions ms_agent/acp/client.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
import asyncio
from contextlib import asynccontextmanager
from typing import Any, Dict, List, Optional
Expand Down
1 change: 1 addition & 0 deletions ms_agent/acp/errors.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
from acp import RequestError


Expand Down
1 change: 1 addition & 0 deletions ms_agent/acp/http_adapter.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
import asyncio
import os
import secrets
Expand Down
1 change: 1 addition & 0 deletions ms_agent/acp/proxy.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
import logging
import os
import sys
Expand Down
1 change: 1 addition & 0 deletions ms_agent/acp/registry.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
import os
import sys
from typing import Any, Dict
Expand Down
1 change: 1 addition & 0 deletions ms_agent/acp/server.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
import logging
import sys
from typing import Any
Expand Down
1 change: 1 addition & 0 deletions ms_agent/acp/session_store.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
import asyncio
import os
import uuid
Expand Down
15 changes: 15 additions & 0 deletions ms_agent/agent/agent.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,21 @@ callbacks:
- input_callback

tools:
file_system:
mcp: false
include:
- write_file
- read_file
- edit_file
- grep
- glob
code_executor:
mcp: false
implementation: python_env
include:
- shell_executor
- python_executor
- notebook_executor

help: |
A commonly use config, try whatever you want!
1 change: 1 addition & 0 deletions ms_agent/agent/base.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
# Copyright (c) ModelScope Contributors. All rights reserved.
import os
from abc import ABC, abstractmethod
Expand Down
2 changes: 1 addition & 1 deletion ms_agent/agent/llm_agent.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
# Copyright (c) ModelScope Contributors. All rights reserved.
import asyncio
import importlib
Expand All @@ -15,7 +16,6 @@

from ms_agent.agent.runtime import Runtime
from ms_agent.callbacks import Callback, callbacks_mapping
from ms_agent.knowledge_search import SirchmunkSearch
from ms_agent.llm.llm import LLM
from ms_agent.llm.utils import Message, ToolResult
from ms_agent.memory import Memory, get_memory_meta_safe, memory_mapping
Expand Down
189 changes: 189 additions & 0 deletions ms_agent/callbacks/repetition_guard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
"""Callback that detects stuck loops and injects strategy-variation prompts.

When the agent repeats the same tool call (same name + same arguments) multiple
times without making progress, this callback injects a user message encouraging
a different approach. After ``max_warnings`` injections, the callback forces
the agent to stop to avoid wasting remaining API budget.
"""

from __future__ import annotations

import hashlib
import json
from collections import Counter
from dataclasses import dataclass
from typing import List

from omegaconf import DictConfig

from ms_agent.agent.runtime import Runtime
from ms_agent.callbacks.base import Callback
from ms_agent.llm.utils import Message
from ms_agent.utils.logger import get_logger

logger = get_logger()

_DEFAULT_THRESHOLD = 3
_DEFAULT_LOOKBACK = 8
_DEFAULT_MAX_WARNINGS = 2

_STRATEGY_PROMPT = (
"IMPORTANT: You have been repeating the same approach multiple times "
"without making progress. The exact same tool call or command has been "
"attempted {count} times with the same arguments.\n\n"
"Repeated action: {description}\n\n"
"Please try a fundamentally different strategy. Consider:\n"
"1. Check whether the prerequisites for your approach are actually met.\n"
"2. Break the problem into smaller, verifiable sub-steps.\n"
"3. Use a different tool or a different command to achieve the same goal.\n"
"4. Read error messages carefully — they often suggest specific fixes.\n"
"5. If a dependency is missing, install it before retrying.\n\n"
"Do NOT repeat the same command again."
)

_FORCE_STOP_PROMPT = (
"You have been warned multiple times about repeating the same approach, "
"but continue to retry the same failing action. "
"To conserve resources, execution is being stopped. "
"Please review the errors above and formulate a new plan before "
"the next attempt."
)


@dataclass(frozen=True)
class _Repetition:
key: str
tool_name: str
count: int
description: str


def _args_hash(arguments: str) -> str:
try:
parsed = json.loads(arguments) if isinstance(arguments, str) else arguments
except (json.JSONDecodeError, TypeError):
parsed = arguments
canonical = json.dumps(parsed, sort_keys=True, ensure_ascii=False)
return hashlib.md5(canonical.encode("utf-8")).hexdigest()[:12]


class RepetitionGuardCallback(Callback):
"""Detects stuck loops and injects strategy-variation prompts."""

def __init__(self, config: DictConfig) -> None:
super().__init__(config)
guard_cfg = getattr(config, "repetition_guard", None) or {}
self.threshold: int = int(guard_cfg.get("threshold", _DEFAULT_THRESHOLD))
self.lookback: int = int(guard_cfg.get("lookback_rounds", _DEFAULT_LOOKBACK))
self.max_warnings: int = int(guard_cfg.get("max_warnings", _DEFAULT_MAX_WARNINGS))
self._warnings_given: int = 0
self._warned_keys: set[str] = set()

async def after_tool_call(self, runtime: Runtime, messages: List[Message]) -> None:
if self._warnings_given >= self.max_warnings:
logger.info(
"[RepetitionGuard] Max warnings (%d) reached — forcing stop.",
self.max_warnings,
)
messages.append(Message(role="user", content=_FORCE_STOP_PROMPT))
runtime.should_stop = True
return

recent = _extract_recent_tool_calls(messages, self.lookback)
repetition = _detect_repetition(recent, self.threshold)

if repetition is None:
return
if repetition.key in self._warned_keys:
return

self._warned_keys.add(repetition.key)
self._warnings_given += 1
logger.info(
"[RepetitionGuard] Stuck loop detected (%s, %dx). Injecting strategy prompt. "
"Warning %d/%d.",
repetition.tool_name,
repetition.count,
self._warnings_given,
self.max_warnings,
)
runtime.should_stop = False
prompt = _STRATEGY_PROMPT.format(
count=repetition.count,
description=repetition.description,
)
messages.append(Message(role="user", content=prompt))


def _extract_recent_tool_calls(
messages: List[Message],
lookback: int,
) -> list[tuple[str, str, str]]:
"""Return ``(tool_name, args_hash, description)`` for recent rounds.

Walks backwards through *messages* collecting assistant tool-call entries.
Stops after scanning *lookback* assistant-with-tool-calls messages.
"""
calls: list[tuple[str, str, str]] = []
rounds_seen = 0

for msg in reversed(messages):
if rounds_seen >= lookback:
break
if msg.role == "assistant" and msg.tool_calls:
rounds_seen += 1
for tc in msg.tool_calls:
name = tc.get("tool_name", "")
raw_args = tc.get("arguments", "{}")
ah = _args_hash(raw_args)
desc = _summarize_call(name, raw_args)
calls.append((name, ah, desc))

return calls


def _detect_repetition(
calls: list[tuple[str, str, str]],
threshold: int,
) -> _Repetition | None:
if not calls:
return None

key_counts: Counter[str] = Counter()
key_to_info: dict[str, tuple[str, str]] = {}

for name, ah, desc in calls:
key = f"{name}:{ah}"
key_counts[key] += 1
if key not in key_to_info:
key_to_info[key] = (name, desc)

most_common_key, count = key_counts.most_common(1)[0]
if count < threshold:
return None

tool_name, description = key_to_info[most_common_key]
return _Repetition(
key=most_common_key,
tool_name=tool_name,
count=count,
description=description,
)


def _summarize_call(tool_name: str, raw_args: str) -> str:
try:
args = json.loads(raw_args) if isinstance(raw_args, str) else raw_args
except (json.JSONDecodeError, TypeError):
args = raw_args

if isinstance(args, dict) and "command" in args:
cmd = str(args["command"])
if len(cmd) > 120:
cmd = cmd[:120] + "..."
return f"{tool_name}(command={cmd})"

summary = json.dumps(args, ensure_ascii=False)
if len(summary) > 120:
summary = summary[:120] + "..."
return f"{tool_name}({summary})"
6 changes: 5 additions & 1 deletion ms_agent/callbacks/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Copyright (c) ModelScope Contributors. All rights reserved.
from ms_agent.callbacks.input_callback import InputCallback
from ms_agent.callbacks.repetition_guard import RepetitionGuardCallback

callbacks_mapping = {'input_callback': InputCallback}
callbacks_mapping = {
'input_callback': InputCallback,
'repetition_guard': RepetitionGuardCallback,
}
2 changes: 2 additions & 0 deletions ms_agent/capabilities/async_task.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

# Copyright (c) ModelScope Contributors. All rights reserved.
import asyncio
import logging
Expand Down
2 changes: 2 additions & 0 deletions ms_agent/capabilities/descriptor.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

# Copyright (c) ModelScope Contributors. All rights reserved.
import os
import shutil
Expand Down
2 changes: 2 additions & 0 deletions ms_agent/capabilities/mcp_server.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

# Copyright (c) ModelScope Contributors. All rights reserved.
import argparse
import json
Expand Down
2 changes: 2 additions & 0 deletions ms_agent/capabilities/registry.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

# Copyright (c) ModelScope Contributors. All rights reserved.
import logging
from typing import Any, Awaitable, Callable
Expand Down
2 changes: 2 additions & 0 deletions ms_agent/capabilities/wrappers/agent_delegate.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

# Copyright (c) ModelScope Contributors. All rights reserved.
import contextlib
import logging
Expand Down
1 change: 1 addition & 0 deletions ms_agent/capabilities/wrappers/code_genesis.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
# Copyright (c) ModelScope Contributors. All rights reserved.
import asyncio
import os
Expand Down
2 changes: 2 additions & 0 deletions ms_agent/capabilities/wrappers/deep_research.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

# Copyright (c) ModelScope Contributors. All rights reserved.
import asyncio
import os
Expand Down
1 change: 1 addition & 0 deletions ms_agent/capabilities/wrappers/doc_research.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
# Copyright (c) ModelScope Contributors. All rights reserved.
import asyncio
import logging
Expand Down
2 changes: 2 additions & 0 deletions ms_agent/capabilities/wrappers/filesystem.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

# Copyright (c) ModelScope Contributors. All rights reserved.
import os
from typing import Any
Expand Down
1 change: 1 addition & 0 deletions ms_agent/capabilities/wrappers/fin_research.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
# Copyright (c) ModelScope Contributors. All rights reserved.
import asyncio
import os
Expand Down
1 change: 1 addition & 0 deletions ms_agent/capabilities/wrappers/singularity_cinema.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
# Copyright (c) ModelScope Contributors. All rights reserved.
import asyncio
import os
Expand Down
1 change: 1 addition & 0 deletions ms_agent/command/builtin/context_cmds.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
from ms_agent.command.router import CommandRouter
from ms_agent.command.types import (
CommandContext,
Expand Down
1 change: 1 addition & 0 deletions ms_agent/command/types.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Awaitable, Callable, Optional
Expand Down
2 changes: 1 addition & 1 deletion ms_agent/llm/anthropic_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ def _call_llm(self,
else:
return self.client.messages.create(**params)

@retry(max_attempts=LLM.retry_count, delay=1.0)
@retry(max_attempts=LLM.retry_count, delay=3.0)
def generate(self,
messages: List[Message],
tools: Optional[List[Tool]] = None,
Expand Down
4 changes: 3 additions & 1 deletion ms_agent/llm/openai_llm.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

# Copyright (c) ModelScope Contributors. All rights reserved.
import httpx
import inspect
Expand Down Expand Up @@ -211,7 +213,7 @@ def format_tools(self,
tools = None
return tools

@retry(max_attempts=LLM.retry_count, delay=1.0)
@retry(max_attempts=LLM.retry_count, delay=3.0)
def generate(self,
messages: List[Message],
tools: Optional[List[Tool]] = None,
Expand Down
Loading