create agent (#6520)

Added the create agent. Use [these
prompts](https://github.com/Stirling-Tools/Stirling-PDF-SaaS/blob/main/docgen/backend/default_templates/sample_prompts.md)
to test or try your own :)

Here’s the one I use

```
Hey, I need to generate an employee expense report for reimbursement.
Company: Summit Consulting Partners Company address: 88 Riverside Plaza, Suite 1400, New York, NY 10069 Accounting department email: [email protected]
Employee details:
* Employee Name: Michael Tran
* Employee ID: EMP-1047
* Department: Client Services
* Report Date: January 20th, 2026
* Reporting Period: January 5th, 2026 – January 16th, 2026
* Manager Approver: Laura Simmons
Trip purpose: Client onsite meetings with Atlantic Energy Solutions in Boston, MA.
Expense items:
* Flight (NYC to Boston roundtrip) — $325.40 — January 5th, 2026 — Airline ticket
* Hotel (3 nights at Harborview Hotel) — $822.75 — January 5th-8th, 2026
* Taxi from airport to hotel — $48.00 — January 5th, 2026
* Client dinner (3 attendees) — $186.20 — January 6th, 2026
* Parking at JFK Airport — $72.00 — January 5th-8th, 2026
* Breakfast (per diem not used) — $18.50 — January 7th, 2026
* Uber to client office — $22.10 — January 7th, 2026
* Printing + presentation materials — $46.90 — January 8th, 2026
* Lunch with client — $39.75 — January 8th, 2026
* Office supplies (notebooks, pens) — $27.60 — January 10th, 2026
* Mileage reimbursement (client visit in NJ, 42 miles @ $0.67/mile) — $28.14 — January 14th, 2026
* Team lunch meeting (internal) — $64.30 — January 15th, 2026
Reimbursement method should be direct deposit.
Add a notes section stating: "All receipts attached. Expenses are business-related and comply with company travel policy."
```

---------

Co-authored-by: Anthony Stirling <[email protected]>
This commit is contained in:
EthanHealy01
2026-06-11 14:18:13 +00:00
committed by GitHub
co-authored by Anthony Stirling
parent 9b877d4f8d
commit 88adb7adad
20 changed files with 1828 additions and 40 deletions
@@ -14,6 +14,7 @@ export function useChat() {
toggleOpen: () => {},
setOpen: (_open: boolean) => {},
sendMessage: async (_content: string) => {},
cancelMessage: () => {},
clearChat: () => {},
};
}
@@ -370,6 +370,7 @@ interface ChatContextValue {
toggleOpen: () => void;
setOpen: (open: boolean) => void;
sendMessage: (content: string) => Promise<void>;
cancelMessage: () => void;
/** Abort any in-flight request and reset the chat to an empty conversation. */
clearChat: () => void;
}
@@ -432,32 +433,32 @@ export function ChatProvider({ children }: { children: ReactNode }) {
const files = await Promise.all(descriptors.map(downloadFile));
const operation: ToolOperation = {
toolId: "ai-workflow",
timestamp: Date.now(),
};
const isVersionMapping =
sourceStubs.length > 0 && files.length === sourceStubs.length;
const stubs = files.map((file, i) =>
isVersionMapping
? createChildStub(sourceStubs[i], operation, file)
: createNewStirlingFileStub(file),
);
const stirlingFiles = files.map((file, i) =>
createStirlingFile(file, stubs[i].id),
);
if (sourceStubs.length > 0) {
// Always consume the inputs so merge/split inputs are removed from the workbench.
// For 1:1 operations (rotate, compress) the outputs carry the version chain; for
// merge/split they're fresh roots.
const operation: ToolOperation = {
toolId: "ai-workflow",
timestamp: Date.now(),
};
const isVersionMapping = files.length === sourceStubs.length;
const stubs = files.map((file, i) =>
isVersionMapping
? createChildStub(sourceStubs[i], operation, file)
: createNewStirlingFileStub(file),
);
const stirlingFiles = files.map((file, i) =>
createStirlingFile(file, stubs[i].id),
);
await fileActions.consumeFiles(
sourceStubs.map((s) => s.id),
stirlingFiles,
stubs,
);
} else {
// No inputs were provided (unlikely for completed workflows, but handle it safely).
// No inputs: pass raw files so addFiles assigns consistent IDs. Pre-assigning stub IDs
// here would cause a fileId mismatch in filesRef, making getFiles() clone the file
// on every render and breaking useFileWithUrl's memoisation (continuous PDF reloads).
await fileActions.addFiles(files, { selectFiles: true });
}
},
@@ -469,6 +470,10 @@ export function ChatProvider({ children }: { children: ReactNode }) {
(open: boolean) => dispatch({ type: "SET_OPEN", open }),
[],
);
const cancelMessage = useCallback(() => {
abortRef.current?.abort();
}, []);
const clearChat = useCallback(() => {
abortRef.current?.abort();
abortRef.current = null;
@@ -509,7 +514,6 @@ export function ChatProvider({ children }: { children: ReactNode }) {
formData.append(`conversationHistory[${i}].role`, message.role);
formData.append(`conversationHistory[${i}].content`, message.content);
});
const response = await fetch("/api/v1/ai/orchestrate/stream", {
method: "POST",
body: formData,
@@ -652,6 +656,7 @@ export function ChatProvider({ children }: { children: ReactNode }) {
toggleOpen,
setOpen,
sendMessage,
cancelMessage,
clearChat,
}}
>
@@ -365,32 +365,32 @@ export function ChatProvider({ children }: { children: ReactNode }) {
const files = await Promise.all(descriptors.map(downloadFile));
const operation: ToolOperation = {
toolId: "ai-workflow",
timestamp: Date.now(),
};
const isVersionMapping =
sourceStubs.length > 0 && files.length === sourceStubs.length;
const stubs = files.map((file, i) =>
isVersionMapping
? createChildStub(sourceStubs[i], operation, file)
: createNewStirlingFileStub(file),
);
const stirlingFiles = files.map((file, i) =>
createStirlingFile(file, stubs[i].id),
);
if (sourceStubs.length > 0) {
// Always consume the inputs so merge/split inputs are removed from the workbench.
// For 1:1 operations (rotate, compress) the outputs carry the version chain; for
// merge/split they're fresh roots.
const operation: ToolOperation = {
toolId: "ai-workflow",
timestamp: Date.now(),
};
const isVersionMapping = files.length === sourceStubs.length;
const stubs = files.map((file, i) =>
isVersionMapping
? createChildStub(sourceStubs[i], operation, file)
: createNewStirlingFileStub(file),
);
const stirlingFiles = files.map((file, i) =>
createStirlingFile(file, stubs[i].id),
);
await fileActions.consumeFiles(
sourceStubs.map((s) => s.id),
stirlingFiles,
stubs,
);
} else {
// No inputs were provided (unlikely for completed workflows, but handle it safely).
// No inputs: pass raw files so addFiles assigns consistent IDs. Pre-assigning stub IDs
// here would cause a fileId mismatch in filesRef, making getFiles() clone the file
// on every render and breaking useFileWithUrl's memoisation (continuous PDF reloads).
await fileActions.addFiles(files, { selectFiles: true });
}
},