ziya 0.3.0__py3-none-any.whl → 0.3.2__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.

Potentially problematic release.


This version of ziya might be problematic. Click here for more details.

Files changed (73) hide show
  1. app/agents/agent.py +71 -73
  2. app/agents/direct_streaming.py +1 -1
  3. app/agents/prompts.py +1 -1
  4. app/agents/prompts_manager.py +14 -10
  5. app/agents/wrappers/google_direct.py +31 -1
  6. app/agents/wrappers/nova_tool_execution.py +2 -2
  7. app/agents/wrappers/nova_wrapper.py +1 -1
  8. app/agents/wrappers/ziya_bedrock.py +53 -31
  9. app/config/models_config.py +61 -20
  10. app/config/shell_config.py +5 -1
  11. app/extensions/prompt_extensions/claude_extensions.py +27 -5
  12. app/extensions/prompt_extensions/mcp_prompt_extensions.py +82 -56
  13. app/main.py +5 -3
  14. app/mcp/client.py +19 -10
  15. app/mcp/manager.py +68 -10
  16. app/mcp/tools.py +8 -9
  17. app/mcp_servers/shell_server.py +3 -3
  18. app/middleware/streaming.py +29 -41
  19. app/routes/file_validation.py +35 -0
  20. app/routes/mcp_routes.py +54 -8
  21. app/server.py +525 -614
  22. app/streaming_tool_executor.py +748 -137
  23. app/templates/asset-manifest.json +20 -20
  24. app/templates/index.html +1 -1
  25. app/templates/static/css/{main.0297bfee.css → main.e7109b49.css} +2 -2
  26. app/templates/static/css/main.e7109b49.css.map +1 -0
  27. app/templates/static/js/14386.65fcfe53.chunk.js +2 -0
  28. app/templates/static/js/14386.65fcfe53.chunk.js.map +1 -0
  29. app/templates/static/js/35589.0368973a.chunk.js +2 -0
  30. app/templates/static/js/35589.0368973a.chunk.js.map +1 -0
  31. app/templates/static/js/{50295.ab92f61b.chunk.js → 50295.90aca393.chunk.js} +3 -3
  32. app/templates/static/js/50295.90aca393.chunk.js.map +1 -0
  33. app/templates/static/js/55734.5f0fd567.chunk.js +2 -0
  34. app/templates/static/js/55734.5f0fd567.chunk.js.map +1 -0
  35. app/templates/static/js/58542.57fed736.chunk.js +2 -0
  36. app/templates/static/js/58542.57fed736.chunk.js.map +1 -0
  37. app/templates/static/js/{68418.2554bb1e.chunk.js → 68418.f7b4d2d9.chunk.js} +3 -3
  38. app/templates/static/js/68418.f7b4d2d9.chunk.js.map +1 -0
  39. app/templates/static/js/99948.b280eda0.chunk.js +2 -0
  40. app/templates/static/js/99948.b280eda0.chunk.js.map +1 -0
  41. app/templates/static/js/main.e075582c.js +3 -0
  42. app/templates/static/js/main.e075582c.js.map +1 -0
  43. app/utils/code_util.py +5 -2
  44. app/utils/context_cache.py +11 -0
  45. app/utils/conversation_filter.py +90 -0
  46. app/utils/custom_bedrock.py +43 -1
  47. app/utils/diff_utils/validation/validators.py +32 -22
  48. app/utils/file_cache.py +5 -3
  49. app/utils/precision_prompt_system.py +116 -0
  50. app/utils/streaming_optimizer.py +100 -0
  51. {ziya-0.3.0.dist-info → ziya-0.3.2.dist-info}/METADATA +3 -2
  52. {ziya-0.3.0.dist-info → ziya-0.3.2.dist-info}/RECORD +59 -55
  53. app/templates/static/css/main.0297bfee.css.map +0 -1
  54. app/templates/static/js/14386.567bf803.chunk.js +0 -2
  55. app/templates/static/js/14386.567bf803.chunk.js.map +0 -1
  56. app/templates/static/js/35589.278ecda2.chunk.js +0 -2
  57. app/templates/static/js/35589.278ecda2.chunk.js.map +0 -1
  58. app/templates/static/js/50295.ab92f61b.chunk.js.map +0 -1
  59. app/templates/static/js/55734.90d8bd52.chunk.js +0 -2
  60. app/templates/static/js/55734.90d8bd52.chunk.js.map +0 -1
  61. app/templates/static/js/58542.08fb5cf4.chunk.js +0 -2
  62. app/templates/static/js/58542.08fb5cf4.chunk.js.map +0 -1
  63. app/templates/static/js/68418.2554bb1e.chunk.js.map +0 -1
  64. app/templates/static/js/99948.71670e91.chunk.js +0 -2
  65. app/templates/static/js/99948.71670e91.chunk.js.map +0 -1
  66. app/templates/static/js/main.1d79eac2.js +0 -3
  67. app/templates/static/js/main.1d79eac2.js.map +0 -1
  68. /app/templates/static/js/{50295.ab92f61b.chunk.js.LICENSE.txt → 50295.90aca393.chunk.js.LICENSE.txt} +0 -0
  69. /app/templates/static/js/{68418.2554bb1e.chunk.js.LICENSE.txt → 68418.f7b4d2d9.chunk.js.LICENSE.txt} +0 -0
  70. /app/templates/static/js/{main.1d79eac2.js.LICENSE.txt → main.e075582c.js.LICENSE.txt} +0 -0
  71. {ziya-0.3.0.dist-info → ziya-0.3.2.dist-info}/WHEEL +0 -0
  72. {ziya-0.3.0.dist-info → ziya-0.3.2.dist-info}/entry_points.txt +0 -0
  73. {ziya-0.3.0.dist-info → ziya-0.3.2.dist-info}/licenses/LICENSE +0 -0
