janito 2.16.0__py3-none-any.whl → 2.17.1__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.
@@ -167,7 +167,7 @@ def setup_agent(
167
167
  """
168
168
  Creates an agent. A system prompt is rendered from a template only when a profile is specified.
169
169
  """
170
- if no_tools_mode:
170
+ if no_tools_mode or zero_mode:
171
171
  tools_provider = None
172
172
  else:
173
173
  tools_provider = get_local_tools_adapter()
@@ -92,6 +92,7 @@ def get_driver_info():
92
92
  ("janito.drivers.openai.driver", "OpenAIModelDriver"),
93
93
  ("janito.drivers.azure_openai.driver", "AzureOpenAIModelDriver"),
94
94
  ("janito.drivers.zai.driver", "ZAIModelDriver"),
95
+ ("janito.drivers.cerebras.driver", "CerebrasModelDriver"),
95
96
  ]
96
97
 
97
98
  for module_path, class_name in driver_modules:
@@ -4,6 +4,7 @@ CLI Command: Set API key for the current or selected provider
4
4
 
5
5
  from janito.provider_config import set_api_key
6
6
  from janito.llm.auth import LLMAuthManager
7
+ from janito.providers.registry import LLMProviderRegistry
7
8
 
8
9
 
9
10
  def handle_set_api_key(args):
@@ -12,8 +13,18 @@ def handle_set_api_key(args):
12
13
  if not provider:
13
14
  print("Error: --set-api-key requires -p/--provider to be specified.")
14
15
  return
