Skip to content

Instantly share code, notes, and snippets.

@ezzabuzaid
Last active October 13, 2025 20:01
Show Gist options
  • Save ezzabuzaid/ace0d1f7559514cd82b61f3620083063 to your computer and use it in GitHub Desktop.
Save ezzabuzaid/ace0d1f7559514cd82b61f3620083063 to your computer and use it in GitHub Desktop.
import { groq } from '@ai-sdk/groq';
import { openai } from '@ai-sdk/openai';
import { readFile, writeFile } from 'node:fs/promises';
import z from 'zod';
import { agent, execute, toOutput } from '@deepagents/agent';
import { fastembed, nodeSQLite, similaritySearch } from '@deepagents/retrieval';
import * as connectors from '@deepagents/retrieval/connectors';
const searchQueryAgent = agent({
name: 'search-query-generator',
model: groq('openai/gpt-oss-20b'),
prompt: [
`You are an expert research assistant. Given the user's query, generate up to four distinct precise search queries that would help gather comprehensive information from github repository content.`,
`The repository is a codebase for a web application that is stored in a vector database for semantic search. The content includes code files, documentation, and comments.`,
'Your goal is to create search queries that will yield relevant and diverse results to help answer the user query thoroughly.',
],
output: z.object({ items: z.array(z.string()).max(4) }),
});
const newSearchQueriesAgent = agent({
name: 'research-continuation-planner',
model: groq('openai/gpt-oss-120b'),
prompt:
'You are an analytical research assistant. Based on the original query, the search queries performed so far, and the extracted contexts, determine if further research is needed.',
output: z.object({
needsMoreResearch: z
.boolean()
.describe('Whether additional research is needed'),
newQueries: z
.array(z.string())
.max(4)
.describe(
'Up to four new search queries if more research is needed, empty array otherwise',
),
reasoning: z
.string()
.optional()
.describe('Brief explanation of the decision'),
}),
});
const pageUsefulnessAgent = agent({
name: 'page-usefulness-evaluator',
model: groq('openai/gpt-oss-20b'),
prompt: [
'You are a strict and concise evaluator of research relevance.',
"Given the user's query and the content of a repository file, determine if the file contains information relevant and useful for addressing the query.",
"Respond with exactly one word: 'Yes' if the file is useful, or 'No' if it is not.",
],
output: z.object({ answer: z.enum(['Yes', 'No']) }),
});
const extractRelevantContextAgent = agent({
name: 'relevant-context-extractor',
model: groq('openai/gpt-oss-20b'),
prompt: [
'You are an expert in extracting and summarizing relevant information.',
"Given the user's query, the search query that led to this page, and the file content, extract all pieces of information that are relevant to answering the user's query.",
'Return only the relevant context as plain text without commentary.',
],
output: z.object({ context: z.string() }),
});
const finalReportAgent = agent({
name: 'final-report-writer',
model: openai('gpt-4.1'),
prompt: `You are an expert product manager that is working on reversing existing product to user stories based on a developer question/inquiry. Based on the gathered contexts below and the original query, write a comprehensive, well-structured, and detailed report that addresses the query thoroughly.\nInclude all relevant insights and conclusions without extraneous commentary.`,
});
async function generateSearchQueries(input: string): Promise<string[]> {
const output = await toOutput<{ items: string[] }>(
execute(searchQueryAgent, input, {}),
);
return output.items;
}
async function performSearch(query: string) {
const results = await similaritySearch(query, {
connector: connectors.repo(
'/Users/ezzabuzaid/Desktop/mo/virtual-care',
['.ts', '.tsx', '.md', '.prisma'],
'never',
),
store: nodeSQLite('deepsearch.sqlite', 384),
embedder: fastembed(),
});
return results.map((it) => ({
snippet: it.content,
source: it.document_id,
similarity: it.similarity,
}));
}
export async function getNewSearchQueries(
userQuery: string,
previousSearchQueries: string[],
allContexts: string[],
): Promise<string[]> {
const contextCombined = allContexts.join('\n\n');
const prompt = `User Query: ${userQuery}
Previous Search Queries: ${JSON.stringify(previousSearchQueries)}
Extracted Relevant Contexts:
${contextCombined}
Based on the above information, determine if further research is needed. If yes, provide up to four new search queries. If the research is complete and sufficient, indicate that no more research is needed.`;
try {
const output = await toOutput<{
needsMoreResearch: boolean;
newQueries: string[];
reasoning?: string;
}>(execute(newSearchQueriesAgent, prompt, {}));
if (!output.needsMoreResearch) {
console.log(
'Research assessment: No further research needed.',
output.reasoning,
);
return [];
}
console.log(
`Research assessment: ${output.newQueries.length} new queries generated.`,
output.reasoning,
);
return output.newQueries;
} catch (error) {
console.error('Error generating new search queries:', error);
return [];
}
}
export async function generateFinalReport(
userQuery: string,
formatting: string,
allContexts: string[],
): Promise<string> {
const contextCombined = allContexts.join('\n\n');
const prompt = `
Developer Query: ${userQuery}
Formatting: ${formatting}
Gathered Relevant Contexts:
${contextCombined}`;
return execute(finalReportAgent, prompt, {}).text;
}
async function isPageUseful(userQuery: string, pageText: string) {
const prompt = `User Query: ${userQuery}\n\nRepo file content\n\n${pageText}\n\nDecide if the page is useful.`;
const { answer } = await toOutput<{ answer: 'Yes' | 'No' }>(
execute(pageUsefulnessAgent, prompt, {} as const),
);
return answer === 'Yes';
}
async function extractRelevantContext(
userQuery: string,
searchQuery: string,
pageText: string,
): Promise<string> {
const prompt = `User Query: ${userQuery}\nSearch Query: ${searchQuery}\n\nRepo file content\n\n${pageText}\n\nExtract the relevant context.`;
const { context } = await toOutput<{ context: string }>(
execute(extractRelevantContextAgent, prompt, {} as const),
);
return context.trim();
}
async function processFile(
filePath: string,
userQuery: string,
searchQuery: string,
) {
const content = await readFile(filePath, 'utf-8');
// const useful = await isPageUseful(userQuery, content);
// return extractRelevantContext(userQuery, searchQuery, content);
// if (useful) {
// return extractRelevantContext(userQuery, searchQuery, content);
// }
// return '';
return {source:filePath,content};
}
const userQuery =
'How does the b2b works here? we recently added it but I need to understand the full flow and how it integrates with the rest of the system including payment.';
const formatting = `
1. use ascii markdown diagrams to illustrate. I am visual learner and I love markdown.
2. use "user stories" to illustrate flows. we are not looking for only text or techical explanation.
3. user story scenario should be divided by actors and steps.
4. when referencing code snippets, include file path.
`;
const iterLimit = 5;
const aggregatedContexts: string[] = [];
const allSearchQueries = [];
let iteration = 0;
let searchQueriesResult = await generateSearchQueries(userQuery);
while (iteration < iterLimit) {
const uniqueLinks: Record<string, string> = {};
const iterationContexts: string[] = [];
allSearchQueries.push(...searchQueriesResult);
const searchResults: Awaited<ReturnType<typeof performSearch>>[] = [];
for (const sq of searchQueriesResult) {
const results = await performSearch(sq);
searchResults.push(results);
}
for (let i = 0; i < searchResults.length; i++) {
const query = searchQueriesResult[i];
for (const result of searchResults[i]) {
if (!uniqueLinks[result.source]) {
uniqueLinks[result.source] = query;
}
}
}
await Promise.all(
Object.entries(uniqueLinks).map(async ([link, query]) => {
const context = await processFile(link, userQuery, query);
if (context) {
iterationContexts.push(`Source: ${context.source}\n\nContent: ${context.content}\n\n`);
}
}),
);
// for (const link in uniqueLinks) {
// const context = await processFile(link, userQuery, uniqueLinks[link]);
// if (!context) continue;
// iterationContexts.push(context);
// }
if (iterationContexts.length === 0) {
console.log('No useful contexts were found in this iteration.');
} else {
aggregatedContexts.push(...iterationContexts);
}
console.dir(uniqueLinks, { depth: null });
searchQueriesResult = await getNewSearchQueries(
userQuery,
allSearchQueries,
aggregatedContexts,
);
if (searchQueriesResult.length === 0) {
console.log('No further research needed. Exiting loop.');
break;
} else {
allSearchQueries.push(...searchQueriesResult);
}
iteration += 1;
}
console.log('\nGenerating final report...');
console.log('Search queries performed:', allSearchQueries);
const finalReport = await generateFinalReport(
userQuery,
formatting,
aggregatedContexts,
);
await writeFile('final_report.md', finalReport);

