Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
e31e8a7
Add Subject and Description automation actions and a strict mode
thykel Oct 12, 2026
114e077
Add the ai_assistance flag, permission and journal cause
thykel Oct 12, 2026
758fe29
Add AI assistant, skill, run and finding models
thykel Oct 12, 2026
36c3c5a
Add the skill registry and the health check tree rules
thykel Oct 12, 2026
18fcca9
Add the health check relation and staleness rules
thykel Oct 12, 2026
d27e52a
Add the health check rules for linked pull requests
thykel Oct 12, 2026
bba4f13
Add the run service, the run controllers and the run dialog
thykel Oct 12, 2026
9a75fd8
Add the AI Assistance menu to the work package toolbars
thykel Oct 12, 2026
4975f52
Add the AI review to the health check
thykel Oct 12, 2026
44fc072
Apply proposed changes from AI findings
thykel Oct 12, 2026
1c95afe
Add admin pages for AI assistants and their skills
thykel Oct 12, 2026
038443d
Document the AI Assistance concept and the review split
thykel Oct 12, 2026
9feb8f1
Add the AI Assistance chat on work packages
thykel Oct 12, 2026
897403a
Add custom prompt presets, a comment-only scope and a copy button
thykel Oct 12, 2026
57783c5
Use "AI review" in the interface
thykel Oct 12, 2026
5f7dc95
Rename the AI judgement to AI review, and move shared proposal classe…
thykel Oct 12, 2026
6cf7eef
Clean up AI Assistance after review
thykel Oct 12, 2026
e3a078f
Show a spinner while the AI review runs
thykel Oct 12, 2026
6943bff
Hide AI Assistance without an LLM, and do not call a partial check co…
thykel Oct 12, 2026
a6c7872
Call the health check "Refresh work package" in the interface
thykel Oct 13, 2026
3e68882
Send the project name and related meeting agendas to the model
thykel Oct 13, 2026
8250225
Document the OpenProject work for a coding agent integration
thykel Oct 13, 2026
61159ef
Fix two AI Assistance specs after the cleanup
thykel Oct 13, 2026
58eda62
Add personal AI assistants in My account
thykel Oct 13, 2026
dd69bc4
Delete AI Assistance records with their user
thykel Oct 13, 2026
462f382
Accept the pull_requests area in the AI review
thykel Oct 13, 2026
e340620
Simplify AI Assistance after the second review
thykel Oct 13, 2026
8971222
Let a group own an AI assistant
thykel Oct 13, 2026
dbcdb94
Seed a sample group assistant in the development data
thykel Oct 13, 2026
2330d7d
Seed one sample assistant for each owner in the development data
thykel Oct 13, 2026
da1bced
Give the sample COMMS assistant to a COMMS team
thykel Oct 13, 2026
b599eda
Trim the seeded AI assistants to one global OP assistant
thykel Oct 13, 2026
070b839
Sort the AI Assistance locale keys for Yamllint
thykel Oct 13, 2026
9f6d426
Offer AI Assistance skills only where their conditions match
thykel Oct 13, 2026
b3a8257
Generate the output rules, and share instructions across an assistant…
thykel Oct 13, 2026
dbb9f7a
Remove the unused template reference of AI Assistance skills
thykel Oct 13, 2026
bc9bf7f
Use the default spacing between the AI Assistance form sections
thykel Oct 13, 2026
7d08846
Show skill conditions in the list, and keep them valid
thykel Oct 13, 2026
a274dbc
Make health check findings stable, and propose changes as proposals
thykel Oct 13, 2026
307f8a3
Give the AI context the accountable person, and widen the history dialog
thykel Oct 14, 2026
c517a52
Describe the split between core skills and agent skills
thykel Oct 14, 2026
bab4eaf
Store the proposals of a conversation answer as their own records
thykel Oct 14, 2026
1ca8664
Replace the AI skill types with one conversation type and settings
thykel Oct 14, 2026
2a07985
Answer with findings in the conversation, and with several proposals
thykel Oct 14, 2026
2929bac
Give AI skills a first message instead of start and answer settings
thykel Oct 14, 2026
a2703bb
Open every AI skill in the conversation, with its proposals as cards
thykel Oct 14, 2026
cdfbc9d
Remove AI runs and the built-in rules, and check consistency with the…
thykel Oct 14, 2026
32bc1ac
Describe AI Assistance as conversations with proposals
thykel Oct 14, 2026
dbbcd42
Keep AI answers short when they carry proposals
thykel Oct 14, 2026
28daceb
Remove leftovers of the AI rules from proposals
thykel Oct 14, 2026
69e8a53
Merge remote-tracking branch 'origin/dev' into ai-assistance/health-c…
thykel Oct 14, 2026
a1a679a
Resolve the AI Assistance model through Llm::Runtime
thykel Oct 14, 2026
1d6f867
Squash the AI Assistance migrations into one
thykel Oct 14, 2026
27fcaad
Start AI skills with a start line instead of their label
thykel Oct 14, 2026
e55f048
Remove leftovers of the AI skill label as first message
thykel Oct 14, 2026
2f10b3f
Add an open filter and a count tool to the MCP work package tools
thykel Oct 15, 2026
a89c1bd
Let AI Assistance skills call the read-only MCP tools
thykel Oct 15, 2026
2c0c916
Show AI tool calls while the answer loads, and stop repeated calls
thykel Oct 15, 2026
0717aaf
Document the MCP tools of AI Assistance
thykel Oct 15, 2026
6c99d32
Return the values of list custom fields from the MCP items tool
thykel Oct 15, 2026
7db563e
Tell the AI not to call a tool again to check a result
thykel Oct 15, 2026
48007f1
Let an AI skill opt out of the MCP tools
thykel Oct 15, 2026
17940c0
Fix the ERB layout of the AI skill form
thykel Oct 15, 2026
1a6fa5a
Show the typed AI skill prompt in the full prompt preview, and rename…
thykel Oct 15, 2026
578d590
Move the AI Assistance button into the app header
thykel Oct 15, 2026
0e87f3a
Link AI journal entries to their chat
thykel Oct 15, 2026
3b16049
Group the AI Assistance menu by assistant
thykel Oct 15, 2026
982a2b4
Give each AI skill an icon, and drop the assistant icon
thykel Oct 15, 2026
9c28369
Separate History from the skills in the AI Assistance menu
thykel Oct 15, 2026
8d22432
Do not start a second AI answer while one is running
thykel Oct 15, 2026
23a6f75
Offer AI Assistance on every page
thykel Oct 15, 2026
7783fb9
Show AI assistants as sections with their skills
thykel Oct 15, 2026
48aa972
Link AI assistant owners to their public profiles
thykel Oct 15, 2026
d018cc2
Copy AI assistants and skills
thykel Oct 15, 2026
b2beab1
Rework the AI Assistance seed data
thykel Oct 15, 2026
0e67caa
Rename the seeded OP assistant to OPAssistant
thykel Oct 15, 2026
6c99add
Count work per person, and seed the COMMS developers' workloads
thykel Oct 15, 2026
7b0b409
Show the owner icon of each assistant in the AI Assistance menu
thykel Oct 15, 2026
3ca7731
Log AI tool results and the model's text, and stop repeats early
thykel Oct 15, 2026
af809f1
Put the owner icon after the assistant name in the AI Assistance menu
thykel Oct 15, 2026
924c090
Log the model's reasoning, and answer now after a repeated tool call
thykel Oct 15, 2026
f15dbe9
Dim the owner icon in the AI Assistance menu headings
thykel Oct 15, 2026
42e3cec
Dim the owner icon with opacity
thykel Oct 15, 2026
e8f316e
Ask AI answers to name people, not guess pronouns
thykel Oct 15, 2026
52f389f
Merge remote-tracking branch 'origin/dev' into ai-assistance/health-c…
thykel Oct 15, 2026
8f294ad
Seed the AI Assistance demo on every fresh install of this branch
thykel Oct 15, 2026
9081ea0
Merge remote-tracking branch 'origin/dev' into ai-assistance/health-c…
thykel Oct 18, 2026
7e0bd77
rename a clashing migration
thykel Oct 18, 2026
8cbd090
Keep AI findings that other models label differently
thykel Oct 18, 2026
e6f7fce
Count work packages through search_work_packages
thykel Oct 18, 2026
69be44a
Merge remote-tracking branch 'origin/dev' into ai-assistance/health-c…
thykel Oct 25, 2026
913c804
Move AI Assistance into modules/llm
thykel Oct 25, 2026
1d3cb32
Fix the AI Assistance specs and associations after the move
thykel Oct 25, 2026
a456a95
Import the work package event from the renamed my-time-management helper
thykel Oct 25, 2026
88d94c2
Hide personal AI assistants from admins
thykel Oct 25, 2026
eba59d8
Move the AI Assistance menu back into the work package toolbars
thykel Oct 25, 2026
8d53a12
Show the chat controls of a skill only on "Chat about this"
thykel Oct 25, 2026
d4c7f0d
Offer Chat about this and Run again only once the skill answered
thykel Oct 25, 2026
6ed5c79
Make the Details toggle of an AI answer subtle
thykel Oct 25, 2026
7de53b2
Seed three custom actions for the AI Assistance demo
thykel Oct 25, 2026
38a459a
Fix the RuboCop, ERB lint and Yamllint offenses of AI Assistance
thykel Oct 25, 2026
aa8a4b2
Merge dev into ai-assistance/health-check
thykel Oct 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/pullpreview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
echo "OPENPROJECT_FEATURE__SHOW__CHANGES__ACTIVE=true" >> .env.pullpreview
echo "OPENPROJECT_FEATURE__AI__TEXT__TRANSFORM__ACTIONS__ACTIVE=true" >> .env.pullpreview
echo "OPENPROJECT_FEATURE__LLM__CONNECTION__ACTIVE=true" >> .env.pullpreview
echo "OPENPROJECT_FEATURE__AI__ASSISTANCE__ACTIVE=true" >> .env.pullpreview
echo "OPENPROJECT_LOOKBOOK__ENABLED=true" >> .env.pullpreview
echo "OPENPROJECT_HSTS=false" >> .env.pullpreview
echo "OPENPROJECT_NOTIFICATIONS_POLLING_INTERVAL=10000" >> .env.pullpreview
Expand Down
4 changes: 4 additions & 0 deletions app/models/automations/actions/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ def priority
DEFAULT_PRIORITY
end