15
- set_api_key(provider, api_key)
16
- auth_manager = LLMAuthManager()
17
- print(
18
- f"API key set for provider '{provider}'. Auth file updated: {auth_manager._auth_file}"
19
- )
16
+
17
+ # Validate provider name
18
+ if provider not in LLMProviderRegistry.list_providers():
19
+ valid_providers = LLMProviderRegistry.list_providers()
20
+ print(f"Error: Unknown provider '{provider}'. Valid providers are: {', '.join(valid_providers)}")
21
+ return
22
+
23
+ try:
24
+ set_api_key(provider, api_key)
25
+ auth_manager = LLMAuthManager()
26
+ print(
27
+ f"API key set for provider '{provider}'. Auth file updated: {auth_manager._auth_file}"
28
+ )
29
+ except ValueError as e:
30
+ print(f"Error: {e}")
@@ -37,6 +37,8 @@ def setup_agent_and_prompt_handler(
37
37
  no_tools_mode = False
38
38
  if hasattr(args, 'no_tools_mode'):
39
39
  no_tools_mode = getattr(args, 'no_tools_mode', False)
40
+
41
+ zero_mode = getattr(args, 'zero', False)
40
42
  agent = create_configured_agent(
41
43
  provider_instance=provider_instance,
42
44
  llm_driver_config=llm_driver_config,
@@ -46,6 +48,7 @@ def setup_agent_and_prompt_handler(
46
48
  allowed_permissions=allowed_permissions,
47
49
  profile=profile,
48
50
  profile_system_prompt=profile_system_prompt,
51
+ zero_mode=zero_mode,
49
52
  no_tools_mode=no_tools_mode,
50
53
  )
51
54
 
@@ -0,0 +1 @@
1
+ # Cerebras driver package
@@ -7,3 +7,4 @@ import janito.providers.deepseek.provider
7
7
  import janito.providers.moonshotai.provider
8
8
  import janito.providers.alibaba.provider
9
9
  import janito.providers.zai.provider
10
+ import janito.providers.cerebras.provider
@@ -17,9 +17,7 @@ class AlibabaProvider(LLMProvider):
17
17
  NAME = "alibaba"
18
18
  MAINTAINER = "João Pinto <janito@ikignosis.org>"
19
19
  MODEL_SPECS = MODEL_SPECS
20
- DEFAULT_MODEL = (
21
- "qwen3-coder-plus" # Options: qwen-turbo, qwen-plus, qwen-max, qwen3-coder-plus
22
- )
20
+ DEFAULT_MODEL = "qwen3-coder-plus" # 128k context, coding-focused model
23
21
 
24
22
  def __init__(
25
23
  self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None
@@ -0,0 +1 @@
1
+ # Cerebras provider package
@@ -0,0 +1,76 @@
1
+ """Model specifications for Cerebras Inference API."""
2
+
3
+ from janito.llm.model import LLMModelInfo
4
+
5
+ MODEL_SPECS = {
6
+ "qwen-3-32b": LLMModelInfo(
7
+ name="qwen-3-32b",
8
+ max_input=128000,
9
+ max_response=16384,
10
+ default_temp=0.7,
11
+ driver="CerebrasModelDriver",
12
+ other={
13
+ "description": "Qwen 3 32B model for general instruction following",
14
+ "pricing": {
15
+ "input_per_1k_tokens": 0.0002,
16
+ "output_per_1k_tokens": 0.0006
17
+ }
18
+ }
19
+ ),
20
+ "qwen-3-235b-a22b-instruct-2507": LLMModelInfo(
21
+ name="qwen-3-235b-a22b-instruct-2507",
22
+ max_input=128000,
23
+ max_response=16384,
24
+ default_temp=0.7,
25
+ driver="CerebrasModelDriver",
26
+ other={
27
+ "description": "Qwen 3 235B A22B instruction-tuned model (preview)",
28
+ "pricing": {
29
+ "input_per_1k_tokens": 0.001,
30
+ "output_per_1k_tokens": 0.003
31
+ }
32
+ }
33
+ ),
34
+ "qwen-3-235b-a22b-thinking-2507": LLMModelInfo(
35
+ name="qwen-3-235b-a22b-thinking-2507",
36
+ max_input=128000,
37
+ max_response=16384,
38
+ default_temp=0.7,
39
+ driver="CerebrasModelDriver",
40
+ other={
41
+ "description": "Qwen 3 235B A22B thinking model for reasoning tasks (preview)",
42
+ "pricing": {
43
+ "input_per_1k_tokens": 0.001,
44
+ "output_per_1k_tokens": 0.003
45
+ }
46
+ }
47
+ ),
48
+ "qwen-3-coder-480b": LLMModelInfo(
49
+ name="qwen-3-coder-480b",
50
+ max_input=128000,
51
+ max_response=16384,
52
+ default_temp=0.7,
53
+ driver="CerebrasModelDriver",
54
+ other={
55
+ "description": "Qwen 3 Coder 480B model for programming tasks (preview)",
56
+ "pricing": {
57
+ "input_per_1k_tokens": 0.002,
58
+ "output_per_1k_tokens": 0.006
59
+ }
60
+ }
61
+ ),
62
+ "gpt-oss-120b": LLMModelInfo(
63
+ name="gpt-oss-120b",
64
+ max_input=128000,
65
+ max_response=16384,
66
+ default_temp=0.7,
67
+ driver="CerebrasModelDriver",
68
+ other={
69
+ "description": "GPT-OSS 120B open-source model (preview)",
70
+ "pricing": {
71
+ "input_per_1k_tokens": 0.0008,
72
+ "output_per_1k_tokens": 0.0024
73
+ }
74
+ }
75
+ )
76
+ }
@@ -0,0 +1,145 @@
1
+ """Cerebras Inference provider implementation."""
2
+
3
+ from typing import Dict, Any
4
+ from janito.llm.provider import LLMProvider
5
+ from janito.llm.auth import LLMAuthManager
6
+ from janito.llm.driver_config import LLMDriverConfig
7
+ from janito.drivers.openai.driver import OpenAIModelDriver
8
+ from janito.tools import get_local_tools_adapter
9
+ from janito.providers.registry import LLMProviderRegistry
10
+ from .model_info import MODEL_SPECS
11
+
12
+
13
+ class CerebrasProvider(LLMProvider):
14
+ """Cerebras Inference API provider."""
15
+
16
+ name = "cerebras"
17
+ NAME = "cerebras"
18
+ DEFAULT_MODEL = "qwen-3-coder-480b"
19
+ MAINTAINER = "João Pinto <janito@ikignosis.org>"
20
+ MODEL_SPECS = MODEL_SPECS
21
+
22
+ def __init__(self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None):
23
+ """Initialize Cerebras provider with optional configuration."""
24
+ super().__init__()
25
+ self._tools_adapter = get_local_tools_adapter()
26
+ self._driver = None
27
+ self._tools_adapter = get_local_tools_adapter()
28
+ self._driver = None
29
+ if not self.available:
30
+ return
31
+
32
+ self._initialize_config(auth_manager, config)
33
+ self._setup_model_config()
34
+ self.fill_missing_device_info(self._driver_config)
35
+
36
+ if not self.available:
37
+ return
38
+
39
+ self._initialize_config(None, None)
40
+ self._driver_config.base_url = "https://api.cerebras.ai/v1"
41
+
42
+ def _initialize_config(self, auth_manager, config):
43
+ """Initialize configuration and API key."""
44
+ self.auth_manager = auth_manager or LLMAuthManager()
45
+ self._api_key = self.auth_manager.get_credentials(type(self).NAME)
46
+ if not self._api_key:
47
+ from janito.llm.auth_utils import handle_missing_api_key
48
+
49
+ handle_missing_api_key(self.name, "CEREBRAS_API_KEY")
50
+
51
+ self._driver_config = config or LLMDriverConfig(model=None)
52
+ if not self._driver_config.model:
53
+ self._driver_config.model = self.DEFAULT_MODEL
54
+ if not self._driver_config.api_key:
55
+ self._driver_config.api_key = self._api_key
56
+
57
+ self._setup_model_config()
58
+ self.fill_missing_device_info(self._driver_config)
59
+
60
+ def _setup_model_config(self):
61
+ """Configure token limits based on model specifications."""
62
+ model_name = self._driver_config.model
63
+ model_spec = self.MODEL_SPECS.get(model_name)
64
+
65
+ # Reset token parameters
66
+ if hasattr(self._driver_config, "max_tokens"):
67
+ self._driver_config.max_tokens = None
68
+ if hasattr(self._driver_config, "max_completion_tokens"):
69
+ self._driver_config.max_completion_tokens = None
70
+
71
+ if model_spec:
72
+ # Set context length
73
+ if hasattr(model_spec, "context") and model_spec.context:
74
+ self._driver_config.context_length = model_spec.context
75
+
76
+ # Set max tokens based on model spec
77
+ if hasattr(model_spec, "max_response") and model_spec.max_response:
78
+ self._driver_config.max_tokens = model_spec.max_response
79
+
80
+ # Set max completion tokens if thinking is supported
81
+ if getattr(model_spec, "thinking_supported", False):
82
+ max_cot = getattr(model_spec, "max_cot", None)
83
+ if max_cot and max_cot != "N/A":
84
+ self._driver_config.max_completion_tokens = int(max_cot)
85
+ else:
86
+ max_response = getattr(model_spec, "max_response", None)
87
+ if max_response and max_response != "N/A":
88
+ self._driver_config.max_tokens = int(max_response)
89
+
90
+ @property
91
+ @property
92
+ def driver(self) -> OpenAIModelDriver:
93
+ if not self.available:
94
+ raise ImportError(
95
+ f"CerebrasProvider unavailable: {self.unavailable_reason}"
96
+ )
97
+ if self._driver is None:
98
+ self._driver = self.create_driver()
99
+ return self._driver
100
+
101
+ @property
102
+ def available(self):
103
+ return OpenAIModelDriver.available
104
+
105
+ @property
106
+ def unavailable_reason(self):
107
+ return OpenAIModelDriver.unavailable_reason
108
+
109
+ def create_driver(self) -> OpenAIModelDriver:
110
+ """Create and return an OpenAI-compatible Cerebras driver instance."""
111
+ driver = OpenAIModelDriver(
112
+ tools_adapter=self._tools_adapter, provider_name=self.name
113
+ )
114
+ driver.config = self._driver_config
115
+ return driver
116
+
117
+ @property
118
+ def driver_config(self):
119
+ """Return the driver configuration."""
120
+ return self._driver_config
121
+
122
+ def is_model_available(self, model_name: str) -> bool:
123
+ """Check if a model is available for this provider."""
124
+ return model_name in self.MODEL_SPECS
125
+
126
+ def get_model_info(self, model_name: str = None) -> Dict[str, Any]:
127
+ """Get model information for the specified model or all models."""
128
+ if model_name is None:
129
+ return {
130
+ name: model_info.to_dict()
131
+ for name, model_info in self.MODEL_SPECS.items()
132
+ }
133
+
134
+ if model_name in self.MODEL_SPECS:
135
+ return self.MODEL_SPECS[model_name].to_dict()
136
+
137
+ return None
138
+
139
+ def execute_tool(self, tool_name: str, event_bus, *args, **kwargs):
140
+ self._tools_adapter.event_bus = event_bus
141
+ return self._tools_adapter.execute_by_name(tool_name, *args, **kwargs)
142
+
143
+
144
+ # Register the provider
145
+ LLMProviderRegistry.register(CerebrasProvider.name, CerebrasProvider)
@@ -52,4 +52,4 @@ class ReadFilesTool(ToolBase):
52
52
  results.append(
53
53
  f"--- File: {disp_path} (error) ---\nError reading file: {e}\n"
54
54
  )
55
- return "\n".join(results)
55
+ return "\n".join(results)
@@ -135,6 +135,7 @@ def _extract_path_keys_from_schema(schema: Mapping[str, Any]) -> set[str]:
135
135
  path_keys: set[str] = set()
136
136
  if schema is not None:
137
137
  for k, v in schema.get("properties", {}).items():
138
+ # Handle direct path strings
138
139
  if v.get("format") == "path" or (
139
140
  v.get("type") == "string"
140
141
  and (
@@ -144,6 +145,19 @@ def _extract_path_keys_from_schema(schema: Mapping[str, Any]) -> set[str]:
144
145
  )
145
146
  ):
146
147
  path_keys.add(k)
148
+ # Handle arrays of path strings
149
+ elif v.get("type") == "array" and "items" in v:
150
+ items = v["items"]
151
+ if items.get("format") == "path" or (
152
+ items.get("type") == "string"
153
+ and (
154
+ "path" in items.get("description", "").lower()
155
+ or "path" in v.get("description", "").lower()
156
+ or k.endswith("paths")
157
+ or k == "paths"
158
+ )
159
+ ):
160
+ path_keys.add(k)
147
161
  return path_keys
148
162
 
149
163
 
@@ -131,9 +131,15 @@ class ToolsAdapterBase:
131
131
 
132
132
  if arguments is None:
133
133
  arguments = {}
134
- # Ensure the input is a dict to avoid breaking the inspect-based logic
134
+ # If arguments are provided as a non-dict (e.g. a list or a scalar)
135
+ # we skip signature *keyword* validation completely and defer the
136
+ # decision to Python's own call mechanics when the function is
137
+ # eventually invoked. This allows positional / variadic arguments to
138
+ # be supplied by callers that intentionally bypass the structured
139
+ # JSON-schema style interface.
135
140
  if not isinstance(arguments, dict):
136
- return "Tool arguments should be provided as an object / mapping"
141
+ # Nothing to validate at this stage treat as OK.
142
+ return None
137
143
 
138
144
  sig = inspect.signature(func)
139
145
  params = sig.parameters
@@ -193,30 +199,32 @@ class ToolsAdapterBase:
193
199
  )
194
200
 
195
201
  schema = getattr(tool, "schema", None)
196
- try:
197
- validate_paths_in_arguments(arguments, workdir, schema=schema)
198
- except PathSecurityError as sec_err:
199
- # Publish both a ToolCallError and a user-facing ReportEvent for path security errors
200
- self._publish_tool_call_error(
201
- tool_name, request_id, str(sec_err), arguments
202
- )
203
- if self._event_bus:
204
- from janito.report_events import (
205
- ReportEvent,
206
- ReportSubtype,
207
- ReportAction,
202
+ # Only validate paths for dictionary-style arguments
203
+ if isinstance(arguments, dict):
204
+ try:
205
+ validate_paths_in_arguments(arguments, workdir, schema=schema)
206
+ except PathSecurityError as sec_err:
207
+ # Publish both a ToolCallError and a user-facing ReportEvent for path security errors
208
+ self._publish_tool_call_error(
209
+ tool_name, request_id, str(sec_err), arguments
208
210
  )
211
+ if self._event_bus:
212
+ from janito.report_events import (
213
+ ReportEvent,
214
+ ReportSubtype,
215
+ ReportAction,
216
+ )
209
217
 
210
- self._event_bus.publish(
211
- ReportEvent(
212
- subtype=ReportSubtype.ERROR,
213
- message=f"[SECURITY] Path access denied: {sec_err}",
214
- action=ReportAction.EXECUTE,
215
- tool=tool_name,
216
- context={"arguments": arguments, "request_id": request_id},
218
+ self._event_bus.publish(
219
+ ReportEvent(
220
+ subtype=ReportSubtype.ERROR,
221
+ message=f"[SECURITY] Path access denied: {sec_err}",
222
+ action=ReportAction.EXECUTE,
223
+ tool=tool_name,
224
+ context={"arguments": arguments, "request_id": request_id},
225
+ )
217
226
  )
218
- )
219
- return f"Security error: {sec_err}"
227
+ return f"Security error: {sec_err}"
220
228
  # --- END SECURITY ---
221
229
 
222
230
  self._publish_tool_call_started(tool_name, request_id, arguments)
@@ -224,7 +232,18 @@ class ToolsAdapterBase:
224
232
  f"[tools-adapter] Executing tool: {tool_name} with arguments: {arguments}"
225
233
  )
226
234
  try:
227
- result = self.execute(tool, **(arguments or {}), **kwargs)
235
+ # Normalize arguments to ensure proper type handling
236
+ normalized_args = self._normalize_arguments(arguments, tool, func)
237
+
238
+ if isinstance(normalized_args, (list, tuple)):
239
+ # Positional arguments supplied as an array → expand as *args
240
+ result = self.execute(tool, *normalized_args, **kwargs)
241
+ elif isinstance(normalized_args, dict) or normalized_args is None:
242
+ # Keyword-style arguments (the default) – pass as **kwargs
243
+ result = self.execute(tool, **(normalized_args or {}), **kwargs)
244
+ else:
245
+ # Single positional argument (scalar/str/int/…)
246
+ result = self.execute(tool, normalized_args, **kwargs)
228
247
  except Exception as e:
229
248
  self._handle_execution_error(tool_name, request_id, e, arguments)
230
249
  self._print_verbose(
@@ -281,6 +300,65 @@ class ToolsAdapterBase:
281
300
  if self.verbose_tools:
282
301
  print(message)
283
302
 
303
+ def _normalize_arguments(self, arguments, tool, func):
304
+ """
305
+ Normalize arguments to ensure proper type handling at the adapter level.
306
+
307
+ This handles cases where:
308
+ 1. String is passed instead of list for array parameters
309
+ 2. JSON string parsing issues
310
+ 3. Other type mismatches that can be automatically resolved
311
+ """
312
+ import inspect
313
+ import json
314
+
315
+ # If arguments is already a dict or None, return as-is
316
+ if isinstance(arguments, dict) or arguments is None:
317
+ return arguments
318
+
319
+ # If arguments is a list/tuple, return as-is (positional args)
320
+ if isinstance(arguments, (list, tuple)):
321
+ return arguments
322
+
323
+ # Handle string arguments
324
+ if isinstance(arguments, str):
325
+ # Try to parse as JSON if it looks like JSON
326
+ stripped = arguments.strip()
327
+ if (stripped.startswith('{') and stripped.endswith('}')) or \
328
+ (stripped.startswith('[') and stripped.endswith(']')):
329
+ try:
330
+ parsed = json.loads(arguments)
331
+ return parsed
332
+ except json.JSONDecodeError:
333
+ # If it looks like JSON but failed, try to handle common issues
334
+ pass
335
+
336
+ # Check if the function expects a list parameter
337
+ try:
338
+ sig = inspect.signature(func)
339
+ params = list(sig.parameters.values())
340
+
341
+ # Skip 'self' parameter for methods
342
+ if len(params) > 0 and params[0].name == 'self':
343
+ params = params[1:]
344
+
345
+ # If there's exactly one parameter that expects a list, wrap string in list
346
+ if len(params) == 1:
347
+ param = params[0]
348
+ annotation = param.annotation
349
+
350
+ # Check if annotation is list[str] or similar
351
+ if hasattr(annotation, '__origin__') and annotation.__origin__ is list:
352
+ return [arguments]
353
+ elif str(annotation).startswith('list[') or str(annotation) == 'list':
354
+ return [arguments]
355
+
356
+ except (ValueError, TypeError):
357
+ pass
358
+
359
+ # Return original arguments for other cases
360
+ return arguments
361
+
284
362
  def execute_function_call_message_part(self, function_call_message_part):
285
363
  """
286
364
  Execute a FunctionCallMessagePart by extracting the tool name and arguments and dispatching to execute_by_name.
@@ -298,9 +376,23 @@ class ToolsAdapterBase:
298
376
  # Parse arguments if they are a JSON string
299
377
  if isinstance(arguments, str):
300
378
  try:
379
+ # Try to parse as JSON first
301
380
  arguments = json.loads(arguments)
302
- except Exception:
303
- pass # Leave as string if not JSON
381
+ except json.JSONDecodeError:
382
+ # Handle single quotes in JSON strings
383
+ try:
384
+ # Replace single quotes with double quotes for JSON compatibility
385
+ fixed_json = arguments.replace("'", '"')
386
+ arguments = json.loads(fixed_json)
387
+ except (json.JSONDecodeError, ValueError):
388
+ # If it's a string that looks like it might be a single path parameter,
389
+ # try to handle it gracefully
390
+ if arguments.startswith("{") and arguments.endswith("}"):
391
+ # Looks like JSON but failed to parse - this is likely an error
392
+ pass
393
+ else:
394
+ # Single string argument - let the normalization handle it
395
+ pass
304
396
  if self.verbose_tools:
305
397
  print(
306
398
  f"[tools-adapter] Executing FunctionCallMessagePart: tool={tool_name}, arguments={arguments}, tool_call_id={tool_call_id}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: janito
3
- Version: 2.16.0
3
+ Version: 2.17.1
4
4
  Summary: A new Python package called janito.
5
5
  Author-email: João Pinto <janito@ikignosis.org>
6
6
  Project-URL: Homepage, https://github.com/ikignosis/janito
@@ -20,7 +20,7 @@ janito/provider_registry.py,sha256=l0jJZ74KIebOSYXPiy7uqH8d48pckR_WTyAO4iQF98o,6
20
20
  janito/report_events.py,sha256=q4OR_jTZNfcqaQF_fzTjgqo6_VlUIxSGWfhpT4nJWcw,938
21
21
  janito/shell.bak.zip,sha256=hznHbmgfkAkjuQDJ3w73XPQh05yrtUZQxLmtGbanbYU,22
22
22
  janito/utils.py,sha256=eXSsMgM69YyzahgCNrJQLcEbB8ssLI1MQqaa20ONxbE,376
23
- janito/agent/setup_agent.py,sha256=ibi1oHyAFkf0FHgN6QCHXF8tz8IfM79ugAMlVKttWYw,11605
23
+ janito/agent/setup_agent.py,sha256=HQU_h1P8VXiOVURjQ4SwvO-R3rujs6xUcPvrNniRDok,11618
24
24
  janito/agent/templates/profiles/system_prompt_template_Developer_with_Python_Tools.txt.j2,sha256=28TITVITH4RTdOwPpNZFSygm6OSpFb_Jr4mHprrLBhc,2584
25
25
  janito/agent/templates/profiles/system_prompt_template_developer.txt.j2,sha256=zj0ZA17iYt-6c0usgjUw_cLKnb5qDuixpxS9et5ECyw,2272
26
26
  janito/agent/templates/profiles/system_prompt_template_model_conversation_without_tools_or_context.txt.j2,sha256=dTV9aF8ji2r9dzi-l4b9r95kHrbKmjvnRxk5cVpopN4,28
@@ -31,7 +31,7 @@ janito/cli/main.py,sha256=s5odou0txf8pzTf1ADk2yV7T5m8B6cejJ81e7iu776U,312
31
31
  janito/cli/main_cli.py,sha256=21XPZ5Kp4ye2kEzkhcBtWe60Pe7XYAtzlZOf5RHNDuU,15280
32
32
  janito/cli/prompt_core.py,sha256=F68J4Xl6jZMYFN4oBBYZFj15Jp-HTYoLub4bw2XpNRU,11648
33
33
  janito/cli/prompt_handler.py,sha256=SnPTlL64noeAMGlI08VBDD5IDD8jlVMIYA4-fS8zVLg,215
34
- janito/cli/prompt_setup.py,sha256=1s5yccFaWMgDkUjkvnTYGEWJAFPJ6hIiqwbrLfzWxMI,2038
34
+ janito/cli/prompt_setup.py,sha256=1SSvvgS568-3BO_4Sw9A-QF_iLWiIXsNHT0JVqaLwkU,2120
35
35
  janito/cli/rich_terminal_reporter.py,sha256=_-eRzrxM-lCD31KjElCroSVx1vbBcG2Lo8gDVE0v9Yc,6785
36
36
  janito/cli/utils.py,sha256=plCQiDKIf3V8mFhhX5H9-MF2W86i-xRdWf8Xi117Z0w,677
37
37
  janito/cli/verbose_output.py,sha256=wY_B4of5e8Vv7w1fRwOZzNGU2JqbMdcFnGjtEr4hLus,7686
@@ -73,7 +73,7 @@ janito/cli/chat_mode/shell/session/__init__.py,sha256=uTYE_QpZFEn7v9QE5o1LdulpCW
73
73
  janito/cli/chat_mode/shell/session/history.py,sha256=tYav6GgjAZkvWhlI_rfG6OArNqW6Wn2DTv39Hb20QYc,1262
74
74
  janito/cli/chat_mode/shell/session/manager.py,sha256=MwD9reHsRaly0CyRB-S1JJ0wPKz2g8Xdj2VvlU35Hgc,1001
75
75
  janito/cli/cli_commands/list_config.py,sha256=oiQEGaGPjwjG-PrOcakpNMbbqISTsBEs7rkGH3ceQsI,1179
76
- janito/cli/cli_commands/list_drivers.py,sha256=8WhcVL4igdkyyeaxScsYZwqvDgfM_ZSaJgZ1BokjZUk,5056
76
+ janito/cli/cli_commands/list_drivers.py,sha256=r2ENykUcvf_9XYp6LHd3RvLXGXyVUA6oe_Pr0dyv92I,5124
77
77
  janito/cli/cli_commands/list_models.py,sha256=_rqHz89GsNLcH0GGkFqPue7ah4ZbN9YHm0lEP30Aa-A,1111
78
78
  janito/cli/cli_commands/list_profiles.py,sha256=9-HV2EbtP2AdubbMoakjbu7Oq4Ss9UDyO7Eb6CC52wI,2681
79
79
  janito/cli/cli_commands/list_providers.py,sha256=v8OQ8ULnuzNuvgkeKqGXGj69eOiavAlPGhzfR0zavhg,185
@@ -81,7 +81,7 @@ janito/cli/cli_commands/list_providers_region.py,sha256=qrMj_gtgEMty8UH0P_O5SgWC
81
81
  janito/cli/cli_commands/list_tools.py,sha256=JFRdlhPeA3BzhJ2PkjIt3u137IJoNc-vYSjUuPlaOXw,3593
82
82
  janito/cli/cli_commands/model_selection.py,sha256=ANWtwC5glZkGMdaNtARDbEG3QmuBUcDLVxzzC5jeBNo,1643
83
83
  janito/cli/cli_commands/model_utils.py,sha256=U0j2FTpcIBc4eAc40MXz5tyAK3m8lkakpOS2l2bGh4A,2868
84
- janito/cli/cli_commands/set_api_key.py,sha256=iPtWPhS5VeyIlwVX43TGg7OYUwXCcGzugvwoa3KB8A8,605
84
+ janito/cli/cli_commands/set_api_key.py,sha256=ZItSuB0HO14UsbyXXCgTKAXS-EUCHfCkntzg3WAAtK0,1048
85
85
  janito/cli/cli_commands/show_config.py,sha256=eYMcuvU-d7mvvuctbQacZFERqcKHEnxaRRjasyj-_lE,2004
86
86
  janito/cli/cli_commands/show_system_prompt.py,sha256=9ZJGW7lIGJ9LX2JZiWVEm4AbaD0qEQO7LF89jPgk52I,5232
87
87
  janito/cli/core/__init__.py,sha256=YH95fhgY9yBX8RgqX9dSrEkl4exjV0T4rbmJ6xUpG-Y,196
@@ -97,6 +97,7 @@ janito/docs/GETTING_STARTED.md,sha256=EbXV7B3XxjSy1E0XQJFOVITVbTmZBVB7pjth2Mb4_r
97
97
  janito/drivers/dashscope.bak.zip,sha256=9Pv4Xyciju8jO1lEMFVgYXexoZkxmDO3Ig6vw3ODfL8,4936
98
98
  janito/drivers/openai_responses.bak.zip,sha256=E43eDCHGa2tCtdjzj_pMnWDdnsOZzj8BJTR5tJp8wcM,13352
99
99
  janito/drivers/azure_openai/driver.py,sha256=L2rQOl1d0BHaDChHLtZszAeuWNoyYIgwuYuahE1qJps,4152
100
+ janito/drivers/cerebras/__init__.py,sha256=yGkKANI4xKT_2j6x1-RBJhmaRzEGyt1DFaBSLt7EtYU,25
100
101
  janito/drivers/openai/README.md,sha256=bgPdaYX0pyotCoJ9t3cJbYM-teQ_YM1DAFEKLCMP32Q,666
101
102
  janito/drivers/openai/driver.py,sha256=ITwonFiux8pVIlCuD9jy1og3sGc-rHH2_LQFRHZvBRc,19152
102
103
  janito/drivers/zai/__init__.py,sha256=rleES3ZJEslJ8M02TdTPyxHKXxA4-e2fDJa6yjuzY8s,22
@@ -121,16 +122,19 @@ janito/llm/driver_input.py,sha256=Zq7IO4KdQPUraeIo6XoOaRy1IdQAyYY15RQw4JU30uA,38
121
122
  janito/llm/message_parts.py,sha256=QY_0kDjaxdoErDgKPRPv1dNkkYJuXIBmHWNLiOEKAH4,1365
122
123
  janito/llm/model.py,sha256=42hjcffZDTuzjAJoVhDcDqwIXm6rUmmi5UwTOYopf5w,1131
123
124
  janito/llm/provider.py,sha256=3FbhQPrWBSEoIdIi-5DWIh0DD_CM570EFf1NcuGyGko,7961
124
- janito/providers/__init__.py,sha256=P2r90SUduTqn0CumjpJ9yojx2BUKDVy136xdbA8I6VU,407
125
+ janito/providers/__init__.py,sha256=wlb8-dfnWRsZclFTT5cbwYqSWFpppChrAxZEgpdBgng,450
125
126
  janito/providers/dashscope.bak.zip,sha256=BwXxRmZreEivvRtmqbr5BR62IFVlNjAf4y6DrF2BVJo,5998
126
127
  janito/providers/registry.py,sha256=Ygwv9eVrTXOKhv0EKxSWQXO5WMHvajWE2Q_Lc3p7dKo,730
127
128
  janito/providers/alibaba/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
128
129
  janito/providers/alibaba/model_info.py,sha256=evAW2CZUX9qgRAzDhZTp47ZNj4G1T7W66gkV60Nfan8,1264
129
- janito/providers/alibaba/provider.py,sha256=wB8wJEro4ao7osLJyZqd6jpuiTpfbpVTeGEmgZsnWDM,4220
130
+ janito/providers/alibaba/provider.py,sha256=UVNOdUX4SJln1OS10AY-Zq1THp538yhpEKPqLKyEGKU,4178
130
131
  janito/providers/anthropic/model_info.py,sha256=m6pBh0Ia8_xC1KZ7ke_4HeHIFw7nWjnYVItnRpkCSWc,1206
131
132
  janito/providers/anthropic/provider.py,sha256=aGynBxCFc7oTyvGNDUkbutJCKurC_9J4AkReC2LTPYo,3023
132
133
  janito/providers/azure_openai/model_info.py,sha256=TMSqEpQROIIYUGAyulYJ5xGhj7CbLoaKL_JXeLbXaG0,689
133
134
  janito/providers/azure_openai/provider.py,sha256=3pUYcdHrIcK1N1Pmw96tJvFo4lVse2wfZhGS9D2N3dw,5404
135
+ janito/providers/cerebras/__init__.py,sha256=pnbDTkbIG9fyF8YNOZOqdUwOGKc5ehq9oMWt625Jnis,27
136
+ janito/providers/cerebras/model_info.py,sha256=oxgssDXZCluCqkfZ5J1-gZqCVvVqCJIXsT0SFoONik4,2408
137
+ janito/providers/cerebras/provider.py,sha256=ZyGE_wWXKyRJQCYTs_FWOvZYqVu7-xRAmV1h8YMJU5s,5661
134
138
  janito/providers/deepseek/__init__.py,sha256=4sISEpq4bJO29vxFK9cfnO-SRUmKoD7oSdeCvz0hVno,36
135
139
  janito/providers/deepseek/model_info.py,sha256=tAlFRtWiyNF_MKZ1gy5_-VNlvqoIwAinv6bAv9dNFsc,465
136
140
  janito/providers/deepseek/provider.py,sha256=eU-wwVqJog_oJ8VyQyohm6OMHlvrddSszqTfT9Aoc-U,4106
@@ -158,7 +162,7 @@ janito/tools/__init__.py,sha256=W1B39PztC2UF7PS2WyLH6el32MFOETMlN1-LurOROCg,1171
158
162
  janito/tools/disabled_tools.py,sha256=Tx__16wtMWZ9z34cYLdH1gukwot5MCL-9kLjd5MPX6Y,2110
159
163
  janito/tools/inspect_registry.py,sha256=Jo7PrMPRKLuR-j_mBAk9PBcTzeJf1eQrS1ChGofgQk0,538
160
164
  janito/tools/outline_file.bak.zip,sha256=EeI2cBXCwTdWVgJDNiroxKeYlkjwo6NLKeXz3J-2iZI,15607
161
- janito/tools/path_security.py,sha256=dCE8pPCtMElVm1jatpYmXkc8lK9CHCK_4K0JIhqn1f4,7584
165
+ janito/tools/path_security.py,sha256=40b0hV0X3449Dht93A04Q3c9AYSsBQsBFy2BjzM83lA,8214
162
166
  janito/tools/permissions.py,sha256=_viTVXyetZC01HjI2s5c3klIJ8-RkWB1ShdOaV__loY,1508
163
167
  janito/tools/permissions_parse.py,sha256=LHadt0bWglm9Q2BbbVVbKePg4oa7QLeRQ-ChQZsE_dI,384
164
168
  janito/tools/tool_base.py,sha256=TSrXDknqIqOtY3xzuvtsxZ3qwbvmGzUruBiqVzzICfc,3689
@@ -166,7 +170,7 @@ janito/tools/tool_events.py,sha256=czRtC2TYakAySBZvfHS_Q6_NY_7_krxzAzAL1ggRFWA,1
166
170
  janito/tools/tool_run_exception.py,sha256=43yWgTaGBGEtRteo6FvTrane6fEVGo9FU1uOdjMRWJE,525
167
171
  janito/tools/tool_use_tracker.py,sha256=IaEmA22D6RuL1xMUCScOMGv0crLPwEJVGmj49cydIaM,2662
168
172
  janito/tools/tool_utils.py,sha256=alPm9DvtXSw_zPRKvP5GjbebPRf_nfvmWk2TNlL5Cws,1219
169
- janito/tools/tools_adapter.py,sha256=wLtsdiyRFNDp5xFWN_h5yN4b-eFfYP6rEVQa_JNbFVA,14108
173
+ janito/tools/tools_adapter.py,sha256=aPzyJnm1pNwsEKNcXs-gKFurlOaZqzxkiktHOjITp_8,18724
170
174
  janito/tools/tools_schema.py,sha256=rGrKrmpPNR07VXHAJ_haGBRRO-YGLOF51BlYRep9AAQ,4415
171
175
  janito/tools/adapters/__init__.py,sha256=XKixOKtUJs1R-rGwGDXSLVLg5-Kp090gvWbsseWT4LI,92
172
176
  janito/tools/adapters/local/__init__.py,sha256=_nxMg2uPX18DHNtyHR6SDwYMZvDLpy6gyaCt-75unao,2172
@@ -184,7 +188,7 @@ janito/tools/adapters/local/open_url.py,sha256=WHOJ2TaUVye2iUnrcdu93A_xKBx2lYcK0
184
188
  janito/tools/adapters/local/python_code_run.py,sha256=UrQ_rv_qVjY1vNdpACDAma5eFbAj_WhvgQjghRpv9hg,6681
185
189
  janito/tools/adapters/local/python_command_run.py,sha256=M-TxoGND45zKSMrYPjD6juSo0UhfsilXEBiyQdzQkiI,6621
186
190
  janito/tools/adapters/local/python_file_run.py,sha256=OsHc9rpyGWUjLE7Zin9Gl7YOLf9QVe8NoXXcdTkpJyE,6466
187
- janito/tools/adapters/local/read_files.py,sha256=lz17lK5R1NlmCfLdikhFKGzBC4b2TedyIKrM-aM9m5c,2094
191
+ janito/tools/adapters/local/read_files.py,sha256=2wYo60G6FCzpcpiBFv9-XBqSD6j4oO2AUe3v7Gm90kQ,2092
188
192
  janito/tools/adapters/local/remove_directory.py,sha256=g1wkHcWNgtv3mfuZ4GfvqtKU3th-Du_058FMcNmc1TA,1830
189
193
  janito/tools/adapters/local/remove_file.py,sha256=cSs7EIhEqblnLmwjUKrUq2M8axyT2oTXJqZs5waOAFw,2090
190
194
  janito/tools/adapters/local/replace_text_in_file.py,sha256=zFGWORuaw50ZlEFf3q_s7K25Tt0QXu8yOXDeodY6kcE,10791
@@ -213,9 +217,9 @@ janito/tools/adapters/local/validate_file_syntax/ps1_validator.py,sha256=TeIkPt0
213
217
  janito/tools/adapters/local/validate_file_syntax/python_validator.py,sha256=BfCO_K18qy92m-2ZVvHsbEU5e11OPo1pO9Vz4G4616E,130
214
218
  janito/tools/adapters/local/validate_file_syntax/xml_validator.py,sha256=AijlsP_PgNuC8ZbGsC5vOTt3Jur76otQzkd_7qR0QFY,284
215
219
  janito/tools/adapters/local/validate_file_syntax/yaml_validator.py,sha256=TgyI0HRL6ug_gBcWEm5TGJJuA4E34ZXcIzMpAbv3oJs,155
216
- janito-2.16.0.dist-info/licenses/LICENSE,sha256=GSAKapQH5ZIGWlpQTA7v5YrfECyaxaohUb1vJX-qepw,1090
217
- janito-2.16.0.dist-info/METADATA,sha256=R3XPF2v8VmjybUFGs6ReYnItEfJk5kblKsSOjY7LvEo,16365
218
- janito-2.16.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
219
- janito-2.16.0.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
220
- janito-2.16.0.dist-info/top_level.txt,sha256=m0NaVCq0-ivxbazE2-ND0EA9Hmuijj_OGkmCbnBcCig,7
221
- janito-2.16.0.dist-info/RECORD,,
220
+ janito-2.17.1.dist-info/licenses/LICENSE,sha256=GSAKapQH5ZIGWlpQTA7v5YrfECyaxaohUb1vJX-qepw,1090
221
+ janito-2.17.1.dist-info/METADATA,sha256=-5Gl5IbWdd_Fi-ecNEpqQgWNe5O_e_ZuKPKeZimz-zg,16365
222
+ janito-2.17.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
223
+ janito-2.17.1.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
224
+ janito-2.17.1.dist-info/top_level.txt,sha256=m0NaVCq0-ivxbazE2-ND0EA9Hmuijj_OGkmCbnBcCig,7
225
+ janito-2.17.1.dist-info/RECORD,,