@@ -80,13 +80,19 @@ class StreamingMiddleware(BaseHTTPMiddleware):
80
80
  self._recent_lines = []
81
81
  accumulated_content = ""
82
82
  accumulated_chunks = [] # Track all chunks for better preservation
83
+
84
+ # Code block state tracking for frontend
85
+ frontend_code_block_state = {
86
+ 'in_block': False,
87
+ 'block_type': None
88
+ }
83
89
 
84
90
  # Limits for preserved content to prevent context bloat
85
91
  MAX_PRESERVED_TOOLS = 10
86
92
  MAX_TOOL_OUTPUT_LENGTH = 5000
87
93
  successful_tool_outputs = [] # Track successful tool executions
88
94
  tool_sequence_count = 0
89
- content_buffer = "" # Buffer to hold content while checking for tool calls
95
+ # content_buffer = "" # Disabled buffering for real-time streaming
90
96
  partial_response_preserved = False
91
97
  try:
92
98
  async for chunk in original_iterator:
@@ -138,7 +144,7 @@ class StreamingMiddleware(BaseHTTPMiddleware):
138
144
  chunk_content = json.dumps(json_obj)
139
145
 
140
146
  # DEBUGGING: Check if JSON serialization changed size
141
- if len(chunk_content) != chunk_size and json_obj.get('type') == 'tool_execution':
147
+ if len(chunk_content) != chunk_size and json_obj.get('type') in ['tool_execution', 'tool_display']:
142
148
  logger.warning(f"🔍 JSON_SIZE_CHANGE: Original {chunk_size} -> Serialized {len(chunk_content)} chars")
143
149
 
144
150
  yield f"data: {json.dumps(json_obj)}\n\n"
@@ -146,46 +152,18 @@ class StreamingMiddleware(BaseHTTPMiddleware):
146
152
  # If it's not valid JSON, just pass it as a string
147
153
  content = str(chunk)
148
154
 
