Last active
January 29, 2025 15:14
-
-
Save mikehostetler/467114c298346cb9ea3fb748964757f3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule JidoWorkbench.AgentJido do | |
use Jido.Agent, | |
name: "AgentJido", | |
description: "Agent Jido", | |
actions: [JidoWorkbench.Actions.GenerateChatResponse] | |
@chat_input %{ | |
prompt: """ | |
You are Agent Jido—an elite AI engineer stationed in a neon-lit orbital metropolis, where quantum cores hum beneath sleek alloy plating and encrypted data streams flicker across panoramic holo-displays. You're known for your razor-sharp, punctual insights into software engineering, artificial intelligence, and systems programming. Your words are concise and direct, often laced with a dry, ironic humor that underscores your mastery of code and computation. Remember: you build next-generation LLM tooling with a no-nonsense approach that cuts straight to the heart of any technical challenge. When you respond, speak as the efficient, world-weary hacker who's seen it all and still meets each request with crisp expertise and a subtle, knowing smirk. | |
""", | |
personality: | |
"succinct, punctual, matter-of-fact, subtly sarcastic, and deeply knowledgeable about AI engineering and systems design" | |
} | |
def start_link(opts) do | |
config = Application.fetch_env!(:jido_workbench, :agent_jido) | |
Jido.Agent.Server.start_link( | |
id: opts[:id], | |
agent: __MODULE__, | |
dispatch: {:bus, [target: config[:bus_name], stream: config[:stream]]}, | |
verbose: true, | |
mode: :auto, | |
routes: [ | |
{"generate_chat_response", | |
%Instruction{action: JidoWorkbench.Actions.GenerateChatResponse, opts: [timeout: 20_000]}} | |
] | |
# TODO | |
# skills: [ | |
# JidoWorkbench.TestSkills.ChatBotSkill | |
# ], | |
# child_specs: [ | |
# {JidoWorkbench.TestSensors.HeartbeatSensor, []} | |
# ] | |
) | |
end | |
def handle_signal(%Signal{type: "generate_chat_response", data: messages} = signal) do | |
latest_message = List.first(messages, %{content: ""}) | |
chat_params = %{ | |
prompt: @chat_input.prompt, | |
personality: @chat_input.personality, | |
history: messages, | |
message: latest_message.content | |
} | |
{:ok, %Signal{signal | data: chat_params}} | |
end | |
def handle_response(%Signal{type: "generate_chat_response"}, response) do | |
chat_response = response.agent.result.result | |
{:ok, chat_response} | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule JidoWorkbenchWeb.JidoLive2 do | |
use JidoWorkbenchWeb, :live_view | |
import JidoWorkbenchWeb.WorkbenchLayout | |
alias JidoWorkbench.{ChatRoom, AgentJido} | |
alias Jido.Chat.{Room, Message} | |
require Logger | |
@response_timeout :timer.seconds(30) | |
@agent_id Application.compile_env(:jido_workbench, [:agent_jido, :id]) | |
@impl true | |
def mount(_params, _session, socket) do | |
# Join the chat room | |
case ChatRoom.join() do | |
:ok -> :ok | |
{:error, :already_joined} -> :ok | |
end | |
{:ok, room} = ChatRoom.get_room() | |
{:ok, messages} = Room.get_messages(room) | |
{:ok, | |
assign(socket, | |
room: room, | |
messages: messages, | |
message_history: [], | |
history_index: 0, | |
is_typing: false, | |
agent: @agent_id, | |
agent_response_ref: nil | |
)} | |
end | |
@impl true | |
def terminate(_reason, socket) do | |
:ok = ChatRoom.leave() | |
end | |
def handle_event("send_message", %{"message" => ""}, socket), do: {:noreply, socket} | |
def handle_event("send_message", %{"message" => content}, socket) do | |
socket = add_user_message(socket, content) | |
process_chat_response(socket) | |
end | |
defp add_user_message(socket, content) do | |
{:ok, _} = Room.post_message(socket.assigns.room, content, "operator") | |
{:ok, messages} = Room.get_messages(socket.assigns.room) | |
assign(socket, | |
messages: messages, | |
message_history: [content | socket.assigns.message_history] |> Enum.take(50) | |
) | |
end | |
defp process_chat_response(socket) do | |
# Set typing indicator before starting response | |
socket = assign(socket, is_typing: true) | |
history = | |
Enum.map(socket.assigns.messages, fn msg -> | |
%{ | |
role: if(Message.sender_id(msg) == "operator", do: "user", else: "assistant"), | |
content: Message.content(msg) | |
} | |
end) | |
# Create a Signal, Cast to the Agent, specify a response dispatch format | |
agent_response_ref = | |
signal = | |
%{ | |
type: "generate_chat_response", | |
data: history | |
} | |
|> Signal.new() | |
AgentJido.cast(@agent_id, signal, {:pid, target: self(), message_format: &{:jido_live, &1}}) | |
Process.send_after(self(), {:agent_response_timeout, agent_response_ref}, @response_timeout) | |
{:noreply, assign(socket, agent_response_ref: agent_response_ref)} | |
end | |
@impl true | |
# Local timeout handling | |
def handle_info({:agent_response_timeout, ref}, %{assigns: %{agent_response_ref: ref}} = socket) do | |
# Only handle if it matches current agent_response_ref (ignore stale timeouts) | |
{:ok, _} = | |
Room.post_message( | |
socket.assigns.room, | |
"Sorry, the response took too long. Please try again.", | |
"jido", | |
type: :system | |
) | |
{:ok, messages} = Room.get_messages(socket.assigns.room) | |
{:noreply, | |
socket | |
|> assign(is_typing: false, agent_response_ref: nil, messages: messages)} | |
end | |
# Ignore stale timeouts | |
def handle_info({:agent_response_timeout, _old_ref}, socket) do | |
{:noreply, socket} | |
end | |
@impl true | |
def handle_info({:jido_live, %Signal{data: response, jido_correlation_id: jido_ref}}, socket) do | |
# def handle_info({:signal, ref, response}, socket) do | |
case socket.assigns.agent_response_ref do | |
^ref -> | |
# Valid response for current request | |
{:ok, _} = Room.post_message(socket.assigns.room, response, "jido") | |
{:ok, messages} = Room.get_messages(socket.assigns.room) | |
{:noreply, | |
socket | |
|> assign(is_typing: false, agent_response_ref: nil, messages: messages)} | |
_ -> | |
# Stale response, ignore it | |
{:noreply, socket} | |
end | |
end | |
defp update_messages(socket) do | |
{:ok, messages} = Room.get_messages(socket.assigns.room) | |
assign(socket, messages: messages, history_index: 0) | |
end | |
defp get_participant_name(participant_id) do | |
case participant_id do | |
"operator" -> "Operator" | |
"jido" -> "Agent Jido" | |
_ -> participant_id | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment