Disable imported timer heartbeats
Prevent company imports from re-enabling scheduler heartbeats on imported agents and cover both new-company and existing-company import flows in portability tests. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
dcead97650
commit
f9927bdaaa
2 changed files with 69 additions and 1 deletions
|
|
@ -1832,6 +1832,61 @@ describe("company portability", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("disables timer heartbeats on imported agents", async () => {
|
||||||
|
const portability = companyPortabilityService({} as any);
|
||||||
|
|
||||||
|
companySvc.create.mockResolvedValue({
|
||||||
|
id: "company-imported",
|
||||||
|
name: "Imported Paperclip",
|
||||||
|
});
|
||||||
|
agentSvc.create.mockImplementation(async (_companyId: string, input: Record<string, unknown>) => ({
|
||||||
|
id: `agent-${String(input.name).toLowerCase()}`,
|
||||||
|
name: input.name,
|
||||||
|
adapterConfig: input.adapterConfig,
|
||||||
|
runtimeConfig: input.runtimeConfig,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const exported = await portability.exportBundle("company-1", {
|
||||||
|
include: {
|
||||||
|
company: true,
|
||||||
|
agents: true,
|
||||||
|
projects: false,
|
||||||
|
issues: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
agentSvc.list.mockResolvedValue([]);
|
||||||
|
|
||||||
|
await portability.importBundle({
|
||||||
|
source: {
|
||||||
|
type: "inline",
|
||||||
|
rootPath: exported.rootPath,
|
||||||
|
files: exported.files,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
company: true,
|
||||||
|
agents: true,
|
||||||
|
projects: false,
|
||||||
|
issues: false,
|
||||||
|
},
|
||||||
|
target: {
|
||||||
|
mode: "new_company",
|
||||||
|
newCompanyName: "Imported Paperclip",
|
||||||
|
},
|
||||||
|
agents: "all",
|
||||||
|
collisionStrategy: "rename",
|
||||||
|
}, "user-1");
|
||||||
|
|
||||||
|
const createdClaude = agentSvc.create.mock.calls.find(([, input]) => input.name === "ClaudeCoder");
|
||||||
|
expect(createdClaude?.[1]).toMatchObject({
|
||||||
|
runtimeConfig: {
|
||||||
|
heartbeat: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("imports only selected files and leaves unchecked company metadata alone", async () => {
|
it("imports only selected files and leaves unchecked company metadata alone", async () => {
|
||||||
const portability = companyPortabilityService({} as any);
|
const portability = companyPortabilityService({} as any);
|
||||||
|
|
||||||
|
|
@ -1902,6 +1957,11 @@ describe("company portability", () => {
|
||||||
expect(agentSvc.create).toHaveBeenCalledTimes(1);
|
expect(agentSvc.create).toHaveBeenCalledTimes(1);
|
||||||
expect(agentSvc.create).toHaveBeenCalledWith("company-1", expect.objectContaining({
|
expect(agentSvc.create).toHaveBeenCalledWith("company-1", expect.objectContaining({
|
||||||
name: "CMO",
|
name: "CMO",
|
||||||
|
runtimeConfig: {
|
||||||
|
heartbeat: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
expect(result.company.action).toBe("unchanged");
|
expect(result.company.action).toBe("unchanged");
|
||||||
expect(result.agents).toEqual([
|
expect(result.agents).toEqual([
|
||||||
|
|
|
||||||
|
|
@ -619,6 +619,14 @@ function clonePortableRecord(value: unknown) {
|
||||||
return structuredClone(value) as Record<string, unknown>;
|
return structuredClone(value) as Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function disableImportedTimerHeartbeat(runtimeConfig: unknown) {
|
||||||
|
const next = clonePortableRecord(runtimeConfig) ?? {};
|
||||||
|
const heartbeat = isPlainRecord(next.heartbeat) ? { ...next.heartbeat } : {};
|
||||||
|
heartbeat.enabled = false;
|
||||||
|
next.heartbeat = heartbeat;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
function normalizePortableProjectWorkspaceExtension(
|
function normalizePortableProjectWorkspaceExtension(
|
||||||
workspaceKey: string,
|
workspaceKey: string,
|
||||||
value: unknown,
|
value: unknown,
|
||||||
|
|
@ -3853,7 +3861,7 @@ export function companyPortabilityService(db: Db, storage?: StorageService) {
|
||||||
reportsTo: null,
|
reportsTo: null,
|
||||||
adapterType: effectiveAdapterType,
|
adapterType: effectiveAdapterType,
|
||||||
adapterConfig: adapterConfigWithSkills,
|
adapterConfig: adapterConfigWithSkills,
|
||||||
runtimeConfig: manifestAgent.runtimeConfig,
|
runtimeConfig: disableImportedTimerHeartbeat(manifestAgent.runtimeConfig),
|
||||||
budgetMonthlyCents: manifestAgent.budgetMonthlyCents,
|
budgetMonthlyCents: manifestAgent.budgetMonthlyCents,
|
||||||
permissions: manifestAgent.permissions,
|
permissions: manifestAgent.permissions,
|
||||||
metadata: manifestAgent.metadata,
|
metadata: manifestAgent.metadata,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue