Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .changeset/effective-yellow-bug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@inkeep/agents-work-apps": patch
---

Fix error response format consistency in join-from-workspace endpoints
5 changes: 5 additions & 0 deletions .changeset/thundering-sapphire-swift.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@inkeep/agents-manage-ui": patch
---

Add join-from-workspace toggle and auto-invite flow for Slack users
5 changes: 5 additions & 0 deletions .changeset/well-chocolate-scorpion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@inkeep/agents-core": minor
---

Add organization service account, preferred auth method, and Slack workspace join-from-workspace schema support
119 changes: 119 additions & 0 deletions agents-api/__snapshots__/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -39179,6 +39179,125 @@
}
}
},
"/work-apps/slack/workspaces/{teamId}/join-from-workspace": {
"get": {
"description": "Get the join from workspace setting for the workspace",
"operationId": "slack-get-join-from-workspace",
"parameters": [
{
"in": "path",
"name": "teamId",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"properties": {
"shouldAllowJoinFromWorkspace": {
"type": "boolean"
}
},
"required": [
"shouldAllowJoinFromWorkspace"
],
"type": "object"
}
}
},
"description": "Join from workspace setting"
},
"404": {
"description": "Workspace not found"
}
},
"summary": "Get Join From Workspace Setting",
"tags": [
"Work Apps",
"Slack",
"Workspaces"
],
"x-authz": {
"description": "Requires work-apps authentication (OIDC token or Slack signature). Auth is enforced by workAppsAuth middleware in createApp.ts."
}
},
"put": {
"description": "Enable or disable join from workspace for the workspace",
"operationId": "slack-update-join-from-workspace",
"parameters": [
{
"in": "path",
"name": "teamId",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"properties": {
"shouldAllowJoinFromWorkspace": {
"type": "boolean"
}
},
"required": [
"shouldAllowJoinFromWorkspace"
],
"type": "object"
}
}
}
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"properties": {
"success": {
"type": "boolean"
}
},
"required": [
"success"
],
"type": "object"
}
}
},
"description": "Join from workspace setting updated"
},
"401": {
"description": "Unauthorized"
},
"404": {
"description": "Workspace not found"
},
"500": {
"description": "Failed to update setting"
}
},
"summary": "Update Join From Workspace Setting",
"tags": [
"Work Apps",
"Slack",
"Workspaces"
],
"x-authz": {
"description": "Requires Inkeep org admin/owner role to modify workspace settings",
"permission": "admin",
"resource": "organization"
}
}
},
"/work-apps/slack/workspaces/{teamId}/settings": {
"get": {
"description": "Get settings for a Slack workspace including default agent",
Expand Down
16 changes: 15 additions & 1 deletion agents-docs/content/api-reference/(openapi)/slack.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ _openapi:
- depth: 2
title: Check Workspace Health
url: '#check-workspace-health'
- depth: 2
title: Get Join From Workspace Setting
url: '#get-join-from-workspace-setting'
- depth: 2
title: Update Join From Workspace Setting
url: '#update-join-from-workspace-setting'
- depth: 2
title: Get Workspace Settings
url: '#get-workspace-settings'
Expand Down Expand Up @@ -104,6 +110,10 @@ _openapi:
id: set-channel-default-agent
- content: Check Workspace Health
id: check-workspace-health
- content: Get Join From Workspace Setting
id: get-join-from-workspace-setting
- content: Update Join From Workspace Setting
id: update-join-from-workspace-setting
- content: Get Workspace Settings
id: get-workspace-settings
- content: Update Workspace Settings
Expand Down Expand Up @@ -151,6 +161,10 @@ _openapi:
Verify the bot token is valid and check permissions. Returns bot info
and permission status.
heading: check-workspace-health
- content: Get the join from workspace setting for the workspace
heading: get-join-from-workspace-setting
- content: Enable or disable join from workspace for the workspace
heading: update-join-from-workspace-setting
- content: Get settings for a Slack workspace including default agent
heading: get-workspace-settings
- content: Update workspace settings including default agent
Expand All @@ -163,4 +177,4 @@ _openapi:

{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}

<APIPage document={"index"} webhooks={[]} operations={[{"path":"/work-apps/slack/install","method":"get"},{"path":"/work-apps/slack/oauth_redirect","method":"get"},{"path":"/work-apps/slack/users/connect","method":"post"},{"path":"/work-apps/slack/users/disconnect","method":"post"},{"path":"/work-apps/slack/users/link-status","method":"get"},{"path":"/work-apps/slack/users/link/verify-token","method":"post"},{"path":"/work-apps/slack/users/status","method":"get"},{"path":"/work-apps/slack/workspaces","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/channels","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/bulk","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/bulk","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/{channelId}/settings","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/{channelId}/settings","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/{channelId}/settings","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/health","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/settings","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/settings","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/test-message","method":"post"},{"path":"/work-apps/slack/workspaces/{teamId}/users","method":"get"}]} showTitle={true} />
<APIPage document={"index"} webhooks={[]} operations={[{"path":"/work-apps/slack/install","method":"get"},{"path":"/work-apps/slack/oauth_redirect","method":"get"},{"path":"/work-apps/slack/users/connect","method":"post"},{"path":"/work-apps/slack/users/disconnect","method":"post"},{"path":"/work-apps/slack/users/link-status","method":"get"},{"path":"/work-apps/slack/users/link/verify-token","method":"post"},{"path":"/work-apps/slack/users/status","method":"get"},{"path":"/work-apps/slack/workspaces","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/channels","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/bulk","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/bulk","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/{channelId}/settings","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/{channelId}/settings","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/{channelId}/settings","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/health","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/join-from-workspace","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/join-from-workspace","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/settings","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/settings","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/test-message","method":"post"},{"path":"/work-apps/slack/workspaces/{teamId}/users","method":"get"}]} showTitle={true} />
16 changes: 15 additions & 1 deletion agents-docs/content/api-reference/(openapi)/work-apps.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ _openapi:
- depth: 2
title: Check Workspace Health
url: '#check-workspace-health'
- depth: 2
title: Get Join From Workspace Setting
url: '#get-join-from-workspace-setting'
- depth: 2
title: Update Join From Workspace Setting
url: '#update-join-from-workspace-setting'
- depth: 2
title: Get Workspace Settings
url: '#get-workspace-settings'
Expand Down Expand Up @@ -104,6 +110,10 @@ _openapi:
id: set-channel-default-agent
- content: Check Workspace Health
id: check-workspace-health
- content: Get Join From Workspace Setting
id: get-join-from-workspace-setting
- content: Update Join From Workspace Setting
id: update-join-from-workspace-setting
- content: Get Workspace Settings
id: get-workspace-settings
- content: Update Workspace Settings
Expand Down Expand Up @@ -151,6 +161,10 @@ _openapi:
Verify the bot token is valid and check permissions. Returns bot info
and permission status.
heading: check-workspace-health
- content: Get the join from workspace setting for the workspace
heading: get-join-from-workspace-setting
- content: Enable or disable join from workspace for the workspace
heading: update-join-from-workspace-setting
- content: Get settings for a Slack workspace including default agent
heading: get-workspace-settings
- content: Update workspace settings including default agent
Expand All @@ -163,4 +177,4 @@ _openapi:

{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}

<APIPage document={"index"} webhooks={[]} operations={[{"path":"/work-apps/slack/install","method":"get"},{"path":"/work-apps/slack/oauth_redirect","method":"get"},{"path":"/work-apps/slack/users/connect","method":"post"},{"path":"/work-apps/slack/users/disconnect","method":"post"},{"path":"/work-apps/slack/users/link-status","method":"get"},{"path":"/work-apps/slack/users/link/verify-token","method":"post"},{"path":"/work-apps/slack/users/status","method":"get"},{"path":"/work-apps/slack/workspaces","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/channels","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/bulk","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/bulk","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/{channelId}/settings","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/{channelId}/settings","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/{channelId}/settings","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/health","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/settings","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/settings","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/test-message","method":"post"},{"path":"/work-apps/slack/workspaces/{teamId}/users","method":"get"}]} showTitle={true} />
<APIPage document={"index"} webhooks={[]} operations={[{"path":"/work-apps/slack/install","method":"get"},{"path":"/work-apps/slack/oauth_redirect","method":"get"},{"path":"/work-apps/slack/users/connect","method":"post"},{"path":"/work-apps/slack/users/disconnect","method":"post"},{"path":"/work-apps/slack/users/link-status","method":"get"},{"path":"/work-apps/slack/users/link/verify-token","method":"post"},{"path":"/work-apps/slack/users/status","method":"get"},{"path":"/work-apps/slack/workspaces","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/channels","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/bulk","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/bulk","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/{channelId}/settings","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/{channelId}/settings","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/channels/{channelId}/settings","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/health","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/join-from-workspace","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/join-from-workspace","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/settings","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/settings","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/test-message","method":"post"},{"path":"/work-apps/slack/workspaces/{teamId}/users","method":"get"}]} showTitle={true} />
16 changes: 15 additions & 1 deletion agents-docs/content/api-reference/(openapi)/workspaces.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ _openapi:
- depth: 2
title: Check Workspace Health
url: '#check-workspace-health'
- depth: 2
title: Get Join From Workspace Setting
url: '#get-join-from-workspace-setting'
- depth: 2
title: Update Join From Workspace Setting
url: '#update-join-from-workspace-setting'
- depth: 2
title: Get Workspace Settings
url: '#get-workspace-settings'
Expand All @@ -36,6 +42,10 @@ _openapi:
id: uninstall-workspace
- content: Check Workspace Health
id: check-workspace-health
- content: Get Join From Workspace Setting
id: get-join-from-workspace-setting
- content: Update Join From Workspace Setting
id: update-join-from-workspace-setting
- content: Get Workspace Settings
id: get-workspace-settings
- content: Update Workspace Settings
Expand All @@ -55,6 +65,10 @@ _openapi:
Verify the bot token is valid and check permissions. Returns bot info
and permission status.
heading: check-workspace-health
- content: Get the join from workspace setting for the workspace
heading: get-join-from-workspace-setting
- content: Enable or disable join from workspace for the workspace
heading: update-join-from-workspace-setting
- content: Get settings for a Slack workspace including default agent
heading: get-workspace-settings
- content: Update workspace settings including default agent
Expand All @@ -65,4 +79,4 @@ _openapi:

{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}

<APIPage document={"index"} webhooks={[]} operations={[{"path":"/work-apps/slack/workspaces","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/health","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/settings","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/settings","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/test-message","method":"post"}]} showTitle={true} />
<APIPage document={"index"} webhooks={[]} operations={[{"path":"/work-apps/slack/workspaces","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}","method":"delete"},{"path":"/work-apps/slack/workspaces/{teamId}/health","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/join-from-workspace","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/join-from-workspace","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/settings","method":"get"},{"path":"/work-apps/slack/workspaces/{teamId}/settings","method":"put"},{"path":"/work-apps/slack/workspaces/{teamId}/test-message","method":"post"}]} showTitle={true} />
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ import { Label } from '@/components/ui/label';
import { useAuthClient } from '@/contexts/auth-client';
import { useAuthSession } from '@/hooks/use-auth';
import { type InvitationVerification, verifyInvitation } from '@/lib/actions/invitations';
import { getSafeReturnUrl } from '@/lib/utils/auth-redirect';

export default function AcceptInvitationPage({
params,
}: PageProps<'/accept-invitation/[invitationId]'>) {
const router = useRouter();
const searchParams = useSearchParams();
const emailFromUrl = searchParams.get('email');
const returnUrl = searchParams.get('returnUrl');
const { user, isLoading: isAuthLoading } = useAuthSession();
const { invitationId } = use(params);
const authClient = useAuthClient();
Expand Down Expand Up @@ -146,9 +148,8 @@ export default function AcceptInvitationPage({

setSuccess(true);

// Redirect to the organization after a short delay
setTimeout(() => {
router.push(orgId ? `/${orgId}/projects` : '/');
router.push(getSafeReturnUrl(returnUrl, orgId ? `/${orgId}/projects` : '/'));
}, 2000);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to create account');
Expand Down Expand Up @@ -186,7 +187,7 @@ export default function AcceptInvitationPage({
setSuccess(true);

setTimeout(() => {
router.push(orgId ? `/${orgId}/projects` : '/');
router.push(getSafeReturnUrl(returnUrl, orgId ? `/${orgId}/projects` : '/'));
}, 2000);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to accept invitation');
Expand Down
6 changes: 4 additions & 2 deletions agents-manage-ui/src/app/link/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { AlertCircleIcon, CheckCircle2, Loader2, MessageSquare } from 'lucide-react';
import { useRouter, useSearchParams } from 'next/navigation';
import { Suspense, useCallback, useEffect, useState } from 'react';
import { Suspense, useCallback, useEffect, useRef, useState } from 'react';
import { InkeepIcon } from '@/components/icons/inkeep';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
Expand Down Expand Up @@ -113,8 +113,10 @@ function SlackLinkForm() {
[user]
);

const linkingRef = useRef(false);
useEffect(() => {
if (isAuthenticated && user?.id && state === 'waiting' && initialToken) {
if (isAuthenticated && user?.id && state === 'waiting' && initialToken && !linkingRef.current) {
linkingRef.current = true;
handleLinkWithToken(initialToken);
}
}, [initialToken, isAuthenticated, user?.id, state, handleLinkWithToken]);
Expand Down
10 changes: 10 additions & 0 deletions agents-manage-ui/src/contexts/auth-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ const createConfiguredAuthClient = (baseURL: string) =>
},
},
},
organization: {
additionalFields: {
preferredAuthMethod: {
type: 'string',
},
serviceAccountUserId: {
type: 'string',
},
},
},
}),
}),
deviceAuthorizationClient(),
Expand Down
Loading
Loading