vibecore 0.2.0__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.

Potentially problematic release.


This version of vibecore might be problematic. Click here for more details.

Files changed (63) hide show
  1. vibecore/__init__.py +0 -0
  2. vibecore/agents/default.py +79 -0
  3. vibecore/agents/prompts.py +12 -0
  4. vibecore/agents/task_agent.py +66 -0
  5. vibecore/cli.py +150 -0
  6. vibecore/context.py +24 -0
  7. vibecore/handlers/__init__.py +5 -0
  8. vibecore/handlers/stream_handler.py +231 -0
  9. vibecore/main.py +506 -0
  10. vibecore/main.tcss +0 -0
  11. vibecore/mcp/__init__.py +6 -0
  12. vibecore/mcp/manager.py +167 -0
  13. vibecore/mcp/server_wrapper.py +109 -0
  14. vibecore/models/__init__.py +5 -0
  15. vibecore/models/anthropic.py +239 -0
  16. vibecore/prompts/common_system_prompt.txt +64 -0
  17. vibecore/py.typed +0 -0
  18. vibecore/session/__init__.py +5 -0
  19. vibecore/session/file_lock.py +127 -0
  20. vibecore/session/jsonl_session.py +236 -0
  21. vibecore/session/loader.py +193 -0
  22. vibecore/session/path_utils.py +81 -0
  23. vibecore/settings.py +161 -0
  24. vibecore/tools/__init__.py +1 -0
  25. vibecore/tools/base.py +27 -0
  26. vibecore/tools/file/__init__.py +5 -0
  27. vibecore/tools/file/executor.py +282 -0
  28. vibecore/tools/file/tools.py +184 -0
  29. vibecore/tools/file/utils.py +78 -0
  30. vibecore/tools/python/__init__.py +1 -0
  31. vibecore/tools/python/backends/__init__.py +1 -0
  32. vibecore/tools/python/backends/terminal_backend.py +58 -0
  33. vibecore/tools/python/helpers.py +80 -0
  34. vibecore/tools/python/manager.py +208 -0
  35. vibecore/tools/python/tools.py +27 -0
  36. vibecore/tools/shell/__init__.py +5 -0
  37. vibecore/tools/shell/executor.py +223 -0
  38. vibecore/tools/shell/tools.py +156 -0
  39. vibecore/tools/task/__init__.py +5 -0
  40. vibecore/tools/task/executor.py +51 -0
  41. vibecore/tools/task/tools.py +51 -0
  42. vibecore/tools/todo/__init__.py +1 -0
  43. vibecore/tools/todo/manager.py +31 -0
  44. vibecore/tools/todo/models.py +36 -0
  45. vibecore/tools/todo/tools.py +111 -0
  46. vibecore/utils/__init__.py +5 -0
  47. vibecore/utils/text.py +28 -0
  48. vibecore/widgets/core.py +332 -0
  49. vibecore/widgets/core.tcss +63 -0
  50. vibecore/widgets/expandable.py +121 -0
  51. vibecore/widgets/expandable.tcss +69 -0
  52. vibecore/widgets/info.py +25 -0
  53. vibecore/widgets/info.tcss +17 -0
  54. vibecore/widgets/messages.py +232 -0
  55. vibecore/widgets/messages.tcss +85 -0
  56. vibecore/widgets/tool_message_factory.py +121 -0
  57. vibecore/widgets/tool_messages.py +483 -0
  58. vibecore/widgets/tool_messages.tcss +289 -0
  59. vibecore-0.2.0.dist-info/METADATA +407 -0
  60. vibecore-0.2.0.dist-info/RECORD +63 -0
  61. vibecore-0.2.0.dist-info/WHEEL +4 -0
  62. vibecore-0.2.0.dist-info/entry_points.txt +2 -0
  63. vibecore-0.2.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,156 @@
