mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 17:45:53 +01:00
Reconcile Briefs surface with current master
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
741b55dbf8
commit
8e8b391bfe
12 files changed
+37
-43
No files matched your search
@@ -85,12 +85,6 @@ describe("instance experimental settings validators", () => {
|
||||
expect(settings.enableApps).toBe(false);
|
||||
});
|
||||
|
||||
it("defaults built-in agents off", () => {
|
||||
const settings = instanceExperimentalSettingsSchema.parse({});
|
||||
|
||||
expect(settings.enableBuiltInAgents).toBe(false);
|
||||
});
|
||||
|
||||
it("accepts worktree run execution patches", () => {
|
||||
expect(
|
||||
patchInstanceExperimentalSettingsSchema.parse({
|
||||
|
||||
@@ -111,6 +111,7 @@ async function deleteCompanySkillsAfterLateHeartbeatWritesDrain(db: Db) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 25));
|
||||
}
|
||||
}
|
||||
throw lastError;
|
||||
}
|
||||
|
||||
function expectNoCanary(value: unknown, ...markers: string[]) {
|
||||
|
||||
@@ -21,6 +21,7 @@ const apiPrefixes: Record<string, string> = {
|
||||
"assets.ts": "/api",
|
||||
"auth.ts": "/api/auth",
|
||||
"board-chat.ts": "/api",
|
||||
"briefs.ts": "/api",
|
||||
"built-in-agents.ts": "/api",
|
||||
"cloud.ts": "/api/cloud",
|
||||
"companies.ts": "/api/companies",
|
||||
|
||||
@@ -25,6 +25,7 @@ import { companySkillRoutes } from "./routes/company-skills.js";
|
||||
import { companySkillPolicyRoutes } from "./routes/company-skill-policy.js";
|
||||
import { inboxAgentPolicyRoutes } from "./routes/inbox-agent-policy.js";
|
||||
import { builtInAgentRoutes } from "./routes/built-in-agents.js";
|
||||
import { briefsRoutes } from "./routes/briefs.js";
|
||||
import { folderRoutes } from "./routes/folders.js";
|
||||
import { summarySlotRoutes } from "./routes/summary-slots.js";
|
||||
import { statusCardRoutes } from "./routes/status-cards.js";
|
||||
@@ -419,6 +420,7 @@ export async function createApp(
|
||||
api.use(companySkillPolicyRoutes(db));
|
||||
api.use(inboxAgentPolicyRoutes(db));
|
||||
api.use(builtInAgentRoutes(db));
|
||||
api.use(briefsRoutes(db));
|
||||
api.use(summarySlotRoutes(db));
|
||||
api.use(statusCardRoutes(db));
|
||||
api.use(teamsCatalogRoutes(db));
|
||||
|
||||
@@ -4,6 +4,7 @@ export { companySkillRoutes } from "./company-skills.js";
|
||||
export { companySkillPolicyRoutes } from "./company-skill-policy.js";
|
||||
export { inboxAgentPolicyRoutes } from "./inbox-agent-policy.js";
|
||||
export { builtInAgentRoutes } from "./built-in-agents.js";
|
||||
export { briefsRoutes } from "./briefs.js";
|
||||
export { folderRoutes } from "./folders.js";
|
||||
export { summarySlotRoutes } from "./summary-slots.js";
|
||||
export { statusCardRoutes } from "./status-cards.js";
|
||||
|
||||
@@ -571,6 +571,10 @@ const responses = {
|
||||
description: "Conflict",
|
||||
content: { "application/json": { schema: ErrorSchema } },
|
||||
},
|
||||
preconditionFailed: {
|
||||
description: "Precondition failed",
|
||||
content: { "application/json": { schema: ErrorSchema } },
|
||||
},
|
||||
payloadTooLarge: {
|
||||
description: "Payload too large",
|
||||
content: { "application/json": { schema: ErrorSchema } },
|
||||
@@ -3564,6 +3568,20 @@ registry.registerPath({
|
||||
responses: { 200: r.ok(), 401: r.unauthorized },
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/api/companies/{companyId}/briefs/overview",
|
||||
tags: ["briefs"],
|
||||
summary: "Get Briefs overview",
|
||||
request: { params: z.object({ companyId: z.string() }) },
|
||||
responses: {
|
||||
200: r.ok(),
|
||||
401: r.unauthorized,
|
||||
403: r.forbidden,
|
||||
412: r.preconditionFailed,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/api/companies/{companyId}/recovery-observability",
|
||||
|
||||
@@ -615,21 +615,6 @@ export function agentService(db: Db) {
|
||||
});
|
||||
}
|
||||
|
||||
function assertBuiltInAgentMetadataMutationAllowed(
|
||||
beforeMetadata: unknown,
|
||||
afterMetadata: unknown,
|
||||
options?: { allowBuiltInAgentMetadata?: boolean },
|
||||
) {
|
||||
if (options?.allowBuiltInAgentMetadata) return;
|
||||
const beforeMarker = readBuiltInAgentMarker(beforeMetadata);
|
||||
const afterMarker = readBuiltInAgentMarker(afterMetadata);
|
||||
if (builtInAgentMarkersEqual(beforeMarker, afterMarker)) return;
|
||||
throw conflict("Built-in agent marker is managed by Paperclip and cannot be edited directly", {
|
||||
code: "built_in_agent_marker_readonly",
|
||||
key: beforeMarker?.key ?? afterMarker?.key ?? null,
|
||||
});
|
||||
}
|
||||
|
||||
async function updateAgent(
|
||||
id: string,
|
||||
data: Partial<typeof agents.$inferInsert>,
|
||||
|
||||
@@ -1804,21 +1804,6 @@ export function authorizationService(db: Db) {
|
||||
if (policyEffect.kind === "restricted") return denyRestrictedAssignmentPolicy(policyEffect);
|
||||
return grantDecision;
|
||||
}
|
||||
if (input.action === "agent_config:read") {
|
||||
return decideWithAgentConfigReadGrant("user", input.actor.userId);
|
||||
}
|
||||
if (input.action === "agent_config:update") {
|
||||
return decideWithProtectedChangeGrants("user", input.actor.userId, {
|
||||
direct: "agents:configure",
|
||||
suggest: "agents:suggest-changes",
|
||||
});
|
||||
}
|
||||
if (input.action === "skill_config:update") {
|
||||
return decideWithProtectedChangeGrants("user", input.actor.userId, {
|
||||
direct: "skills:create",
|
||||
suggest: "skills:suggest-changes",
|
||||
});
|
||||
}
|
||||
return decidePrincipalGrant({
|
||||
companyId,
|
||||
principalType: "user",
|
||||
|
||||
@@ -6,6 +6,7 @@ export { feedbackService } from "./feedback.js";
|
||||
export { companySkillService } from "./company-skills.js";
|
||||
export { companySkillPolicyService, normalizeSkillPolicySourceType } from "./company-skill-policy.js";
|
||||
export { folderService } from "./folders.js";
|
||||
export { briefsService } from "./briefs.js";
|
||||
export { agentService, deduplicateAgentName } from "./agents.js";
|
||||
export {
|
||||
builtInAgentService,
|
||||
|
||||
@@ -195,13 +195,6 @@ export function AgentActionButtons({
|
||||
pauseConfirm?: { title: string; description: ReactNode };
|
||||
/** Hide the Terminate action (e.g. built-in agents are undeletable). */
|
||||
hideTerminate?: boolean;
|
||||
/**
|
||||
* When set, pausing prompts a confirmation dialog first (e.g. for built-in
|
||||
* agents that power a feature). Omit for the immediate-pause default.
|
||||
*/
|
||||
pauseConfirm?: { title: string; description: ReactNode };
|
||||
/** Hide the Terminate action (e.g. built-in agents are undeletable). */
|
||||
hideTerminate?: boolean;
|
||||
/**
|
||||
* Optional inline error reporter. When provided it is used instead of a toast
|
||||
* for action failures (preserves the detail page's inline error banner). When
|
||||
|
||||
@@ -157,6 +157,9 @@ export const queryKeys = {
|
||||
builtInAgents: {
|
||||
list: (companyId: string) => ["built-in-agents", companyId] as const,
|
||||
},
|
||||
briefs: {
|
||||
overview: (companyId: string) => ["briefs", companyId, "overview"] as const,
|
||||
},
|
||||
summarySlots: {
|
||||
detail: (companyId: string, scopeKind: string, slotKey: string, scopeId?: string | null) =>
|
||||
["summary-slots", companyId, scopeKind, slotKey, scopeId ?? null] as const,
|
||||
|
||||
@@ -34,6 +34,10 @@ const builtInAgentsApiMock = vi.hoisted(() => ({
|
||||
|
||||
const resumeMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
const instanceSettingsApiMock = vi.hoisted(() => ({
|
||||
getExperimental: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/context/CompanyContext", () => ({
|
||||
useCompany: () => companyState,
|
||||
}));
|
||||
@@ -58,6 +62,10 @@ vi.mock("@/api/agents", () => ({
|
||||
agentsApi: { resume: resumeMock },
|
||||
}));
|
||||
|
||||
vi.mock("@/api/instanceSettings", () => ({
|
||||
instanceSettingsApi: instanceSettingsApiMock,
|
||||
}));
|
||||
|
||||
vi.mock("@/components/ConfigureBuiltInAgentModal", () => ({
|
||||
ConfigureBuiltInAgentModal: ({ open }: { open: boolean }) =>
|
||||
open ? <div data-testid="configure-modal" /> : null,
|
||||
@@ -161,7 +169,9 @@ describe("Briefs page", () => {
|
||||
briefsApiMock.overview.mockReset();
|
||||
builtInAgentsApiMock.list.mockReset();
|
||||
resumeMock.mockReset();
|
||||
instanceSettingsApiMock.getExperimental.mockReset();
|
||||
breadcrumbState.setBreadcrumbs.mockReset();
|
||||
instanceSettingsApiMock.getExperimental.mockResolvedValue({ enableBuiltInAgents: true });
|
||||
builtInAgentsApiMock.list.mockResolvedValue([makeBuiltInState("ready")]);
|
||||
briefsApiMock.overview.mockResolvedValue(makeOverview());
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user