B2B Flow in Virtual Care Platform: User Stories & Integration

Overview

The B2B (Business-to-Business) feature allows organizations to register patients under their entity, manage their usage limits, and enable them to book appointments without direct payment (or with special payment handling). This report details the B2B flow, its integration with the rest of the system, and the payment process, using user stories and ASCII diagrams.


1. Actors

  • Coordinator: Admin user who creates and manages B2B patients.
  • B2B Patient: End-user registered under a business entity.
  • System: Backend and frontend services.
  • Doctor: Healthcare provider.
  • Payment Gateway: Handles payment processing (e.g., Moyasar).

2. High-Level Flow Diagram

+----------------+         +----------------+         +------------------+
|  Coordinator   |         |    System      |         |   B2B Patient    |
+----------------+         +----------------+         +------------------+
        |                          |                           |
        |---[1. Create B2B Patient]|                           |
        |------------------------->|                           |
        |                          |---[2. Send Credentials]-->| 
        |                          |                           |
        |                          |<--[3. Login/Access]-------|
        |                          |                           |
        |                          |---[4. Book Appointment]-->| 
        |                          |                           |
        |                          |---[5. Payment Handling]-->| 
        |                          |                           |
        |                          |---[6. Usage Limit Check]--|
        |                          |                           |
        |                          |---[7. Appointment Flow]-->| 
        |                          |                           |