1
+ """Shell and system tools for Vibecore agents."""
2
+
3
+ from agents import RunContextWrapper, function_tool
4
+
5
+ from vibecore.context import VibecoreContext
6
+
7
+ from .executor import bash_executor, glob_files, grep_files, list_directory
8
+
9
+
10
+ @function_tool
11
+ async def bash(
12
+ ctx: RunContextWrapper[VibecoreContext],
13
+ command: str,
14
+ timeout: int | None = None,
15
+ description: str | None = None,
16
+ ) -> str:
17
+ """Executes a given bash command in a persistent shell session with optional timeout, ensuring proper handling
18
+ and security measures.
19
+
20
+ Before executing the command, please follow these steps:
21
+
22
+ 1. Directory Verification:
23
+ - If the command will create new directories or files, first use the LS tool to verify the parent directory
24
+ exists and is the correct location
25
+ - For example, before running "mkdir foo/bar", first use LS to check that "foo" exists and is the intended
26
+ parent directory
27
+
28
+ 2. Command Execution:
29
+ - Always quote file paths that contain spaces with double quotes (e.g., cd "path with spaces/file.txt")
30
+ - Examples of proper quoting:
31
+ - cd "/Users/name/My Documents" (correct)
32
+ - cd /Users/name/My Documents (incorrect - will fail)
33
+ - python "/path/with spaces/script.py" (correct)
34
+ - python /path/with spaces/script.py (incorrect - will fail)
35
+ - After ensuring proper quoting, execute the command.
36
+ - Capture the output of the command.
37
+
38
+ Usage notes:
39
+ - The command argument is required.
40
+ - You can specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). If not specified, commands
41
+ will timeout after 120000ms (2 minutes).
42
+ - It is very helpful if you write a clear, concise description of what this command does in 5-10 words.
43
+ - If the output exceeds 30000 characters, output will be truncated before being returned to you.
44
+ - VERY IMPORTANT: You MUST avoid using search commands like `find` and `grep`. Instead use Grep, Glob, or Task
45
+ to search. You MUST avoid read tools like `cat`, `head`, `tail`, and `ls`, and use Read and LS to read files.
46
+ - If you _still_ need to run `grep`, STOP. ALWAYS USE ripgrep at `rg` first, which all users have pre-installed.
47
+ - When issuing multiple commands, use the ';' or '&&' operator to separate them. DO NOT use newlines (newlines
48
+ are ok in quoted strings).
49
+ - Try to maintain your current working directory throughout the session by using absolute paths and avoiding
50
+ usage of `cd`. You may use `cd` if the User explicitly requests it.
51
+
52
+ Args:
53
+ ctx: The run context wrapper
54
+ command: The command to execute
55
+ timeout: Optional timeout in milliseconds (max 600000)
56
+ description: Clear, concise description of what this command does in 5-10 words
57
+
58
+ Returns:
59
+ The command output or error message
60
+ """
61
+ output, exit_code = await bash_executor(command, timeout)
62
+ if exit_code != 0:
63
+ return f"{output}\nExit code: {exit_code}"
64
+ return output
65
+
66
+
67
+ @function_tool
68
+ async def glob(
69
+ ctx: RunContextWrapper[VibecoreContext],
70
+ pattern: str,
71
+ path: str | None = None,
72
+ ) -> str:
73
+ """Fast file pattern matching tool that works with any codebase size.
74
+
75
+ - Supports glob patterns like "**/*.js" or "src/**/*.ts"
76
+ - Returns matching file paths sorted by modification time
77
+ - Use this tool when you need to find files by name patterns
78
+ - When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the
79
+ Agent tool instead
80
+ - You have the capability to call multiple tools in a single response. It is always better to speculatively
81
+ perform multiple searches as a batch that are potentially useful.
82
+
83
+ Args:
84
+ ctx: The run context wrapper
85
+ pattern: The glob pattern to match files against
86
+ path: The directory to search in. If not specified, the current working directory will be used.
87
+ IMPORTANT: Omit this field to use the default directory. DO NOT enter "undefined" or "null" -
88
+ simply omit it for the default behavior. Must be a valid directory path if provided.
89
+
90
+ Returns:
91
+ List of matching file paths, one per line
92
+ """
93
+ files = await glob_files(pattern, path)
94
+ if files and files[0].startswith("Error:"):
95
+ return files[0]
96
+ return "\n".join(files) if files else "No files found matching pattern"
97
+
98
+
99
+ @function_tool
100
+ async def grep(
101
+ ctx: RunContextWrapper[VibecoreContext],
102
+ pattern: str,
103
+ path: str | None = None,
104
+ include: str | None = None,
105
+ ) -> str:
106
+ """Fast content search tool that works with any codebase size.
107
+
108
+ - Searches file contents using regular expressions
109
+ - Supports full regex syntax (eg. "log.*Error", "function\\s+\\w+", etc.)
110
+ - Filter files by pattern with the include parameter (eg. "*.js", "*.{ts,tsx}")
111
+ - Returns file paths with at least one match sorted by modification time
112
+ - Use this tool when you need to find files containing specific patterns
113
+ - If you need to identify/count the number of matches within files, use the Bash tool with `rg` (ripgrep)
114
+ directly. Do NOT use `grep`.
115
+ - When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the
116
+ Agent tool instead
117
+
118
+ Args:
119
+ ctx: The run context wrapper
120
+ pattern: The regular expression pattern to search for in file contents
121
+ path: The directory to search in. Defaults to the current working directory.
122
+ include: File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")
123
+
124
+ Returns:
125
+ List of file paths containing matches, one per line
126
+ """
127
+ files = await grep_files(pattern, path, include)
128
+ if files and files[0].startswith("Error:"):
129
+ return files[0]
130
+ return "\n".join(files) if files else "No files found containing pattern"
131
+
132
+
133
+ @function_tool
134
+ async def ls(
135
+ ctx: RunContextWrapper[VibecoreContext],
136
+ path: str,
137
+ ignore: list[str] | None = None,
138
+ ) -> str:
139
+ """Lists files and directories in a given path.
140
+
141
+ The path parameter must be an absolute path, not a relative path. You can optionally provide an array of glob
142
+ patterns to ignore with the ignore parameter. You should generally prefer the Glob and Grep tools, if you know
143
+ which directories to search.
144
+
145
+ Args:
146
+ ctx: The run context wrapper
147
+ path: The absolute path to the directory to list (must be absolute, not relative)
148
+ ignore: List of glob patterns to ignore
149
+
150
+ Returns:
151
+ List of entries in the directory, one per line
152
+ """
153
+ entries = await list_directory(path, ignore)
154
+ if entries and entries[0].startswith("Error:"):
155
+ return entries[0]
156
+ return "\n".join(entries) if entries else "Empty directory"
@@ -0,0 +1,5 @@
1
+ """Task tool for spawning sub-agents to execute specific tasks."""
2
+
3
+ from .tools import task
4
+
5
+ __all__ = ["task"]
@@ -0,0 +1,51 @@
1
+ """Task execution logic for spawning sub-agents."""
2
+
3
+ import traceback
4
+
5
+ from agents import (
6
+ Runner,
7
+ )
8
+ from textual import log
9
+
10
+ from vibecore.agents.task_agent import create_task_agent
11
+ from vibecore.context import VibecoreContext
12
+ from vibecore.settings import settings
13
+
14
+
15
+ async def execute_task(
16
+ context: VibecoreContext,
17
+ description: str,
18
+ prompt: str,
19
+ tool_name: str,
20
+ tool_call_id: str,
21
+ ) -> str:
22
+ """Execute a task using a sub-agent with streaming support.
23
+
24
+ Args:
25
+ context: The vibecore context to pass to the task agent
26
+ description: Short task description (for logging/display)
27
+ prompt: Full task instructions
28
+ tool_name: Name of the tool being invoked (e.g., "task")
29
+ tool_call_id: Unique identifier for this tool call
30
+
31
+ Returns:
32
+ Task execution results as a string with formatted sub-agent activity
33
+ """
34
+ try:
35
+ # Create the task agent
36
+ task_agent = create_task_agent(prompt)
37
+
38
+ # Run the task agent with streaming
39
+ result = Runner.run_streamed(task_agent, prompt, context=context, max_turns=settings.max_turns)
40
+
41
+ # Check if app is available for streaming
42
+ if context.app:
43
+ # Stream events to app handler
44
+ async for event in result.stream_events():
45
+ await context.app.handle_task_tool_event(tool_name, tool_call_id, event)
46
+
47
+ return result.final_output
48
+
49
+ except Exception as e:
50
+ log.error(f"Task execution error: {type(e).__name__}: {e!s}\n%s", traceback.format_exc())
51
+ return f"Task '{description}' failed with error: {e!s}"
@@ -0,0 +1,51 @@
1
+ """Task tool for spawning sub-agents to execute specific tasks."""
2
+
3
+ from agents import function_tool
4
+ from agents.tool_context import ToolContext
5
+
6
+ from vibecore.context import VibecoreContext
7
+
8
+ from .executor import execute_task
9
+
10
+
11
+ @function_tool
12
+ async def task(
13
+ ctx: ToolContext[VibecoreContext],
14
+ description: str,
15
+ prompt: str,
16
+ ) -> str:
17
+ """Launch a new agent to execute a specific task with access to all tools except the Task tool itself.
18
+
19
+ The task agent has access to: bash, glob, grep, ls, read, edit, multi_edit, write, execute_python,
20
+ todo_read, and todo_write. Use this tool when you need to delegate complex, multi-step operations
21
+ or searches to a sub-agent.
22
+
23
+ When to use the Task tool:
24
+ - When searching for a keyword like "config" or "logger" across many files
25
+ - For questions like "which file does X?" where you're not sure of the location
26
+ - When you need to perform complex multi-step operations autonomously
27
+ - When the task requires extensive file exploration or analysis
28
+
29
+ When NOT to use the Task tool:
30
+ - If you want to read a specific file path (use Read instead)
31
+ - If searching for a specific class definition like "class Foo" (use Grep instead)
32
+ - If searching within a specific file or set of 2-3 files (use Read instead)
33
+ - For simple, single-step operations (use the appropriate tool directly)
34
+
35
+ Usage notes:
36
+ 1. Launch multiple tasks concurrently when possible by using multiple tool calls
37
+ 2. The task agent returns a single final message - you should summarize results for the user
38
+ 3. Each task invocation is stateless - provide complete instructions in the prompt
39
+ 4. Clearly specify whether the agent should write code or just research/analyze
40
+ 5. The agent is not aware of the user's original request - be explicit in instructions
41
+
42
+ Args:
43
+ ctx: The run context wrapper
44
+ description: A short task description (3-5 words)
45
+ prompt: Full task instructions for the agent - be highly detailed and specify
46
+ exactly what information should be returned
47
+
48
+ Returns:
49
+ The task execution results as a string
50
+ """
51
+ return await execute_task(ctx.context, description, prompt, ctx.tool_name, ctx.tool_call_id)
@@ -0,0 +1 @@
1
+ """Todo management tools."""
@@ -0,0 +1,31 @@
1
+ """Todo list manager."""
2
+
3
+ from typing import Any
4
+
5
+ from .models import TodoItem, TodoPriority, TodoStatus
6
+
7
+
8
+ class TodoManager:
9
+ """Manages a session-scoped todo list."""
10
+
11
+ def __init__(self):
12
+ self.todos: list[TodoItem] = []
13
+
14
+ def read(self) -> list[dict[str, Any]]:
15
+ """Read all todos."""
16
+ return [
17
+ {"id": todo.id, "content": todo.content, "status": todo.status.value, "priority": todo.priority.value}
18
+ for todo in self.todos
19
+ ]
20
+
21
+ def write(self, todos: list[dict[str, Any]]) -> None:
22
+ """Replace the entire todo list."""
23
+ self.todos = [
24
+ TodoItem(
25
+ id=todo["id"],
26
+ content=todo["content"],
27
+ status=TodoStatus(todo["status"]),
28
+ priority=TodoPriority(todo["priority"]),
29
+ )
30
+ for todo in todos
31
+ ]
@@ -0,0 +1,36 @@
1
+ """Todo data models."""
2
+
3
+ import uuid
4
+ from dataclasses import dataclass, field
5
+ from enum import Enum
6
+
7
+ from pydantic import BaseModel
8
+
9
+
10
+ class TodoStatus(str, Enum):
11
+ PENDING = "pending"
12
+ IN_PROGRESS = "in_progress"
13
+ COMPLETED = "completed"
14
+
15
+
16
+ class TodoPriority(str, Enum):
17
+ HIGH = "high"
18
+ MEDIUM = "medium"
19
+ LOW = "low"
20
+
21
+
22
+ @dataclass
23
+ class TodoItem:
24
+ content: str
25
+ status: TodoStatus
26
+ priority: TodoPriority
27
+ id: str = field(default_factory=lambda: str(uuid.uuid4()))
28
+
29
+
30
+ class TodoItemModel(BaseModel):
31
+ """Pydantic model for todo items."""
32
+
33
+ id: str
34
+ content: str
35
+ status: str
36
+ priority: str
@@ -0,0 +1,111 @@
1
+ """Todo management tools."""
2
+
3
+ from typing import Any
4
+
5
+ from agents import RunContextWrapper, function_tool
6
+
7
+ from vibecore.context import VibecoreContext
8
+
9
+ from .models import TodoItemModel
10
+
11
+
12
+ @function_tool
13
+ async def todo_read(ctx: RunContextWrapper[VibecoreContext]) -> list[dict[str, Any]]:
14
+ """Use this tool to read the current to-do list for the session. This tool should be used proactively and
15
+ frequently to ensure that you are aware of the status of the current task list. You should make use of this
16
+ tool as often as possible, especially in the following situations:
17
+ - At the beginning of conversations to see what's pending
18
+ - Before starting new tasks to prioritize work
19
+ - When the user asks about previous tasks or plans
20
+ - Whenever you're uncertain about what to do next
21
+ - After completing tasks to update your understanding of remaining work
22
+ - After every few messages to ensure you're on track
23
+
24
+ Usage:
25
+ - This tool takes in no parameters. So leave the input blank or empty. DO NOT include a dummy object,
26
+ placeholder string or a key like "input" or "empty". LEAVE IT BLANK.
27
+ - Returns a list of todo items with their status, priority, and content
28
+ - Use this information to track progress and plan next steps
29
+ - If no todos exist yet, an empty list will be returned
30
+
31
+ Args:
32
+ ctx: The run context wrapper containing the todo manager.
33
+
34
+ Returns:
35
+ A list of todo items with their status, priority, and content.
36
+ """
37
+ return ctx.context.todo_manager.read()
38
+
39
+
40
+ @function_tool
41
+ async def todo_write(ctx: RunContextWrapper[VibecoreContext], todos: list[TodoItemModel]) -> str:
42
+ """Use this tool to create and manage a structured task list for your current coding session. This helps you
43
+ track progress, organize complex tasks, and demonstrate thoroughness to the user. It also helps the user
44
+ understand the progress of the task and overall progress of their requests.
45
+
46
+ ## When to Use This Tool
47
+ Use this tool proactively in these scenarios:
48
+
49
+ 1. Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
50
+ 2. Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
51
+ 3. User explicitly requests todo list - When the user directly asks you to use the todo list
52
+ 4. User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
53
+ 5. After receiving new instructions - Immediately capture user requirements as todos
54
+ 6. When you start working on a task - Mark it as in_progress BEFORE beginning work. Ideally you should only
55
+ have one todo as in_progress at a time
56
+ 7. After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation
57
+
58
+ ## When NOT to Use This Tool
59
+
60
+ Skip using this tool when:
61
+ 1. There is only a single, straightforward task
62
+ 2. The task is trivial and tracking it provides no organizational benefit
63
+ 3. The task can be completed in less than 3 trivial steps
64
+ 4. The task is purely conversational or informational
65
+
66
+ NOTE that you should not use this tool if there is only one trivial task to do. In this case you are
67
+ better off just doing the task directly.
68
+
69
+ ## Task States and Management
70
+
71
+ 1. **Task States**: Use these states to track progress:
72
+ - pending: Task not yet started
73
+ - in_progress: Currently working on (limit to ONE task at a time)
74
+ - completed: Task finished successfully
75
+
76
+ 2. **Task Management**:
77
+ - Update task status in real-time as you work
78
+ - Mark tasks complete IMMEDIATELY after finishing (don't batch completions)
79
+ - Only have ONE task in_progress at any time
80
+ - Complete current tasks before starting new ones
81
+ - Remove tasks that are no longer relevant from the list entirely
82
+
83
+ 3. **Task Completion Requirements**:
84
+ - ONLY mark a task as completed when you have FULLY accomplished it
85
+ - If you encounter errors, blockers, or cannot finish, keep the task as in_progress
86
+ - When blocked, create a new task describing what needs to be resolved
87
+ - Never mark a task as completed if:
88
+ - Tests are failing
89
+ - Implementation is partial
90
+ - You encountered unresolved errors
91
+ - You couldn't find necessary files or dependencies
92
+
93
+ 4. **Task Breakdown**:
94
+ - Create specific, actionable items
95
+ - Break complex tasks into smaller, manageable steps
96
+ - Use clear, descriptive task names
97
+
98
+ When in doubt, use this tool. Being proactive with task management demonstrates attentiveness and ensures
99
+ you complete all requirements successfully.
100
+
101
+ Args:
102
+ ctx: The run context wrapper containing the todo manager.
103
+ todos: The updated todo list.
104
+
105
+ Returns:
106
+ Success message.
107
+ """
108
+ # Convert Pydantic models to dicts for the implementation
109
+ todos_dict = [todo.model_dump() for todo in todos]
110
+ ctx.context.todo_manager.write(todos_dict)
111
+ return "Todo list updated successfully."
@@ -0,0 +1,5 @@
1
+ """Utility modules for vibecore."""
2
+
3
+ from vibecore.utils.text import TextExtractor
4
+
5
+ __all__ = ["TextExtractor"]
vibecore/utils/text.py ADDED
@@ -0,0 +1,28 @@
1
+ """Text extraction utilities for vibecore."""
2
+
3
+ from openai.types.responses.response_output_message import Content
4
+ from openai.types.responses.response_output_refusal import ResponseOutputRefusal
5
+ from openai.types.responses.response_output_text import ResponseOutputText
6
+
7
+
8
+ class TextExtractor:
9
+ """Utility class for extracting text from various content formats."""
10
+
11
+ @staticmethod
12
+ def extract_from_content(content: list[Content]) -> str:
13
+ """Extract text from various content formats.
14
+
15
+ Args:
16
+ content: List of content items from OpenAI response
17
+
18
+ Returns:
19
+ Concatenated text from all text content items
20
+ """
21
+ text_parts = []
22
+ for item in content:
23
+ match item:
24
+ case ResponseOutputText(text=text):
25
+ text_parts.append(text)
26
+ case ResponseOutputRefusal(refusal=text):
27
+ text_parts.append(text)
28
+ return "".join(text_parts)