Skip to content

[AI-100] DO NOT MERGE: description assistant prototype on the AI-3 LLM connection - #25245

Draft
jonasjabari wants to merge 54 commits into
devfrom
demo/ai-100-prototype-pullpreview
Draft

jonasjabari wants to merge 54 commits into
devfrom
demo/ai-100-prototype-pullpreview

Conversation

@jonasjabari

@jonasjabari jonasjabari commented Sep 10, 2026 •

Copy link
Copy Markdown
Collaborator

Ticket

https://community.openproject.org/wp/AI-100

What is this?

A demo-only prototype of the AI description assistant (AI-100, AI-126), running on the real LLM connection from the AI-3 stack. Never to be merged: the branch is the open part of the AI-3 stack (PR 7 #24885 up to PR 12 #25349; PRs 1 to 6 are on dev since 2026-09-30) plus dev plus the demo commits, so the diff shows both. AI-133 to AI-136 are on dev. Rebuilt on 2026-10-02 after the AI-3 migrations were renumbered on dev; a demo-only migration drops the LLM tables of the earlier stack once, so LLM settings entered before have to be entered again. Last synced with dev on 2026-10-23.

What it demonstrates:

  • The merged AI-133 and AI-135 code (runs with an append-only event log, availability rules, streaming job with cancel and time budget) and the AI-136 run endpoints (POST /api/v3/ai_text_transform_runs, GET …/:uuid?after=<seq>, POST …/:uuid/cancel).
  • AI::TextTransforms::LlmGateway, the AI-137 shape: Llm::Runtime.for(:description_assistant) with streaming, zero retries and error translation.
  • An admin sandbox below every text transform action form (Administration → AI → Text transform actions → edit) that posts text, polls the run and shows the streamed result, the stored system prompt and the polled events.

Editor demo (AI-126)

Open a work package and click into the description. The "Assistant" split button at the right end of the toolbar is the real CKEditor plugin from AI-101 (opf/commonmark-ckeditor-build#131, bundle built from build-repo master plus that PR). It lists the actions the API offers for the work package (AI-134); the main part runs the last used action, the arrow opens the list.

Only the button is taken from AI-101 (#25770). The result pane is the real implementation: AI-172 from dev plus the open PR branches of AI-173 (#26091, floating behaviour) and AI-175 (#26138, endpoints), merged into this branch; the parts no ticket delivers yet (footer forms, polling, the applied wait) are demo glue until AI-175/AI-176 land. What happens after the click:

  • The core AiActionsService.run(action, editor, resource) reads the selection from the editor model and posts to AI::TextTransformPanesController through turboRequests, like the wiki page link macro requests its dialog. The controller starts the run and appends the result pane (Primer::Beta::BorderBox) to the body.
  • The pane polls the controller. Each answer brings the text so far, already formatted with format_text, or 204 when nothing changed. No separate markdown endpoint; the API v3 run endpoints are not used by the pane.
  • Replace, close and Try again are Turbo forms. The finished text returns to the service through the dispatchEvent stream action, tied to the request by a requestId, and is applied with model.insertContent.

With text selected, only the selection is sent and replaced; otherwise the whole description. Replace keeps the editor's undo history. The pane can be dragged and resized from four handles. Append ?ai_demo_fault=blocked or ?ai_demo_fault=failed to the page URL to see the "stopped" and "failed" states.

Try it in the PullPreview

  1. Administration → AI → LLM connection: base URL including the version segment (e.g. https://…/v1), API key, save, sync models, enable. If the gateway's models are missing from the list, add them by hand.
  2. AI models: bind a chat model to "Description assistant" or set a default chat model.
  3. Text transform actions: switch the assistant on, activate an action, open it and use the sandbox at the bottom. "Save and stay" keeps the sandbox state while editing the prompt.

Findings for AI-3 while building this (found on the stack version of 2026-09-09, not re-checked against the rewrite)

  • Llm::Session sends instructions with the developer role; OpenAI-compatible gateways drop it silently, so the whole system prompt is lost. Patched here with openai_use_system_role = true.
  • For api_format: openrouter the model list is registry-backed, not fetched from the server; a bound model may not exist on the gateway.
  • The base URL must contain the version segment; without it completions hit /chat/completions and 404.
  • The gateway's GET /v1/models returns a bare JSON array, not the OpenAI { "data": [...] } envelope, which blocked saving the connection. Fixed upstream in [AI-3] Discover the embedding models OpenRouter serves separately #25349; the demo-only patch is gone.

The real implementation lands as AI-133 to AI-137.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

Deploying openproject with ⚡ PullPreview

Field Value
Latest commit e289c77
Job deploy
Status ✅ Deploy successful
Preview URL https://pr-25245-ai-100-prototype-pu-ip-78-47-93-79.my.opf.run:443

View logs

@jonasjabari

Copy link
Copy Markdown
Collaborator Author
Bildschirmaufnahme.2026-09-10.um.17.47.03.mov

@github-actions

Copy link
Copy Markdown

Warning

Flaky specs

  • rspec ./spec/features/notifications/navigation_spec.rb[1:1:1]
🤖 Ask Copilot to investigate

Copy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer.

@copilot The following spec(s) are flaky in CI (first seen on PR #25245, linked for reference only):

- `rspec ./spec/features/notifications/navigation_spec.rb[1:1:1]`

Treat this as a standalone task, unrelated to PR #25245. Create a new branch from origin/dev and open a new pull request targeting dev — do not stack it on PR #25245 or reuse that branch.

Follow the playbook in docs/development/testing/handling-flaky-tests/README.md to find the root cause and fix the underlying race — do not skip, delete, or weaken the spec to make it pass; disabling is a last resort per the playbook, and only with a bug ticket. Verify the fix by running the spec(s) repeatedly (e.g. `script/bulk_run_rspec --run-count 10`).

If you cannot reproduce the flake or are not confident in a fix after reasonable investigation, do not fabricate a change or skip the spec to force CI green. Instead, leave the pull request in draft and document what you tried, the suspected cause, and any leads in its description, then assign @jonasjabari to take over.

Once the fix is verified, title the PR after the spec(s) it fixes, and use the PR description to explain the root cause, how the change resolves it, and the before/after results. Label the PR `flaky-spec`, assign @jonasjabari, and request a review from @jonasjabari.
On every commit, set @jonasjabari as the sole co-author with a `Co-authored-by:` trailer (use their GitHub no-reply email so it links to their account), so it is traceable who dispatched the fix.

@jonasjabari
jonasjabari force-pushed the demo/ai-100-prototype-pullpreview branch from 75c760c to 79b2a3e Compare September 16, 2026 15:51
@github-actions

Copy link
Copy Markdown

Warning

Flaky specs

  • rspec ./modules/reporting/spec/features/work_package_costlog_spec.rb[1:1:1]
🤖 Ask Copilot to investigate

Copy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer.

@copilot The following spec(s) are flaky in CI (first seen on PR #25245, linked for reference only):

- `rspec ./modules/reporting/spec/features/work_package_costlog_spec.rb[1:1:1]`

Treat this as a standalone task, unrelated to PR #25245. Create a new branch from origin/dev and open a new pull request targeting dev — do not stack it on PR #25245 or reuse that branch.

Follow the playbook in docs/development/testing/handling-flaky-tests/README.md to find the root cause and fix the underlying race — do not skip, delete, or weaken the spec to make it pass; disabling is a last resort per the playbook, and only with a bug ticket. Verify the fix by running the spec(s) repeatedly (e.g. `script/bulk_run_rspec --run-count 10`).

If you cannot reproduce the flake or are not confident in a fix after reasonable investigation, do not fabricate a change or skip the spec to force CI green. Instead, leave the pull request in draft and document what you tried, the suspected cause, and any leads in its description, then assign @jonasjabari to take over.

Once the fix is verified, title the PR after the spec(s) it fixes, and use the PR description to explain the root cause, how the change resolves it, and the before/after results. Label the PR `flaky-spec`, assign @jonasjabari, and request a review from @jonasjabari.
On every commit, set @jonasjabari as the sole co-author with a `Co-authored-by:` trailer (use their GitHub no-reply email so it links to their account), so it is traceable who dispatched the fix.

@github-actions

Copy link
Copy Markdown

Warning

Flaky specs

  • rspec ./modules/gantt/spec/features/timeline/timeline_dates_spec.rb[1:2:1]
🤖 Ask Copilot to investigate

Copy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer.

@copilot The following spec(s) are flaky in CI (first seen on PR #25245, linked for reference only):

- `rspec ./modules/gantt/spec/features/timeline/timeline_dates_spec.rb[1:2:1]`

Treat this as a standalone task, unrelated to PR #25245. Create a new branch from origin/dev and open a new pull request targeting dev — do not stack it on PR #25245 or reuse that branch.

Follow the playbook in docs/development/testing/handling-flaky-tests/README.md to find the root cause and fix the underlying race — do not skip, delete, or weaken the spec to make it pass; disabling is a last resort per the playbook, and only with a bug ticket. Verify the fix by running the spec(s) repeatedly (e.g. `script/bulk_run_rspec --run-count 10`).

If you cannot reproduce the flake or are not confident in a fix after reasonable investigation, do not fabricate a change or skip the spec to force CI green. Instead, leave the pull request in draft and document what you tried, the suspected cause, and any leads in its description, then assign @jonasjabari to take over.

Once the fix is verified, title the PR after the spec(s) it fixes, and use the PR description to explain the root cause, how the change resolves it, and the before/after results. Label the PR `flaky-spec`, assign @jonasjabari, and request a review from @jonasjabari.
On every commit, set @jonasjabari as the sole co-author with a `Co-authored-by:` trailer (use their GitHub no-reply email so it links to their account), so it is traceable who dispatched the fix.

jonasjabari and others added 20 commits October 2, 2026 15:22
Adds a sandbox below the text transform action form that posts text
against the run API and polls the run, so the whole stack can be tried
in the browser. The representer exposes the stored system prompt for
this sandbox only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
Replaces the environment-configured prototype gateway with a gateway on
Llm::Runtime, so the description assistant uses the connection and the
model binding an administrator configures in the admin UI. Enables the
llm_connection feature flag for PullPreview.

Demo only, never to be merged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
RubyLLM sends instructions with the role "developer" unless
openai_use_system_role is set. OpenAI-compatible gateways such as the
one used for this demo ignore that role, so the whole system prompt was
dropped. This is a finding for the AI-3 stack (Llm::Session); patched
here for the demo only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
Primer form with a context selector that explains when a work package
or a project and type are needed, selects instead of raw id fields, a
spinner with an elapsed timer while the run is polled, and a details
dialog with the stored system prompt and the polled events.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
…dbox

Replaces the preloaded selects with Primer select panels that fetch up
to 20 matches from a small admin-only search endpoint while typing, so
the sandbox also works on installations with many work packages and
projects.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
A second submit button updates the action and answers with a Turbo
Stream that replaces only the form, so the sandbox below keeps its
state instead of being lost to the redirect to the index page.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
The admin sandbox shows the assembled system prompt in its details dialog.
The real API (AI-136) keeps it hidden; this is demo-only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
…ends

Returning to the tab after a run had finished scheduled one more poll,
which re-entered finish() and moved finishedAt to the current time, so the
timer showed the time away from the tab instead of the run duration.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
Reasoning models stream minutes of chunks without content. The gateway
dropped them, so the execution never got a chance to look at the cancel
wish or its time budget before the first content chunk. Empty chunks are
now passed on as empty deltas.

The gateway also restores any error the caller raises inside the stream
block, not only the cancellation: Llm::Errors.wrap turned an exceeded
budget into a generic upstream error.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
AI-126 asks for a "generation stopped" state when a guardrail blocks the
stream. The event vocabulary has no such reason and the real signal of the
LLM stack is unknown, so the demo adds the reason "blocked" and a gateway
wrapper that produces it, or a connection failure, when the run API is
called with the demo-only parameter demoFault.

Also holds the locale keys of the editor menu and the result popover.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
…pover

Editor demo for AI-126, mode A only (the whole description):

- The description editor mounts an AI action menu at the end of its toolbar
  row. The server renders the Primer ActionMenu shell, the items come from
  the list endpoints of AI-134.
- The result popover runs the chosen action through the run API of AI-136,
  renders the streamed markdown through the markdown render endpoint and
  offers cancel, copy, discard, replace and try again. It can be dragged.
- The run client (create, cursor polling, cancel) is extracted from the
  admin sandbox and shared by both.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
- A menu item was a submit button inside the edit field's form, so choosing
  an action saved the description and closed the editor. Items are plain
  buttons now, and Replace finds its editor again.
- The popover stayed empty: the API v3 render endpoints were removed from
  dev (OP-19480). A demo endpoint renders the streamed markdown instead.
- The prototype controls are gone from the popover. A blocked or failed
  generation can still be forced with ?ai_demo_fault=blocked|failed in the
  page URL. The grip moved into the footer as in the mockup.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
Requested after the first UI test: a plain border instead of the popover
caret, the drag grip in line with the footer buttons, and a resize handle
in the bottom right corner (minimum 320x240, kept inside the viewport).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
With text selected in the description editor, the chosen action receives
exactly that selection as markdown and Replace swaps the same range, even
if the user kept typing meanwhile. Actions that inject the type template
still run on the whole description.

Built on the CKEditor model and data APIs of the vendored build: the
selection becomes markdown through the build's turndown processor, a
marker pins the range, and insertContent puts the answer back with undo
intact. Nothing changes in the backend or the run API. The selection is
sent as is, not expanded to whole blocks, so structural breakages surface.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
…tion

Replace in document mode now goes through insertContent over the root
range instead of setData, so the user can undo the AI result like any
other edit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
The pane wraps Primer::Alpha::Overlay instead of the Popover: header with
close button, body and footer slots, shown in the browser top layer. It is
a manual popover so clicks into the editor do not dismiss it, anchored to a
fixed point top right below the app header.

Following the design system rule not to change Primer components for a
feature, dragging and resizing stay on the wrapper's Stimulus controller.
A dragged or resized pane is pinned with important inline styles, because
anchored-position re-anchors on every window or document resize.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
anchored-position re-anchors on window and document resizes by assigning
inline top and left, which also drops an inline important. The dragged or
resized position now lives in CSS variables behind a scoped pinned rule.

Also resets the text alignment: the align="end" anchoring attribute on
anchored-position is read as the legacy alignment attribute and right-
aligned the whole pane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
jonasjabari and others added 11 commits October 15, 2026 14:07
The ai-text-transform-pane controller makes the result pane a
non-modal floating window: drag by header or footer grip, resize from
four handles (min 320x240, 8px viewport margin), keep the pinned
geometry when the pane element is replaced, close on Escape through
the close form (or remove the pane without one), copy the raw text
with short "Copied" feedback and focus the pane on connect.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Attaches ai-text-transform-pane to the pane wrapper with the close form
id, copy labels and the Escape action; marks the pane as focusable
target, the header and footer grip as drag handles, the resize spans
with beginResize, the Copy button label and the raw template. The
apply-failed banner gets its targets for AI-176.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Review follow-up:
- Copy uses Primer::Beta::ClipboardCopyButton (icon-only, copy to check
  feedback, live region) instead of an own clipboard call; drop the
  unused pane.copied locale key.
- Gate drag starts with closestDragBlockingElement and the primary
  button, end pointer actions on pointercancel, track listeners with an
  AbortController and set touch-action: none on drag surfaces.
- Clear max-width while resizing so the left handle keeps the right
  edge; clamp restored geometry and re-clamp on window resize.
- Wire the header close button to the close action.
- action helper takes several actions per element.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Apply review suggestions: query the pane, close button and link by
role, dispatch events with fireEvent and assert with jest-dom matchers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Routes under /ai/text_transform_panes for starting, polling, closing,
applying and cancelling a result pane run. The contract validates the
request id (UUID v4), scope and context ids every pane request carries.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The create action resolves the context, starts a run (or repeats one
of the user's own runs) and appends the pane to the body. Unavailable
actions render the pane as failed; invalid parameters answer 400.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
show answers polls with updated body and footer sections (204 while
nothing changed), destroy cancels the run and removes the pane, apply
dispatches the completed text to the editor and cancel stops a run
whose pane disappeared. All lookups are scoped to the user's own runs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Validate action_id, input and retry_of in the contract, reject a work
package combined with a project and a project without a type (like the
API v3 run endpoint), and accept blank context ids. Only failed runs
can be retried. Polls resolve the context only when they render, the
pane append renders lazily like the other turbo stream helpers, and
new events are detected through TextTransformRun#events_after.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Panes for a new work package have no work package to derive the
project from, so project-relative links such as wiki links did not
resolve. The pane state now carries the context's project.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
jonasjabari and others added 3 commits October 23, 2026 14:15
…pullpreview

# Conflicts:
#	app/components/ai/text_transforms/result_pane_component.html.erb
#	app/components/ai/text_transforms/result_pane_component.rb
#	app/components/ai/text_transforms/result_pane_component.sass
#	app/components/ai/text_transforms/result_pane_helpers.rb
#	app/components/ai/text_transforms/result_pane_state.rb
#	config/locales/en.yml
#	frontend/src/app/shared/components/editor/components/ckeditor/ckeditor-setup.service.ts
#	frontend/src/app/shared/components/editor/components/ckeditor/op-ckeditor.component.ts
The demo keeps its own result pane (target architecture with forms and
polling); the presentational components that AI-172 merged into dev under
the same names are not used here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
Brings the editor side of tangopium's AI-101 into the demo, but only the
button: the CKEditor bundle is built from commonmark-ckeditor-build master
plus opf/commonmark-ckeditor-build#131, and the core registers the
aiActions plugin service with actionsFor and defaultAction as in #25770.
The service's run follows the result pane architecture instead of the
prototype in #25770: it reads the selection from the editor model, posts
to the pane controller through turboRequests and applies the text the
pane hands back with model.insertContent (undo keeps working).

The demo's own AI menu next to the toolbar and the editor wrapper events
are gone; the pane's event names move next to the service.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
jonasjabari and others added 5 commits October 23, 2026 15:02
CKEditor 49 colours a hovered split button with
--ck-color-split-button-hover-background, falling back to
--ck-color-base-hover, which stays light in the dark theme. The Assistant
button is the first split button in the editor toolbar, so the mapping to
the Primer button hover colour was missing until now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
The result pane from AI-172 is on dev. The demo drops its own pane
(section component, pane controller, Stimulus controller, routes) and
takes the dev files again, so the open AI-173 and AI-175 branches can be
merged on top.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
…ane-behaviour' into demo/ai-100-prototype-pullpreview
…e-endpoints' into demo/ai-100-prototype-pullpreview
The pane now comes from AI-172 (dev) with the open AI-173 and AI-175
branches merged in. What those do not cover yet is demo glue:

- the footer renders the close, apply and retry forms and a state element
  (AI-175's component part), wired to AI-173's close action;
- a small Stimulus controller on that state element polls while the run
  generates, waits for the editor's applied answer and cancels the run
  when the pane disappears mid-run (AI-176's pane part);
- the pane controller accepts ?ai_demo_fault= for the demo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
jonasjabari and others added 7 commits October 26, 2026 17:12
The CKEditor Assistant button asks the core aiActions plugin service
which text transform actions the work package description editor may
offer, and which of them to show first: the one run last in this
browser, or the first by position. The service resolves the list
through the work package endpoint, or the project and type endpoint for
a new work package; any failure leaves the list empty, which keeps the
button hidden.

run is only the seam the plugin calls: it remembers the chosen action.
The result pane wiring follows in AI-176.

Ported from #25770 without the prototype run.

https://community.openproject.org/wp/AI-101

Co-authored-by: Andreas Eiselt <andreas.eiselt@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Comments, wiki pages, forum messages, meetings, custom fields and admin
texts now list the actions scoped "everywhere" through the context-free
endpoint. Only the work package description keeps the work package or
project endpoint, which adds type-scoped actions and requires the right
to edit the work package.

https://community.openproject.org/wp/AI-101

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Built from opf/commonmark-ckeditor-build master (83a9f79) plus #131
rebased onto it (213c255). The plugin sits in builtinPlugins, so the full
and the constrained editors both show the button once the service lists
actions. The label is capped at 12em so an admin-defined name cannot push
the button out of the toolbar.

https://community.openproject.org/wp/AI-101

Co-authored-by: Andreas Eiselt <andreas.eiselt@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
CKEditor 49 colours a hovered split button with
--ck-color-split-button-hover-background, which falls back to
--ck-color-base-hover and stays light in the dark theme: the Assistant
button turned light with white text on hover and while its menu was
open. It is the first split button in the editor toolbar.

https://community.openproject.org/wp/AI-101

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
With a ready gateway, the description editor offers the type-scoped and
the "everywhere" actions, and the comment editor only the "everywhere"
ones.

https://community.openproject.org/wp/AI-101

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…0-prototype-pullpreview

The demo keeps its pane run in AiActionsService on top of AI-101's
actionsFor for every editor; outside the work package description the
pane request carries no context.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB
CKEditor's config.get deep-clones the value it returns; cloning the whole
openProject config fails on the context's HAL resource (read-only
getters), so the click on an action threw before the pane request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HL6QmQW5pV6v8FAig2gJB

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants