Skip to content

Commit 24c3ccf

Browse files
committed
feat: introduce AgentTide module for enhanced code context and patch generation
1 parent dee4bb4 commit 24c3ccf

2 files changed

Lines changed: 67 additions & 79 deletions

File tree

README.md

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,9 +446,57 @@ Here’s what’s next for CodeTide:
446446
447447
~~- 🧭 **Handle relative imports** in Python projects
448448
→ Improve resolution for intra-package navigation.~~
449-
- 🤖 **Long-term vision**: Release a native **CodeTide Agent**
450-
→ Seamless, intelligent context resolution directly integrated into the CodeTide core.
451-
→ Unlock **clinical issue detection**, **guided refactors**, and **agent-level navigation**.
449+
450+
---
451+
452+
## 🤖 Agents Module: AgentTide
453+
454+
CodeTide now includes an `agents` module, featuring **AgentTide**—a precision-driven software engineering agent that connects directly to your codebase and executes your requests with full code context.
455+
456+
**AgentTide** leverages CodeTide’s symbolic code understanding to:
457+
- Retrieve and reason about relevant code context for any request
458+
- Generate atomic, high-precision patches using strict protocols
459+
- Apply changes directly to your codebase, with robust validation
460+
461+
### Where to Find It
462+
- Source: [`codetide/agents/tide/agent.py`](codetide/agents/tide/agent.py)
463+
464+
### What It Does
465+
AgentTide acts as an autonomous agent that:
466+
- Connects to your codebase using CodeTide’s parsing and context tools
467+
- Interacts with users via a conversational interface
468+
- Identifies relevant files, classes, and functions for any request
469+
- Generates and applies diff-style patches, ensuring code quality and requirements fidelity
470+
471+
### Example Usage
472+
To use AgentTide, ensure you have the `aicore` package installed (`pip install codetide[agents]`), then instantiate and run the agent:
473+
474+
```python
475+
from codetide import CodeTide
476+
from codetide.agents.tide.agent import AgentTide
477+
from aicore.llm import Llm, LlmConfig
478+
import os, asyncio
479+
480+
async def main():
481+
tide = await CodeTide.from_path("/path/to/your/repo")
482+
llm = Llm.from_config(
483+
LlmConfig(
484+
model="deepseek-chat",
485+
provider="deepseek",
486+
temperature=0,
487+
api_key=os.getenv("DEEPSEEK-API-KEY")
488+
)
489+
)
490+
agent = AgentTide(llm=llm, tide=tide)
491+
await agent.run()
492+
493+
if __name__ == "__main__":
494+
asyncio.run(main())
495+
```
496+
497+
AgentTide will prompt you for requests, retrieve the relevant code context, and generate precise patches to fulfill your requirements.
498+
499+
For more details, see the [agents module source code](codetide/agents/tide/agent.py).
452500
453501
---
454502

examples/agent_tide.py

Lines changed: 16 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,36 @@
11
"""
2-
install aicore - pip install core-for-ai
3-
Make sure to set `CODETIDE_WORKSPACE` env var which will be requried for the MCP server to work
2+
Install the agents version with pip install codetide[agents]
43
"""
54

6-
from codetide.mcp.agent_tide_system import AGENT_TIDE_SYSTEM_PROMPT
7-
from codetide.mcp import codeTideMCPServer
5+
from codetide.mcp.utils import initCodeTide
6+
from codetide.agents.tide import AgentTide
87
from aicore.llm import Llm, LlmConfig
9-
from aicore.logger import _logger
10-
11-
from prompt_toolkit.key_binding import KeyBindings
12-
from prompt_toolkit import PromptSession
13-
from typing import Optional
148
import os
159

16-
AGENT_TIDE_ASCII_ART = """
17-
18-
█████╗ ██████╗ ███████╗███╗ ██╗████████╗ ████████╗██╗██████╗ ███████╗
19-
██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝ ╚══██╔══╝██║██╔══██╗██╔════╝
20-
███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ██║ ██║██║ ██║█████╗
21-
██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ██║ ██║██║ ██║██╔══╝
22-
██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ██║ ██║██████╔╝███████╗
23-
╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝╚═════╝ ╚══════╝
24-
25-
"""
26-
2710
def init_llm()->Llm:
2811
llm = Llm.from_config(
2912
LlmConfig(
30-
model="deepseek-chat",
31-
provider="deepseek",
13+
# model="deepseek-chat",
14+
# provider="deepseek",
15+
# api_key=os.getenv("DEEPSEEK-API-KEY")
16+
model="gpt-4.1",
17+
provider="openai",
18+
api_key=os.getenv("OPENAI-API-KEY"),
3219
temperature=0,
33-
api_key=os.getenv("DEEPSEEK-API-KEY")
3420
)
3521
)
36-
37-
llm.provider.mcp.add_server(name=codeTideMCPServer.name, parameters=codeTideMCPServer)
3822
return llm
3923

40-
def trim_messages(messages, tokenizer_fn, max_tokens :Optional[int]=None):
41-
max_tokens = max_tokens or int(os.environ.get("MAX_HISTORY_TOKENS", 1028))
42-
while messages and sum(len(tokenizer_fn(msg)) for msg in messages) > max_tokens:
43-
messages.pop(0) # Remove from the beginning
44-
45-
async def main(max_tokens: int = 48000):
24+
async def main():
4625
llm = init_llm()
47-
history = []
48-
49-
# 1. Set up key bindings
50-
bindings = KeyBindings()
51-
52-
@bindings.add('escape')
53-
def _(event):
54-
"""When Esc is pressed, exit the application."""
55-
_logger.logger.warning("Escape key pressed — exiting...")
56-
event.app.exit()
26+
tide = await initCodeTide()
5727

58-
# 2. Create a prompt session with the custom key bindings
59-
session = PromptSession(key_bindings=bindings)
28+
tide = AgentTide(llm=llm, tide=tide)
29+
await tide.run()
6030

61-
_logger.logger.info(f"\n{AGENT_TIDE_ASCII_ART}\nReady to surf. Press ESC to exit.\n")
62-
try:
63-
while True:
64-
try:
65-
# 3. Use the async prompt instead of input()
66-
message = await session.prompt_async("You: ")
67-
message = message.strip()
68-
69-
if not message:
70-
continue
71-
72-
except (EOFError, KeyboardInterrupt):
73-
# prompt_toolkit raises EOFError on Ctrl-D and KeyboardInterrupt on Ctrl-C
74-
_logger.warning("\nExiting...")
75-
break
76-
77-
history.append(message)
78-
trim_messages(history, llm.tokenizer, max_tokens)
79-
80-
print("Agent: Thinking...")
81-
response = await llm.acomplete(history, system_prompt=[AGENT_TIDE_SYSTEM_PROMPT], as_message_records=True)
82-
print(f"Agent: {response}")
83-
history.extend(response)
84-
85-
except asyncio.CancelledError:
86-
# This can happen if the event loop is shut down
87-
pass
88-
finally:
89-
_logger.logger.info("\nExited by user. Goodbye!")
90-
91-
if __name__ == "__main__":
31+
if __name__ == "__main__":
9232
from dotenv import load_dotenv
9333
import asyncio
94-
34+
9535
load_dotenv()
96-
asyncio.run(main())
36+
asyncio.run(main())

0 commit comments

Comments
 (0)