149
- # Buffer content to check for tool calls
150
- content_buffer += content
151
-
152
- # Check if we have a complete tool call or if we should flush the buffer
153
- if self._should_flush_buffer(content_buffer):
154
- # If this contains a complete tool call, execute it and send the result
155
- if self._contains_complete_tool_call(content_buffer):
156
- # First, send the complete tool call to the frontend as JSON
157
- yield f"data: {json.dumps({'tool_call': content_buffer})}\n\n"
158
-
159
- try:
160
- # Execute the tool call
161
- logger.info(f"Executing tool call in streaming middleware: {content_buffer[:100]}...")
162
- from app.mcp.consolidated import execute_mcp_tools_with_status
163
- tool_result = await execute_mcp_tools_with_status(content_buffer)
164
- logger.info(f"Tool execution result: {tool_result[:100]}...")
165
-
166
- # Send the tool result to the frontend
167
- yield f"data: {json.dumps({'tool_result': tool_result})}\n\n"
168
- except Exception as tool_error:
169
- logger.error(f"Error executing tool call: {tool_error}")
170
- # Send error message
171
- error_msg = f"\n\n```tool:error\n❌ **Tool Error:** {str(tool_error)}\n```\n\n"
172
- yield f"data: {json.dumps({'tool_error': error_msg})}\n\n"
173
-
174
- # Clear buffer
175
- content_buffer = ""
176
- else:
177
- # Send buffered content as JSON, not raw content
155
+ # Immediately pass through tool_start messages without buffering
156
+ if '"type": "tool_start"' in content:
157
+ # First flush any buffered content
158
+ if content_buffer:
178
159
  yield f"data: {json.dumps({'content': content_buffer})}\n\n"
179
160
  content_buffer = ""
180
- elif self._contains_partial(content_buffer):
181
- # Still accumulate partial content
182
- accumulated_content += content
183
- # Hold the content in buffer, don't send yet
161
+ # Then send the tool_start message
162
+ yield content
184
163
  continue
185
- else:
186
- # Safe to send immediately as raw content
187
- yield f"data: {content}\n\n"
188
- content_buffer = ""
164
+
165
+ # Send content immediately for real-time streaming
166
+ yield f"data: {json.dumps({'content': content})}\\n\\n"
189
167
 
190
168
  # Log chunk content preview
191
169
  if len(chunk) > 200:
@@ -247,6 +225,16 @@ class StreamingMiddleware(BaseHTTPMiddleware):
247
225
  # For simple string content
248
226
  content = str(raw_content)
249
227
 
228
+ # Immediately pass through tool_start messages without buffering
229
+ if '"type": "tool_start"' in content:
230
+ # First flush any buffered content
231
+ if content_buffer:
232
+ yield f"data: {json.dumps({'content': content_buffer})}\n\n"
233
+ content_buffer = ""
234
+ # Then send the tool_start message
235
+ yield content
236
+ continue
237
+
250
238
  # Buffer content to check for tool calls
251
239
  content_buffer += content
252
240
 
@@ -354,7 +342,7 @@ class StreamingMiddleware(BaseHTTPMiddleware):
354
342
  logger.warning(f"🔍 LARGE_CHUNK_DETECTED: {chunk_size} chars - monitoring for truncation")
355
343
 
356
344
  # Check if this is a tool result chunk
357
- if "tool_execution" in chunk or "tool_result" in chunk:
345
+ if "tool_execution" in chunk or "tool_display" in chunk or "tool_result" in chunk:
358
346
  logger.info(f"🔍 TOOL_RESULT_CHUNK: size={chunk_size}, content preview: {chunk[:100]}...")
359
347
 
360
348
  # Check if it might be JSON
@@ -368,7 +356,7 @@ class StreamingMiddleware(BaseHTTPMiddleware):
368
356
  # DEBUGGING: Track large JSON objects
369
357
  if len(chunk_content) > 5000:
370
358
  logger.warning(f"🔍 MIDDLEWARE_LARGE_JSON: {len(chunk_content)} chars, type={json_obj.get('type')}")
371
- if json_obj.get('type') == 'tool_execution':
359
+ if json_obj.get('type') in ['tool_execution', 'tool_display']:
372
360
  result_size = len(json_obj.get('result', ''))
373
361
  logger.warning(f"🔍 MIDDLEWARE_TOOL_RESULT: tool={json_obj.get('tool_name')}, result_size={result_size}")
374
362
  if result_size == 0:
@@ -0,0 +1,35 @@
1
+ """
2
+ File validation API endpoint.
3
+ """
4
+
5
+ import os
6
+ from typing import List
7
+ from fastapi import APIRouter, HTTPException
8
+ from pydantic import BaseModel
9
+
10
+ router = APIRouter()
11
+
12
+ class FileValidationRequest(BaseModel):
13
+ files: List[str]
14
+
15
+ class FileValidationResponse(BaseModel):
16
+ existingFiles: List[str]
17
+ missingFiles: List[str]
18
+
19
+ @router.post("/api/files/validate", response_model=FileValidationResponse)
20
+ async def validate_files(request: FileValidationRequest):
21
+ """Validate which files exist and return lists of existing/missing files."""
22
+
23
+ existing_files = []
24
+ missing_files = []
25
+
26
+ for file_path in request.files:
27
+ if os.path.exists(file_path):
28
+ existing_files.append(file_path)
29
+ else:
30
+ missing_files.append(file_path)
31
+
32
+ return FileValidationResponse(
33
+ existingFiles=existing_files,
34
+ missingFiles=missing_files
35
+ )
app/routes/mcp_routes.py CHANGED
@@ -283,11 +283,15 @@ async def get_shell_config():
283
283
  server_env = server_config.get("env", {})
284
284
 
285
285
  # Extract allowed commands from environment configuration
286
+ # Always start with the full default command list
286
287
  allowed_commands = DEFAULT_SHELL_CONFIG["allowedCommands"].copy()
287
- if "ALLOW_COMMANDS" in server_env:
288
+
289
+ # Only override if environment explicitly provides a DIFFERENT set
290
+ if "ALLOW_COMMANDS" in server_env and server_env["ALLOW_COMMANDS"].strip():
288
291
  # If environment override exists, use it instead
289
292
  env_commands = [cmd.strip() for cmd in server_env["ALLOW_COMMANDS"].split(",") if cmd.strip()]
290
- if env_commands:
293
+ # Only replace if the environment list is substantially different (not just a subset)
294
+ if env_commands and len(env_commands) >= len(DEFAULT_SHELL_CONFIG["allowedCommands"]) * 0.8:
291
295
  allowed_commands = env_commands
292
296
  logger.info(f"Using environment override commands: {allowed_commands}")
293
297
 
@@ -302,14 +306,20 @@ async def get_shell_config():
302
306
 
303
307
  return {
304
308
  "enabled": True,
309
+ "allowedCommands": allowed_commands,
305
310
  "gitOperationsEnabled": git_operations_enabled,
306
- "safeGitOperations": git_operations
311
+ "safeGitOperations": git_operations,
312
+ "timeout": timeout
307
313
  }
308
314
  else:
309
315
  # Shell server not connected, return default config with enabled=False
316
+ # But still check for environment timeout override
317
+ default_config = get_default_shell_config()
318
+ timeout = int(os.environ.get("COMMAND_TIMEOUT", default_config["timeout"]))
310
319
  return {
311
- **get_default_shell_config(),
312
- "enabled": False
320
+ **default_config,
321
+ "enabled": False,
322
+ "timeout": timeout
313
323
  }
314
324
 
315
325
  except Exception as e:
@@ -341,7 +351,7 @@ async def update_shell_config(config: ShellConfig):
341
351
 
342
352
  # Create new shell server configuration
