Coverage for sources/agentsmgr/commands/context.py: 15%

44 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-10-13 00:43 +0000

1# vim: set filetype=python fileencoding=utf-8: 

2# -*- coding: utf-8 -*- 

3 

4#============================================================================# 

5# # 

6# Licensed under the Apache License, Version 2.0 (the "License"); # 

7# you may not use this file except in compliance with the License. # 

8# You may obtain a copy of the License at # 

9# # 

10# http://www.apache.org/licenses/LICENSE-2.0 # 

11# # 

12# Unless required by applicable law or agreed to in writing, software # 

13# distributed under the License is distributed on an "AS IS" BASIS, # 

14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

15# See the License for the specific language governing permissions and # 

16# limitations under the License. # 

17# # 

18#============================================================================# 

19 

20 

21''' Template rendering context normalization and tool mapping. 

22 

23 Provides context transformation for template rendering, including 

24 hyphen-to-underscore normalization and coder-specific tool mapping. 

25''' 

26 

27 

28from . import __ 

29 

30 

31ToolSpecification: __.typx.TypeAlias = ( 

32 str | dict[ str, __.typx.Any ] ) 

33 

34 

35_SEMANTIC_TOOLS_CLAUDE: dict[ str, str ] = { 

36 'read': 'Read', 

37 'edit': 'Edit', 

38 'multi-edit': 'MultiEdit', 

39 'write': 'Write', 

40 'list-directory': 'LS', 

41 'glob': 'Glob', 

42 'grep': 'Grep', 

43 'todo-write': 'TodoWrite', 

44 'web-fetch': 'WebFetch', 

45 'web-search': 'WebSearch', 

46} 

47 

48 

49def normalize_render_context( 

50 context_data: __.cabc.Mapping[ str, __.typx.Any ], 

51 coder_config: __.cabc.Mapping[ str, __.typx.Any ], 

52) -> dict[ str, __.typx.Any ]: 

53 ''' Normalizes template rendering context with tool mapping. 

54 

55 Transforms hyphenated keys to underscored keys, wraps configurations 

56 in SimpleNamespace objects for dot-notation access, and maps 

57 allowed-tools specifications to coder-specific syntax. 

58 ''' 

59 coder_name = coder_config.get( 'name', 'unknown' ) 

60 normalized_context = { 

61 key.replace( '-', '_' ): value 

62 for key, value in context_data.items( ) } 

63 if 'allowed_tools' in normalized_context: 

64 raw_tools = normalized_context[ 'allowed_tools' ] 

65 normalized_context[ 'allowed_tools' ] = ( 

66 _map_tools_for_coder( raw_tools, coder_name ) ) 

67 context_namespace = __.types.SimpleNamespace( **normalized_context ) 

68 coder_namespace = __.types.SimpleNamespace( **coder_config ) 

69 return { 

70 'context': context_namespace, 

71 'coder': coder_namespace, 

72 } 

73 

74 

75def _map_tools_for_coder( 

76 tool_specs: __.cabc.Sequence[ ToolSpecification ], 

77 coder_name: str, 

78) -> list[ str ]: 

79 ''' Maps tool specifications to coder-specific syntax. 

80 

81 Dispatches to coder-specific mapping function based on coder name. 

82 Currently supports Claude; extensible for other coders. 

83 ''' 

84 if coder_name == 'claude': 

85 return _map_tools_claude( tool_specs ) 

86 return [ ] 

87 

88 

89def _map_tools_claude( 

90 tool_specs: __.cabc.Sequence[ ToolSpecification ] 

91) -> list[ str ]: 

92 ''' Maps tool specifications to Claude-specific syntax. 

93 

94 Handles three specification types: 

95 - String literals (semantic names): 'read' → 'Read' 

96 - Shell commands: { tool = 'shell', arguments, ... } → 'Bash(...)' 

97 - MCP tools: { server, tool } → 'mcp__server__tool' 

98 

99 Returns tools sorted alphabetically for consistent output. 

100 ''' 

101 mapped: list[ str ] = [ ] 

102 for spec in tool_specs: 

103 if isinstance( spec, str ): 

104 mapped.append( _map_semantic_tool_claude( spec ) ) 

105 elif isinstance( spec, dict ): 

106 if 'server' in spec: 

107 mapped.append( _map_mcp_tool_claude( spec ) ) 

108 elif spec.get( 'tool' ) == 'shell': 

109 mapped.append( _map_shell_tool_claude( spec ) ) 

110 else: 

111 raise __.ToolSpecificationInvalidity( str( spec ) ) 

112 else: 

113 raise __.ToolSpecificationTypeInvalidity( type( spec ).__name__ ) 

114 return sorted( mapped ) 

115 

116 

117def _map_semantic_tool_claude( tool_name: str ) -> str: 

118 ''' Maps semantic tool name to Claude tool name. 

119 

120 Uses lookup table for known semantic names. 

121 Raises ToolSpecificationInvalidity for unknown tools. 

122 ''' 

123 if tool_name not in _SEMANTIC_TOOLS_CLAUDE: 

124 raise __.ToolSpecificationInvalidity( tool_name ) 

125 return _SEMANTIC_TOOLS_CLAUDE[ tool_name ] 

126 

127 

128def _map_shell_tool_claude( spec: dict[ str, __.typx.Any ] ) -> str: 

129 ''' Maps shell command specification to Claude Bash tool syntax. 

130 

131 Format: { tool = 'shell', arguments = 'git status' } 

132 → 'Bash(git status)' 

133 

134 With wildcard: { tool = 'shell', arguments = 'git pull', 

135 allow-extra-arguments = true } 

136 → 'Bash(git pull:*)' 

137 ''' 

138 arguments = spec.get( 'arguments', '' ) 

139 allow_extra = spec.get( 'allow-extra-arguments', False ) 

140 if allow_extra: 

141 return f"Bash({arguments}:*)" 

142 return f"Bash({arguments})" 

143 

144 

145def _map_mcp_tool_claude( spec: dict[ str, __.typx.Any ] ) -> str: 

146 ''' Maps MCP tool specification to Claude MCP tool syntax. 

147 

148 Format: { server = 'librovore', tool = 'query-inventory' } 

149 → 'mcp__librovore__query_inventory' 

150 ''' 

151 server = spec.get( 'server', '' ) 

152 tool = spec.get( 'tool', '' ) 

153 tool_normalized = tool.replace( '-', '_' ) 

154 return f"mcp__{server}__{tool_normalized}"