Current section

53 Versions

Jump to

Compare versions

12 files changed
+244 additions
-13 deletions
  @@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8 8 ## [Unreleased]
9 9
10 + ## [0.4.1] - 2025-07-24
11 +
12 + ### Added
13 + - **New `process_text` tool** - Text processing capabilities with upper, lower, reverse, and length operations
14 + - **New `get_stats` tool** - Real-time adapter and system monitoring with memory usage, CPU usage, and system information
15 + - **Enhanced ShowcaseAdapter** - Added missing tools (adapter_info, echo, process_text, get_stats) for complete tool bridge demonstration
16 +
17 + ### Fixed
18 + - **gRPC tool registration issues** - Resolved async/sync mismatch causing UnaryUnaryCall objects to be returned instead of actual responses
19 + - **Missing tool errors** - Fixed "Unknown tool: adapter_info" and "Unknown tool: echo" errors by implementing missing @tool decorated methods
20 + - **Automatic session initialization** - Fixed "Failed to register tools: not_found" error by automatically creating sessions before tool registration
21 + - **Remote tool dispatch** - Implemented complete bidirectional tool execution between Elixir BridgeServer and Python workers
22 + - **Async/sync compatibility** - Added proper handling for both sync and async gRPC stubs with fallback logic for UnaryUnaryCall objects
23 +
24 + ### Changed
25 + - **BridgeServer enhancement** - Added remote tool execution capabilities with worker port lookup and gRPC forwarding
26 + - **Python gRPC server** - Enhanced with automatic session initialization before tool registration
27 + - **ShowcaseAdapter refactoring** - Expanded tool set to demonstrate full bidirectional tool bridge capabilities
28 +
10 29 ## [0.4.0] - 2025-07-23
11 30
12 31 ### Added
  @@ -176,6 +195,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
176 195 - Configurable pool sizes and timeouts
177 196 - Built-in bridge scripts for Python and JavaScript
178 197
198 + [0.4.1]: https://github.com/nshkrdotcom/snakepit/releases/tag/v0.4.1
199 + [0.4.0]: https://github.com/nshkrdotcom/snakepit/releases/tag/v0.4.0
179 200 [0.3.3]: https://github.com/nshkrdotcom/snakepit/releases/tag/v0.3.3
180 201 [0.3.2]: https://github.com/nshkrdotcom/snakepit/releases/tag/v0.3.2
181 202 [0.3.1]: https://github.com/nshkrdotcom/snakepit/releases/tag/v0.3.1
  @@ -42,6 +42,20 @@ Snakepit is a battle-tested Elixir library that provides a robust pooling system