# Called once the work package is saved with the changes of every action. Actions with
# an effect outside the work package (a notification, a call, a run) do it here.
def after_success(_work_package, _user); end

protected

def write_raw_values(new_values)
Expand Down
47 changes: 47 additions & 0 deletions app/models/automations/actions/comment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

# Adds a comment to the work package. It runs after Notify, which sets the comment text,
# and appends to it.
class Automations::Actions::Comment < Automations::Actions::Base
include Automations::Actions::Strategies::Text

def self.key
:comment
end

def priority
DEFAULT_PRIORITY + 1
end

def apply(work_package)
work_package.journal_notes = [work_package.journal_notes.presence, values.first].compact.join("\n\n")
end
end
41 changes: 41 additions & 0 deletions app/models/automations/actions/description.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# frozen_string_literal: true

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class Automations::Actions::Description < Automations::Actions::Base
include Automations::Actions::Strategies::Text

def self.key
:description
end

def apply(work_package)
work_package.description = values.first
end
end
45 changes: 45 additions & 0 deletions app/models/automations/actions/subject.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# frozen_string_literal: true

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class Automations::Actions::Subject < Automations::Actions::Base
include Automations::Actions::Strategies::String

def self.key
:subject
end

def apply(work_package)
work_package.subject = values.first
end

