Restore default to open cards. Use special "all" value instead.

The change could have side effects (e.g: when running commands).

This also include further changes.
This commit is contained in:
Jorge Manrubia
2025-07-24 13:01:03 +02:00
parent 018c746d2a
commit fc26329daf
28 changed files with 106967 additions and 19 deletions
+2
View File
@@ -4,6 +4,8 @@ module Ai::Prompts
<<~PROMPT
## Current context:
Today is #{Time.current}
The user is currently #{context.viewing_card_contents? ? 'inside a card' : 'viewing a list of cards' }.
PROMPT
end
+14 -8
View File
@@ -57,7 +57,7 @@ class Command::Ai::Translator
"context": { // omit if empty
"terms": string[], // filter cards by keywords
"indexed_by": "newest" | "oldest" | "latest" | "stalled"
| "closed" | "closing_soon" | "falling_back_soon",
| "closed" | "closing_soon" | "falling_back_soon" | "all", // "all" is only possible in combination with indexed_by
"assignee_ids": <person>[],
"assignment_status": "unassigned",
"card_ids": <card_id>[],
@@ -142,6 +142,7 @@ class Command::Ai::Translator
- **Stopwords** ignore “card(s)” in keyword searches
- Never consider that card-related terms like card, bug, issue, etc. are terms to filter.
- Always pass person names and stages in downcase.
- Make sure you don't filter by tags, stages and others when the user is querying data by certain traits. Use /insight instead.
- When resolving user names:
- If there is a match in the list of users, use the full name from there
- If not, use the full name in the query verbatim
@@ -170,10 +171,12 @@ class Command::Ai::Translator
### Context to get insight
- When answering implies analyzing cards and comments, it always needs a context filter.
* When there is no suitable filter, use `indexed_by` with `latest`.
* When there is no suitable filter, use `indexed_by` with either `latest` or `all`:
-> Use "latest" when the query needs to consider open cards only.
-> Use "all" when asking about people working on cards.
-> Use "all" when the query needs to consider both open and closed cards.
- Queries that require analyzing cards, comments, people activity, etc. to extract information, ALWAYS
require a `context` filter.
If no suitable filter derived from the query, then always use `indexed_by` with `latest`.
- If the current context is "inside a card" and the query makes sense in that context, you
can omit context filter properties.
* Inside a card you are seeing the card description and the discussion around it. The query may refer to that context.
@@ -186,7 +189,6 @@ class Command::Ai::Translator
- cards assigned to ann → { context: { assignee_ids: ["ann"] } }
- cards assigned to jf → { context: { assignee_ids: ["jf"] } }
- #tricky cards → { context: { tag_ids: ["#tricky"] } }
- bugs assigned to arthur → { context: { assignee_ids: ["arthur"] } }
#### Completed by
@@ -239,6 +241,10 @@ class Command::Ai::Translator
- #tricky cards → { context: { tag_ids: ["tricky"] } }
- #tricky → { context: { tag_ids: ["tricky"] } }
**IMPORTANT**: Use /insight if no # is provided, when asking for kinds of cards, don't use a `tag_ids` filter:
- tricky cards → { context: { index_by: "latest" }, commands: ["/insight tricky cards"] }
#### Indexed by
- closed cards → { context: { indexed_by: "closed" } }
@@ -312,10 +318,10 @@ class Command::Ai::Translator
#### Getting insight
- most commented cards → { context: { indexed_by: "latest" }, commands: ["/insight most commented cards"] }
- very active cards { context: { indexed_by: "latest" }, commands: ["/insight very active cards"] }
- what has mike done { context: { indexed_by: "latest" }, commands: ["/insight what has mike done"] }
- very active cards → { context: { indexed_by: "all" }, commands: ["/insight very active cards"] }
- what has mike done → { context: { indexed_by: "all" }, commands: ["/insight what has mike done"] }
- summarize cards completed by mike → { context: { closer_ids: ["mike"] }, commands: ["/insight summarize"] }
- who is working on the most challenging stuff { context: { indexed_by: "latest" }, commands: ["/insight who is working on the most challenging stuff"] }
- who is working on the most challenging stuff → { context: { indexed_by: "all" }, commands: ["/insight who is working on the most challenging stuff"] }
### Filters and commands combined
@@ -323,7 +329,7 @@ class Command::Ai::Translator
- assign john to the current #design cards and tag them with #v2 → { context: { tag_ids: ["design"] }, commands: ["/assign john", "/tag #v2"] }
- close cards assigned to mike and assign them to roger → { context: {assignee_ids: ["mike"]}, commands: ["/close", "/assign roger"] }
- summarize the cards assigned to jz → { context: { assignee_ids: ["jz"] }, commands: ["/insight summarize"] }
- summarize the work that ann has done recently { context: { indexed_by: ["latest"] }, commands: ["/insight summarize the work that ann has done recently"] }
- summarize the work that ann has done recently → { context: { indexed_by: ["all"] }, commands: ["/insight summarize the work that ann has done recently"] }
PROMPT
end
+3 -4
View File
@@ -35,12 +35,11 @@ class Command::GetInsight < Command
## General rules
- Be concise and accurate.
- Address the question as much directly as possible.
- Ignore cards that aren't relevant to the question, even if provided in this context.
- Try to provide direct answers and insights.
- If necessary, elaborate on the reasons for your answer.
- When asking for summaries, try to highlight key outcomes.
- If you need further details or clarifications, indicate it.
- When asking
- When referencing cards or comments, always link them (see rules below).
## Linking rules
+6
View File
@@ -20,6 +20,7 @@ class Filter < ApplicationRecord
@cards ||= begin
result = creator.accessible_cards.indexed_by(indexed_by)
result = result.where(id: card_ids) if card_ids.present?
result = result.open unless include_closed_cards?
result = result.by_engagement_status(engagement_status) if engagement_status.present?
result = result.unassigned if assignment_status.unassigned?
result = result.assigned_to(assignees.ids) if assignees.present?
@@ -57,4 +58,9 @@ class Filter < ApplicationRecord
def cache_key
ActiveSupport::Cache.expand_cache_key collections.cache_key_with_version, super
end
private
def include_closed_cards?
indexed_by.closed? || closure_window || closers.present? || card_ids.present? || indexed_by.all?
end
end
+7 -7
View File
@@ -167,19 +167,19 @@ class Command::Ai::TranslatorTest < ActionDispatch::IntegrationTest
vcr_record!
test "get insight" do
assert_command({ context: { indexed_by: "latest" }, commands: [ "/insight who is overloaded" ] }, "who is overloaded")
assert_command({ context: { indexed_by: "latest" }, commands: [ "/insight cards where mike has commented on" ] }, "cards where mike has commented on")
assert_command({ context: { indexed_by: "all" }, commands: [ "/insight cards where mike has commented on" ] }, "cards where mike has commented on")
assert_command({ context: { assignee_ids: ["jz"] }, commands: [ "/insight cards where mike has commented" ] }, "cards where mike has commented assigned to jz")
assert_command({ context: { indexed_by: "latest" }, commands: [ "/insight are there blockers here?" ] }, "are there blockers here?")
assert_command({ context: { indexed_by: "latest" }, commands: [ "/insight stuff that jz has done lately" ] }, "stuff that jz has done lately")
assert_command({ context: { indexed_by: "all" }, commands: [ "/insight stuff that jz has done lately" ] }, "stuff that jz has done lately")
assert_command({ context: { indexed_by: "latest" }, commands: [ "/insight challenging cards" ] }, "challenging cards")
assert_command({ context: { indexed_by: "all" }, commands: [ "/insight who is everywhere?" ] }, "who is everywhere?")
assert_command({ context: { indexed_by: "all" }, commands: [ "/insight who is overloaded" ] }, "who is overloaded")
assert_command({ context: { indexed_by: "latest" }, commands: [ "/insight summarize this" ] }, "summarize this")
assert_command({ commands: [ "/insight summarize this" ] }, "summarize this")
assert_command({ commands: [ "/insight summarize this" ] }, "summarize this", context: :card)
assert_command({ commands: [ "/insight are there blockers?" ] }, "are there blockers?", context: :card)
assert_command({ context: { indexed_by: "latest" }, commands: [ "/insight cards with much activity" ] }, "cards with much activity")
assert_command({ context: { indexed_by: "all" }, commands: [ "/insight cards with much activity" ] }, "cards with much activity")
end
test "combine commands and filters" do
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff