@opencx/mcp 1.15.28 → 1.15.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/follow-up-tools.spec.d.ts +2 -0
- package/dist/follow-up-tools.spec.d.ts.map +1 -0
- package/dist/follow-up-tools.spec.js +139 -0
- package/dist/follow-up-tools.spec.js.map +1 -0
- package/dist/phone-agent-card-spec.spec.d.ts +2 -0
- package/dist/phone-agent-card-spec.spec.d.ts.map +1 -0
- package/dist/phone-agent-card-spec.spec.js +29 -0
- package/dist/phone-agent-card-spec.spec.js.map +1 -0
- package/dist/schema.d.ts +305 -23
- package/dist/schema.d.ts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -1
- package/dist/tools/campaign-channel.d.ts.map +1 -1
- package/dist/tools/campaign-channel.js +4 -2
- package/dist/tools/campaign-channel.js.map +1 -1
- package/dist/tools/campaign-spine.d.ts.map +1 -1
- package/dist/tools/campaign-spine.js +16 -3
- package/dist/tools/campaign-spine.js.map +1 -1
- package/dist/tools/email.js +1 -1
- package/dist/tools/email.js.map +1 -1
- package/dist/tools/follow-ups.d.ts +4 -0
- package/dist/tools/follow-ups.d.ts.map +1 -0
- package/dist/tools/follow-ups.js +113 -0
- package/dist/tools/follow-ups.js.map +1 -0
- package/dist/tools/phone.d.ts.map +1 -1
- package/dist/tools/phone.js +21 -13
- package/dist/tools/phone.js.map +1 -1
- package/dist/tools/sessions.d.ts.map +1 -1
- package/dist/tools/sessions.js +10 -4
- package/dist/tools/sessions.js.map +1 -1
- package/dist/tools/whatsapp.js +1 -1
- package/dist/tools/whatsapp.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"follow-up-tools.spec.d.ts","sourceRoot":"","sources":["../src/follow-up-tools.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { connectInMemory, fetchCallUrl, toolTextResultSchema } from './spec-helpers.js';
|
|
3
|
+
import { jsonValueSchema } from './utils/json.js';
|
|
4
|
+
function mockResponse(body, status = 200, statusText = 'OK') {
|
|
5
|
+
return new Response(JSON.stringify(body), { status, statusText });
|
|
6
|
+
}
|
|
7
|
+
function recordedCall(fetchSpy) {
|
|
8
|
+
const [call] = fetchSpy.mock.calls;
|
|
9
|
+
if (!call)
|
|
10
|
+
throw new Error('fetch was not called');
|
|
11
|
+
return call;
|
|
12
|
+
}
|
|
13
|
+
function callMethod(call) {
|
|
14
|
+
const [input, init] = call;
|
|
15
|
+
if (input instanceof Request)
|
|
16
|
+
return input.method;
|
|
17
|
+
return init?.method ?? 'GET';
|
|
18
|
+
}
|
|
19
|
+
async function callBody(call) {
|
|
20
|
+
const [input, init] = call;
|
|
21
|
+
const text = input instanceof Request ? await input.clone().text() : init?.body;
|
|
22
|
+
return typeof text === 'string' && text ? jsonValueSchema.parse(JSON.parse(text)) : undefined;
|
|
23
|
+
}
|
|
24
|
+
const followUp = {
|
|
25
|
+
id: 'fu-1',
|
|
26
|
+
session_id: '11111111-1111-4111-8111-111111111111',
|
|
27
|
+
ticket_number: 42,
|
|
28
|
+
prompt: 'check the export',
|
|
29
|
+
fire_at: '2026-09-05T15:00:00.000Z',
|
|
30
|
+
is_active: true,
|
|
31
|
+
created_at: '2026-09-05T14:55:00.000Z',
|
|
32
|
+
};
|
|
33
|
+
describe('follow-up tools', () => {
|
|
34
|
+
let client;
|
|
35
|
+
let cleanup;
|
|
36
|
+
let fetchSpy;
|
|
37
|
+
beforeEach(async () => {
|
|
38
|
+
fetchSpy = vi.fn();
|
|
39
|
+
vi.stubGlobal('fetch', fetchSpy);
|
|
40
|
+
({ client, cleanup } = await connectInMemory());
|
|
41
|
+
});
|
|
42
|
+
afterEach(async () => {
|
|
43
|
+
await cleanup();
|
|
44
|
+
vi.unstubAllGlobals();
|
|
45
|
+
});
|
|
46
|
+
it('registers all three tools with session_id as a required argument', async () => {
|
|
47
|
+
const { tools } = await client.listTools();
|
|
48
|
+
const names = tools.map((t) => t.name);
|
|
49
|
+
expect(names).toEqual(expect.arrayContaining(['schedule_followup', 'list_followups', 'cancel_followup']));
|
|
50
|
+
for (const name of ['schedule_followup', 'list_followups', 'cancel_followup']) {
|
|
51
|
+
const tool = tools.find((t) => t.name === name);
|
|
52
|
+
expect(tool?.inputSchema.required, name).toContain('session_id');
|
|
53
|
+
}
|
|
54
|
+
const schedule = tools.find((t) => t.name === 'schedule_followup');
|
|
55
|
+
expect(schedule?.description).toContain('continue THIS session later');
|
|
56
|
+
expect(schedule?.description).toContain('back off (5 → 15 → 60 minutes)');
|
|
57
|
+
});
|
|
58
|
+
it('schedule_followup POSTs to the session follow-ups route with the API body shape', async () => {
|
|
59
|
+
fetchSpy.mockResolvedValueOnce(mockResponse(followUp, 201, 'Created'));
|
|
60
|
+
const result = toolTextResultSchema.parse(await client.callTool({
|
|
61
|
+
name: 'schedule_followup',
|
|
62
|
+
arguments: { session_id: followUp.session_id, delay_minutes: 5, prompt: 'check the export' },
|
|
63
|
+
}));
|
|
64
|
+
const call = recordedCall(fetchSpy);
|
|
65
|
+
expect(fetchCallUrl(call)).toBe(`https://api.test.com/chat/sessions/${followUp.session_id}/follow-ups`);
|
|
66
|
+
expect(callMethod(call)).toBe('POST');
|
|
67
|
+
expect(await callBody(call)).toEqual({ delay_minutes: 5, prompt: 'check the export' });
|
|
68
|
+
expect(result.isError).toBeUndefined();
|
|
69
|
+
expect(JSON.parse(result.content[0].text)).toEqual(followUp);
|
|
70
|
+
});
|
|
71
|
+
it('schedule_followup rejects a delay outside 1–43200 or an empty prompt before calling the API', async () => {
|
|
72
|
+
for (const args of [
|
|
73
|
+
{ session_id: 's', delay_minutes: 0, prompt: 'x' },
|
|
74
|
+
{ session_id: 's', delay_minutes: 43201, prompt: 'x' },
|
|
75
|
+
{ session_id: 's', delay_minutes: 2.5, prompt: 'x' },
|
|
76
|
+
{ session_id: 's', delay_minutes: 5, prompt: '' },
|
|
77
|
+
{ session_id: '', delay_minutes: 5, prompt: 'x' },
|
|
78
|
+
]) {
|
|
79
|
+
const result = toolTextResultSchema.parse(await client.callTool({ name: 'schedule_followup', arguments: args }));
|
|
80
|
+
expect(result.isError, JSON.stringify(args)).toBe(true);
|
|
81
|
+
}
|
|
82
|
+
expect(fetchSpy).not.toHaveBeenCalled();
|
|
83
|
+
});
|
|
84
|
+
it('schedule_followup surfaces a cap refusal (409) as a tool error the model can act on', async () => {
|
|
85
|
+
fetchSpy.mockResolvedValueOnce(mockResponse({ message: 'At most 5 pending follow-ups per session' }, 409, 'Conflict'));
|
|
86
|
+
const result = toolTextResultSchema.parse(await client.callTool({
|
|
87
|
+
name: 'schedule_followup',
|
|
88
|
+
arguments: { session_id: 's', delay_minutes: 5, prompt: 'x' },
|
|
89
|
+
}));
|
|
90
|
+
expect(result.isError).toBe(true);
|
|
91
|
+
expect(result.content[0].text).toContain('cap reached');
|
|
92
|
+
expect(result.content[0].text).toContain('At most 5 pending');
|
|
93
|
+
});
|
|
94
|
+
it('schedule_followup tells the model not to retry when the feature is off (403)', async () => {
|
|
95
|
+
fetchSpy.mockResolvedValueOnce(mockResponse({ message: 'nope' }, 403, 'Forbidden'));
|
|
96
|
+
const result = toolTextResultSchema.parse(await client.callTool({
|
|
97
|
+
name: 'schedule_followup',
|
|
98
|
+
arguments: { session_id: 's', delay_minutes: 5, prompt: 'x' },
|
|
99
|
+
}));
|
|
100
|
+
expect(result.isError).toBe(true);
|
|
101
|
+
expect(result.content[0].text).toContain('not enabled');
|
|
102
|
+
expect(result.content[0].text).toContain('do not retry');
|
|
103
|
+
});
|
|
104
|
+
it('list_followups GETs the session follow-ups route', async () => {
|
|
105
|
+
fetchSpy.mockResolvedValueOnce(mockResponse({ follow_ups: [followUp], limits: { max_active_per_session: 5, max_total_per_session: 50 } }));
|
|
106
|
+
const result = toolTextResultSchema.parse(await client.callTool({ name: 'list_followups', arguments: { session_id: 'abc' } }));
|
|
107
|
+
const call = recordedCall(fetchSpy);
|
|
108
|
+
expect(fetchCallUrl(call)).toBe('https://api.test.com/chat/sessions/abc/follow-ups');
|
|
109
|
+
expect(callMethod(call)).toBe('GET');
|
|
110
|
+
expect(JSON.parse(result.content[0].text).follow_ups).toEqual([followUp]);
|
|
111
|
+
});
|
|
112
|
+
it('cancel_followup DELETEs the follow-up route and returns the inactive follow-up', async () => {
|
|
113
|
+
fetchSpy.mockResolvedValueOnce(mockResponse({ ...followUp, is_active: false }));
|
|
114
|
+
const result = toolTextResultSchema.parse(await client.callTool({
|
|
115
|
+
name: 'cancel_followup',
|
|
116
|
+
arguments: { session_id: 'abc', follow_up_id: 'fu-1' },
|
|
117
|
+
}));
|
|
118
|
+
const call = recordedCall(fetchSpy);
|
|
119
|
+
expect(fetchCallUrl(call)).toBe('https://api.test.com/chat/sessions/abc/follow-ups/fu-1');
|
|
120
|
+
expect(callMethod(call)).toBe('DELETE');
|
|
121
|
+
expect(JSON.parse(result.content[0].text).is_active).toBe(false);
|
|
122
|
+
});
|
|
123
|
+
it('a 404 (foreign or unknown session / follow-up) is a tool error, not a crash', async () => {
|
|
124
|
+
fetchSpy.mockResolvedValueOnce(mockResponse({ message: 'Not Found' }, 404, 'Not Found'));
|
|
125
|
+
const result = toolTextResultSchema.parse(await client.callTool({
|
|
126
|
+
name: 'cancel_followup',
|
|
127
|
+
arguments: { session_id: 'abc', follow_up_id: 'nope' },
|
|
128
|
+
}));
|
|
129
|
+
expect(result.isError).toBe(true);
|
|
130
|
+
expect(result.content[0].text).toContain('No such session or follow-up');
|
|
131
|
+
});
|
|
132
|
+
it('an unexpected API failure (500) still propagates as an error result', async () => {
|
|
133
|
+
fetchSpy.mockResolvedValueOnce(mockResponse({ message: 'boom' }, 500, 'Internal Server Error'));
|
|
134
|
+
const result = toolTextResultSchema.parse(await client.callTool({ name: 'list_followups', arguments: { session_id: 'abc' } }));
|
|
135
|
+
expect(result.isError).toBe(true);
|
|
136
|
+
expect(result.content[0].text).toContain('500');
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
//# sourceMappingURL=follow-up-tools.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"follow-up-tools.spec.js","sourceRoot":"","sources":["../src/follow-up-tools.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phone-agent-card-spec.spec.d.ts","sourceRoot":"","sources":["../src/phone-agent-card-spec.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { buildPhoneAgentCardSpec } from './tools/phone.js';
|
|
3
|
+
/**
|
|
4
|
+
* The card a phone tool hands back is a ` ```spec ` fence of JSONL patch
|
|
5
|
+
* lines — the one format the widget stream, the widget's history parser, and
|
|
6
|
+
* the inbox all render. A whole-tree object would be dropped by the stream.
|
|
7
|
+
*/
|
|
8
|
+
describe('buildPhoneAgentCardSpec', () => {
|
|
9
|
+
it('emits root-first patch lines inside a spec fence', () => {
|
|
10
|
+
const fence = buildPhoneAgentCardSpec({ id: 'a1', name: 'Support line', model: 'oppie-vox-livekit' });
|
|
11
|
+
const lines = fence.split('\n');
|
|
12
|
+
expect(lines[0]).toBe('```spec');
|
|
13
|
+
expect(lines.at(-1)).toBe('```');
|
|
14
|
+
const patches = lines.slice(1, -1).map((line) => JSON.parse(line));
|
|
15
|
+
expect(patches).toEqual([
|
|
16
|
+
{ op: 'add', path: '/root', value: 'phone-agent-a1' },
|
|
17
|
+
{
|
|
18
|
+
op: 'add',
|
|
19
|
+
path: '/elements/phone-agent-a1',
|
|
20
|
+
value: {
|
|
21
|
+
type: 'PhoneAgentCard',
|
|
22
|
+
props: { agentId: 'a1', agentName: 'Support line', model: 'oppie-vox-livekit' },
|
|
23
|
+
children: [],
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
]);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=phone-agent-card-spec.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phone-agent-card-spec.spec.js","sourceRoot":"","sources":["../src/phone-agent-card-spec.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAE3D;;;;GAIG;AACH,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,KAAK,GAAG,uBAAuB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACtG,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACnE,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;YACtB,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE;YACrD;gBACE,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,0BAA0B;gBAChC,KAAK,EAAE;oBACL,IAAI,EAAE,gBAAgB;oBACtB,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,mBAAmB,EAAE;oBAC/E,QAAQ,EAAE,EAAE;iBACb;aACF;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|