Skip to content

Commit d05df39

Browse files
separated into it's own command system-prompt
1 parent a836157 commit d05df39

File tree

3 files changed

+155
-45
lines changed

3 files changed

+155
-45
lines changed

src/codegate/db/connection.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,7 @@ async def add_workspace(self, workspace_name: str) -> Optional[Workspace]:
256256
It may raise a ValidationError if the workspace name is invalid.
257257
or a AlreadyExistsError if the workspace already exists.
258258
"""
259-
workspace = Workspace(id=str(uuid.uuid4()), name=workspace_name)
260-
259+
workspace = Workspace(id=str(uuid.uuid4()), name=workspace_name, system_prompt=None)
261260
sql = text(
262261
"""
263262
INSERT INTO workspaces (id, name)

src/codegate/pipeline/cli/cli.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
PipelineResult,
99
PipelineStep,
1010
)
11-
from codegate.pipeline.cli.commands import Version, Workspace
11+
from codegate.pipeline.cli.commands import SystemPrompt, Version, Workspace
1212

1313
HELP_TEXT = """
1414
## CodeGate CLI\n
@@ -32,6 +32,7 @@ async def codegate_cli(command):
3232
available_commands = {
3333
"version": Version().exec,
3434
"workspace": Workspace().exec,
35+
"system-prompt": SystemPrompt().exec,
3536
}
3637
out_func = available_commands.get(command[0])
3738
if out_func is None:

src/codegate/pipeline/cli/commands.py

+152-42
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from abc import ABC, abstractmethod
2-
from typing import List
2+
from typing import Awaitable, Callable, Dict, List, Tuple
33

44
from pydantic import ValidationError
55

@@ -8,18 +8,29 @@
88
from codegate.workspaces import crud
99

1010

11+
class NoFlagValueError(Exception):
12+
pass
13+
14+
class NoSubcommandError(Exception):
15+
pass
16+
1117
class CodegateCommand(ABC):
1218
@abstractmethod
1319
async def run(self, args: List[str]) -> str:
1420
pass
1521

22+
@property
23+
@abstractmethod
24+
def command_name(self) -> str:
25+
pass
26+
1627
@property
1728
@abstractmethod
1829
def help(self) -> str:
1930
pass
2031

2132
async def exec(self, args: List[str]) -> str:
22-
if args and args[0] == "-h":
33+
if len(args) > 0 and args[0] == "-h":
2334
return self.help
2435
return await self.run(args)
2536

@@ -28,6 +39,10 @@ class Version(CodegateCommand):
2839
async def run(self, args: List[str]) -> str:
2940
return f"CodeGate version: {__version__}"
3041

42+
@property
43+
def command_name(self) -> str:
44+
return "version"
45+
3146
@property
3247
def help(self) -> str:
3348
return (
@@ -38,18 +53,90 @@ def help(self) -> str:
3853
)
3954

4055

41-
class Workspace(CodegateCommand):
56+
class CodegateCommandSubcommand(CodegateCommand):
57+
58+
@property
59+
@abstractmethod
60+
def subcommands(self) -> Dict[str, Callable[[List[str]], Awaitable[str]]]:
61+
pass
62+
63+
@property
64+
@abstractmethod
65+
def flags(self) -> List[str]:
66+
pass
67+
68+
def _parse_flags_and_subocomand(self, args: List[str]) -> Tuple[Dict[str, str], List[str], str]:
69+
i = 0
70+
read_flags = {}
71+
# Parse all recognized flags at the start
72+
while i < len(args):
73+
if args[i] in self.flags:
74+
flag_name = args[i]
75+
if i + 1 >= len(args):
76+
raise NoFlagValueError(f"Flag {flag_name} needs a value, but none provided.")
77+
read_flags[flag_name] = args[i+1]
78+
i += 2
79+
else:
80+
# Once we encounter something that's not a recognized flag,
81+
# we assume it's the subcommand
82+
break
83+
84+
if i >= len(args):
85+
raise NoSubcommandError("No subcommand found after optional flags.")
86+
87+
subcommand = args[i]
88+
i += 1
89+
90+
# The rest of the arguments after the subcommand
91+
rest = args[i:]
92+
return read_flags, rest, subcommand
93+
94+
async def run(self, args: List[str]) -> str:
95+
try:
96+
flags, rest, subcommand = self._parse_flags_and_subocomand(args)
97+
except NoFlagValueError:
98+
return (
99+
f"Error reading the command. Flag without value found. "
100+
f"Use `codegate {self.command_name} -h` to see available subcommands"
101+
)
102+
except NoSubcommandError:
103+
return (
104+
f"Submmand not found "
105+
f"Use `codegate {self.command_name} -h` to see available subcommands"
106+
)
107+
108+
command_to_execute = self.subcommands.get(subcommand)
109+
if command_to_execute is None:
110+
return (
111+
f"Submmand not found "
112+
f"Use `codegate {self.command_name} -h` to see available subcommands"
113+
)
114+
115+
return await command_to_execute(flags, rest)
116+
117+
118+
class Workspace(CodegateCommandSubcommand):
42119

43120
def __init__(self):
44121
self.workspace_crud = crud.WorkspaceCrud()
45-
self.commands = {
122+
123+
@property
124+
def command_name(self) -> str:
125+
return "workspace"
126+
127+
@property
128+
def flags(self) -> List[str]:
129+
return []
130+
131+
@property
132+
def subcommands(self) -> Dict[str, Callable[[List[str]], Awaitable[str]]]:
133+
return {
46134
"list": self._list_workspaces,
47135
"add": self._add_workspace,
48136
"activate": self._activate_workspace,
49-
"system-prompt": self._add_system_prompt,
50137
}
51138

52-
async def _list_workspaces(self, *args: List[str]) -> str:
139+
async def _list_workspaces(self, flags: Dict[str, str], args: List[str]) -> str:
53140
"""
54141
List all workspaces
55142
"""
@@ -62,7 +149,7 @@ async def _list_workspaces(self, *args: List[str]) -> str:
62149
respond_str += "\n"
63150
return respond_str
64151

65-
async def _add_workspace(self, args: List[str]) -> str:
152+
async def _add_workspace(self, flags: Dict[str, str], args: List[str]) -> str:
66153
"""
67154
Add a workspace
68155
"""
@@ -84,7 +171,7 @@ async def _add_workspace(self, args: List[str]) -> str:
84171

85172
return f"Workspace `{new_workspace_name}` has been added"
86173

87-
async def _activate_workspace(self, args: List[str]) -> str:
174+
async def _activate_workspace(self, flags: Dict[str, str], args: List[str]) -> str:
88175
"""
89176
Activate a workspace
90177
"""
@@ -105,18 +192,60 @@ async def _activate_workspace(self, args: List[str]) -> str:
105192
return "An error occurred while activating the workspace"
106193
return f"Workspace **{workspace_name}** has been activated"
107194

108-
async def _add_system_prompt(self, args: List[str]):
109-
if len(args) < 2:
195+
@property
196+
def help(self) -> str:
197+
return (
198+
"### CodeGate Workspace\n"
199+
"Manage workspaces.\n\n"
200+
"**Usage**: `codegate workspace <command> [args]`\n\n"
201+
"Available commands:\n"
202+
"- `list`: List all workspaces\n"
203+
" - *args*: None\n"
204+
" - **Usage**: `codegate workspace list`\n"
205+
"- `add`: Add a workspace\n"
206+
" - *args*:\n"
207+
" - `workspace_name`\n"
208+
" - **Usage**: `codegate workspace add <workspace_name>`\n"
209+
"- `activate`: Activate a workspace\n"
210+
" - *args*:\n"
211+
" - `workspace_name`\n"
212+
" - **Usage**: `codegate workspace activate <workspace_name>`\n"
213+
)
214+
215+
216+
class SystemPrompt(CodegateCommandSubcommand):
217+
218+
def __init__(self):
219+
self.workspace_crud = crud.WorkspaceCrud()
220+
221+
@property
222+
def command_name(self) -> str:
223+
return "system-prompt"
224+
225+
@property
226+
def flags(self) -> List[str]:
227+
return ["-w"]
228+
229+
@property
230+
def subcommands(self) -> Dict[str, Callable[[List[str]], Awaitable[str]]]:
231+
return {
232+
"set": self._set_system_prompt,
233+
}
234+
235+
async def _set_system_prompt(self, flags: Dict[str, str], args: List[str]) -> str:
236+
if len(args) == 0:
110237
return (
111238
"Please provide a workspace name and a system prompt. "
112-
"Use `codegate workspace system-prompt <workspace_name> <system_prompt>`"
239+
"Use `codegate workspace system-prompt -w <workspace_name> <system_prompt>`"
113240
)
114241

115-
workspace_name = args[0]
116-
sys_prompt_lst = args[1:]
242+
workspace_name = flags.get("-w")
243+
if not workspace_name:
244+
active_workspace = await self.workspace_crud.get_active_workspace()
245+
workspace_name = active_workspace.name
117246

118247
updated_worksapce = await self.workspace_crud.update_workspace_system_prompt(
119-
workspace_name, sys_prompt_lst
248+
workspace_name, args
120249
)
121250
if not updated_worksapce:
122251
return (
@@ -128,37 +257,18 @@ async def _add_system_prompt(self, args: List[str]):
128257
f"updated to:\n```\n{updated_worksapce.system_prompt}\n```"
129258
)
130259

131-
async def run(self, args: List[str]) -> str:
132-
if not args:
133-
return "Please provide a command. Use `codegate workspace -h` to see available commands"
134-
command = args[0]
135-
command_to_execute = self.commands.get(command)
136-
if command_to_execute is not None:
137-
return await command_to_execute(args[1:])
138-
else:
139-
return "Command not found. Use `codegate workspace -h` to see available commands"
140-
141260
@property
142261
def help(self) -> str:
143262
return (
144-
"### CodeGate Workspace\n"
145-
"Manage workspaces.\n\n"
146-
"**Usage**: `codegate workspace <command> [args]`\n\n"
263+
"### CodeGate System Prompt\n"
264+
"Manage the system prompts of workspaces.\n\n"
265+
"**Usage**: `codegate system-prompt -w <workspace_name> <command>`\n\n"
266+
"*args*:\n"
267+
"- `workspace_name`: Optional workspace name. If not specified will use the "
268+
"active workspace\n\n"
147269
"Available commands:\n"
148-
"- `list`: List all workspaces\n"
149-
" - *args*: None\n"
150-
" - **Usage**: `codegate workspace list`\n"
151-
"- `add`: Add a workspace\n"
270+
"- `set`: Set the system prompt of the workspace\n"
152271
" - *args*:\n"
153-
" - `workspace_name`\n"
154-
" - **Usage**: `codegate workspace add <workspace_name>`\n"
155-
"- `activate`: Activate a workspace\n"
156-
" - *args*:\n"
157-
" - `workspace_name`\n"
158-
" - **Usage**: `codegate workspace activate <workspace_name>`\n"
159-
"- `system-prompt`: Modify the system-prompt of a workspace\n"
160-
" - *args*:\n"
161-
" - `workspace_name`\n"
162-
" - `system_prompt`\n"
163-
" - **Usage**: `codegate workspace system-prompt <workspace_name> <system_prompt>`\n"
272+
" - `system_prompt`: The system prompt to set\n"
273+
" - **Usage**: `codegate system-prompt -w <workspace_name> set <system_prompt>`\n"
164274
)

0 commit comments

Comments
 (0)