This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
import {
|
||||
accounts,
|
||||
allocations,
|
||||
capacityCommitments,
|
||||
contacts,
|
||||
contractObligations,
|
||||
contracts,
|
||||
demandDeals,
|
||||
slaMetricTargets,
|
||||
slaTerms,
|
||||
supplyDeals,
|
||||
type Database,
|
||||
} from '@pig/db';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { z } from 'zod';
|
||||
import type { PiggyChatContext } from './chat';
|
||||
import { defineTool, type AgentTool } from './provider';
|
||||
|
||||
const noInput = z.object({}).strict();
|
||||
|
||||
/** Interactive chat gets one record-scoped read tool and no ambient access. */
|
||||
export function createInteractivePigTools(
|
||||
db: Database,
|
||||
context: PiggyChatContext | undefined,
|
||||
): AgentTool[] {
|
||||
if (!context) {
|
||||
return [
|
||||
defineTool({
|
||||
name: 'pig_get_workspace_summary',
|
||||
description:
|
||||
'Read a bounded summary of the PIG workspace: active deals, commitments, allocations ' +
|
||||
'and contracts. This cannot inspect the filesystem or external systems.',
|
||||
inputSchema: noInput,
|
||||
execute: async () => readWorkspaceSummary(db),
|
||||
}),
|
||||
];
|
||||
}
|
||||
return [
|
||||
defineTool({
|
||||
name: 'pig_get_record',
|
||||
description:
|
||||
'Read the PIG record currently in focus and its directly related commercial data. ' +
|
||||
'This tool accepts no id and cannot inspect a different record.',
|
||||
inputSchema: noInput,
|
||||
execute: async () => readFocusedRecord(db, context),
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
async function readWorkspaceSummary(db: Database): Promise<unknown> {
|
||||
const [demand, supply, commitments, reservations, paperwork] = await Promise.all([
|
||||
db.select().from(demandDeals).limit(100),
|
||||
db.select().from(supplyDeals).limit(100),
|
||||
db.select().from(capacityCommitments).limit(100),
|
||||
db.select().from(allocations).limit(200),
|
||||
db.select().from(contracts).limit(100),
|
||||
]);
|
||||
return {
|
||||
demandDeals: demand,
|
||||
supplyDeals: supply,
|
||||
capacityCommitments: commitments,
|
||||
allocations: reservations,
|
||||
contracts: paperwork,
|
||||
truncated: {
|
||||
demandDeals: demand.length === 100,
|
||||
supplyDeals: supply.length === 100,
|
||||
capacityCommitments: commitments.length === 100,
|
||||
allocations: reservations.length === 200,
|
||||
contracts: paperwork.length === 100,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function readFocusedRecord(db: Database, context: PiggyChatContext): Promise<unknown> {
|
||||
if (context.type === 'account') {
|
||||
const [account] = await db.select().from(accounts).where(eq(accounts.id, context.id)).limit(1);
|
||||
if (!account) throw new Error('The account in focus no longer exists.');
|
||||
const [people, demand, supply, paperwork] = await Promise.all([
|
||||
db.select().from(contacts).where(eq(contacts.accountId, context.id)).limit(100),
|
||||
db.select().from(demandDeals).where(eq(demandDeals.accountId, context.id)).limit(100),
|
||||
db.select().from(supplyDeals).where(eq(supplyDeals.accountId, context.id)).limit(100),
|
||||
db.select().from(contracts).where(eq(contracts.accountId, context.id)).limit(100),
|
||||
]);
|
||||
return { account, contacts: people, demandDeals: demand, supplyDeals: supply, contracts: paperwork };
|
||||
}
|
||||
|
||||
if (context.type === 'contact') {
|
||||
const [contact] = await db.select().from(contacts).where(eq(contacts.id, context.id)).limit(1);
|
||||
if (!contact) throw new Error('The contact in focus no longer exists.');
|
||||
const [account] = contact.accountId
|
||||
? await db.select().from(accounts).where(eq(accounts.id, contact.accountId)).limit(1)
|
||||
: [];
|
||||
return { contact, account: account ?? null };
|
||||
}
|
||||
|
||||
if (context.type === 'demand_deal') {
|
||||
const [deal] = await db.select().from(demandDeals).where(eq(demandDeals.id, context.id)).limit(1);
|
||||
if (!deal) throw new Error('The demand deal in focus no longer exists.');
|
||||
const [account] = await db.select().from(accounts).where(eq(accounts.id, deal.accountId)).limit(1);
|
||||
const reservations = await db
|
||||
.select()
|
||||
.from(allocations)
|
||||
.where(eq(allocations.demandDealId, deal.id))
|
||||
.limit(100);
|
||||
return { deal, account: account ?? null, allocations: reservations };
|
||||
}
|
||||
|
||||
if (context.type === 'supply_deal') {
|
||||
const [deal] = await db.select().from(supplyDeals).where(eq(supplyDeals.id, context.id)).limit(1);
|
||||
if (!deal) throw new Error('The supply deal in focus no longer exists.');
|
||||
const [account] = await db.select().from(accounts).where(eq(accounts.id, deal.accountId)).limit(1);
|
||||
const commitments = await db
|
||||
.select()
|
||||
.from(capacityCommitments)
|
||||
.where(eq(capacityCommitments.supplyDealId, deal.id))
|
||||
.limit(100);
|
||||
return { deal, account: account ?? null, commitments };
|
||||
}
|
||||
|
||||
if (context.type === 'commitment') {
|
||||
const [commitment] = await db
|
||||
.select()
|
||||
.from(capacityCommitments)
|
||||
.where(eq(capacityCommitments.id, context.id))
|
||||
.limit(1);
|
||||
if (!commitment) throw new Error('The capacity commitment in focus no longer exists.');
|
||||
const reservations = await db
|
||||
.select()
|
||||
.from(allocations)
|
||||
.where(eq(allocations.capacityCommitmentId, commitment.id))
|
||||
.limit(100);
|
||||
return { commitment, allocations: reservations };
|
||||
}
|
||||
|
||||
const [contract] = await db.select().from(contracts).where(eq(contracts.id, context.id)).limit(1);
|
||||
if (!contract) throw new Error('The contract in focus no longer exists.');
|
||||
const [serviceLevels, obligations] = await Promise.all([
|
||||
db.select().from(slaTerms).where(eq(slaTerms.contractId, contract.id)).limit(10),
|
||||
db
|
||||
.select()
|
||||
.from(contractObligations)
|
||||
.where(eq(contractObligations.contractId, contract.id))
|
||||
.limit(100),
|
||||
]);
|
||||
const metrics = serviceLevels[0]
|
||||
? await db
|
||||
.select()
|
||||
.from(slaMetricTargets)
|
||||
.where(eq(slaMetricTargets.slaTermId, serviceLevels[0].id))
|
||||
.limit(100)
|
||||
: [];
|
||||
return { contract, slaTerms: serviceLevels, slaMetricTargets: metrics, obligations };
|
||||
}
|
||||
Reference in New Issue
Block a user