def required?
true
end
end
3 changes: 3 additions & 0 deletions app/models/automations/register.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ def actions
Automations::Actions::CustomField,
Automations::Actions::Type,
Automations::Actions::Project,
Automations::Actions::Subject,
Automations::Actions::Description,
Automations::Actions::Comment,
Automations::Actions::Notify,
Automations::Actions::DoneRatio,
Automations::Actions::EstimatedHours,
Expand Down
9 changes: 9 additions & 0 deletions app/models/journal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,14 @@ class Journal < ApplicationRecord
status_changes
meeting_id
source_meeting_id
source
depth
run_id
skill_key
assistant_name
chat_id
message_id
proposal_id
],
prefix: true

Expand All @@ -104,6 +111,8 @@ class Journal < ApplicationRecord
].freeze

VALID_CAUSE_TYPES = (%w[
assistant_chat
assistant_skill
default_attribute_written
forum_message
import
Expand Down
55 changes: 55 additions & 0 deletions app/seeders/development_data/admin_name_seeder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

module DevelopmentData
# Gives the seeded admin user a person's name, so that it reads as a team member in the
# development data. The login stays the same.
class AdminNameSeeder < Seeder
def seed_data!
print_status " ↳ Naming the admin user" do
admin.update!(firstname:, lastname:)
end
end

def applicable?
firstname.present? && admin.present? && [admin.firstname, admin.lastname] != [firstname, lastname]
end

private

def firstname = seed_data.lookup("development_admin.firstname")

def lastname = seed_data.lookup("development_admin.lastname")

def admin
seed_data.find_reference(:openproject_admin, default: nil) || admin_user
end
end
end
49 changes: 49 additions & 0 deletions app/seeders/development_data/ai_assistants_seeder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

module DevelopmentData
# Sample AI assistants of the development data, one for each kind of owner: global,
# a department (its direct members see it) and a user. A sample without a principal
# reference is global.
class AiAssistantsSeeder < BasicData::Llm::AiAssistantSeeder
self.seed_data_model_key = "development_ai_assistants"
self.attribute_names_for_required_references = %w[principal]

def applicable?
AI::Assistant.where(name: models_data.pluck("name")).none? &&
seed_data.all_references_exist?(all_required_references)
end

def model_attributes(assistant_data)
reference = assistant_data["principal"]
super.merge(principal_id: reference && seed_data.find_reference(reference).id)
end
end
end
70 changes: 70 additions & 0 deletions app/seeders/development_data/custom_actions_seeder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# frozen_string_literal: true

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

module DevelopmentData
# Custom actions (automations with a button) that the work packages of the AI Assistance
# demo offer. Runs after the demo data, which creates the statuses and priorities.
class CustomActionsSeeder < Seeder
def seed_data!
print_status " -Creating the custom actions" do
User.execute_as(admin_user) do
custom_actions.each { |custom_action| create_custom_action(custom_action) }
end
end
end

def applicable?
custom_actions.any? && Automation.where(name: custom_actions.pluck("name")).none?
end

private

def create_custom_action(custom_action)
name = custom_action["name"]
attributes = {
name:,
actions: custom_action["actions"].transform_values { |value| [action_value(value)] },
triggers_attributes: [{ type: Automations::Triggers::Button.name, button_label: name }]
}

Automations::CreateService.new(user: admin_user)
.call(attributes: attributes.with_indifferent_access)
.on_failure { |result| raise "#{name}: #{result.errors.full_messages.to_sentence}" }
end

def action_value(value)
seed_data.find_reference(value, default: nil)&.id&.to_s || value
end

def custom_actions
Array(seed_data.lookup("development_custom_actions"))
end
end
end
Loading
Loading