Introduced 1 production defect in 180 days, median 11 days to fix.
'use client';
import { useCallback, useRef, useState } from 'react';
import { useNavigate } from 'react-router';
import type { Editor } from '@tiptap/core';
import { SubagentCreateDialog, type CreatedSubagent } from './SubagentCreateDialog';
import { insertSubagentRef, scopeAtCursor } from './playbookExtensions';
import { brainDocumentPath } from '@/modules/brain/brain-routes';
interface UseSubagentCreationOptions {
/** User AOP id (user scope, and to resolve the org link for org scope). */
aopId?: string;
/** Org AOP id when known (composite passes the loaded orgAopId). */
orgAopId?: string;
/** Scope used when the cursor isn't inside a scope card (single-scope editors). */
baseScope?: 'user' | 'org';
/** The playbook's owner, forwarded to the create mutation. */
ownerUserId?: string | null;
/** Persist the current playbook before navigating away (so the inserted ref survives). */
save?: () => Promise<unknown>;
}
/**
* Wires the playbook editor's "Subagent" `/` and `#` option to the create flow.
* `onCreateSubagent` captures the editor + resolves the target scope (the org/user
* card the cursor is in, else `baseScope`) and opens the name dialog. On submit the
* dialog creates the subagent doc in the correct folder, then we insert a `<ref>`
* (auto-wrapped in a trigger when needed), persist the playbook via `save`, and
* navigate to the new doc in the same tab.
*/
export function useSubagentCreation({
aopId,
orgAopId,
baseScope = 'user',
ownerUserId,
save,
}: UseSubagentCreationOptions) {
const navigate = useNavigate();
const [open, setOpen] = useState(false);
const [scope, setScope] = useState<'user' | 'org'>(baseScope);
const editorRef = useRef<Editor | null>(null);
const onCreateSubagent = useCallback(
(editor: Editor) => {
editorRef.current = editor;
setScope(scopeAtCursor(editor) ?? baseScope);
setOpen(true);
},
[baseScope],
);
const onCreated = useCallback(
async (result: CreatedSubagent) => {
if (editorRef.current) insertSubagentRef(editorRef.current, result.documentId);
try {
await save?.();
} catch {
// Best-effort — still navigate to the new subagent.
}
setOpen(false);
navigate(brainDocumentPath(result.documentId, ownerUserId ?? undefined));
},
[navigate, save, ownerUserId],
);
const subagentDialog = (
<SubagentCreateDialog
open={open}
onOpenChange={setOpen}
scope={scope}
aopId={aopId}
orgAopId={orgAopId}
targetUserId={ownerUserId ?? undefined}
onCreated={onCreated}
/>
);
return { onCreateSubagent, subagentDialog };
}