mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-31 06:04:11 +01:00
Merge origin/master into provider routing connections
This commit is contained in:
commit
b6bc28667e
627 files changed
+97335
-5708
No files matched your search
@@ -226,11 +226,12 @@ export const agentsApi = {
|
||||
adapterModels: (
|
||||
companyId: string,
|
||||
type: string,
|
||||
options?: { refresh?: boolean; environmentId?: string | null; provider?: string },
|
||||
options?: { refresh?: boolean; environmentId?: string | null; provider?: string; poolId?: string },
|
||||
) => {
|
||||
const params = new URLSearchParams();
|
||||
if (options?.refresh) params.set("refresh", "1");
|
||||
if (options?.provider) params.set("provider", options.provider);
|
||||
if (options?.poolId) params.set("poolId", options.poolId);
|
||||
if (options?.environmentId) params.set("environmentId", options.environmentId);
|
||||
const query = params.size > 0 ? `?${params.toString()}` : "";
|
||||
return api.get<AdapterModel[]>(
|
||||
@@ -246,7 +247,7 @@ export const agentsApi = {
|
||||
type: string,
|
||||
data: {
|
||||
adapterConfig: Record<string, unknown>;
|
||||
aiConnection?: import("@paperclipai/shared").AiConnectionBinding;
|
||||
aiConnection?: import("@paperclipai/shared").AiRuntimeConnectionBinding;
|
||||
agentId?: string;
|
||||
testCredentials?: Record<string, string>;
|
||||
environmentId?: string | null;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { AiConnectionPool, AiConnectionPoolConfig, AiConnectionUsage } from "@paperclipai/shared";
|
||||
import { api } from "./client";
|
||||
export type PoolInspection = Record<string, { reason: string; checkedAt: string | null; usage?: AiConnectionUsage }>;
|
||||
export const aiConnectionPoolsApi = {
|
||||
list: (companyId: string) => api.get<AiConnectionPool[]>(`/companies/${companyId}/ai-connection-pools`),
|
||||
save: (companyId: string, body: { pluginKey: string; id?: string; expectedRevision?: number; config: AiConnectionPoolConfig }) => api.post<AiConnectionPool>(`/companies/${companyId}/ai-connection-pools`, body),
|
||||
inspect: (companyId: string, id: string) => api.get<PoolInspection>(`/companies/${companyId}/ai-connection-pools/${id}/inspection`),
|
||||
remove: (companyId: string, id: string, expectedRevision: number) => api.delete(`/companies/${companyId}/ai-connection-pools/${id}`, { expectedRevision }),
|
||||
};
|
||||
@@ -34,6 +34,8 @@ export type ArtifactKindFilter = Exclude<CompanyArtifactMediaKind, "empty"> | "a
|
||||
export interface ListArtifactsParams {
|
||||
kind?: ArtifactKindFilter;
|
||||
projectId?: string;
|
||||
/** Only artifacts attributed to this agent. */
|
||||
agentId?: string;
|
||||
q?: string;
|
||||
/** Grouping mode. `none` (default) returns the flat artifact grid. */
|
||||
groupBy?: CompanyArtifactGroupBy;
|
||||
@@ -47,6 +49,7 @@ function buildArtifactsQuery(params?: ListArtifactsParams): string {
|
||||
const search = new URLSearchParams();
|
||||
if (params?.kind && params.kind !== "all") search.set("kind", params.kind);
|
||||
if (params?.projectId) search.set("projectId", params.projectId);
|
||||
if (params?.agentId) search.set("agentId", params.agentId);
|
||||
if (params?.q) search.set("q", params.q);
|
||||
if (params?.groupBy && params.groupBy !== "none") search.set("groupBy", params.groupBy);
|
||||
if (params?.groupIssueId) search.set("groupIssueId", params.groupIssueId);
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
tenantSessionRecovery,
|
||||
} from "@/lib/tenant-session-recovery";
|
||||
import { __inflightGetCount, api, detachInflightGet } from "./client";
|
||||
import { toolsApi } from "./tools";
|
||||
|
||||
interface Deferred<T> {
|
||||
promise: Promise<T>;
|
||||
@@ -199,3 +200,20 @@ describe("per-caller abort semantics", () => {
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("managed-account request isolation", () => {
|
||||
it("does not share a previous viewing user's pending account response", async () => {
|
||||
const previous = deferred<Response>();
|
||||
const current = deferred<Response>();
|
||||
fetchMock.mockReturnValueOnce(previous.promise).mockReturnValueOnce(current.promise);
|
||||
const previousUser = toolsApi.listAggregatorApps("shared-gateway");
|
||||
const currentUser = toolsApi.listAggregatorApps("shared-gateway");
|
||||
expect(fetchMock).toHaveBeenCalledTimes(2);
|
||||
expect(fetchMock.mock.calls.every(([, options]) => options.cache === "no-store")).toBe(true);
|
||||
current.resolve(jsonResponse({ apps: ["current-user-account"] }));
|
||||
previous.resolve(jsonResponse({ apps: ["previous-user-account"] }));
|
||||
expect(await currentUser).toEqual({ apps: ["current-user-account"] });
|
||||
expect(await previousUser).toEqual({ apps: ["previous-user-account"] });
|
||||
});
|
||||
});
|
||||
@@ -6,6 +6,7 @@ const mockApi = vi.hoisted(() => ({
|
||||
|
||||
vi.mock("./client", () => ({
|
||||
api: mockApi,
|
||||
detachInflightGet: vi.fn(),
|
||||
}));
|
||||
|
||||
import { toolsApi } from "./tools";
|
||||
|
||||
+22
-1
@@ -1,3 +1,5 @@
|
||||
import type { AggregatorAppsResponse, ArcadeDiscoverySetupInput } from "@paperclipai/shared/aggregator-apps";
|
||||
import type { ComposioAppAccountInput, ComposioAppSetupInput, ComposioAppSetupResult, ComposioAppSnapshot, ComposioAppsResponse } from "@paperclipai/shared";
|
||||
import type {
|
||||
ToolApplication,
|
||||
ConfigureRailwaySsh,
|
||||
@@ -64,7 +66,7 @@ import type {
|
||||
ToolConnectionCreateCapabilities,
|
||||
ToolAppMetadataPreflightResult,
|
||||
} from "@paperclipai/shared";
|
||||
import { api } from "./client";
|
||||
import { api, detachInflightGet } from "./client";
|
||||
|
||||
/**
|
||||
* Tools & Access API client (Phase 6, PAP-10389).
|
||||
@@ -156,6 +158,7 @@ export interface CreateToolConnectionInput {
|
||||
}
|
||||
|
||||
export interface UpdateToolConnectionInput {
|
||||
agentInstructions?: import("@paperclipai/shared").ConnectionAgentInstructions | null;
|
||||
name?: string;
|
||||
status?: ToolConnection["status"];
|
||||
config?: Record<string, unknown>;
|
||||
@@ -320,6 +323,7 @@ export const toolsApi = {
|
||||
enabledCatalogEntryIds: string[];
|
||||
askFirstCatalogEntryIds: string[];
|
||||
reviewedCatalogEntryIds?: string[];
|
||||
agentInstructions?: import("@paperclipai/shared").ConnectionAgentInstructions | null;
|
||||
access: "all_agents" | { agentIds: string[] };
|
||||
}) =>
|
||||
api.post<FinishToolAppResult>(
|
||||
@@ -431,6 +435,23 @@ export const toolsApi = {
|
||||
api.get<ToolConnectionTestAgentAccessResponse>(
|
||||
`/tool-connections/${connectionId}/test-agents/${agentId}/access`,
|
||||
),
|
||||
setupComposioApp: (connectionId: string, toolkit: string, input: ComposioAppSetupInput) =>
|
||||
api.post<ComposioAppSetupResult>(`/tool-connections/${connectionId}/composio/apps/${encodeURIComponent(toolkit)}/setup`, input),
|
||||
listAggregatorApps: (connectionId: string) => {
|
||||
const path = `/tool-connections/${connectionId}/aggregator/apps`;
|
||||
// React Query already deduplicates within a viewing-user key. Path-only
|
||||
// request coalescing could hand a previous user's in-flight response to a new account.
|
||||
detachInflightGet(path);
|
||||
return api.get<AggregatorAppsResponse>(path, { cache: "no-store" });
|
||||
},
|
||||
syncAggregatorApps: (connectionId: string, force = false) => api.post<AggregatorAppsResponse>(`/tool-connections/${connectionId}/aggregator/apps/sync`, { force }),
|
||||
refreshAggregatorApps: (connectionId: string, toolkits: string[] = []) => api.post<AggregatorAppsResponse>(`/tool-connections/${connectionId}/aggregator/apps/refresh`, { toolkits }),
|
||||
configureArcadeDiscovery: (connectionId: string, input: ArcadeDiscoverySetupInput) => api.put<AggregatorAppsResponse>(`/tool-connections/${connectionId}/aggregator/discovery`, input),
|
||||
listComposioApps: (connectionId: string) => api.get<ComposioAppsResponse>(`/tool-connections/${connectionId}/composio/apps`),
|
||||
syncComposioApps: (connectionId: string, force = false) => api.post<ComposioAppsResponse>(`/tool-connections/${connectionId}/composio/apps/sync`, { force }),
|
||||
refreshComposioApps: (connectionId: string, toolkits: string[]) => api.post<ComposioAppsResponse>(`/tool-connections/${connectionId}/composio/apps/refresh`, { toolkits }),
|
||||
manageComposioAppAccount: (connectionId: string, toolkit: string, input: ComposioAppAccountInput) =>
|
||||
api.post<ComposioAppSetupResult & { apps: ComposioAppSnapshot[] }>(`/tool-connections/${connectionId}/composio/apps/${encodeURIComponent(toolkit)}/accounts`, input),
|
||||
runTestCall: (
|
||||
connectionId: string,
|
||||
input: { agentId: string; toolName: string; parameters?: Record<string, unknown> },
|
||||
|
||||
Reference in new issue
Block a user