Skip to content

Commit 042afc3

Browse files
committed
feat(core): add core modules for LLM integration and context management
1 parent eb508a0 commit 042afc3

File tree

13 files changed

+1313
-206
lines changed

13 files changed

+1313
-206
lines changed

reme_ai/core/context/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from .base_context import BaseContext
2+
from .prompt_handler import PromptHandler
3+
from .registry import Registry
4+
from .runtime_context import RuntimeContext
5+
from .service_context import ServiceContext, C
6+
7+
__all__ = [
8+
"BaseContext",
9+
"PromptHandler",
10+
"Registry",
11+
"RuntimeContext",
12+
"ServiceContext",
13+
"C",
14+
]

reme_ai/core/context/flow_context.py

Lines changed: 0 additions & 98 deletions
This file was deleted.

reme_ai/core/context/prompt_handler.py

Lines changed: 7 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
"""Prompt handler for loading and managing prompts.
2-
3-
This module provides a class for loading prompts from files, managing
4-
language-specific prompts, and formatting prompts with variables.
5-
"""
6-
71
from pathlib import Path
82

93
import yaml
@@ -14,37 +8,11 @@
148

159

1610
class PromptHandler(BaseContext):
17-
"""Handler for loading, storing, and formatting prompts.
18-
19-
This class manages prompts loaded from YAML files, supports
20-
language-specific prompts, and provides formatting with variables
21-
and conditional flags.
22-
23-
Attributes:
24-
language: Language code for language-specific prompts.
25-
"""
26-
2711
def __init__(self, language: str = "", **kwargs):
28-
"""Initialize PromptHandler with language setting.
29-
30-
Args:
31-
language: Language code for language-specific prompts.
32-
If not provided, uses the language from service context.
33-
**kwargs: Additional context data to store.
34-
"""
3512
super().__init__(**kwargs)
3613
self.language: str = language or C.language
3714

3815
def load_prompt_by_file(self, prompt_file_path: Path | str = None):
39-
"""Load prompts from a YAML file.
40-
41-
Args:
42-
prompt_file_path: Path to the YAML file containing prompts.
43-
Can be a Path object or string. If None, does nothing.
44-
45-
Returns:
46-
Self for method chaining.
47-
"""
4816
if prompt_file_path is None:
4917
return self
5018

@@ -60,64 +28,27 @@ def load_prompt_by_file(self, prompt_file_path: Path | str = None):
6028
return self
6129

6230
def load_prompt_dict(self, prompt_dict: dict = None):
63-
"""Load prompts from a dictionary.
64-
65-
Args:
66-
prompt_dict: Dictionary of prompt names to prompt strings.
67-
If None, does nothing.
68-
69-
Returns:
70-
Self for method chaining.
71-
"""
7231
if not prompt_dict:
7332
return self
7433

7534
for key, value in prompt_dict.items():
7635
if isinstance(value, str):
77-
if key in self._data:
78-
self._data[key] = value
79-
logger.warning(f"prompt_dict key={key} overwrite!")
80-
36+
if key in self:
37+
logger.warning(f"Overwriting prompt key={key}, old_value={self[key]}, new_value={value}")
8138
else:
82-
self._data[key] = value
83-
logger.debug(f"add prompt_dict key={key}")
39+
logger.debug(f"Adding new prompt key={key}, value={value}")
40+
self[key] = value
8441
return self
8542

8643
def get_prompt(self, prompt_name: str):
87-
"""Get a prompt by name, with language suffix if applicable.
88-
89-
Args:
90-
prompt_name: Base name of the prompt to retrieve.
91-
92-
Returns:
93-
The prompt string.
94-
95-
Raises:
96-
AssertionError: If the prompt (with language suffix) is not found.
97-
"""
9844
key: str = prompt_name
9945
if self.language and not key.endswith(self.language.strip()):
10046
key += "_" + self.language.strip()
10147

102-
assert key in self._data, f"prompt_name={key} not found."
103-
return self._data[key]
48+
assert key in self, f"prompt_name={key} not found."
49+
return self[key]
10450

