toolCallDetails.test.ts5.3 KBView on GitHub /**
* `describeToolCall` — what a tool-call row says, and what it reveals when expanded.
*
* These are the labels the transcript is READ from. Before them every call into an action
* family rendered as `Executing linkedin-write`, so four invitations to four people were four
* identical lines and the transcript recorded nothing about who was contacted or whether a
* note went with it.
*/
import { describeToolCall, nameFromLinkedinSlug } from '@/modules/cedar-os/src/components/renderers/toolCallDetails';
describe('nameFromLinkedinSlug', () => {
it('reads a name out of a hyphenated slug', () => {
expect(nameFromLinkedinSlug('jason-kobs')).toBe('Jason Kobs');
});
it('drops the random discriminator LinkedIn appends to a taken handle', () => {
expect(nameFromLinkedinSlug('leo-ohaus-90b3351b0')).toBe('Leo Ohaus');
});
it('leaves an unsplittable handle alone rather than guessing word boundaries', () => {
expect(nameFromLinkedinSlug('jackbartlett13')).toBe('jackbartlett13');
});
});
describe('describeToolCall — LinkedIn', () => {
it('names the person a connection request is going to, and links their profile', () => {
const described = describeToolCall('linkedin-write', {
action: 'send-invitation',
sendInvitation: { url: 'https://www.linkedin.com/in/jason-kobs' },
});
expect(described?.label).toBe('Sending a LinkedIn connection request to Jason Kobs');
expect(described?.rows).toContainEqual({
label: 'Profile',
value: 'https://www.linkedin.com/in/jason-kobs',
href: 'https://www.linkedin.com/in/jason-kobs',
});
});
it('says out loud that an invitation carried no note', () => {
const described = describeToolCall('linkedin-write', {
action: 'send-invitation',
sendInvitation: { url: 'https://www.linkedin.com/in/jason-kobs' },
});
expect(described?.rows).toContainEqual({ label: 'Note', value: 'No note — invitation only' });
});
it('shows the note when there was one', () => {
const described = describeToolCall('linkedin-write', {
action: 'send-invitation',
sendInvitation: { url: 'https://www.linkedin.com/in/jack', note: 'Hey Jack — I work with Willem.' },
});
expect(described?.rows).toContainEqual({ label: 'Note', value: 'Hey Jack — I work with Willem.' });
});
it('does not invent a name for a member addressed only by provider id', () => {
const described = describeToolCall('linkedin-write', {
action: 'send-invitation',
sendInvitation: { providerId: 'ACoAABVHhO8B2EWRp7HE4YiPw6vI3fYjaYlOA0w' },
});
expect(described?.label).toBe('Sending a LinkedIn connection request to a LinkedIn member');
expect(described?.rows).toContainEqual({
label: 'Member id',
value: 'ACoAABVHhO8B2EWRp7HE4YiPw6vI3fYjaYlOA0w',
});
});
it('distinguishes a profile view from a connection request', () => {
expect(
describeToolCall('linkedin-read', { action: 'view-profile', viewProfile: { identifier: 'odin-hoffmann' } })?.label,
).toBe("Viewing Odin Hoffmann's LinkedIn profile");
expect(describeToolCall('linkedin-read', { action: 'list-connections' })?.label).toBe(
'Reading your LinkedIn connections',
);
});
});
describe('describeToolCall — tables', () => {
it('names the table being created and the columns it declares', () => {
const described = describeToolCall('table', {
action: 'create',
path: 'conversation/5d14874e/listen-labs-aes',
create: { schema: { columns: [{ key=[redacted], label: 'Name' }, { key=[redacted], label: 'Connection Status' }] } },
});
expect(described?.label).toBe('Creating the table listen-labs-aes');
expect(described?.rows).toContainEqual({ label: 'Columns', value: 'Name, Connection Status' });
});
it('counts the cells a set writes, and previews them', () => {
const described = describeToolCall('table', {
action: 'set',
path: 'conversation/5d14874e/listen-labs-aes',
set: { assignments: 'jack.status = reached out\njason.status = reached out' },
});
expect(described?.label).toBe('Filling in 2 cells in listen-labs-aes');
expect(described?.rows).toContainEqual({
label: 'Changes',
value: 'jack.status = reached out\njason.status = reached out',
});
});
it("surfaces a select column's option ORDER, which is also its sort order", () => {
const described = describeToolCall('table', {
action: 'add_columns',
path: '#kb/aes',
add_columns: {
columns: [
{ key=[redacted], label: 'Connection Status', type: 'select', options: ['not connected', 'reached out', 'connected'] },
],
},
});
expect(described?.label).toBe('Adding the Connection Status column in aes');
expect(described?.rows).toContainEqual({
label: 'Connection Status',
value: 'not connected → reached out → connected',
});
});
});
describe('describeToolCall — the generic tail', () => {
it('names the action of a family it has no specific branch for', () => {
expect(describeToolCall('conversation-write', { action: 'update-fields' })?.label).toBe(
'Conversation write · Update fields',
);
});
it('defers to the static mapping when the args say nothing', () => {
expect(describeToolCall('find-emails', {})).toBeNull();
});
});