Add workspace context to provider requests
This commit is contained in:
1 parent
e81a0e2d26
commit
cf2ed628b0
3 files changed
+49
-7
No files matched your search
@@ -135,6 +135,7 @@ export function SettingsPage({ snapshot, actions }: PageProps) {
|
|||||||
providers={providers}
|
providers={providers}
|
||||||
catalog={snapshot.providerCatalog}
|
catalog={snapshot.providerCatalog}
|
||||||
agents={agents}
|
agents={agents}
|
||||||
|
workspaces={workspaces}
|
||||||
providerRateLimits={providerRateLimits}
|
providerRateLimits={providerRateLimits}
|
||||||
providerRequests={providerRequests}
|
providerRequests={providerRequests}
|
||||||
actions={actions}
|
actions={actions}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState, type FormEvent } from "react";
|
import { useState, type FormEvent } from "react";
|
||||||
import type { ProviderCatalogEntry, ProviderRecord, ProviderRequestRecord } from "../../../../shared/domain";
|
import type { ProviderCatalogEntry, ProviderRecord, ProviderRequestRecord, WorkspaceRecord } from "../../../../shared/domain";
|
||||||
import { PROVIDER_DATA_POLICY, PROVIDER_EXECUTION_MODE, PROVIDER_REQUEST_STATE, type ProviderExecutionMode } from "../../../../shared/domain";
|
import { PROVIDER_DATA_POLICY, PROVIDER_EXECUTION_MODE, PROVIDER_REQUEST_STATE, type ProviderExecutionMode } from "../../../../shared/domain";
|
||||||
import type { SnapshotActions } from "../../app/useSnapshot";
|
import type { SnapshotActions } from "../../app/useSnapshot";
|
||||||
import { Button, Field, Icon, Pill, Segmented } from "../../shared/ui";
|
import { Button, Field, Icon, Pill, Segmented } from "../../shared/ui";
|
||||||
@@ -8,6 +8,7 @@ interface ProviderRequestPanelProps {
|
|||||||
orgId: string;
|
orgId: string;
|
||||||
providers: ProviderRecord[];
|
providers: ProviderRecord[];
|
||||||
catalog: ProviderCatalogEntry[];
|
catalog: ProviderCatalogEntry[];
|
||||||
|
workspaces: WorkspaceRecord[];
|
||||||
providerRequests: ProviderRequestRecord[];
|
providerRequests: ProviderRequestRecord[];
|
||||||
actions: SnapshotActions;
|
actions: SnapshotActions;
|
||||||
}
|
}
|
||||||
@@ -26,15 +27,18 @@ export function ProviderRequestPanel({
|
|||||||
orgId,
|
orgId,
|
||||||
providers,
|
providers,
|
||||||
catalog,
|
catalog,
|
||||||
|
workspaces,
|
||||||
providerRequests,
|
providerRequests,
|
||||||
actions,
|
actions,
|
||||||
}: ProviderRequestPanelProps) {
|
}: ProviderRequestPanelProps) {
|
||||||
const executableProviders = providers.filter((provider) => provider.enabled && provider.authType === "api_key");
|
const executableProviders = providers.filter((provider) => provider.enabled && provider.authType === "api_key");
|
||||||
const [providerId, setProviderId] = useState(executableProviders[0]?.id ?? "");
|
const [providerId, setProviderId] = useState(executableProviders[0]?.id ?? "");
|
||||||
|
const [workspaceId, setWorkspaceId] = useState(workspaces[0]?.id ?? "");
|
||||||
const [mode, setMode] = useState<ProviderExecutionMode>(PROVIDER_EXECUTION_MODE.FOREGROUND);
|
const [mode, setMode] = useState<ProviderExecutionMode>(PROVIDER_EXECUTION_MODE.FOREGROUND);
|
||||||
const selectedProvider = resolveSelectedProvider(executableProviders, providerId);
|
const selectedProvider = resolveSelectedProvider(executableProviders, providerId);
|
||||||
const canRunBackground = selectedProvider ? isBackgroundReady(selectedProvider, catalog) : false;
|
const canRunBackground = selectedProvider ? isBackgroundReady(selectedProvider, catalog) : false;
|
||||||
const selectedMode = canRunBackground ? mode : PROVIDER_EXECUTION_MODE.FOREGROUND;
|
const selectedMode = canRunBackground ? mode : PROVIDER_EXECUTION_MODE.FOREGROUND;
|
||||||
|
const effectiveWorkspaceId = selectedWorkspaceValue(workspaces, workspaceId);
|
||||||
const recentRequests = providerRequests
|
const recentRequests = providerRequests
|
||||||
.filter((request) => executableProviders.some((provider) => provider.id === request.providerId))
|
.filter((request) => executableProviders.some((provider) => provider.id === request.providerId))
|
||||||
.slice(0, 8);
|
.slice(0, 8);
|
||||||
@@ -51,6 +55,7 @@ export function ProviderRequestPanel({
|
|||||||
void actions.run(() => window.agentCompany.createProviderResponse({
|
void actions.run(() => window.agentCompany.createProviderResponse({
|
||||||
orgId,
|
orgId,
|
||||||
providerId: requireProviderId(selectedProvider),
|
providerId: requireProviderId(selectedProvider),
|
||||||
|
workspaceId: selectedWorkspaceId(workspaces, effectiveWorkspaceId),
|
||||||
prompt,
|
prompt,
|
||||||
instructions: instructions || null,
|
instructions: instructions || null,
|
||||||
executionMode: selectedMode,
|
executionMode: selectedMode,
|
||||||
@@ -61,7 +66,7 @@ export function ProviderRequestPanel({
|
|||||||
<>
|
<>
|
||||||
<div className="section-label" style={{ marginBottom: 10 }}>Requests</div>
|
<div className="section-label" style={{ marginBottom: 10 }}>Requests</div>
|
||||||
<form className="card" style={{ marginBottom: 10 }} onSubmit={submit}>
|
<form className="card" style={{ marginBottom: 10 }} onSubmit={submit}>
|
||||||
<div style={{ display: "grid", gridTemplateColumns: "minmax(150px, 1fr) minmax(200px, 1fr) auto", gap: 10, alignItems: "end" }}>
|
<div style={{ display: "grid", gridTemplateColumns: "minmax(150px, 1fr) minmax(150px, 1fr) minmax(200px, 1fr) auto", gap: 10, alignItems: "end" }}>
|
||||||
<Field label="Provider">
|
<Field label="Provider">
|
||||||
<select
|
<select
|
||||||
className="input"
|
className="input"
|
||||||
@@ -74,6 +79,20 @@ export function ProviderRequestPanel({
|
|||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</Field>
|
</Field>
|
||||||
|
<Field label="Workspace">
|
||||||
|
<select
|
||||||
|
className="input"
|
||||||
|
aria-label="Request workspace"
|
||||||
|
value={effectiveWorkspaceId}
|
||||||
|
disabled={workspaces.length === 0}
|
||||||
|
onChange={(event) => setWorkspaceId(event.target.value)}
|
||||||
|
>
|
||||||
|
{workspaces.length === 0 && <option value="">Organization</option>}
|
||||||
|
{workspaces.map((workspace) => (
|
||||||
|
<option key={workspace.id} value={workspace.id}>{workspace.name}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</Field>
|
||||||
<div className="field">
|
<div className="field">
|
||||||
<span>Mode</span>
|
<span>Mode</span>
|
||||||
<div style={{ alignSelf: "flex-start" }}>
|
<div style={{ alignSelf: "flex-start" }}>
|
||||||
@@ -99,9 +118,9 @@ export function ProviderRequestPanel({
|
|||||||
</Field>
|
</Field>
|
||||||
</form>
|
</form>
|
||||||
{recentRequests.length > 0 && (
|
{recentRequests.length > 0 && (
|
||||||
<div className="card" style={{ padding: 0, overflow: "hidden", marginBottom: 28 }}>
|
<div className="card" style={{ padding: 0, overflowX: "auto", marginBottom: 28 }}>
|
||||||
<div className="table-row head" style={{ gridTemplateColumns: "minmax(120px, 1fr) 92px 100px minmax(120px, 1fr) 86px" }}>
|
<div className="table-row head" style={{ gridTemplateColumns: "minmax(120px, 1fr) minmax(120px, 1fr) 92px 100px minmax(120px, 1fr) 86px", minWidth: 760 }}>
|
||||||
<div>Provider</div><div>Mode</div><div>State</div><div>Output</div><div>Action</div>
|
<div>Provider</div><div>Workspace</div><div>Mode</div><div>State</div><div>Output</div><div>Action</div>
|
||||||
</div>
|
</div>
|
||||||
{recentRequests.map((request, index) => (
|
{recentRequests.map((request, index) => (
|
||||||
<ProviderRequestRow
|
<ProviderRequestRow
|
||||||
@@ -109,6 +128,7 @@ export function ProviderRequestPanel({
|
|||||||
orgId={orgId}
|
orgId={orgId}
|
||||||
request={request}
|
request={request}
|
||||||
provider={requireRequestProvider(providers, request)}
|
provider={requireRequestProvider(providers, request)}
|
||||||
|
workspace={resolveRequestWorkspace(workspaces, request)}
|
||||||
last={index === recentRequests.length - 1}
|
last={index === recentRequests.length - 1}
|
||||||
actions={actions}
|
actions={actions}
|
||||||
/>
|
/>
|
||||||
@@ -123,12 +143,14 @@ function ProviderRequestRow({
|
|||||||
orgId,
|
orgId,
|
||||||
request,
|
request,
|
||||||
provider,
|
provider,
|
||||||
|
workspace,
|
||||||
last,
|
last,
|
||||||
actions,
|
actions,
|
||||||
}: {
|
}: {
|
||||||
orgId: string;
|
orgId: string;
|
||||||
request: ProviderRequestRecord;
|
request: ProviderRequestRecord;
|
||||||
provider: ProviderRecord;
|
provider: ProviderRecord;
|
||||||
|
workspace: WorkspaceRecord | null;
|
||||||
last: boolean;
|
last: boolean;
|
||||||
actions: SnapshotActions;
|
actions: SnapshotActions;
|
||||||
}) {
|
}) {
|
||||||
@@ -140,7 +162,8 @@ function ProviderRequestRow({
|
|||||||
<div
|
<div
|
||||||
className="table-row"
|
className="table-row"
|
||||||
style={{
|
style={{
|
||||||
gridTemplateColumns: "minmax(120px, 1fr) 92px 100px minmax(120px, 1fr) 86px",
|
gridTemplateColumns: "minmax(120px, 1fr) minmax(120px, 1fr) 92px 100px minmax(120px, 1fr) 86px",
|
||||||
|
minWidth: 760,
|
||||||
borderBottom: last ? "none" : "1px solid var(--border-soft)",
|
borderBottom: last ? "none" : "1px solid var(--border-soft)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -148,6 +171,7 @@ function ProviderRequestRow({
|
|||||||
<div style={{ fontWeight: 540, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{provider.label}</div>
|
<div style={{ fontWeight: 540, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{provider.label}</div>
|
||||||
<div className="mono" style={{ fontSize: 11, color: "var(--text-3)" }}>{request.model}</div>
|
<div className="mono" style={{ fontSize: 11, color: "var(--text-3)" }}>{request.model}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mono" style={{ color: "var(--text-2)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{workspace?.name ?? "Organization"}</div>
|
||||||
<div className="mono" style={{ color: "var(--text-2)" }}>{request.executionMode}</div>
|
<div className="mono" style={{ color: "var(--text-2)" }}>{request.executionMode}</div>
|
||||||
<div><Pill tone={stateTone(request.state)}>{request.state}</Pill></div>
|
<div><Pill tone={stateTone(request.state)}>{request.state}</Pill></div>
|
||||||
<div className="mono" style={{ color: "var(--text-2)" }}>{request.outputCharCount} chars</div>
|
<div className="mono" style={{ color: "var(--text-2)" }}>{request.outputCharCount} chars</div>
|
||||||
@@ -179,6 +203,20 @@ function resolveSelectedProvider(providers: ProviderRecord[], providerId: string
|
|||||||
return provider ?? providers[0] ?? null;
|
return provider ?? providers[0] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function selectedWorkspaceId(workspaces: WorkspaceRecord[], workspaceId: string): string | null {
|
||||||
|
return workspaces.some((workspace) => workspace.id === workspaceId) ? workspaceId : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectedWorkspaceValue(workspaces: WorkspaceRecord[], workspaceId: string): string {
|
||||||
|
if (workspaces.some((workspace) => workspace.id === workspaceId)) return workspaceId;
|
||||||
|
return workspaces[0]?.id ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveRequestWorkspace(workspaces: WorkspaceRecord[], request: ProviderRequestRecord): WorkspaceRecord | null {
|
||||||
|
if (!request.workspaceId) return null;
|
||||||
|
return workspaces.find((workspace) => workspace.id === request.workspaceId) ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
function requireProviderId(provider: ProviderRecord | null): string {
|
function requireProviderId(provider: ProviderRecord | null): string {
|
||||||
if (!provider) throw new Error("Provider is required.");
|
if (!provider) throw new Error("Provider is required.");
|
||||||
return provider.id;
|
return provider.id;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import type {
|
|||||||
ProviderRateLimitStateRecord,
|
ProviderRateLimitStateRecord,
|
||||||
ProviderRecord,
|
ProviderRecord,
|
||||||
ProviderRequestRecord,
|
ProviderRequestRecord,
|
||||||
|
WorkspaceRecord,
|
||||||
} from "../../../../shared/domain";
|
} from "../../../../shared/domain";
|
||||||
import { PROVIDER_DATA_POLICY } from "../../../../shared/domain";
|
import { PROVIDER_DATA_POLICY } from "../../../../shared/domain";
|
||||||
import { ProviderLogo } from "./ProviderLogo";
|
import { ProviderLogo } from "./ProviderLogo";
|
||||||
@@ -19,6 +20,7 @@ interface ProvidersPanelProps {
|
|||||||
providers: ProviderRecord[];
|
providers: ProviderRecord[];
|
||||||
catalog: ProviderCatalogEntry[];
|
catalog: ProviderCatalogEntry[];
|
||||||
agents: AgentRecord[];
|
agents: AgentRecord[];
|
||||||
|
workspaces: WorkspaceRecord[];
|
||||||
providerRateLimits: ProviderRateLimitStateRecord[];
|
providerRateLimits: ProviderRateLimitStateRecord[];
|
||||||
providerRequests: ProviderRequestRecord[];
|
providerRequests: ProviderRequestRecord[];
|
||||||
actions: SnapshotActions;
|
actions: SnapshotActions;
|
||||||
@@ -35,7 +37,7 @@ const CLOUD_DEFAULTS: CloudFields = { baseUrl: "", region: "", projectId: "", de
|
|||||||
const POLICY_GRID = "minmax(150px, 1.2fr) minmax(118px, 0.8fr) minmax(140px, 1fr) 112px 124px 92px";
|
const POLICY_GRID = "minmax(150px, 1.2fr) minmax(118px, 0.8fr) minmax(140px, 1fr) 112px 124px 92px";
|
||||||
type WorkspaceScope = "organization" | "workspace";
|
type WorkspaceScope = "organization" | "workspace";
|
||||||
|
|
||||||
export function ProvidersPanel({ orgId, employeeId, providers, catalog, agents, providerRateLimits, providerRequests, actions }: ProvidersPanelProps) {
|
export function ProvidersPanel({ orgId, employeeId, providers, catalog, agents, workspaces, providerRateLimits, providerRequests, actions }: ProvidersPanelProps) {
|
||||||
const [active, setActive] = useState<ProviderRecord | null>(null);
|
const [active, setActive] = useState<ProviderRecord | null>(null);
|
||||||
const [signInLaunched, setSignInLaunched] = useState(false);
|
const [signInLaunched, setSignInLaunched] = useState(false);
|
||||||
const connected = providers.filter((provider) => provider.enabled);
|
const connected = providers.filter((provider) => provider.enabled);
|
||||||
@@ -96,6 +98,7 @@ export function ProvidersPanel({ orgId, employeeId, providers, catalog, agents,
|
|||||||
orgId={orgId}
|
orgId={orgId}
|
||||||
providers={connected}
|
providers={connected}
|
||||||
catalog={catalog}
|
catalog={catalog}
|
||||||
|
workspaces={workspaces}
|
||||||
providerRequests={providerRequests}
|
providerRequests={providerRequests}
|
||||||
actions={actions}
|
actions={actions}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in new issue
Block a user