Add skill runtime snapshots

This commit is contained in:
ZacharyZhang-NY committed 2026-05-20 23:38:56 -04:00
1 parent c694b7fc2c
commit 0e920b409a
7 files changed
+98 -2

No files matched your search

@@ -65,6 +65,7 @@ export function registerIpcHandlers(deps: IpcDeps): void {
});
ipcMain.handle(IPC_CHANNELS.importSkillDirectory, (_event, input) => mutate(() => skills.importDirectory(input)));
ipcMain.handle(IPC_CHANNELS.bindSkill, (_event, input) => mutate(() => skills.bind(input)));
ipcMain.handle(IPC_CHANNELS.resolveAgentSkills, (_event, input) => mutate(() => skills.resolveRuntimeSnapshot(input)));
ipcMain.handle(IPC_CHANNELS.createSocialAccount, (_event, input) => mutate(() => social.createAccount(input)));
ipcMain.handle(IPC_CHANNELS.launchSocialLogin, (_event, input) => {
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
import { basename, join } from "node:path";
import type { DatabaseSync } from "node:sqlite";
import type { BindSkillInput, ImportSkillDirectoryInput } from "../../shared/commands";
import type { BindSkillInput, ImportSkillDirectoryInput, ResolveAgentSkillsInput } from "../../shared/commands";
import { createId } from "../../shared/ids";
import { AuditService } from "./audit-service";
@@ -127,4 +127,71 @@ export class SkillService {
});
return id;
}
resolveRuntimeSnapshot(input: ResolveAgentSkillsInput): string {
const agent = this.db.prepare("select id from agents where id = ? and org_id = ?")
.get(input.agentId, input.orgId) as { id: string } | undefined;
if (!agent) throw new Error("Agent was not found.");
const rows = this.db.prepare(`
select
sr.id as revision_id,
sr.version_semver,
sr.manifest_json,
sa.object_key
from skill_bindings sb
join skill_revisions sr on sr.id = sb.pinned_revision_id
join skill_artifacts sa on sa.revision_id = sr.id and sa.artifact_type = 'markdown'
where sb.org_id = ? and sb.agent_id = ? and sb.enabled = 1
order by sb.priority asc, sr.published_at asc
`).all(input.orgId, input.agentId) as unknown as RuntimeSkillRow[];
if (rows.length === 0) throw new Error("Agent has no enabled skills.");
const compiledParts: string[] = [];
const tools = new Set<string>();
const revisionIds: string[] = [];
for (const row of rows) {
if (!existsSync(row.object_key)) throw new Error(`Skill artifact is missing: ${row.object_key}`);
const manifest = JSON.parse(row.manifest_json) as SkillManifest;
for (const tool of manifest.requiredTools) tools.add(tool);
revisionIds.push(row.revision_id);
compiledParts.push([
`# Skill: ${manifest.name}`,
`Version: ${row.version_semver}`,
readFileSync(row.object_key, "utf8").trim(),
].join("\n\n"));
}
const snapshotId = createId("srs");
this.db.prepare(`
insert into skill_runtime_snapshots(
id, agent_id, run_id, compiled_prompt, tools_manifest, source_revision_ids, created_at
)
values (?, ?, ?, ?, ?, ?, ?)
`).run(
snapshotId,
input.agentId,
input.runId,
compiledParts.join("\n\n---\n\n"),
JSON.stringify({ requiredTools: [...tools].sort() }),
JSON.stringify(revisionIds),
new Date().toISOString(),
);
this.audit.record({
orgId: input.orgId,
entityType: "skill_runtime_snapshot",
entityId: snapshotId,
actorType: "system",
actorId: null,
action: "resolved",
payload: { agentId: input.agentId, runId: input.runId, revisionIds },
});
return snapshotId;
}
}
interface RuntimeSkillRow {
revision_id: string;
version_semver: string;
manifest_json: string;
object_key: string;
}
+1
View File
@@ -19,6 +19,7 @@ const api: DesktopApi = {
createProviderResponse: (input) => invoke(IPC_CHANNELS.createProviderResponse, input),
importSkillDirectory: (input) => invoke(IPC_CHANNELS.importSkillDirectory, input),
bindSkill: (input) => invoke(IPC_CHANNELS.bindSkill, input),
resolveAgentSkills: (input) => invoke(IPC_CHANNELS.resolveAgentSkills, input),
createSocialAccount: (input) => invoke(IPC_CHANNELS.createSocialAccount, input),
launchSocialLogin: (input) => invoke(IPC_CHANNELS.launchSocialLogin, input),
importFile: (input) => invoke(IPC_CHANNELS.importFile, input),
+6
View File
@@ -92,6 +92,12 @@ export interface BindSkillInput {
revisionId: string;
}
export interface ResolveAgentSkillsInput {
orgId: string;
agentId: string;
runId: string;
}
export interface CreateSocialAccountInput {
orgId: string;
platform: SocialPlatform;
@@ -12,6 +12,7 @@ import type {
ImportFileInput,
ImportSkillDirectoryInput,
LaunchSocialLoginInput,
ResolveAgentSkillsInput,
SaveProviderCredentialInput,
SendMessageInput,
UpdateTaskStatusInput,
@@ -34,6 +35,7 @@ export interface DesktopApi {
createProviderResponse(input: CreateProviderResponseInput): Promise<DesktopResult<AppSnapshot>>;
importSkillDirectory(input: ImportSkillDirectoryInput): Promise<DesktopResult<AppSnapshot>>;
bindSkill(input: BindSkillInput): Promise<DesktopResult<AppSnapshot>>;
resolveAgentSkills(input: ResolveAgentSkillsInput): Promise<DesktopResult<AppSnapshot>>;
createSocialAccount(input: CreateSocialAccountInput): Promise<DesktopResult<AppSnapshot>>;
launchSocialLogin(input: LaunchSocialLoginInput): Promise<DesktopResult<null>>;
importFile(input: ImportFileInput): Promise<DesktopResult<AppSnapshot>>;
+1
View File
@@ -11,6 +11,7 @@ export const IPC_CHANNELS = {
createProviderResponse: "agentcompany:create-provider-response",
importSkillDirectory: "agentcompany:import-skill-directory",
bindSkill: "agentcompany:bind-skill",
resolveAgentSkills: "agentcompany:resolve-agent-skills",
createSocialAccount: "agentcompany:create-social-account",
launchSocialLogin: "agentcompany:launch-social-login",
importFile: "agentcompany:import-file",
@@ -76,6 +76,8 @@ describe("domain services", () => {
mkdirSync(skillDir, { recursive: true });
writeFileSync(join(skillDir, "SKILL.md"), "---\nname: review-routes\n---\n# Review Routes\n");
let orgId = "";
let agentId = "";
let revisionId = "";
connection.transaction(() => {
orgId = organization.createOrganization({
@@ -84,13 +86,29 @@ describe("domain services", () => {
mission: "Coordinate agents with auditable approvals.",
goal: "Ship a verified control plane.",
});
skills.importDirectory({ orgId, directoryPath: skillDir, versionSemver: "1.0.0" });
agentId = organization.createAgent({
orgId,
name: "Ada",
role: "Architecture reviewer",
department: "Engineering",
modelProviderId: null,
modelId: null,
budgetCents: 10000,
managerAgentId: null,
});
revisionId = skills.importDirectory({ orgId, directoryPath: skillDir, versionSemver: "1.0.0" });
const skill = connection.db.prepare("select id from skill_definitions where org_id = ? and slug = ?")
.get(orgId, "review-routes") as { id: string };
skills.bind({ orgId, agentId, skillId: skill.id, revisionId });
skills.resolveRuntimeSnapshot({ orgId, agentId, runId: "run-review-1" });
});
const state = snapshot.load();
expect(state.skillDefinitions[0]?.slug).toBe("review-routes");
expect(state.skillRevisions[0]?.versionSemver).toBe("1.0.0");
expect(state.skillRevisions[0]?.immutableChecksum).toHaveLength(64);
expect(state.skillRuntimeSnapshots[0]?.sourceRevisionIds).toContain(revisionId);
expect(state.skillRuntimeSnapshots[0]?.compiledPrompt).toContain("# Review Routes");
connection.close();
});