Skip to content

feat(llm): integrate GitLab DWS tool approval with permission system#19955

Merged
rekram1-node merged 66 commits intoanomalyco:devfrom
vglafirov:feat/gitlab-dws-approval-integration
Apr 9, 2026
Merged

feat(llm): integrate GitLab DWS tool approval with permission system#19955
rekram1-node merged 66 commits intoanomalyco:devfrom
vglafirov:feat/gitlab-dws-approval-integration

Conversation

@vglafirov
Copy link
Copy Markdown
Contributor

@vglafirov vglafirov commented Mar 29, 2026

Issue for this PR

Closes #19958

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Wires the GitLab Duo Workflow Service (DWS) tool-call approval checkpoint into opencode's existing permission system. When DWS requires approval before executing a sensitive tool, the user sees opencode's standard permission prompt instead of the session silently failing or hanging.

Changes in packages/opencode/src/session/llm.ts:

  • Set sessionPreapprovedTools from the merged agent+session ruleset — tools without an explicit ask rule are pre-approved for the DWS session, preserving the existing behaviour where tools run without interruption by default
  • Set approvalHandler (wrapped with Instance.bind to restore AsyncLocalStorage context across the async boundary) that delegates to Permission.ask with permission type workflow_tool_approval
  • When the user selects "Allow always", approved tool names are appended to sessionPreapprovedTools so subsequent DWS turns skip the prompt
  • Returning { approved: false } causes the provider to send the rejection payload to DWS, cleanly ending the workflow
  • Exports preapprovedWorkflowTools helper using findLast rule-precedence logic

Bumps gitlab-ai-provider to 6.1.0 which includes two fixes required for this feature:

  • approvalPending flag on StreamState that defers the stream close/complete event while waiting for user decision (without this the session ended before the prompt appeared)
  • Fix for rejection not being forwarded to DWS (the rejection payload was built but never sent)

How did you verify your code works?

  • bun test test/session/ — 155 pass, 0 fail
  • bun typecheck — clean
  • Tested end-to-end against a live GitLab DWS instance: approval prompt appears, "Allow once" and "Allow always" resume the workflow correctly, "Reject" sends the rejection to DWS and closes the session cleanly

Screenshots / recordings

If this is a UI change, please include a screenshot or recording.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

If you do not follow this template your PR will be automatically rejected.

Wire approvalHandler and sessionPreapprovedTools on GitLabWorkflowLanguageModel
so that DWS tool-call approval checkpoints surface as opencode permission prompts.

- Set sessionPreapprovedTools from the merged agent+session ruleset so tools
  without an explicit 'ask' rule are pre-approved for the DWS session
- Set approvalHandler (wrapped with Instance.bind to restore ALS context)
  that delegates to Permission.ask with permission type 'workflow_tool_approval'
- Capture the Bus Replied event to detect 'always' replies and extend
  sessionPreapprovedTools for subsequent DWS turns
- Return { approved: true/false } so approveAndResume reconnects with the
  correct approval or rejection payload
- Bump gitlab-ai-provider to 6.1.0 which includes the approvalPending
  stream-close deferral and rejection forwarding fixes
- Add preapprovedWorkflowTools helper (exported for testing) that filters
  tools using findLast rule precedence matching ask-only exclusion
@github-actions github-actions bot added contributor needs:compliance This means the issue will auto-close after 2 hours. labels Mar 29, 2026
@github-actions github-actions bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Mar 29, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

- Use SessionID.make() instead of SessionID.zod.parse() to match other call sites
- Inline preapproved tool filter logic instead of exporting a standalone function
- Remove standalone test file for the inlined logic
- Set sessionID on workflowModel for per-session DWS workflow keying
- Show tool name + title in approval patterns for better UX
- Add workflowDefinition passthrough in provider getModel
@vglafirov vglafirov requested a review from rekram1-node March 31, 2026 17:23
vglafirov and others added 23 commits April 6, 2026 12:29
@rekram1-node
Copy link
Copy Markdown
Collaborator

we need to come back do a pass on cleaning this up but ill merge for now

@rekram1-node rekram1-node merged commit cd8e8a9 into anomalyco:dev Apr 9, 2026
10 of 13 checks passed
NicholasDominici added a commit to jairad26/opencode that referenced this pull request Apr 9, 2026
* fix: bump openrouter ai sdk pkg to fix openrouter issues (anomalyco#21242)

* chore: update nix node_modules hashes

* chore: remove ai-sdk/provider-utils patch and update pkg (anomalyco#21245)

* chore: update nix node_modules hashes

* chore: bump anthropic ai sdk pkg, delete patch (anomalyco#21247)

* refactor(core): add full http proxy and change workspace adaptor interface (anomalyco#21239)

* go: add mimo

* feat: add --dangerously-skip-permissions flag to opencode run (anomalyco#21266)

* chore: update nix node_modules hashes

* feat(opencode): Add PDF attachment Drag and Drop (anomalyco#16926)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>

* feat(app): show full names on composer attachment chips (anomalyco#21306)

* style(app): redesign jump-to-bottom button per figma spec (anomalyco#21313)

* Move auto-accept permissions to settings (anomalyco#21308)

* go: support coupon

* fix(opencode): keep user message variants scoped to model (anomalyco#21332)

* chore: generate

* chore: update web stats

* feat(app): better subagent experience (anomalyco#20708)

* refactor(core): support multiple event streams in worker and remove workspaces from plugin api (anomalyco#21348)

* fix(tui): use sentence case for theme mode command palette items (anomalyco#21192)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>

* fix: ensure the alibaba provider errors are retried (anomalyco#21355)

* fix(opencode): improve console login transport errors (anomalyco#21350)

* chore: generate

* feat(tui): allow variant_list keybind for the "Switch model variant" command (anomalyco#21185)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>

* test: disable GPG signing in test fixtures (anomalyco#20386)

* fix(opencode): clear webfetch timeouts on failed fetches (anomalyco#21378)

* feat(opencode): add OTLP observability support (anomalyco#21387)

* zen: glm5.1 doc

* zen: glm5.1 doc

* go: glm5.1

* core: refactor tool system to remove agent context from initialization (anomalyco#21052)

* refactor(snapshot): store unified patches in file diffs (anomalyco#21244)

Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>

* chore: generate

* release: v1.4.0

* chore: update nix node_modules hashes

* fix(tui): simplify console org display (anomalyco#21339)

Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>

* ui: fix sticky session diffs header (anomalyco#21486)

* test: update webfetch test (anomalyco#21398)

Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>

* fix: ensure that /providers list and shell endpoints are correctly typed in sdk and openapi schema (anomalyco#21543)

* fix(app): patch tool diff rendering

* fix(app): diff list normalization

* fix: dont show invalid variants for BP (anomalyco#21555)

* tweak: separate ModelsDev.Model and Config model schemas (anomalyco#21561)

* refactor(effect): build task tool from agent services (anomalyco#21017)

* fix(app): skip url password setting for same-origin server and web app (anomalyco#19923)

* fix: propagate abort signal to inline read tool (anomalyco#21584)

* refactor(effect): inline session processor interrupt cleanup (anomalyco#21593)

* feat(llm): integrate GitLab DWS tool approval with permission system (anomalyco#19955)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>

* chore: update nix node_modules hashes

* fix(lsp): remove CMakeLists.txt and Makefile from clangd root markers (anomalyco#21466)

* Remove CLI from electron app (anomalyco#17803)

Co-authored-by: LukeParkerDev <10430890+Hona@users.noreply.github.com>

* chore: generate

* chore: update nix node_modules hashes

* feat: add opencode go upsell modal when limits are hit (anomalyco#21583)

Co-authored-by: Frank <frank@anoma.ly>

* release: v1.4.1

* app: remove min loading duration (anomalyco#21655)

* fix: preserve interrupted bash output in tool results (anomalyco#21598)

* fix: preserve text part timing in session processor (anomalyco#21691)

* refactor(effect): drop shell abort signals from runner (anomalyco#21599)

* refactor: fix tool call state handling and clean up imports (anomalyco#21709)

* release: v1.4.2

* feat(mcp): add OAuth redirect URI configuration for MCP servers (anomalyco#21385)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>

* chore: generate

* fix(tui): restore hidden session scrollbar default (anomalyco#20947)

* feat: add support for fast modes for claude and gpt models (that support it) (anomalyco#21706)

* opencode: lazy-load top-level CLI commands

The CLI imports every top-level command before argument parsing has
decided which handler will run. This makes simple invocations pay for
the full command graph up front and slows down the default startup path.

Parse the root argv first and load only the command module that matches
the selected top-level command. Keep falling back to the default TUI
path for non-command positionals, and preserve root help, version and
completion handling

* delete unused withALS method (anomalyco#21723)

* Revert "opencode: lazy-load top-level CLI commands" (anomalyco#21726)

* fix(effect): suspend agent default layer construction (anomalyco#21732)

---------

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: James Long <longster@gmail.com>
Co-authored-by: Frank <frank@anoma.ly>
Co-authored-by: gitpush-gitpaid <149759805+gitpush-gitpaid@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
Co-authored-by: Dax <mail@thdxr.com>
Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>
Co-authored-by: Ariane Emory <97994360+ariane-emory@users.noreply.github.com>
Co-authored-by: Kit Langton <kit.langton@gmail.com>
Co-authored-by: Kyle Altendorf <sda@fstab.net>
Co-authored-by: opencode <opencode@sst.dev>
Co-authored-by: Brendan Allan <brendonovich@outlook.com>
Co-authored-by: OpeOginni <107570612+OpeOginni@users.noreply.github.com>
Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com>
Co-authored-by: Cho HyeonJong <mbin96@gmail.com>
Co-authored-by: LukeParkerDev <10430890+Hona@users.noreply.github.com>
Co-authored-by: Aleksandr Lossenko <aleksandr.lossenko@gmail.com>
Co-authored-by: Simon Klee <hello@simonklee.dk>
timrichardson pushed a commit to timrichardson/opencode that referenced this pull request Apr 9, 2026
…nomalyco#19955)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
q107580018 pushed a commit to q107580018/opencode that referenced this pull request Apr 10, 2026
…nomalyco#19955)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: GitLab Duo Workflow Service tool-call approval integration

2 participants