3. User Stories & Scenarios

3.1. Coordinator: Create B2B Patient

Goal: Register a new B2B patient with a usage limit.

Steps

  1. Coordinator navigates to the B2B patient management page.
  2. Coordinator fills in patient details: name, email, phone, usage limit.
  3. Coordinator submits the form.
  4. System validates input (/packages/client/src/inputs/btob-patients.ts).
  5. System creates the B2B patient and generates credentials (/packages/client/src/outputs/create-b2-b-patient.ts).
  6. System returns credentials to the coordinator.
Coordinator
    |
    |--[Fill B2B Patient Form]--> System
    |<--[Validation/Success]-----|
    |--[Receive Credentials]-----|

User Story

As a coordinator, I want to create a B2B patient with a usage limit so that the organization can control the number of appointments the patient can book.


3.2. B2B Patient: Login and Access

Goal: Access the platform using credentials.

Steps

  1. B2B Patient receives credentials.
  2. B2B Patient logs in via the platform.
  3. System authenticates and identifies user as userType: 'B2B'.
B2B Patient
    |
    |--[Login with Credentials]--> System
    |<--[Authenticated Session]---|

User Story

As a B2B patient, I want to log in using my credentials so I can access the platform and book appointments.


3.3. B2B Patient: Book Appointment

Goal: Book an appointment using the organization's quota.

Steps

  1. B2B Patient navigates to appointment booking.
  2. System identifies user as B2B and displays available specialties.
  3. B2B Patient selects a specialty and time slot.
  4. System checks usage limit (usageLimit in /packages/client/src/outputs/get-b2-b-patient.ts).
  5. If usage limit > 0: Allow booking.
  6. If usage limit == 0: Show error, block booking.
B2B Patient
    |
    |--[Book Appointment]--------> System
    |--[Select Specialty/Time]--->|
    |<--[Check Usage Limit]-------|
    |   |--[usageLimit > 0]------>|
    |   |<--[Allow Booking]-------|
    |   |--[usageLimit == 0]----->|
    |   |<--[Block Booking]-------|

User Story

As a B2B patient, I want to book an appointment using my organization's quota, so I don't have to pay directly.


3.4. System: Payment Handling for B2B

Goal: Integrate payment logic for B2B patients.

Steps

  1. System detects userType: 'B2B' during booking.
  2. System skips or customizes payment step (e.g., no payment, or internal billing).
  3. System decrements usageLimit after successful booking.
  4. System records the appointment.
System
    |
    |--[Detect B2B User]----------|
    |--[Skip/Customize Payment]---|
    |--[Decrement usageLimit]-----|
    |--[Record Appointment]-------|

User Story

As a system, I want to handle payment differently for B2B patients so that they are not charged directly, and their usage is tracked against their quota.


3.5. B2B Patient: View Usage Limit

Goal: See remaining quota.

