llms-py 3.0.7__py3-none-any.whl → 3.0.9__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.
@@ -67,7 +67,7 @@ const RecentResults = {
67
67
 
68
68
  const normalized = (s) => (s || '').toString().toLowerCase()
69
69
  const replaceChars = new Set('<>`*|#'.split(''))
70
- const clean = s => [...s].map(c => replaceChars.has(c) ? ' ' : c).join('')
70
+ const clean = s => [...(s || '')].map(c => replaceChars.has(c) ? ' ' : c).join('')
71
71
 
72
72
  const loadMore = async (reset = false) => {
73
73
  if (reset) {
@@ -139,10 +139,11 @@ async function updateThread(threadId, updates) {
139
139
  }
140
140
  }
141
141
 
142
- async function deleteMessageFromThread(threadId, messageId) {
142
+ async function deleteMessageFromThread(threadId, timestamp) {
143
143
  const thread = await getThread(threadId)
144
144
  if (!thread) throw new Error('Thread not found')
145
- const updatedMessages = thread.messages.filter(m => m.id !== messageId)
145
+ const updatedMessages = thread.messages.filter(m => m.timestamp !== timestamp)
146
+ console.log('deleteMessageFromThread', threadId, timestamp, updatedMessages)
146
147
  await updateThread(threadId, { messages: updatedMessages })
147
148
  }
148
149
 
@@ -150,7 +151,7 @@ async function updateMessageInThread(threadId, messageId, updates) {
150
151
  const thread = await getThread(threadId)
151
152
  if (!thread) throw new Error('Thread not found')
152
153
 
153
- const messageIndex = thread.messages.findIndex(m => m.id === messageId)
154
+ const messageIndex = thread.messages.findIndex(m => m.timestamp === messageId)
154
155
  if (messageIndex === -1) throw new Error('Message not found')
155
156
 
156
157
  const updatedMessages = [...thread.messages]
@@ -538,12 +538,13 @@ def get_current_time(tz_name: Optional[str] = None) -> str:
538
538
  def install(ctx):
539
539
  global g_ctx
540
540
  g_ctx = ctx
541
+ group = "core_tools"
541
542
  # Examples of registering tools using automatic definition generation
542
- ctx.register_tool(memory_read)
543
- ctx.register_tool(memory_write)
543
+ ctx.register_tool(memory_read, group=group)
544
+ ctx.register_tool(memory_write, group=group)
544
545
  # ctx.register_tool(semantic_search) # TODO: implement
545
- ctx.register_tool(read_file)
546
- ctx.register_tool(write_file)
546
+ ctx.register_tool(read_file, group=group)
547
+ ctx.register_tool(write_file, group=group)
547
548
  ctx.register_tool(
548
549
  edit_file,
549
550
  {
@@ -562,15 +563,16 @@ def install(ctx):
562
563
  },
563
564
  },
564
565
  },
566
+ group=group,
565
567
  )
566
- ctx.register_tool(list_directory)
567
- ctx.register_tool(glob_paths)
568
- ctx.register_tool(calc)
569
- ctx.register_tool(run_python)
570
- ctx.register_tool(run_typescript)
571
- ctx.register_tool(run_javascript)
572
- ctx.register_tool(run_csharp)
573
- ctx.register_tool(get_current_time)
568
+ ctx.register_tool(list_directory, group=group)
569
+ ctx.register_tool(glob_paths, group=group)
570
+ ctx.register_tool(calc, group=group)
571
+ ctx.register_tool(run_python, group=group)
572
+ ctx.register_tool(run_typescript, group=group)
573
+ ctx.register_tool(run_javascript, group=group)
574
+ ctx.register_tool(run_csharp, group=group)
575
+ ctx.register_tool(get_current_time, group=group)
574
576
 
575
577
  def exec_language(language: str, code: str) -> Dict[str, Any]:
576
578
  if language == "python":
@@ -471,9 +471,9 @@ def install_google(ctx):
471
471
  if "usageMetadata" in obj:
472
472
  usage = obj["usageMetadata"]
473
473
  response["usage"] = {
474
- "completion_tokens": usage["candidatesTokenCount"],
475
- "total_tokens": usage["totalTokenCount"],
476
- "prompt_tokens": usage["promptTokenCount"],
474
+ "completion_tokens": usage.get("candidatesTokenCount", 0),
475
+ "total_tokens": usage.get("totalTokenCount", 0),
476
+ "prompt_tokens": usage.get("promptTokenCount", 0),
477
477
  }
478
478
 
479
479
  return ctx.log_json(self.to_response(response, chat, started_at))
@@ -1,5 +1,144 @@
1
+ import json
2
+
1
3
  from aiohttp import web
2
4
 
3
5
 
4
6
  def install(ctx):
5
- ctx.add_get("/", lambda r: web.json_response(ctx.app.tool_definitions))
7
+ async def tools_handler(request):
8
+ return web.json_response(
9
+ {
10
+ "groups": ctx.app.tool_groups,
11
+ "definitions": ctx.app.tool_definitions,
12
+ }
13
+ )
14
+
15
+ ctx.add_get("", tools_handler)
16
+
17
+ def prop_def_types(prop_def):
18
+ prop_type = prop_def.get("type")
19
+ if not prop_type:
20
+ any_of = prop_def.get("anyOf")
21
+ if any_of:
22
+ return [item.get("type") for item in any_of]
23
+ else:
24
+ return []
25
+ return [prop_type]
26
+
27
+ def tool_prop_value(value, prop_def):
28
+ """
29
+ Convert a value to the specified type.
30
+ types: string, number, integer, boolean, object, array, null
31
+ example prop_def = [
32
+ {
33
+ "type": "string"
34
+ },
35
+ {
36
+ "default": "name",
37
+ "type": "string",
38
+ "enum": ["name", "size"]
39
+ },
40
+ {
41
+ "default": [],
42
+ "type": "array",
43
+ "items": {
44
+ "type": "string"
45
+ }
46
+ },
47
+ {
48
+ "anyOf": [
49
+ {
50
+ "type": "string"
51
+ },
52
+ {
53
+ "type": "null"
54
+ }
55
+ ],
56
+ "default": null,
57
+ },
58
+ ]
59
+ """
60
+ if value is None:
61
+ default = prop_def.get("default")
62
+ if default is not None:
63
+ default = tool_prop_value(default, prop_def)
64
+ return default
65
+
66
+ prop_types = prop_def_types(prop_def)
67
+ if "integer" in prop_types:
68
+ return int(value)
69
+ elif "number" in prop_types:
70
+ return float(value)
71
+ elif "boolean" in prop_types:
72
+ return bool(value)
73
+ elif "object" in prop_types:
74
+ return value if isinstance(value, dict) else json.loads(value)
75
+ elif "array" in prop_types:
76
+ return value if isinstance(value, list) else value.split(",")
77
+ else:
78
+ enum = prop_def.get("enum")
79
+ if enum and value not in enum:
80
+ raise Exception(f"'{value}' is not in {enum}")
81
+ return value
82
+
83
+ async def exec_handler(request):
84
+ name = request.match_info.get("name")
85
+ args = await request.json()
86
+
87
+ tool_def = ctx.get_tool_definition(name)
88
+ if not tool_def:
89
+ raise Exception(f"Tool '{name}' not found")
90
+
91
+ type = tool_def.get("type")
92
+ if type != "function":
93
+ raise Exception(f"Tool '{name}' of type '{type}' is not supported")
94
+
95
+ ctx.dbg(f"Executing tool '{name}' with args:\n{json.dumps(args, indent=2)}")
96
+ function_args = {}
97
+ parameters = tool_def.get("function", {}).get("parameters")
98
+ if parameters:
99
+ properties = parameters.get("properties")
100
+ required_props = parameters.get("required", [])
101
+ if properties:
102
+ for prop_name, prop_def in properties.items():
103
+ prop_title = prop_def.get("title", prop_name)
104
+ prop_types = prop_def_types(prop_def)
105
+ value = None
106
+ if prop_name in args:
107
+ value = tool_prop_value(args[prop_name], prop_def)
108
+ elif prop_name in required_props:
109
+ if "null" in prop_types:
110
+ value = None
111
+ elif "default" in prop_def:
112
+ value = tool_prop_value(prop_def["default"], prop_def)
113
+ else:
114
+ raise Exception(f"Missing required parameter '{prop_title}' for tool '{name}'")
115
+ if value is not None or "null" in prop_types:
116
+ function_args[prop_name] = value
117
+ else:
118
+ ctx.dbg(f"tool '{name}' has no properties:\n{json.dumps(tool_def, indent=2)}")
119
+ else:
120
+ ctx.dbg(f"tool '{name}' has no parameters:\n{json.dumps(tool_def, indent=2)}")
121
+
122
+ try:
123
+ text, resources = await ctx.exec_tool(name, function_args)
124
+
125
+ results = []
126
+ if text:
127
+ results.append(
128
+ {
129
+ "type": "text",
130
+ "text": text,
131
+ }
132
+ )
133
+ if resources:
134
+ results.extend(resources)
135
+
136
+ return web.json_response(results)
137
+ except Exception as e:
138
+ ctx.err(f"Failed to execute tool '{name}' with args:\n{json.dumps(function_args, indent=2)}", e)
139
+ raise e
140
+
141
+ ctx.add_post("exec/{name}", exec_handler)
142
+
143
+
144
+ __install__ = install