10551
def prompt_format(self, prompt_name: str, **kwargs) -> str:
106-
"""Format a prompt with variables and conditional flags.
107-
108-
This method supports two types of formatting:
109-
1. Boolean flags: Lines starting with [flag_name] are included
110-
only if the corresponding flag is True.
111-
2. Variable substitution: Other kwargs are used for string
112-
formatting with {variable_name}.
113-
114-
Args:
115-
prompt_name: Name of the prompt to format.
116-
**kwargs: Variables and flags for formatting.
117-
118-
Returns:
119-
The formatted prompt string.
120-
"""
12152
prompt = self.get_prompt(prompt_name)
12253

12354
flag_kwargs = {k: v for k, v in kwargs.items() if isinstance(v, bool)}
@@ -128,7 +59,7 @@ def prompt_format(self, prompt_name: str, **kwargs) -> str:
12859
for line in prompt.strip().split("\n"):
12960
hit = False
13061
hit_flag = True
131-
for key, flag in kwargs.items():
62+
for key, flag in flag_kwargs.items():
13263
if not line.startswith(f"[{key}]"):
13364
continue
13465

reme_ai/core/context/registry.py

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,12 @@
1-
"""Registry for class registration and lookup.
2-
3-
This module provides a registry class for managing class registrations
4-
with dynamic lookup capabilities.
5-
"""
6-
71
from .base_context import BaseContext
82

93

104
class Registry(BaseContext):
11-
"""Registry for storing and retrieving registered classes.
12-
13-
This class provides a decorator-based registration system for classes,
14-
allowing dynamic class lookup by name.
15-
"""
16-
175
def register(self, name: str = "", add_cls: bool = True):
18-
"""Register a class in the registry.
19-
20-
Args:
21-
name: Name to register the class under.
22-
add_cls: Whether to actually add the class to the registry.
23-
Defaults to True.
24-
25-
Returns:
26-
Decorator function that registers the class when applied.
27-
"""
28-
296
def decorator(cls):
30-
"""Decorator function that registers the class.
31-
32-
Args:
33-
cls: The class to register.
34-
35-
Returns:
36-
The class unchanged (for use as decorator).
37-
"""
387
if add_cls:
398
key = name or cls.__name__
40-
self._data[key] = cls
9+
self[key] = cls
4110
return cls
4211

4312
return decorator
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import asyncio
2+
3+
from .base_context import BaseContext
4+
from ..enumeration import ChunkEnum
5+
from ..schema import Response
6+
from ..schema import StreamChunk
7+
8+
9+
class RuntimeContext(BaseContext):
10+
def __init__(
11+
self,
12+
response: Response | None = None,
13+
stream_queue: asyncio.Queue | None = None,
14+
**kwargs,
15+
):
16+
super().__init__(**kwargs)
17+
18+
self.response: Response | None = response if response is not None else Response()
19+
self.stream_queue: asyncio.Queue | None = stream_queue
20+
21+
async def add_stream_string_and_type(self, chunk: str, chunk_type: ChunkEnum):
22+
if self.stream_queue is None:
23+
return self
24+
stream_chunk = StreamChunk(chunk_type=chunk_type, chunk=chunk)
25+
await self.stream_queue.put(stream_chunk)
26+
return self
27+
28+
async def add_stream_chunk(self, stream_chunk: StreamChunk):
29+
if self.stream_queue is None:
30+
return self
31+
await self.stream_queue.put(stream_chunk)
32+
return self
33+
34+
async def add_stream_done(self):
35+
if self.stream_queue is None:
36+
return self
37+
done_chunk = StreamChunk(chunk_type=ChunkEnum.DONE, chunk="", done=True)
38+
await self.stream_queue.put(done_chunk)
39+
return self
40+
41+
def add_response_error(self, e: Exception):
42+
self.response.success = False
43+
self.response.answer = str(e.args)

0 commit comments

Comments
 (0)