pascal-agent 0.3.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.
pascal/schemas.py ADDED
@@ -0,0 +1,183 @@
1
+ """Tool schemas for Pascal Function Calling.
2
+
3
+ Used by loop.py to pass actual tool definitions to the LLM instead of tools=[].
4
+ Each schema maps to one action in actions.py.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any, Literal
10
+
11
+
12
+ ToolPreset = Literal["minimal", "standard", "full"]
13
+
14
+ _MINIMAL_TOOL_NAMES = (
15
+ "think",
16
+ "pick_task",
17
+ "handle_notification",
18
+ "dismiss_notification",
19
+ "create_task",
20
+ "execute",
21
+ "wait",
22
+ "escalate",
23
+ )
24
+
25
+ _STANDARD_TOOL_NAMES = _MINIMAL_TOOL_NAMES + (
26
+ "plan",
27
+ "delegate",
28
+ "complete_task",
29
+ "fail_task",
30
+ "pause_task",
31
+ "block_task",
32
+ "create_subtask",
33
+ "add_todo",
34
+ "complete_todo",
35
+ "memorize",
36
+ "add_rule",
37
+ "remove_rule",
38
+ "set_context",
39
+ )
40
+
41
+ _TOOL_PRESETS: dict[ToolPreset, frozenset[str]] = {
42
+ "minimal": frozenset(_MINIMAL_TOOL_NAMES),
43
+ "standard": frozenset(_STANDARD_TOOL_NAMES),
44
+ # FULL uses the same Pascal action schemas as STANDARD. loop.py adds
45
+ # the desktop/UIA guidance to the system prompt when FULL is selected.
46
+ "full": frozenset(_STANDARD_TOOL_NAMES),
47
+ }
48
+
49
+
50
+ def build_tool_schemas(*, preset: ToolPreset = "standard") -> list[dict[str, Any]]:
51
+ """Build the Pascal tool list for the selected LLM preset.
52
+
53
+ Returns OpenAI-compatible tool definitions. Each tool corresponds to
54
+ one Pascal action (think, execute, plan, etc.).
55
+ """
56
+ try:
57
+ allowed_names = _TOOL_PRESETS[preset]
58
+ except KeyError as exc:
59
+ raise ValueError(f"Unknown tool preset: {preset}") from exc
60
+ return [tool for tool in _PASCAL_TOOLS if tool["function"]["name"] in allowed_names]
61
+
62
+
63
+ def _tool(name: str, description: str, properties: dict, required: list[str] | None = None) -> dict:
64
+ """Helper to build one OpenAI-compatible tool definition."""
65
+ return {
66
+ "type": "function",
67
+ "function": {
68
+ "name": name,
69
+ "description": description,
70
+ "parameters": {
71
+ "type": "object",
72
+ "properties": properties,
73
+ "required": required or [],
74
+ },
75
+ },
76
+ }
77
+
78
+
79
+ _PASCAL_TOOLS: list[dict[str, Any]] = [
80
+ _tool("think", "Reason about the current situation before acting.", {
81
+ "thought": {"type": "string", "description": "Your reasoning"},
82
+ }, ["thought"]),
83
+
84
+ _tool("execute", "Execute a shell command, built-in/MCP tool, or Python code snippet.", {
85
+ "command": {"type": "string", "description": "Shell command to run"},
86
+ "tool": {"type": "string", "description": "Tool name (mutually exclusive with command)"},
87
+ "tool_params": {"type": "object", "description": "Parameters for the tool"},
88
+ "code": {"type": "string", "description": "Python code to run in sandbox (for data processing, file ops — more efficient than multiple tool calls)"},
89
+ "reason": {"type": "string"},
90
+ }),
91
+
92
+ _tool("plan", "Create or patch a multi-step execution plan.", {
93
+ "reason": {"type": "string"},
94
+ "plan_tree": {"type": "object", "description": "Plan tree: {id, kind, title, children, done_when, action}"},
95
+ "steps": {"type": "array", "description": "Legacy flat steps array (auto-wrapped into tree)", "items": {"type": "object"}},
96
+ "patch_node_id": {"type": "string", "description": "Failed node ID to repair in existing plan"},
97
+ }, ["reason"]),
98
+
99
+ _tool("delegate", "Delegate a task to Claude Code or Codex CLI.", {
100
+ "tool": {"type": "string", "enum": ["claude-code", "codex"], "description": "Which agent to delegate to"},
101
+ "task": {"type": "string", "description": "Task description for the delegate"},
102
+ "context": {"type": "string", "description": "Additional context"},
103
+ "success_criteria": {"type": "string"},
104
+ "timeout": {"type": "integer", "description": "Timeout in seconds (max 600)"},
105
+ }, ["tool", "task"]),
106
+
107
+ _tool("pick_task", "Activate a pending task to work on.", {
108
+ "task_id": {"type": "string", "description": "ID of the task to activate"},
109
+ "reason": {"type": "string"},
110
+ }, ["task_id"]),
111
+
112
+ _tool("create_task", "Create a new task.", {
113
+ "goal": {"type": "string", "description": "What the task should accomplish"},
114
+ "priority": {"type": "string", "enum": ["urgent", "normal", "low"]},
115
+ "estimated_effect": {"type": "string", "description": "E0-E5 effect level"},
116
+ }, ["goal"]),
117
+
118
+ _tool("create_subtask", "Create a subtask under the active task.", {
119
+ "subtask_goal": {"type": "string"},
120
+ "subtask_priority": {"type": "string", "enum": ["urgent", "normal", "low"]},
121
+ }, ["subtask_goal"]),
122
+
123
+ _tool("handle_notification", "Handle a pending notification.", {
124
+ "notification_id": {"type": "string"},
125
+ "response": {"type": "string", "description": "Internal note about how you handled it"},
126
+ "reply_text": {"type": "string", "description": "Text to send back to the human (or NO_REPLY)"},
127
+ }, ["notification_id"]),
128
+
129
+ _tool("dismiss_notification", "Dismiss a notification without handling.", {
130
+ "notification_id": {"type": "string"},
131
+ }, ["notification_id"]),
132
+
133
+ _tool("pause_task", "Pause the current active task.", {
134
+ "pause_reason": {"type": "string"},
135
+ }),
136
+
137
+ _tool("block_task", "Block the current active task (waiting for external input).", {
138
+ "reason": {"type": "string"},
139
+ }),
140
+
141
+ _tool("fail_task", "Mark the current active task as failed.", {
142
+ "reason": {"type": "string"},
143
+ }, ["reason"]),
144
+
145
+ _tool("complete_task", "Mark the current active task as done.", {
146
+ "summary": {"type": "string", "description": "What was accomplished"},
147
+ }, ["summary"]),
148
+
149
+ _tool("add_todo", "Add a TODO item to the active task.", {
150
+ "todo_title": {"type": "string"},
151
+ }, ["todo_title"]),
152
+
153
+ _tool("complete_todo", "Mark a TODO item as done.", {
154
+ "todo_id": {"type": "string"},
155
+ }, ["todo_id"]),
156
+
157
+ _tool("memorize", "Save a memory for future reference.", {
158
+ "memory_kind": {"type": "string", "enum": ["fact", "lesson", "preference", "procedure"]},
159
+ "memory_content": {"type": "string"},
160
+ }, ["memory_kind", "memory_content"]),
161
+
162
+ _tool("add_rule", "Add a behavior rule.", {
163
+ "rule": {"type": "string"},
164
+ }, ["rule"]),
165
+
166
+ _tool("remove_rule", "Remove a mutable rule.", {
167
+ "rule_id": {"type": "string"},
168
+ }, ["rule_id"]),
169
+
170
+ _tool("set_context", "Set a working memory key-value pair.", {
171
+ "key": {"type": "string"},
172
+ "value": {}, # any type
173
+ "ttl_hours": {"type": "number", "description": "Optional TTL in hours"},
174
+ }, ["key", "value"]),
175
+
176
+ _tool("wait", "Do nothing and wait for new events.", {
177
+ "wait_reason": {"type": "string"},
178
+ }),
179
+
180
+ _tool("escalate", "Ask a human for help.", {
181
+ "question": {"type": "string", "description": "What you need help with"},
182
+ }, ["question"]),
183
+ ]