diff --git a/fern/openapi.json b/fern/openapi.json index 625cf1db..f0c6b88c 100644 --- a/fern/openapi.json +++ b/fern/openapi.json @@ -12342,14 +12342,6 @@ ], "nullable": true }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] - }, "children": { "type": "array", "items": { @@ -12402,14 +12394,6 @@ {} ], "nullable": true - }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] } }, "required": ["tool_name"] @@ -12457,14 +12441,6 @@ {} ], "nullable": true - }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] } }, "required": ["tool_name"] @@ -12513,14 +12489,6 @@ ], "nullable": true }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] - }, "default_child": { "oneOf": [ { @@ -12608,14 +12576,6 @@ {} ], "nullable": true - }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] } }, "required": ["tool_name"] @@ -12663,14 +12623,6 @@ {} ], "nullable": true - }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] } }, "required": ["tool_name"] @@ -12719,14 +12671,6 @@ ], "nullable": true }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] - }, "max_count_limit": { "type": "number" } @@ -12780,14 +12724,6 @@ ], "nullable": true }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] - }, "children": { "type": "array", "items": { @@ -12840,14 +12776,6 @@ {} ], "nullable": true - }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] } }, "required": ["tool_name"] @@ -12912,14 +12840,6 @@ ], "nullable": true }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] - }, "children": { "type": "array", "items": { @@ -12975,14 +12895,6 @@ {} ], "nullable": true - }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] } }, "required": ["tool_name"] @@ -13030,14 +12942,6 @@ {} ], "nullable": true - }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] } }, "required": ["tool_name"] @@ -13086,14 +12990,6 @@ ], "nullable": true }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] - }, "default_child": { "oneOf": [ { @@ -13181,14 +13077,6 @@ {} ], "nullable": true - }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] } }, "required": ["tool_name"] @@ -13236,14 +13124,6 @@ {} ], "nullable": true - }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] } }, "required": ["tool_name"] @@ -13292,14 +13172,6 @@ ], "nullable": true }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] - }, "max_count_limit": { "type": "number" } @@ -13353,14 +13225,6 @@ ], "nullable": true }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] - }, "children": { "type": "array", "items": { @@ -13416,14 +13280,6 @@ {} ], "nullable": true - }, - "requires_force_tool_call": { - "oneOf": [ - { - "type": "boolean" - }, - {} - ] } }, "required": ["tool_name"] @@ -23545,11 +23401,6 @@ "title": "Prompt Template", "description": "Optional template string (ignored)." }, - "requires_force_tool_call": { - "type": "boolean", - "title": "Requires Force Tool Call", - "default": true - }, "children": { "items": { "type": "string" @@ -23637,11 +23488,6 @@ "title": "Prompt Template", "description": "Optional template string (ignored)." }, - "requires_force_tool_call": { - "type": "boolean", - "title": "Requires Force Tool Call", - "default": true - }, "default_child": { "anyOf": [ { @@ -23872,11 +23718,6 @@ ], "title": "Prompt Template", "description": "Optional template string (ignored)." - }, - "requires_force_tool_call": { - "type": "boolean", - "title": "Requires Force Tool Call", - "default": false } }, "additionalProperties": false, @@ -27131,11 +26972,6 @@ ], "title": "Prompt Template", "description": "Optional template string (ignored). Rendering uses fast built-in formatting for performance." - }, - "requires_force_tool_call": { - "type": "boolean", - "title": "Requires Force Tool Call", - "default": true } }, "additionalProperties": false, @@ -29252,11 +29088,6 @@ "title": "Prompt Template", "description": "Optional template string (ignored)." }, - "requires_force_tool_call": { - "type": "boolean", - "title": "Requires Force Tool Call", - "default": false - }, "max_count_limit": { "type": "integer", "title": "Max Count Limit", @@ -30285,11 +30116,6 @@ "title": "Prompt Template", "description": "Optional template string (ignored)." }, - "requires_force_tool_call": { - "type": "boolean", - "title": "Requires Force Tool Call", - "default": true - }, "children": { "items": { "type": "string" @@ -31118,11 +30944,6 @@ ], "title": "Prompt Template", "description": "Optional template string (ignored)." - }, - "requires_force_tool_call": { - "type": "boolean", - "title": "Requires Force Tool Call", - "default": false } }, "additionalProperties": false, @@ -31155,11 +30976,6 @@ ], "title": "Prompt Template", "description": "Optional template string (ignored). Rendering uses fast built-in formatting for performance." - }, - "requires_force_tool_call": { - "type": "boolean", - "title": "Requires Force Tool Call", - "default": false } }, "additionalProperties": false, @@ -33054,11 +32870,6 @@ ], "title": "Prompt Template", "description": "Optional template string (ignored)." - }, - "requires_force_tool_call": { - "type": "boolean", - "title": "Requires Force Tool Call", - "default": false } }, "additionalProperties": false, diff --git a/letta/schemas/tool_rule.py b/letta/schemas/tool_rule.py index c8bc5c09..94116e55 100644 --- a/letta/schemas/tool_rule.py +++ b/letta/schemas/tool_rule.py @@ -18,7 +18,6 @@ class BaseToolRule(LettaBase): None, description="Optional template string (ignored). Rendering uses fast built-in formatting for performance.", ) - requires_force_tool_call: bool = False def __hash__(self): """Base hash using tool_name and type.""" @@ -37,6 +36,13 @@ class BaseToolRule(LettaBase): """Default implementation returns None. Subclasses provide optimized strings.""" return None + @property + def requires_force_tool_call(self) -> bool: + """Whether this tool rule requires forcing a tool call in the LLM request when active. + When True, the LLM must use a tool; when False, tool use is optional. + Default is False for most rules.""" + return False + class ChildToolRule(BaseToolRule): """ @@ -49,7 +55,11 @@ class ChildToolRule(BaseToolRule): default=None, description="Optional template string (ignored).", ) - requires_force_tool_call: bool = True + + @property + def requires_force_tool_call(self) -> bool: + """Child tool rules require forcing tool calls.""" + return True def __hash__(self): """Hash including children list (sorted for consistency).""" @@ -78,7 +88,11 @@ class ParentToolRule(BaseToolRule): type: Literal[ToolRuleType.parent_last_tool] = ToolRuleType.parent_last_tool children: List[str] = Field(..., description="The children tools that can be invoked.") prompt_template: Optional[str] = Field(default=None, description="Optional template string (ignored).") - requires_force_tool_call: bool = True + + @property + def requires_force_tool_call(self) -> bool: + """Parent tool rules require forcing tool calls.""" + return True def __hash__(self): """Hash including children list (sorted for consistency).""" @@ -109,7 +123,11 @@ class ConditionalToolRule(BaseToolRule): child_output_mapping: Dict[Any, str] = Field(..., description="The output case to check for mapping") require_output_mapping: bool = Field(default=False, description="Whether to throw an error when output doesn't match any case") prompt_template: Optional[str] = Field(default=None, description="Optional template string (ignored).") - requires_force_tool_call: bool = True + + @property + def requires_force_tool_call(self) -> bool: + """Conditional tool rules require forcing tool calls.""" + return True def __hash__(self): """Hash including all configuration fields.""" @@ -191,7 +209,11 @@ class InitToolRule(BaseToolRule): """ type: Literal[ToolRuleType.run_first] = ToolRuleType.run_first - requires_force_tool_call: bool = True + + @property + def requires_force_tool_call(self) -> bool: + """Initial tool rules require forcing tool calls.""" + return True class TerminalToolRule(BaseToolRule): @@ -201,7 +223,6 @@ class TerminalToolRule(BaseToolRule): type: Literal[ToolRuleType.exit_loop] = ToolRuleType.exit_loop prompt_template: Optional[str] = Field(default=None, description="Optional template string (ignored).") - requires_force_tool_call: bool = False def render_prompt(self) -> str | None: return f"\n{self.tool_name} ends your response (yields control) when called\n" @@ -214,7 +235,6 @@ class ContinueToolRule(BaseToolRule): type: Literal[ToolRuleType.continue_loop] = ToolRuleType.continue_loop prompt_template: Optional[str] = Field(default=None, description="Optional template string (ignored).") - requires_force_tool_call: bool = False def render_prompt(self) -> str | None: return f"\n{self.tool_name} requires continuing your response when called\n" @@ -227,7 +247,6 @@ class RequiredBeforeExitToolRule(BaseToolRule): type: Literal[ToolRuleType.required_before_exit] = ToolRuleType.required_before_exit prompt_template: Optional[str] = Field(default=None, description="Optional template string (ignored).") - requires_force_tool_call: bool = False def get_valid_tools(self, tool_call_history: List[str], available_tools: Set[str], last_function_response: Optional[str]) -> Set[str]: """Returns all available tools - the logic for preventing exit is handled elsewhere.""" @@ -245,7 +264,6 @@ class MaxCountPerStepToolRule(BaseToolRule): type: Literal[ToolRuleType.max_count_per_step] = ToolRuleType.max_count_per_step max_count_limit: int = Field(..., description="The max limit for the total number of times this tool can be invoked in a single step.") prompt_template: Optional[str] = Field(default=None, description="Optional template string (ignored).") - requires_force_tool_call: bool = False def __hash__(self): """Hash including max_count_limit.""" @@ -277,7 +295,6 @@ class RequiresApprovalToolRule(BaseToolRule): """ type: Literal[ToolRuleType.requires_approval] = ToolRuleType.requires_approval - requires_force_tool_call: bool = False def get_valid_tools(self, tool_call_history: List[str], available_tools: Set[str], last_function_response: Optional[str]) -> Set[str]: """Does not enforce any restrictions on which tools are valid"""