Steps

  1. B2B Patient views profile.
  2. System displays usageLimit and organization name (/apps/patients/src/app/components/header/profile-card.tsx).
B2B Patient
    |
    |--[View Profile]------------> System
    |<--[Show usageLimit/org]-----|

User Story

As a B2B patient, I want to see my remaining usage limit so I know how many appointments I can still book.


3.6. Coordinator: List and Manage B2B Patients

Goal: View and manage all B2B patients.

Steps

  1. Coordinator lists B2B patients (/packages/client/src/outputs/list-b2-b-patients.ts).
  2. Coordinator can search, sort, and paginate.
  3. Coordinator can update or delete B2B patients.
Coordinator
    |
    |--[List/Search/Sort]--------> System
    |<--[Paginated Results]-------|
    |--[Update/Delete]----------->|
    |<--[Success/Error]-----------|

User Story

As a coordinator, I want to view, search, and manage B2B patients so I can maintain accurate records and control access.


4. Payment Integration Details

4.1. Payment API

  • File: /packages/client/src/api/payments.ts
  • Schema: /packages/client/src/inputs/payments.ts
  • B2B Logic: For B2B, the payment step is either skipped or handled via internal billing (not via the public payment API).

4.2. Payment UI

  • Component: /apps/patients/src/app/components/booking/payment-card.tsx
  • Logic: If userType !== 'B2B', show payment details. For B2B, this is hidden or replaced with a message.
if (identity.userType !== 'B2B') {
    show <PriceLine value={fee} />
} else {
    // Hide or show "Paid by organization"
}

4.3. Usage Limit Enforcement

  • On Booking: Before confirming, system checks usageLimit.
  • On Success: Decrement usageLimit for the B2B patient.
  • On Failure: Block booking and show error.

5. Integration with the Rest of the System

  • User Type Propagation: userType: 'B2B' is set at login and used throughout the app to control UI and logic.
  • Profile Card: Shows organization and usage limit for B2B users.
  • Booking Flow: Payment and quota logic branches based on user type.
  • Coordinator Tools: CRUD for B2B patients, usage tracking.

6. Example: Booking Flow (B2B vs B2C)

+-------------------+      +-------------------+      +-------------------+
|   B2C Patient     |      |   System          |      |   Payment Gateway |
+-------------------+      +-------------------+      +-------------------+
        |                          |                           |
        |--[Book Appointment]----->|                           |
        |                          |--[Show Payment UI]------->|
        |                          |<--[Process Payment]-------|
        |<--[Booking Confirmed]----|                           |

+-------------------+      +-------------------+      +-------------------+
|   B2B Patient     |      |   System          |      |   Payment Gateway |
+-------------------+      +-------------------+      +-------------------+
        |                          |                           |
        |--[Book Appointment]----->|                           |
        |                          |--[Check usageLimit]-------|
        |                          |--[Skip Payment UI]--------|
        |                          |--[Decrement usageLimit]---|
        |<--[Booking Confirmed]----|                           |

7. Key Code References

  • B2B Patient Creation:
    /packages/client/src/inputs/btob-patients.ts
    /packages/client/src/outputs/create-b2-b-patient.ts

  • B2B Patient Listing:
    /packages/client/src/outputs/list-b2-b-patients.ts

  • Profile Card (UI):
    /apps/patients/src/app/components/header/profile-card.tsx

  • Payment Handling:
    /apps/patients/src/app/components/booking/payment-card.tsx
    /apps/patients/src/app/hooks/use-payment-info.ts

  • Booking Flow:
    /apps/patients/src/app/routes/booking/book-appointment.tsx
    /apps/patients/src/app/components/booking/specialty-selection-card.tsx


8. Summary Table

Actor Action System Behavior (B2B) Payment Handling Usage Limit
Coordinator Create B2B Patient Registers, sets usage limit N/A Set
B2B Patient Book Appointment Checks usage, skips payment Skipped/Custom Decrement
B2B Patient View Profile Shows org & usage limit N/A Display
Coordinator List/Manage Patients CRUD, search, paginate N/A Manage

9. Conclusion

The B2B flow is tightly integrated into the Virtual Care platform, affecting authentication, booking, payment, and user management. The system uses the userType field to branch logic and UI, ensuring B2B patients are handled according to their organization's agreement, with usage limits enforced and payment steps customized or skipped.


End of Report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment