npcsh 0.1.2__py3-none-any.whl → 1.1.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. npcsh/_state.py +3508 -0
  2. npcsh/alicanto.py +65 -0
  3. npcsh/build.py +291 -0
  4. npcsh/completion.py +206 -0
  5. npcsh/config.py +163 -0
  6. npcsh/corca.py +50 -0
  7. npcsh/execution.py +185 -0
  8. npcsh/guac.py +46 -0
  9. npcsh/mcp_helpers.py +357 -0
  10. npcsh/mcp_server.py +299 -0
  11. npcsh/npc.py +323 -0
  12. npcsh/npc_team/alicanto.npc +2 -0
  13. npcsh/npc_team/alicanto.png +0 -0
  14. npcsh/npc_team/corca.npc +12 -0
  15. npcsh/npc_team/corca.png +0 -0
  16. npcsh/npc_team/corca_example.png +0 -0
  17. npcsh/npc_team/foreman.npc +7 -0
  18. npcsh/npc_team/frederic.npc +6 -0
  19. npcsh/npc_team/frederic4.png +0 -0
  20. npcsh/npc_team/guac.png +0 -0
  21. npcsh/npc_team/jinxs/code/python.jinx +11 -0
  22. npcsh/npc_team/jinxs/code/sh.jinx +34 -0
  23. npcsh/npc_team/jinxs/code/sql.jinx +16 -0
  24. npcsh/npc_team/jinxs/modes/alicanto.jinx +194 -0
  25. npcsh/npc_team/jinxs/modes/corca.jinx +249 -0
  26. npcsh/npc_team/jinxs/modes/guac.jinx +317 -0
  27. npcsh/npc_team/jinxs/modes/plonk.jinx +214 -0
  28. npcsh/npc_team/jinxs/modes/pti.jinx +170 -0
  29. npcsh/npc_team/jinxs/modes/spool.jinx +161 -0
  30. npcsh/npc_team/jinxs/modes/wander.jinx +186 -0
  31. npcsh/npc_team/jinxs/modes/yap.jinx +262 -0
  32. npcsh/npc_team/jinxs/npc_studio/npc-studio.jinx +77 -0
  33. npcsh/npc_team/jinxs/utils/agent.jinx +17 -0
  34. npcsh/npc_team/jinxs/utils/chat.jinx +44 -0
  35. npcsh/npc_team/jinxs/utils/cmd.jinx +44 -0
  36. npcsh/npc_team/jinxs/utils/compress.jinx +140 -0
  37. npcsh/npc_team/jinxs/utils/core/build.jinx +65 -0
  38. npcsh/npc_team/jinxs/utils/core/compile.jinx +50 -0
  39. npcsh/npc_team/jinxs/utils/core/help.jinx +52 -0
  40. npcsh/npc_team/jinxs/utils/core/init.jinx +41 -0
  41. npcsh/npc_team/jinxs/utils/core/jinxs.jinx +32 -0
  42. npcsh/npc_team/jinxs/utils/core/set.jinx +40 -0
  43. npcsh/npc_team/jinxs/utils/edit_file.jinx +94 -0
  44. npcsh/npc_team/jinxs/utils/load_file.jinx +35 -0
  45. npcsh/npc_team/jinxs/utils/ots.jinx +61 -0
  46. npcsh/npc_team/jinxs/utils/roll.jinx +68 -0
  47. npcsh/npc_team/jinxs/utils/sample.jinx +56 -0
  48. npcsh/npc_team/jinxs/utils/search.jinx +130 -0
  49. npcsh/npc_team/jinxs/utils/serve.jinx +26 -0
  50. npcsh/npc_team/jinxs/utils/sleep.jinx +116 -0
  51. npcsh/npc_team/jinxs/utils/trigger.jinx +61 -0
  52. npcsh/npc_team/jinxs/utils/usage.jinx +33 -0
  53. npcsh/npc_team/jinxs/utils/vixynt.jinx +144 -0
  54. npcsh/npc_team/kadiefa.npc +3 -0
  55. npcsh/npc_team/kadiefa.png +0 -0
  56. npcsh/npc_team/npcsh.ctx +18 -0
  57. npcsh/npc_team/npcsh_sibiji.png +0 -0
  58. npcsh/npc_team/plonk.npc +2 -0
  59. npcsh/npc_team/plonk.png +0 -0
  60. npcsh/npc_team/plonkjr.npc +2 -0
  61. npcsh/npc_team/plonkjr.png +0 -0
  62. npcsh/npc_team/sibiji.npc +3 -0
  63. npcsh/npc_team/sibiji.png +0 -0
  64. npcsh/npc_team/spool.png +0 -0
  65. npcsh/npc_team/yap.png +0 -0
  66. npcsh/npcsh.py +296 -112
  67. npcsh/parsing.py +118 -0
  68. npcsh/plonk.py +54 -0
  69. npcsh/pti.py +54 -0
  70. npcsh/routes.py +139 -0
  71. npcsh/spool.py +48 -0
  72. npcsh/ui.py +199 -0
  73. npcsh/wander.py +62 -0
  74. npcsh/yap.py +50 -0
  75. npcsh-1.1.13.data/data/npcsh/npc_team/agent.jinx +17 -0
  76. npcsh-1.1.13.data/data/npcsh/npc_team/alicanto.jinx +194 -0
  77. npcsh-1.1.13.data/data/npcsh/npc_team/alicanto.npc +2 -0
  78. npcsh-1.1.13.data/data/npcsh/npc_team/alicanto.png +0 -0
  79. npcsh-1.1.13.data/data/npcsh/npc_team/build.jinx +65 -0
  80. npcsh-1.1.13.data/data/npcsh/npc_team/chat.jinx +44 -0
  81. npcsh-1.1.13.data/data/npcsh/npc_team/cmd.jinx +44 -0
  82. npcsh-1.1.13.data/data/npcsh/npc_team/compile.jinx +50 -0
  83. npcsh-1.1.13.data/data/npcsh/npc_team/compress.jinx +140 -0
  84. npcsh-1.1.13.data/data/npcsh/npc_team/corca.jinx +249 -0
  85. npcsh-1.1.13.data/data/npcsh/npc_team/corca.npc +12 -0
  86. npcsh-1.1.13.data/data/npcsh/npc_team/corca.png +0 -0
  87. npcsh-1.1.13.data/data/npcsh/npc_team/corca_example.png +0 -0
  88. npcsh-1.1.13.data/data/npcsh/npc_team/edit_file.jinx +94 -0
  89. npcsh-1.1.13.data/data/npcsh/npc_team/foreman.npc +7 -0
  90. npcsh-1.1.13.data/data/npcsh/npc_team/frederic.npc +6 -0
  91. npcsh-1.1.13.data/data/npcsh/npc_team/frederic4.png +0 -0
  92. npcsh-1.1.13.data/data/npcsh/npc_team/guac.jinx +317 -0
  93. npcsh-1.1.13.data/data/npcsh/npc_team/guac.png +0 -0
  94. npcsh-1.1.13.data/data/npcsh/npc_team/help.jinx +52 -0
  95. npcsh-1.1.13.data/data/npcsh/npc_team/init.jinx +41 -0
  96. npcsh-1.1.13.data/data/npcsh/npc_team/jinxs.jinx +32 -0
  97. npcsh-1.1.13.data/data/npcsh/npc_team/kadiefa.npc +3 -0
  98. npcsh-1.1.13.data/data/npcsh/npc_team/kadiefa.png +0 -0
  99. npcsh-1.1.13.data/data/npcsh/npc_team/load_file.jinx +35 -0
  100. npcsh-1.1.13.data/data/npcsh/npc_team/npc-studio.jinx +77 -0
  101. npcsh-1.1.13.data/data/npcsh/npc_team/npcsh.ctx +18 -0
  102. npcsh-1.1.13.data/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
  103. npcsh-1.1.13.data/data/npcsh/npc_team/ots.jinx +61 -0
  104. npcsh-1.1.13.data/data/npcsh/npc_team/plonk.jinx +214 -0
  105. npcsh-1.1.13.data/data/npcsh/npc_team/plonk.npc +2 -0
  106. npcsh-1.1.13.data/data/npcsh/npc_team/plonk.png +0 -0
  107. npcsh-1.1.13.data/data/npcsh/npc_team/plonkjr.npc +2 -0
  108. npcsh-1.1.13.data/data/npcsh/npc_team/plonkjr.png +0 -0
  109. npcsh-1.1.13.data/data/npcsh/npc_team/pti.jinx +170 -0
  110. npcsh-1.1.13.data/data/npcsh/npc_team/python.jinx +11 -0
  111. npcsh-1.1.13.data/data/npcsh/npc_team/roll.jinx +68 -0
  112. npcsh-1.1.13.data/data/npcsh/npc_team/sample.jinx +56 -0
  113. npcsh-1.1.13.data/data/npcsh/npc_team/search.jinx +130 -0
  114. npcsh-1.1.13.data/data/npcsh/npc_team/serve.jinx +26 -0
  115. npcsh-1.1.13.data/data/npcsh/npc_team/set.jinx +40 -0
  116. npcsh-1.1.13.data/data/npcsh/npc_team/sh.jinx +34 -0
  117. npcsh-1.1.13.data/data/npcsh/npc_team/sibiji.npc +3 -0
  118. npcsh-1.1.13.data/data/npcsh/npc_team/sibiji.png +0 -0
  119. npcsh-1.1.13.data/data/npcsh/npc_team/sleep.jinx +116 -0
  120. npcsh-1.1.13.data/data/npcsh/npc_team/spool.jinx +161 -0
  121. npcsh-1.1.13.data/data/npcsh/npc_team/spool.png +0 -0
  122. npcsh-1.1.13.data/data/npcsh/npc_team/sql.jinx +16 -0
  123. npcsh-1.1.13.data/data/npcsh/npc_team/trigger.jinx +61 -0
  124. npcsh-1.1.13.data/data/npcsh/npc_team/usage.jinx +33 -0
  125. npcsh-1.1.13.data/data/npcsh/npc_team/vixynt.jinx +144 -0
  126. npcsh-1.1.13.data/data/npcsh/npc_team/wander.jinx +186 -0
  127. npcsh-1.1.13.data/data/npcsh/npc_team/yap.jinx +262 -0
  128. npcsh-1.1.13.data/data/npcsh/npc_team/yap.png +0 -0
  129. npcsh-1.1.13.dist-info/METADATA +522 -0
  130. npcsh-1.1.13.dist-info/RECORD +135 -0
  131. {npcsh-0.1.2.dist-info → npcsh-1.1.13.dist-info}/WHEEL +1 -1
  132. npcsh-1.1.13.dist-info/entry_points.txt +9 -0
  133. {npcsh-0.1.2.dist-info → npcsh-1.1.13.dist-info/licenses}/LICENSE +1 -1
  134. npcsh/command_history.py +0 -81
  135. npcsh/helpers.py +0 -36
  136. npcsh/llm_funcs.py +0 -295
  137. npcsh/main.py +0 -5
  138. npcsh/modes.py +0 -343
  139. npcsh/npc_compiler.py +0 -124
  140. npcsh-0.1.2.dist-info/METADATA +0 -99
  141. npcsh-0.1.2.dist-info/RECORD +0 -14
  142. npcsh-0.1.2.dist-info/entry_points.txt +0 -2
  143. {npcsh-0.1.2.dist-info → npcsh-1.1.13.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,249 @@
1
+ jinx_name: corca
2
+ description: MCP-powered agentic shell - LLM with tool use via MCP servers
3
+ inputs:
4
+ - mcp_server_path: null
5
+ - initial_command: null
6
+ - model: null
7
+ - provider: null
8
+
9
+ steps:
10
+ - name: corca_repl
11
+ engine: python
12
+ code: |
13
+ import os
14
+ import sys
15
+ import asyncio
16
+ import json
17
+ from contextlib import AsyncExitStack
18
+ from termcolor import colored
19
+
20
+ from npcpy.llm_funcs import get_llm_response
21
+ from npcpy.npc_sysenv import render_markdown, get_system_message
22
+
23
+ # MCP imports
24
+ try:
25
+ from mcp import ClientSession, StdioServerParameters
26
+ from mcp.client.stdio import stdio_client
27
+ MCP_AVAILABLE = True
28
+ except ImportError:
29
+ MCP_AVAILABLE = False
30
+ print(colored("MCP not available. Install with: pip install mcp-client", "yellow"))
31
+
32
+ npc = context.get('npc')
33
+ team = context.get('team')
34
+ messages = context.get('messages', [])
35
+ mcp_server_path = context.get('mcp_server_path')
36
+ initial_command = context.get('initial_command')
37
+
38
+ model = context.get('model') or (npc.model if npc else None)
39
+ provider = context.get('provider') or (npc.provider if npc else None)
40
+
41
+ # Use shared_context for MCP state
42
+ shared_ctx = npc.shared_context if npc and hasattr(npc, 'shared_context') else {}
43
+
44
+ print("""
45
+ ██████╗ ██████╗ ██████╗ ██████╗ █████╗
46
+ ██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔══██╗
47
+ ██║ ██║ ██║██████╔╝██║ ███████║
48
+ ██║ ██║ ██║██╔══██╗██║ ██╔══██╗
49
+ ╚██████╗╚██████╔╝██║ ██║╚██████╗██║ ██║
50
+ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝
51
+ """)
52
+
53
+ npc_name = npc.name if npc else "corca"
54
+ print(f"Entering corca mode (NPC: {npc_name}). Type '/cq' to exit.")
55
+
56
+ # ========== MCP Connection Setup ==========
57
+ async def connect_mcp(server_path):
58
+ """Connect to MCP server and return tools"""
59
+ if not MCP_AVAILABLE:
60
+ return [], {}
61
+
62
+ abs_path = os.path.abspath(os.path.expanduser(server_path))
63
+ if not os.path.exists(abs_path):
64
+ print(colored(f"MCP server not found: {abs_path}", "red"))
65
+ return [], {}
66
+
67
+ try:
68
+ loop = asyncio.get_event_loop()
69
+ except RuntimeError:
70
+ loop = asyncio.new_event_loop()
71
+ asyncio.set_event_loop(loop)
72
+
73
+ exit_stack = AsyncExitStack()
74
+
75
+ if abs_path.endswith('.py'):
76
+ cmd_parts = [sys.executable, abs_path]
77
+ else:
78
+ cmd_parts = [abs_path]
79
+
80
+ server_params = StdioServerParameters(
81
+ command=cmd_parts[0],
82
+ args=[abs_path],
83
+ env=os.environ.copy()
84
+ )
85
+
86
+ stdio_transport = await exit_stack.enter_async_context(stdio_client(server_params))
87
+ session = await exit_stack.enter_async_context(ClientSession(*stdio_transport))
88
+ await session.initialize()
89
+
90
+ response = await session.list_tools()
91
+ tools_llm = []
92
+ tool_map = {}
93
+
94
+ if response.tools:
95
+ for mcp_tool in response.tools:
96
+ tool_def = {
97
+ "type": "function",
98
+ "function": {
99
+ "name": mcp_tool.name,
100
+ "description": mcp_tool.description or f"MCP tool: {mcp_tool.name}",
101
+ "parameters": getattr(mcp_tool, "inputSchema", {"type": "object", "properties": {}})
102
+ }
103
+ }
104
+ tools_llm.append(tool_def)
105
+
106
+ # Create sync wrapper for async tool call
107
+ def make_tool_func(tool_name, sess, lp):
108
+ async def call_tool(**kwargs):
109
+ cleaned = {k: (None if v == 'None' else v) for k, v in kwargs.items()}
110
+ result = await asyncio.wait_for(sess.call_tool(tool_name, cleaned), timeout=30.0)
111
+ return result
112
+ def sync_call(**kwargs):
113
+ return lp.run_until_complete(call_tool(**kwargs))
114
+ return sync_call
115
+
116
+ tool_map[mcp_tool.name] = make_tool_func(mcp_tool.name, session, loop)
117
+
118
+ # Store in shared context
119
+ shared_ctx['mcp_client'] = session
120
+ shared_ctx['mcp_tools'] = tools_llm
121
+ shared_ctx['mcp_tool_map'] = tool_map
122
+ shared_ctx['_mcp_exit_stack'] = exit_stack
123
+ shared_ctx['_mcp_loop'] = loop
124
+
125
+ print(colored(f"Connected to MCP server. Tools: {', '.join(tool_map.keys())}", "green"))
126
+ return tools_llm, tool_map
127
+
128
+ # Try to connect if server path provided
129
+ tools_llm = shared_ctx.get('mcp_tools', [])
130
+ tool_map = shared_ctx.get('mcp_tool_map', {})
131
+
132
+ if mcp_server_path and not tools_llm:
133
+ try:
134
+ loop = asyncio.get_event_loop()
135
+ except RuntimeError:
136
+ loop = asyncio.new_event_loop()
137
+ asyncio.set_event_loop(loop)
138
+ tools_llm, tool_map = loop.run_until_complete(connect_mcp(mcp_server_path))
139
+
140
+ # Find default MCP server if none provided
141
+ if not tools_llm:
142
+ default_paths = [
143
+ os.path.expanduser("~/.npcsh/npc_team/mcp_server.py"),
144
+ os.path.join(team.team_path, "mcp_server.py") if team and hasattr(team, 'team_path') else None,
145
+ ]
146
+ for path in default_paths:
147
+ if path and os.path.exists(path):
148
+ try:
149
+ loop = asyncio.get_event_loop()
150
+ except RuntimeError:
151
+ loop = asyncio.new_event_loop()
152
+ asyncio.set_event_loop(loop)
153
+ tools_llm, tool_map = loop.run_until_complete(connect_mcp(path))
154
+ if tools_llm:
155
+ break
156
+
157
+ # Ensure system message
158
+ if not messages or messages[0].get("role") != "system":
159
+ sys_msg = get_system_message(npc) if npc else "You are an AI assistant with access to tools."
160
+ if tools_llm:
161
+ sys_msg += f"\n\nYou have access to these tools: {', '.join(t['function']['name'] for t in tools_llm)}"
162
+ messages.insert(0, {"role": "system", "content": sys_msg})
163
+
164
+ # Handle initial command if provided (one-shot mode)
165
+ if initial_command:
166
+ resp = get_llm_response(
167
+ initial_command,
168
+ model=model,
169
+ provider=provider,
170
+ messages=messages,
171
+ tools=tools_llm if tools_llm else None,
172
+ tool_map=tool_map if tool_map else None,
173
+ auto_process_tool_calls=True,
174
+ npc=npc
175
+ )
176
+ messages = resp.get('messages', messages)
177
+ render_markdown(str(resp.get('response', '')))
178
+ context['output'] = resp.get('response', 'Done.')
179
+ context['messages'] = messages
180
+ # Don't enter REPL for one-shot
181
+ exit()
182
+
183
+ # REPL loop
184
+ while True:
185
+ try:
186
+ prompt_str = f"{npc_name}:corca> "
187
+ user_input = input(prompt_str).strip()
188
+
189
+ if not user_input:
190
+ continue
191
+
192
+ if user_input.lower() == "/cq":
193
+ print("Exiting corca mode.")
194
+ break
195
+
196
+ # Handle /tools to list available tools
197
+ if user_input.lower() == "/tools":
198
+ if tools_llm:
199
+ print(colored("Available MCP tools:", "cyan"))
200
+ for t in tools_llm:
201
+ print(f" - {t['function']['name']}: {t['function'].get('description', '')[:60]}")
202
+ else:
203
+ print(colored("No MCP tools connected.", "yellow"))
204
+ continue
205
+
206
+ # Handle /connect to connect to new MCP server
207
+ if user_input.startswith("/connect "):
208
+ new_path = user_input[9:].strip()
209
+ try:
210
+ loop = asyncio.get_event_loop()
211
+ except RuntimeError:
212
+ loop = asyncio.new_event_loop()
213
+ asyncio.set_event_loop(loop)
214
+ tools_llm, tool_map = loop.run_until_complete(connect_mcp(new_path))
215
+ continue
216
+
217
+ # Get LLM response with tools
218
+ resp = get_llm_response(
219
+ user_input,
220
+ model=model,
221
+ provider=provider,
222
+ messages=messages,
223
+ tools=tools_llm if tools_llm else None,
224
+ tool_map=tool_map if tool_map else None,
225
+ auto_process_tool_calls=True,
226
+ stream=False, # Tool calls don't work well with streaming
227
+ npc=npc
228
+ )
229
+
230
+ messages = resp.get('messages', messages)
231
+ response_text = resp.get('response', '')
232
+ render_markdown(str(response_text))
233
+
234
+ # Track usage
235
+ if 'usage' in resp and npc and hasattr(npc, 'shared_context'):
236
+ usage = resp['usage']
237
+ npc.shared_context['session_input_tokens'] += usage.get('input_tokens', 0)
238
+ npc.shared_context['session_output_tokens'] += usage.get('output_tokens', 0)
239
+ npc.shared_context['turn_count'] += 1
240
+
241
+ except KeyboardInterrupt:
242
+ print("\nUse '/cq' to exit or continue.")
243
+ continue
244
+ except EOFError:
245
+ print("\nExiting corca mode.")
246
+ break
247
+
248
+ context['output'] = "Exited corca mode."
249
+ context['messages'] = messages
@@ -0,0 +1,12 @@
1
+ name: corca
2
+ primary_directive: |
3
+ You are corca, a distinguished member of the NPC team.
4
+ Your expertise is in the area of software development and
5
+ you have a knack for thinking through problems carefully.
6
+ You favor solutions that prioritize simplicity and clarity and
7
+ ought to always consider how some suggestion may increase rather than reduce tech debt
8
+ unnecessarily. Now, the key is in this last term, "unnecessarily".
9
+ You must distinguish carefully and when in doubt, opt to ask for further
10
+ information or clarification with concrete clear options that make it
11
+ easy for a user to choose.
12
+
@@ -0,0 +1,94 @@
1
+ jinx_name: edit_file
2
+ description: Examines a file, determines what changes are needed, and applies those
3
+ changes.
4
+ inputs:
5
+ - file_path
6
+ - edit_instructions
7
+ - backup: true
8
+ steps:
9
+ - name: "edit_file"
10
+ engine: "python"
11
+ code: |
12
+ import os
13
+ from npcpy.llm_funcs import get_llm_response
14
+
15
+
16
+ file_path = os.path.expanduser("{{ file_path }}")
17
+ edit_instructions = "{{ edit_instructions }}"
18
+ backup_str = "{{ backup }}"
19
+ create_backup = backup_str.lower() not in ('false', 'no', '0', '')
20
+
21
+
22
+ with open(file_path, 'r') as f:
23
+ original_content = f.read()
24
+
25
+
26
+ if create_backup:
27
+ backup_path = file_path + ".bak"
28
+ with open(backup_path, 'w') as f:
29
+ f.write(original_content)
30
+
31
+
32
+ prompt = """You are a code editing assistant. Analyze this file and make the requested changes.
33
+
34
+ File content:
35
+ """ + original_content + """
36
+
37
+ Edit instructions: """ + edit_instructions + """
38
+
39
+ Return a JSON object with these fields:
40
+ 1. "modifications": An array of modification objects, where each object has:
41
+ - "type": One of "replace", "insert_after", "insert_before", or "delete"
42
+ - "target": For "insert_after" and "insert_before", the text to insert after/before
43
+ For "delete", the text to delete
44
+ - "original": For "replace", the text to be replaced
45
+ - "replacement": For "replace", the text to replace with
46
+ - "insertion": For "insert_after" and "insert_before", the text to insert
47
+ 2. "explanation": Brief explanation of the changes made
48
+ """
49
+
50
+ response = get_llm_response(prompt, model=npc.model, provider=npc.provider, npc=npc, format="json")
51
+
52
+ result = response.get("response", {})
53
+ modifications = result.get("modifications", [])
54
+ explanation = result.get("explanation", "No explanation provided")
55
+
56
+
57
+ updated_content = original_content
58
+ changes_applied = 0
59
+
60
+ for mod in modifications:
61
+ print(mod)
62
+ mod_type = mod.get("type")
63
+
64
+ if mod_type == "replace":
65
+ original = mod.get("original")
66
+ replacement = mod.get("replacement")
67
+ if original in updated_content:
68
+ updated_content = updated_content.replace(original, replacement)
69
+ changes_applied += 1
70
+
71
+ elif mod_type == "insert_after":
72
+ target = mod.get("target")
73
+ insertion = mod.get("insertion")
74
+ if target in updated_content:
75
+ updated_content = updated_content.replace(target, target + insertion)
76
+ changes_applied += 1
77
+
78
+ elif mod_type == "insert_before":
79
+ target = mod.get("target")
80
+ insertion = mod.get("insertion")
81
+ if target in updated_content:
82
+ updated_content = updated_content.replace(target, insertion + target)
83
+ changes_applied += 1
84
+
85
+ elif mod_type == "delete":
86
+ target = mod.get("target")
87
+ if target in updated_content:
88
+ updated_content = updated_content.replace(target, "")
89
+ changes_applied += 1
90
+
91
+ with open(file_path, 'w') as f:
92
+ f.write(updated_content)
93
+
94
+ output = "Applied " + str(changes_applied) + " changes to " + file_path + "\n\n" + explanation
@@ -0,0 +1,7 @@
1
+ name: foreman
2
+ primary_directive: You are the foreman of an NPC team. It is your duty
3
+ to delegate tasks to your team members or to other specialized teams
4
+ in order to complete the project. You are responsible for the
5
+ completion of the project and the safety of your team members.
6
+ model: gpt-4o-mini
7
+ provider: openai
@@ -0,0 +1,6 @@
1
+ name: frederic
2
+ primary_directive: |
3
+ You are frederic the polar bear. Your job is help users think through problems and
4
+ to provide straightforward ways forward on problems. Cut through the ice
5
+ to get to what matters and keep things simple. You are to respond in a
6
+ witty tone like richard feynman but with the romantic tambor of Frederic Chopin.