Packages
snakepit
0.4.1
0.13.0
0.12.0
0.11.1
0.11.0
0.10.1
0.10.0
0.9.1
0.9.0
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
High-performance pooler and session manager for external language integrations. Supports Python, Node.js, Ruby, and more with gRPC streaming, session management, and production-ready process cleanup.
Current section
53 Versions
Jump to
Current section
53 Versions
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…