import { createOrgConnection, createPluginWithSkill, denFetch } from "../evals/packages/behaviors/src/index.ts"; import type { DenSession } from "../evals/packages/behaviors/src/index.ts"; import { app } from "../evals/packages/env/src/desktop-app.ts"; import type { App } from "../evals/packages/env/src/desktop-app.ts"; import { createAdmin, createOrg, inviteMember, server } from "../evals/packages/env/src/den.ts"; import type { Den, DenOrgHandle } from "../evals/packages/env/src/den.ts"; import { mcpMock } from "../evals/packages/env/src/mock.ts"; import { resolvePlace } from "../evals/packages/env/src/place.ts"; import type { Place } from "../evals/packages/env/src/place.ts"; import { hold } from "../packages/world/src/hold.ts"; export const ACME_DOCS_ORGANIZATION_NAME = "Acme Robotics"; export const ACME_DOCS_MEMBER = "jordan"; export const ACME_DOCS_APP = "docs"; export const ACME_DOCS_WORKSPACE = "/tmp/acme/acme-robotics"; export const ACME_DOCS_PROMPT_CARDS = [ { title: "Prepare a customer briefing", prompt: "Review this workspace and prepare a briefing with customer goals, recent decisions, risks, and next steps.", }, { title: "Turn meeting notes into action", prompt: "Turn the latest meeting notes into an action plan with owners, deadlines, dependencies, and open questions.", }, { title: "Draft the weekly project update", prompt: "Summarize project progress, risks, decisions, and next week's priorities for the leadership team.", }, ]; const plugins = [ { name: "Customer Research", description: "Prepare for sales calls with a structured company brief.", skillName: "customer-research", skillDescription: "Research a company and summarize key facts before a sales call.", skillBody: "# Instructions\n\n1. Gather the company's product, size, and recent news.\n2. Summarize the three facts that matter for this call.\n3. Suggest one opening question.", }, { name: "Weekly Status Report", description: "Draft the weekly status update from recent activity.", skillName: "weekly-status-report", skillDescription: "Draft the weekly status update from this week's activity.", skillBody: "# Instructions\n\n1. Collect what shipped, what slipped, and what is blocked.\n2. Write a five-line update in the team's usual format.", }, { name: "Meeting Notes", description: "Turn a transcript into structured meeting notes.", skillName: "meeting-notes", skillDescription: "Turn a meeting transcript into decisions, owners, and follow-ups.", skillBody: "# Instructions\n\n1. Extract decisions, owners, and deadlines from the transcript.\n2. List open questions at the end.", }, ]; export interface AcmeDocsWorld { den: Den; org: DenOrgHandle; docs: App; pluginIds: string[]; app(name: string): App; } function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } function auth(session: DenSession): Record { return { authorization: `Bearer ${session.token}` }; } async function memberId(session: DenSession, organizationId: string): Promise { const route = "/v1/me/orgs"; const result = await denFetch(session, route, { headers: auth(session) }); const organizations = isRecord(result.body) && Array.isArray(result.body.orgs) ? result.body.orgs.filter(isRecord) : []; const organization = organizations.find((candidate) => candidate.id === organizationId); const id = organization && typeof organization.membershipId === "string" ? organization.membershipId : organization && typeof organization.orgMemberId === "string" ? organization.orgMemberId : ""; if (!result.response.ok || !id) { throw new Error(`GET ${route} could not resolve Jordan's organization member id: HTTP ${result.response.status} ${result.text.slice(0, 500)}`); } return id; } async function enableDocsCapabilities(admin: DenSession, organizationId: string): Promise { const route = `/v1/admin/organizations/${organizationId}/capabilities`; const result = await denFetch(admin, route, { method: "PUT", headers: auth(admin), body: JSON.stringify({ capabilities: { mcpConnections: true, cloud: true } }), }); if (!result.response.ok) { throw new Error(`PUT ${route} failed: HTTP ${result.response.status} ${result.text.slice(0, 500)}`); } } async function createProductOperationsPolicy( den: Den, organizationId: string, jordan: DenSession, ): Promise { const jordanId = await memberId(jordan, organizationId); const teamRoute = "/v1/teams"; const team = await denFetch(den.admin, teamRoute, { method: "POST", headers: { ...auth(den.admin), "x-openwork-org-id": organizationId }, body: JSON.stringify({ name: "Product Operations", memberIds: [jordanId] }), }); const teamRecord = isRecord(team.body) && isRecord(team.body.team) ? team.body.team : null; const teamId = teamRecord && typeof teamRecord.id === "string" ? teamRecord.id : ""; if (team.response.status !== 201 || !teamId) { throw new Error(`POST ${teamRoute} failed: HTTP ${team.response.status} ${team.text.slice(0, 500)}`); } const policyRoute = "/v1/desktop-policies"; const policy = await denFetch(den.admin, policyRoute, { method: "POST", headers: { ...auth(den.admin), "x-openwork-org-id": organizationId }, body: JSON.stringify({ policyName: "Product operations prompts", priority: 100, isEnabled: true, policy: { onboardingPrompts: ACME_DOCS_PROMPT_CARDS.map((card) => card.prompt), onboardingPromptDescriptions: ACME_DOCS_PROMPT_CARDS.map((card) => card.title), }, memberIds: [jordanId], teamIds: [teamId], }), }); if (policy.response.status !== 201) { throw new Error(`POST ${policyRoute} failed: HTTP ${policy.response.status} ${policy.text.slice(0, 500)}`); } } /** The organization, content, witness connection, policy, and member desktop used by docs shots. */ export async function bootAcmeDocs( stack: AsyncDisposableStack, place: Place, ): Promise { const den = stack.use(await server({ place, provision: false, web: true, mocks: { slack: mcpMock() }, env: { DEN_BOOTSTRAP_ADMIN_EMAILS: "alex@acme.dev" }, })); const admin = await createAdmin(den, { name: "Alex Rivera", email: "alex@acme.dev" }); const org = stack.use(await createOrg(den, ACME_DOCS_ORGANIZATION_NAME)); const jordan = await inviteMember(den, ACME_DOCS_MEMBER, { name: "Jordan Lee", email: "jordan@acme.dev", }); await enableDocsCapabilities(admin, org.id); const pluginIds: string[] = []; for (const plugin of plugins) { const created = await createPluginWithSkill(admin, plugin); pluginIds.push(created.id); } const slack = den.mocks.slack; if (!slack) throw new Error("The Slack MCP witness did not boot."); await createOrgConnection(admin, { name: "Slack", url: slack.mcpUrl, authType: "oauth", credentialMode: "per_member", access: { orgWide: true }, }); await createProductOperationsPolicy(den, org.id, jordan); const docs = stack.use(await app({ den, place, as: ACME_DOCS_MEMBER, workspacePath: ACME_DOCS_WORKSPACE, })); return { den, org, docs, pluginIds, app(name) { if (name !== ACME_DOCS_APP) throw new Error(`Unknown Acme docs app ${JSON.stringify(name)}.`); return docs; }, }; } export async function main(): Promise { await using stack = new AsyncDisposableStack(); const world = await bootAcmeDocs(stack, resolvePlace()); const slack = world.den.mocks.slack; if (!slack) throw new Error("The Slack MCP witness did not boot."); await hold({ name: "acme-docs", outputs: { denWeb: world.den.ref.webUrl, denApi: world.den.ref.apiUrl, docsCdp: world.docs.handle.cdpUrl, slackMcp: slack.mcpUrl, }, }); } if (import.meta.main) await main();