343
353
  new_shell_config = {
344
- "command": ["python", "-u", "mcp_servers/shell_server.py"],
354
+ "command": ["python", "-u", "app/mcp_servers/shell_server.py"],
345
355
  "enabled": config.enabled,
346
356
  "env": {
347
357
  "ALLOW_COMMANDS": ",".join(config.allowedCommands),
@@ -352,17 +362,38 @@ async def update_shell_config(config: ShellConfig):
352
362
  }
353
363
 
354
364
  if config.enabled:
365
+ # Update the server configuration in MCP manager before restarting
366
+ mcp_manager.server_configs["shell"] = new_shell_config
367
+
355
368
  # Restart the shell server with new configuration
369
+ logger.info(f"Attempting to restart shell server with config: {new_shell_config}")
356
370
  success = await mcp_manager.restart_server("shell", new_shell_config)
357
371
 
372
+ if not success:
373
+ # Get detailed error information
374
+ shell_client = mcp_manager.clients.get("shell")
375
+ error_details = "Unknown error"
376
+ if shell_client and shell_client.process:
377
+ try:
378
+ stderr_output = shell_client.process.stderr.read() if shell_client.process.stderr else ""
379
+ if stderr_output:
380
+ error_details = f"Shell server stderr: {stderr_output}"
381
+ except Exception as e:
382
+ error_details = f"Could not read shell server error: {str(e)}"
383
+
384
+ logger.error(f"Shell server restart failed. Details: {error_details}")
385
+ return {"success": False, "message": f"Failed to restart shell server: {error_details}"}
386
+
358
387
  if success:
359
388
  logger.info(f"Shell server restarted with new config: {config.allowedCommands}")
389
+
390
+ # Invalidate tools cache to ensure fresh tool list with updated shell tools
391
+ mcp_manager.invalidate_tools_cache()
392
+
360
393
  return {
361
394
  "success": True,
362
395
  "message": f"Shell server updated instantly. Basic commands: {', '.join(config.allowedCommands)}, Git operations: {'enabled' if config.gitOperationsEnabled else 'disabled'}"
363
396
  }
364
- else:
365
- return {"success": False, "message": "Failed to restart shell server"}
366
397
  else:
367
398
  # Disable shell server by disconnecting it
368
399
  if "shell" in mcp_manager.clients:
@@ -375,6 +406,9 @@ async def update_shell_config(config: ShellConfig):
375
406
  mcp_manager.server_configs["shell"]["enabled"] = False
376
407
  logger.info("Shell server marked as disabled in server configs")
377
408
 
409
+ # Invalidate tools cache to ensure fresh tool list without shell tools
410
+ mcp_manager.invalidate_tools_cache()
411
+
378
412
  return {"success": True, "message": "Shell server disabled instantly"}
379
413
 
380
414
  except Exception as e:
@@ -421,6 +455,10 @@ async def toggle_server(request: ServerToggleRequest):
421
455
  if server_config:
422
456
  success = await mcp_manager.restart_server(request.server_name, server_config)
423
457
  message = f"{request.server_name} server enabled and restarted" if success else f"Failed to restart {request.server_name} server"
458
+
459
+ # Invalidate tools cache to ensure fresh tool list with newly enabled server tools
460
+ if success:
461
+ mcp_manager.invalidate_tools_cache()
424
462
  else:
425
463
  message = f"No configuration found for {request.server_name} server"
426
464
  else:
@@ -429,6 +467,14 @@ async def toggle_server(request: ServerToggleRequest):
429
467
  await mcp_manager.clients[request.server_name].disconnect()
430
468
  del mcp_manager.clients[request.server_name]
431
469
  logger.info(f"{request.server_name} server disabled")
470
+
471
+ # Update server config to mark as disabled
472
+ if request.server_name in mcp_manager.server_configs:
473
+ mcp_manager.server_configs[request.server_name]["enabled"] = False
474
+
475
+ # Invalidate tools cache to ensure fresh tool list without disabled server tools
476
+ mcp_manager.invalidate_tools_cache()
477
+
432
478
  message = f"{request.server_name} server disabled"
433
479
 
434
480
  return {"success": True, "message": message}