Add Agents skills#4327
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an agents/skills/ documentation set intended to help agent CLIs/tools understand Trento’s AI Assistant architecture (Elixir + Phoenix channel side, and React/JS client side), plus a generic sagents v0.7 reference pack.
Changes:
- Added a Trento AI Assistant “backend” skill (
trento-ai-assistant) describing the purported Elixir/Phoenix + sagents/langchain stack. - Added a Trento AI Assistant UI skill (
trento-ai-assistant-ui) documenting the React components andWebSocketAIAgenttransport. - Added a generic sagents v0.7 skill with several topic deep-dives, and a top-level skills README.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| agents/skills/README.md | Introduces the skills directory and how to consume it in different tools. |
| agents/skills/trento-ai-assistant/SKILL.md | Documents the supposed Elixir/Phoenix-channel AI Assistant stack and contracts. |
| agents/skills/trento-ai-assistant-ui/SKILL.md | Documents the React/JS AI Assistant client and AG-UI event flow. |
| agents/skills/sagents/SKILL.md | One-page sagents v0.7 cheat sheet and index of topic docs. |
| agents/skills/sagents/api.md | sagents API reference overview. |
| agents/skills/sagents/context.md | Explains scope vs tool_context vs state.metadata and propagation rules. |
| agents/skills/sagents/disabling-middleware.md | Guidance for safely commenting out built-in middleware while keeping revertability. |
| agents/skills/sagents/filesystem.md | FileSystem middleware usage/persistence/scoping notes. |
| agents/skills/sagents/middleware.md | Middleware callback surface, ordering rules, tools, interrupts, observability. |
| agents/skills/sagents/migration-v0.6-to-v0.7.md | Migration guide for the v0.6 → v0.7 scope signature break. |
| agents/skills/sagents/persistence.md | Agent state vs display-message persistence behaviors and lifecycle. |
| agents/skills/sagents/pubsub-events.md | PubSub topic/event envelope and event category reference. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
de5a1ac to
6975c39
Compare
chargio
left a comment
There was a problem hiding this comment.
Is a skill the best way to do this?
You can add skills for Elixir and Phoenix to the tools directly.
What a new Phoenix app does is to add an AGENTS.md file that explains things like:
- Use 'mix precomit',
- Use the already included library
- Use layouts etc...
Most of it should be adapted to Trento because we don't use LIveView, but we can also add information about the project itself.
For instance,
- Never create PR that are longer than 400 lines
- Store information in xxx
And architecture descriptions that establish the components used, their relationship, how to test, etc.
|
Thanks for the feedback, @chargio! I believe the content is valid, and I am ok in discussing about the form/location.
I am not sure, still experimenting. In any case the content here would be covering only partly the wholeness of Trento, so we'd need more.
What do you mean here?
Yes, agreed. This is definitely we might want to add to AGENTS.md |
6975c39 to
d3f59bf
Compare
| --- | ||
| name: trento-ai-assistant | ||
| description: Use when modifying TrentoWeb.AIAssistantChannel, TrentoWeb.AIAssistant.AgUi, TrentoWeb.AIAssistantTools, the AI Assistant system prompt, or anything under Trento.AI.* (Agent + Server/Supervisor adapters + LLMBuilder + LLMRegistry + Configurations + UserConfiguration) or Trento.Infrastructure.AI.*. Covers the layered architecture from React assistant-ui down to the Gemini API, the PubSub event vocabulary the channel reacts to, the AG-UI event types emitted over the WebSocket, the Mox adapter pattern wrapping sagents, the langchain fork patches, model selection trade-offs, and how to verify changes end-to-end. Also useful when debugging "Sorry, I encountered an error" messages or when adding new tools, new AG-UI event types, or new prompt sections. |
| - Editing `lib/trento_web/channels/ai_assistant_channel.ex` | ||
| - Editing `lib/trento_web/channels/ai_assistant/ag_ui.ex` | ||
| - Editing `lib/trento_web/channels/ai_assistant/ai_assistant_tools.ex` | ||
| - Editing the `@system_prompt` inside `lib/trento/ai/agent.ex` |
| - Debugging an `Sorry, I encountered an error: ...` or `Failed to start agent...` push reaching the React UI | ||
| - Designing a new AG-UI event type to push to the client | ||
| - Adding a new tool to `AIAssistantTools.tools/0` | ||
| - Diagnosing `MALFORMED_FUNCTION_CALL`, `Exceeded max failure count`, `:lists.flatten("")`, or any langchain `LangChainError` |
| | `TrentoWeb.AIAssistant.AgUi` | `lib/trento_web/channels/ai_assistant/ag_ui.ex` | Socket-in/socket-out functions for every AG-UI event the channel emits. Owns the 10 `AgUi.Core.Events.*` struct aliases + the `Phoenix.Channel.push/3` + camelCase encoding via `AgUi.Encoder.EventEncoder`. | | ||
| | `TrentoWeb.AIAssistantTools` | `lib/trento_web/channels/ai_assistant/ai_assistant_tools.ex` | `tools/0` returns 6 `%LangChain.Function{}` for Host/SapSystem/Database/Cluster listing + 2 Prometheus PromQL queries. Each reads `context.scope.id` (the `%Trento.Users.User{id: id}` partial struct passed via `Agent.new!`'s `:scope`). | |
| | Assign | Type | Lifetime | | ||
| |---|---|---| | ||
| | `:current_user_id` | integer | from `UserSocket.connect` | | ||
| | `:current_scope` | `%Trento.Users.User{id: id}` partial struct | from `join/3` | | ||
| | `:loading` | boolean | toggled per run (double-send guard) | | ||
| | `:current_run_id` | UUID string | set per `send_message` (after validation) | | ||
| | `:current_thread_id` | UUID string | set per `send_message` (after validation) | | ||
| | `:message_id` | UUID string (= `current_run_id` today) | set per run | | ||
| | `:message_started` | boolean | per run — drives TEXT_MESSAGE_START dedup + orphan-END guard | | ||
| | `:run_has_started` | boolean | per run — stale-`:idle` guard | |
| ```elixir | ||
| %{ | ||
| "message" => message_text, | ||
| "run_id" => run_id, | ||
| "thread_id" => thread_id | ||
| } | ||
| when is_binary(message_text) and is_binary(run_id) and is_binary(thread_id) | ||
| ``` |
| def handle_info({:agent, {:llm_message, message}}, socket), do: ... | ||
| def handle_info({:agent, {:todos_updated, todos}}, socket), do: ... | ||
| def handle_info({:agent, {:tool_started, info}}, socket), do: ... | ||
| def handle_info({:agent, {:tool_completed, info}}, socket), do: ... | ||
| def handle_info({:agent, {:agent_shutdown, reason}}, socket), do: ... | ||
| def handle_info({:agent, {:display_message_persisted, dm}}, socket), do: ... |
| | Todos | `{:todos_updated, full_list}` | **Full snapshots, not diffs** | | ||
| | Tool lifecycle | `{:tool_started, info}`, `{:tool_completed, info}`, `{:tool_failed, info}`, `{:tool_cancelled, info}`, `{:on_tool_call_identified, info}` | UI display labels propagate via these | | ||
| | Display message | `{:display_message_persisted, dm}` | Fired after DisplayMessagePersistence saves a row | |
| - `{:subagent_cancelled, %{final_messages, turn_count}}` — same payload shape | ||
| - Minimal fallback broadcast fires within 300ms even when sub-agent is blocked mid-LLM-call | ||
|
|
||
| `display_text` re-fires `{:on_tool_call_identified, ...}` once `subagent_type` is known (since v0.6.0) so UI shows "Drafting KB article" instead of generic "Running task". |
| ```js | ||
| this.channel | ||
| .push('send_message', { | ||
| message: extractMessageText(lastMessage), | ||
| thread_id: threadId, | ||
| run_id: runId, | ||
| }) | ||
| .receive('error', (error) => { ... }); | ||
| ``` | ||
|
|
||
| All three fields are required. The channel strict-matches and replies `{:error, :invalid_payload}` if any are missing or non-string. The `.receive('error', ...)` callback catches both transport errors (channel push failure) AND application errors (the channel's `:invalid_payload` reply). | ||
|
|
Description
This PR is the result of many conversations with Claude.
Hoping it to be useful for the team.
Visual here
Many copilot complaints are because referenced content is actually here #4320