42 42 - [Troubleshooting](#troubleshooting)
43 43 - [Contributing](#contributing)
44 44
45 + ## 🆕 What's New in v0.4.1
46 +
47 + ### 🚀 **Enhanced Tool Bridge Functionality**
48 + - **New `process_text` tool** - Text processing with upper, lower, reverse, length operations
49 + - **New `get_stats` tool** - Real-time adapter and system monitoring with memory/CPU usage
50 + - **Fixed gRPC tool registration** - Resolved async/sync issues with UnaryUnaryCall objects
51 + - **Automatic session initialization** - Sessions created automatically when Python tools register
52 +
53 + ### đź”§ **Tool Bridge Improvements**
54 + - **Remote tool dispatch** - Complete bidirectional communication between Elixir and Python
55 + - **Missing tool recovery** - Added adapter_info, echo, process_text, get_stats to ShowcaseAdapter
56 + - **Async/sync compatibility** - Fixed gRPC stub handling with proper response processing
57 + - **Enhanced error handling** - Better diagnostics for tool registration failures
58 +
45 59 ## 🆕 What's New in v0.4
46 60
47 61 ### 🛡️ **Enhanced Process Management & Reliability**
  @@ -103,7 +117,7 @@ Snakepit is a battle-tested Elixir library that provides a robust pooling system
103 117 # In your mix.exs
104 118 def deps do
105 119 [
106 - {:snakepit, "~> 0.4.0"}
120 + {:snakepit, "~> 0.4.1"}
107 121 ]
108 122 end
109 123
  @@ -138,7 +152,7 @@ end)
138 152 ```elixir
139 153 def deps do
140 154 [
141 - {:snakepit, "~> 0.4.0"}
155 + {:snakepit, "~> 0.4.1"}
142 156 ]
143 157 end
144 158 ```
  @@ -60,6 +60,13 @@ ToolRegistry.register_elixir_tool(
60 60 )
61 61 ```
62 62
63 + **Note**: As of v0.4.1, the tool bridge includes automatic session initialization and enhanced tool capabilities. Sessions are automatically created when Python tools attempt to register, eliminating the need for manual session setup in most cases.
64 +
65 + ### New in v0.4.1
66 + - **Enhanced ShowcaseAdapter** with `process_text` and `get_stats` tools
67 + - **Fixed gRPC tool registration** - Resolved async/sync issues with proper response handling
68 + - **Complete remote tool dispatch** - Bidirectional communication between Elixir and Python
69 +
63 70 ### 2. Call Elixir Functions from Python
64 71
65 72 ```python
  @@ -1,6 +1,6 @@
1 1 {<<"links">>,[{<<"GitHub">>,<<"https://github.com/nshkrdotcom/snakepit">>}]}.
2 2 {<<"name">>,<<"snakepit">>}.
3 - {<<"version">>,<<"0.4.0">>}.
3 + {<<"version">>,<<"0.4.1">>}.
4 4 {<<"description">>,
5 5 <<"High-performance pooler and session manager for external language integrations">>}.
6 6 {<<"elixir">>,<<"~> 1.18">>}.
  @@ -474,10 +474,20 @@ defmodule Snakepit.GRPC.BridgeServer do
474 474 ToolRegistry.execute_local_tool(session_id, tool.name, params)
475 475 end
476 476
477 - defp execute_tool_handler(%{type: :remote} = tool, _request, _session_id) do
478 - # Forward to Python worker - this will be implemented later
479 - # For now, return an error
480 - {:error, "Remote tool execution not yet implemented for tool: #{tool.name}"}
477 + defp execute_tool_handler(%{type: :remote} = tool, request, session_id) do
478 + # Forward to Python worker
479 + Logger.debug("Executing remote tool #{tool.name} on worker #{tool.worker_id}")
480 +
481 + with {:ok, worker_port} <- get_worker_port(tool.worker_id),
482 + {:ok, channel} <- create_worker_channel(worker_port),
483 + {:ok, result} <- forward_tool_to_worker(channel, request, session_id) do
484 + # Channel will be cleaned up automatically
485 + {:ok, result}
486 + else
487 + {:error, reason} ->
488 + Logger.error("Failed to execute remote tool #{tool.name}: #{inspect(reason)}")
489 + {:error, "Remote tool execution failed: #{inspect(reason)}"}
490 + end
481 491 end
482 492
483 493 defp decode_tool_parameters(params) do
  @@ -504,6 +514,65 @@ defmodule Snakepit.GRPC.BridgeServer do
504 514 |> Map.new()
505 515 end
506 516
517 + # Helper functions for remote tool execution
518 +
519 + defp get_worker_port(worker_id) do
520 + # For now, try to get from the worker registry
521 + # In a production implementation, this would be stored in a registry
522 + case Registry.lookup(Snakepit.Pool.Registry, worker_id) do
523 + [{pid, _}] when is_pid(pid) ->
524 + # Try to get port from worker state - this is a simplified approach
525 + try do
526 + case GenServer.call(pid, :get_port, 1000) do
527 + {:ok, port} -> {:ok, port}
528 + _ -> {:error, "Could not get port from worker"}
529 + end
530 + catch
531 + _exit, _reason -> {:error, "Worker not responding"}
532 + end
533 +
534 + [] ->
535 + {:error, "Worker not found: #{worker_id}"}
536 + end
537 + end
538 +
539 + defp create_worker_channel(port) do
540 + try do
541 + GRPC.Stub.connect("localhost:#{port}")
542 + rescue
543 + error -> {:error, "Failed to connect to worker: #{inspect(error)}"}
544 + end
545 + end
546 +
547 + defp forward_tool_to_worker(channel, request, session_id) do
548 + # Forward the ExecuteToolRequest to the Python worker's gRPC server
549 + alias Snakepit.Bridge.BridgeService.Stub
550 +
551 + # Create the request to forward to the worker
552 + worker_request = %ExecuteToolRequest{
553 + session_id: session_id,
554 + tool_name: request.tool_name,
555 + parameters: request.parameters,
556 + metadata: request.metadata
557 + }
558 +
559 + try do
560 + case Stub.execute_tool(channel, worker_request) do
561 + {:ok, response} ->
562 + if response.success do
563 + {:ok, response.result}
564 + else
565 + {:error, response.error_message}
566 + end
567 +
568 + {:error, reason} ->
569 + {:error, "gRPC call failed: #{inspect(reason)}"}
570 + end
571 + rescue
572 + error -> {:error, "Exception during gRPC call: #{inspect(error)}"}
573 + end
574 + end
575 +
507 576 def execute_streaming_tool(_request, _stream) do
508 577 raise GRPC.RPCError,
509 578 status: :unimplemented,
Loading more files…