Repository navigation
Conversation
🎩 PreviewA preview build has been created at: |
068de7f to
c8e17a0
Compare
c8e17a0 to
251adc6
Compare
fa6511f to
3ba5491
Compare
61436b5 to
c822e4b
Compare
c822e4b to
3ac6349
Compare
b63ab65 to
1d52a6f
Compare
| export function useTangentActingTeam( | ||
| projectId: string, | ||
| ): (sessionId: string) => string | undefined { | ||
| const teamId = actingTeamId(useTeamForProjects([projectId])); |
There was a problem hiding this comment.
🤖 This is an AI-generated code review comment.
Tangent still grants read-only workspaces per message
actingTeamId(...) returns the team id for any active resolution, including canWrite: false. That means a user with only read access to the workspace still grants the team id to every Tangent message. The session memory tells the agent it may call tools with asTeam, and tangent-shell will receive a team grant for a user who should not be able to create workspace-owned runs/use workspace secrets for writes.
Please only grant getActingTeam when resolution.status === "active" && resolution.team.canWrite. If read-only users should still inspect workspace-scoped data, keep that as a separate read-only code path rather than using the same acting-team grant.
1d52a6f to
c3aaf66
Compare
| case "not-member": | ||
| case "unavailable": | ||
| return teamProjectBrief(team.team); | ||
| default: |
There was a problem hiding this comment.
🤖 This is an AI-generated code review comment.
Whether a session gets the workspace brief depends on who started it.
The brief describes the project, not the person, and the PR calls it "the same for everyone in the session". But it's written once, from the resolution of whoever starts the session, and an error resolution writes no brief. So if the starter's identity check failed, the session never gets the brief, even when a member who types later is granted the team and their turns would need it. Base the brief on the team of the project's workspace (teamOfWorkspace), not on the starter's resolution.
|
✅ Manually smoke tested by @camielvs. |
c3aaf66 to
04050bb
Compare
Moves the tangent-shell packages from 1998f55 to d229883, which adds TangentProvider's getActingTeam. The team it returns is a grant that each agent call opts into. The packages' own dependencies are unchanged, so the lockfile only moves the commit. d229883 is the head of TangleML/tangent-shell#132, not yet merged. Repin to its merge commit before this stack merges. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A Tangent session is shared, so a team fixed when it starts acts for whoever types next, member or not. The team is now granted per message: the page passes TangentProvider a getActingTeam, which Tangent reads as each message is sent and attaches to the agent turns that message causes. That team is a grant, not a default: a team-scoped call acts as it only when its tool asks, and goes as the user otherwise. The server adds the team header itself and strips any copy an agent sends. The getter returns the team only while the signed-in user can act as it, and nothing for any other resolution. It doesn't check that the session belongs to this project: the opening prompt is sent before the session is attached, so such a check would refuse it. The session's memory gets a project-level brief instead of one written for whoever started it. It names the project's workspace and its team id, calls the team the workspace as the UI does, and says a turn may act as the workspace only when its sender is in it and grants it, and that even then each call opts in (asTeam). It also says to check secrets and submit as the same identity, when to choose the workspace, never to send the header, where to see the turn's grant, and not to retry as the user unless asked. A project without a known team gets no brief. The session no longer carries the team in its environment, since agents would read it as the session's. A session still isn't started while the team is being checked, so the opening prompt goes out with the team granted rather than without it. The arrival waits for the team, and New session says to try again. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
04050bb to
8fab1eb
Compare
Closing: per-message team gating is out of scope. The workspace secrets UI ships through #2944, and tangent-shell is expected to handle agents' team submission, so this PR's per-message grant and its pin to TangleML/tangent-shell#132 aren't needed. Nothing below this PR depends on it. #2927–#2944 don't use its code or the newer |
Human Words
Welcome to the top of the stack for the Workspaces x Secrets feature.
The Agentic Tangent-side functionality of this stack is delivered in TangleML/tangent-shell#132.
How it works
This stack builds on top of the Team Impersonation system to allow users to create Workspace-level secrets and execute Pipeline Runs using them.
Workspaces are now associated 1:1 with a Team and through a static config on the backend that Team grants basic roles to users based on their Team membership. Users with Team permissions are then able to create, edit and manage secrets on the entire Workspace, and add them to their pipelines.
When a pipeline is submitted with a Workspace secret the initiating user must have team permissions. That Run will then be Attributed to the team and utilise its secrets. It is not possible to mix user-personal secrets and workspace secrets in one pipeline. Additionally, for runs that do not use secrets the user will have a choice of submitting as themselves or the team. It is also not possible to run a pipeline that uses Workspace secrets from outside of that Workspace.
Tangent agents have access to the same functionality, based on Team membership of the user who initiated the turn, via tangent-shell PRs.
Screenshots
Testing
AI Words
Description
Tangent agents submit runs two ways. The tool bridge into a pipeline or run tab acts as the project's team since #2943. The agent's own server-side tools didn't, so their runs went as the user. A run that used a team secret then failed at launch with "User … does not have secret …".
A Tangent session is shared, so the team can't be fixed when it starts: it would act for whoever types next, member or not. It's granted per message instead:
getActingTeam: the page passes it toTangentProvider. Tangent reads it as each message is sent and attaches the team to the agent turns that message causes, including work Prime hands to sub-agents.asTeam), and goes as the user otherwise. So agents can still list and use the user's own secrets. The tangent-shell server adds the team header itself and strips any copy an agent sends.asTeam). It says to check secrets and submit as the same identity, and to act as the workspace when the user asks or the run needs a secret only the workspace has. It also says never to send the header, where to see the turn's grant, and not to retry as the user unless asked. A project without a known team gets no brief.The tangent-shell side is TangleML/tangent-shell#132, not yet merged. This PR pins
@tangent/embed-reactand@tangent/sharedto its head, d229883, sogetActingTeamexists and the team it grants is one each agent call opts into.Related Issue and Pull requests
tangle_secret_list, anasTeamoption on it and ontangle_run_submit, and reports the turn's grant intangle_root_config_show. The brief refers to all three.Type of Change
Line Breakdown
Checklist
Screenshots (if applicable)
None. There's no UI change beyond the "still being checked" notice.
Test Instructions
Against a local tangent-shell on
feat/per-turn-team-impersonation(TangleML/tangent-shell#132), with thetangle3.6.1 bundle from TangleML/tangent-shell-shopify#15, and a backend that honours the header:master.Additional Comments
If the host's
__TANGLE_TEAM_IMPERSONATION__.headerNameis ever anything other thanx-tangle-impersonate-team-id, the tangent-shell server'sTANGLE_TEAM_HEADERmust be set to match. tangle-ui no longer passes the header name to Tangent.🤖 Generated with Claude Code